Skip to content

Commit b4bc3d2

Browse files
authored
Adding User Management utils, including Custom Claims in the auth package. (#42)
Adding the user management go SDK. This includes the customClaims and the iterator over all users. (as well as Create, Update, Delete User, and GetUser (by UID, Phone or Email)) Proposal : go/firebase-go-user-mgt Code snippets: https://firebase-dot-devsite.googleplex.com/docs/auth/admin/manage-users https://firebase-dot-devsite.googleplex.com/docs/auth/admin/custom-claims TODO: clean up the case of an http.DefaultClient when there are no options.
1 parent 8265adf commit b4bc3d2

File tree

14 files changed

+1923
-52
lines changed

14 files changed

+1923
-52
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
testdata/integration_*
2+
.vscode/*

auth/auth.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ import (
2222
"encoding/pem"
2323
"errors"
2424
"fmt"
25+
"net/http"
2526
"strings"
2627

2728
"firebase.google.com/go/internal"
2829
"golang.org/x/net/context"
30+
"google.golang.org/api/transport"
2931
)
3032

3133
const firebaseAudience = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
3234
const googleCertURL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"
35+
const idToolKitURL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/"
3336
const issuerPrefix = "https://securetoken.google.com/"
3437
const tokenExpSeconds = 3600
3538

@@ -60,9 +63,11 @@ type Token struct {
6063
// Client facilitates generating custom JWT tokens for Firebase clients, and verifying ID tokens issued
6164
// by Firebase backend services.
6265
type Client struct {
66+
hc *internal.HTTPClient
6367
ks keySource
6468
projectID string
6569
snr signer
70+
url string
6671
}
6772

6873
type signer interface {
@@ -105,19 +110,41 @@ func NewClient(ctx context.Context, c *internal.AuthConfig) (*Client, error) {
105110
return nil, err
106111
}
107112
}
108-
109-
ks, err := newHTTPKeySource(ctx, googleCertURL, c.Opts...)
113+
hc := http.DefaultClient
114+
if len(c.Opts) > 0 { // TODO: fix the default when len = 0
115+
hc, _, err = transport.NewHTTPClient(ctx, c.Opts...)
116+
if err != nil {
117+
return nil, err
118+
}
119+
}
120+
ks, err := newHTTPKeySource(googleCertURL, hc)
110121
if err != nil {
111122
return nil, err
112123
}
113124

114125
return &Client{
126+
hc: &internal.HTTPClient{Client: hc},
115127
ks: ks,
116128
projectID: c.ProjectID,
117129
snr: snr,
130+
url: idToolKitURL,
118131
}, nil
119132
}
120133

134+
// Passes the request struct, returns a byte array of the json
135+
func (c *Client) makeHTTPCall(ctx context.Context, serviceName string, payload interface{}, result interface{}) error {
136+
request := &internal.Request{
137+
Method: "POST",
138+
URL: c.url + serviceName,
139+
Body: internal.NewJSONEntity(payload),
140+
}
141+
resp, err := c.hc.Do(ctx, request)
142+
if err != nil {
143+
return err
144+
}
145+
return resp.Unmarshal(200, result)
146+
}
147+
121148
// CustomToken creates a signed custom authentication token with the specified user ID. The resulting
122149
// JWT can be used in a Firebase client SDK to trigger an authentication flow. See
123150
// https://firebase.google.com/docs/auth/admin/create-custom-tokens#sign_in_using_custom_tokens_on_clients

auth/auth_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ func TestMain(m *testing.M) {
4646
ctx context.Context
4747
creds *google.DefaultCredentials
4848
)
49-
5049
if appengine.IsDevAppServer() {
5150
aectx, aedone, err := aetest.NewContext()
5251
if err != nil {
@@ -61,16 +60,17 @@ func TestMain(m *testing.M) {
6160
}
6261
} else {
6362
ctx = context.Background()
64-
creds, err = transport.Creds(ctx, option.WithCredentialsFile("../testdata/service_account.json"))
63+
opt := option.WithCredentialsFile("../testdata/service_account.json")
64+
creds, err = transport.Creds(ctx, opt)
6565
if err != nil {
6666
log.Fatalln(err)
6767
}
6868

6969
ks = &fileKeySource{FilePath: "../testdata/public_certs.json"}
7070
}
71-
7271
client, err = NewClient(ctx, &internal.AuthConfig{
7372
Creds: creds,
73+
Opts: []option.ClientOption{option.WithCredentialsFile("../testdata/service_account.json")},
7474
ProjectID: "mock-project-id",
7575
})
7676
if err != nil {
@@ -88,7 +88,7 @@ func TestNewClientInvalidCredentials(t *testing.T) {
8888
}
8989
conf := &internal.AuthConfig{Creds: creds}
9090
if c, err := NewClient(context.Background(), conf); c != nil || err == nil {
91-
t.Errorf("NewCient() = (%v,%v); want = (nil, error)", c, err)
91+
t.Errorf("NewClient() = (%v,%v); want = (nil, error)", c, err)
9292
}
9393
}
9494

@@ -104,7 +104,7 @@ func TestNewClientInvalidPrivateKey(t *testing.T) {
104104
creds := &google.DefaultCredentials{JSON: b}
105105
conf := &internal.AuthConfig{Creds: creds}
106106
if c, err := NewClient(context.Background(), conf); c != nil || err == nil {
107-
t.Errorf("NewCient() = (%v,%v); want = (nil, error)", c, err)
107+
t.Errorf("NewClient() = (%v,%v); want = (nil, error)", c, err)
108108
}
109109
}
110110

@@ -325,8 +325,8 @@ type mockKeySource struct {
325325
err error
326326
}
327327

328-
func (t *mockKeySource) Keys() ([]*publicKey, error) {
329-
return t.keys, t.err
328+
func (k *mockKeySource) Keys() ([]*publicKey, error) {
329+
return k.keys, k.err
330330
}
331331

332332
// fileKeySource loads a set of public keys from the local file system.

auth/crypto.go

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ import (
3030
"strings"
3131
"sync"
3232
"time"
33-
34-
"golang.org/x/net/context"
35-
36-
"google.golang.org/api/option"
37-
"google.golang.org/api/transport"
3833
)
3934

4035
// publicKey represents a parsed RSA public key along with its unique key ID.
@@ -80,18 +75,7 @@ type httpKeySource struct {
8075
Mutex *sync.Mutex
8176
}
8277

83-
func newHTTPKeySource(ctx context.Context, uri string, opts ...option.ClientOption) (*httpKeySource, error) {
84-
var hc *http.Client
85-
if ctx != nil && len(opts) > 0 {
86-
var err error
87-
hc, _, err = transport.NewHTTPClient(ctx, opts...)
88-
if err != nil {
89-
return nil, err
90-
}
91-
} else {
92-
hc = http.DefaultClient
93-
}
94-
78+
func newHTTPKeySource(uri string, hc *http.Client) (*httpKeySource, error) {
9579
return &httpKeySource{
9680
KeyURI: uri,
9781
HTTPClient: hc,

auth/crypto_test.go

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ import (
2222
"net/http"
2323
"testing"
2424
"time"
25-
26-
"golang.org/x/net/context"
27-
28-
"google.golang.org/api/option"
2925
)
3026

3127
type mockHTTPResponse struct {
@@ -43,7 +39,7 @@ type mockReadCloser struct {
4339
closeCount int
4440
}
4541

46-
func newHTTPClient(data []byte) (*http.Client, *mockReadCloser) {
42+
func newTestHTTPClient(data []byte) (*http.Client, *mockReadCloser) {
4743
rc := &mockReadCloser{
4844
data: string(data),
4945
closeCount: 0,
@@ -87,16 +83,15 @@ func TestHTTPKeySource(t *testing.T) {
8783
if err != nil {
8884
t.Fatal(err)
8985
}
90-
91-
ks, err := newHTTPKeySource(context.Background(), "http://mock.url")
86+
ks, err := newHTTPKeySource("http://mock.url", http.DefaultClient)
9287
if err != nil {
9388
t.Fatal(err)
9489
}
9590

9691
if ks.HTTPClient == nil {
9792
t.Errorf("HTTPClient = nil; want non-nil")
9893
}
99-
hc, rc := newHTTPClient(data)
94+
hc, rc := newTestHTTPClient(data)
10095
ks.HTTPClient = hc
10196
if err := verifyHTTPKeySource(ks, rc); err != nil {
10297
t.Fatal(err)
@@ -109,8 +104,8 @@ func TestHTTPKeySourceWithClient(t *testing.T) {
109104
t.Fatal(err)
110105
}
111106

112-
hc, rc := newHTTPClient(data)
113-
ks, err := newHTTPKeySource(context.Background(), "http://mock.url", option.WithHTTPClient(hc))
107+
hc, rc := newTestHTTPClient(data)
108+
ks, err := newHTTPKeySource("http://mock.url", hc)
114109
if err != nil {
115110
t.Fatal(err)
116111
}
@@ -124,8 +119,8 @@ func TestHTTPKeySourceWithClient(t *testing.T) {
124119
}
125120

126121
func TestHTTPKeySourceEmptyResponse(t *testing.T) {
127-
hc, _ := newHTTPClient([]byte(""))
128-
ks, err := newHTTPKeySource(context.Background(), "http://mock.url", option.WithHTTPClient(hc))
122+
hc, _ := newTestHTTPClient([]byte(""))
123+
ks, err := newHTTPKeySource("http://mock.url", hc)
129124
if err != nil {
130125
t.Fatal(err)
131126
}
@@ -136,8 +131,8 @@ func TestHTTPKeySourceEmptyResponse(t *testing.T) {
136131
}
137132

138133
func TestHTTPKeySourceIncorrectResponse(t *testing.T) {
139-
hc, _ := newHTTPClient([]byte("{\"foo\": 1}"))
140-
ks, err := newHTTPKeySource(context.Background(), "http://mock.url", option.WithHTTPClient(hc))
134+
hc, _ := newTestHTTPClient([]byte("{\"foo\": 1}"))
135+
ks, err := newHTTPKeySource("http://mock.url", hc)
141136
if err != nil {
142137
t.Fatal(err)
143138
}
@@ -153,7 +148,7 @@ func TestHTTPKeySourceTransportError(t *testing.T) {
153148
Err: errors.New("transport error"),
154149
},
155150
}
156-
ks, err := newHTTPKeySource(context.Background(), "http://mock.url", option.WithHTTPClient(hc))
151+
ks, err := newHTTPKeySource("http://mock.url", hc)
157152
if err != nil {
158153
t.Fatal(err)
159154
}

0 commit comments

Comments
 (0)