Skip to content

Commit 02cde4f

Browse files
Merge dev into master
2 parents 928b104 + 6c768ee commit 02cde4f

File tree

13 files changed

+253
-60
lines changed

13 files changed

+253
-60
lines changed

.github/workflows/nightly.yml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Copyright 2021 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: Nightly Builds
16+
17+
on:
18+
# Runs every day at 06:30 AM (PT) and 08:30 PM (PT) / 04:30 AM (UTC) and 02:30 PM (UTC)
19+
# or on 'firebase_nightly_build' repository dispatch event.
20+
schedule:
21+
- cron: "30 4,14 * * *"
22+
repository_dispatch:
23+
types: [firebase_nightly_build]
24+
25+
jobs:
26+
nightly:
27+
28+
runs-on: ubuntu-latest
29+
30+
steps:
31+
- name: Set up Go
32+
uses: actions/setup-go@v1
33+
with:
34+
go-version: 1.12
35+
36+
- name: Install golint
37+
run: go get golang.org/x/lint/golint
38+
39+
- name: Check out code
40+
uses: actions/checkout@v2
41+
with:
42+
ref: ${{ github.event.client_payload.ref || github.ref }}
43+
44+
- name: Run Linter
45+
run: |
46+
GOLINT=`go list -f {{.Target}} golang.org/x/lint/golint`
47+
$GOLINT -set_exit_status ./...
48+
49+
- name: Run Tests
50+
run: ./.github/scripts/run_all_tests.sh
51+
env:
52+
FIREBASE_SERVICE_ACCT_KEY: ${{ secrets.FIREBASE_SERVICE_ACCT_KEY }}
53+
FIREBASE_API_KEY: ${{ secrets.FIREBASE_API_KEY }}
54+
55+
- name: Send email on failure
56+
if: failure()
57+
uses: firebase/firebase-admin-node/.github/actions/send-email@master
58+
with:
59+
api-key: ${{ secrets.OSS_BOT_MAILGUN_KEY }}
60+
domain: ${{ secrets.OSS_BOT_MAILGUN_DOMAIN }}
61+
from: 'GitHub <admin-github@${{ secrets.OSS_BOT_MAILGUN_DOMAIN }}>'
62+
to: ${{ secrets.FIREBASE_ADMIN_GITHUB_EMAIL }}
63+
subject: 'Nightly build ${{github.run_id}} of ${{github.repository}} failed!'
64+
html: >
65+
<b>Nightly workflow ${{github.run_id}} failed on: ${{github.repository}}</b>
66+
<br /><br />Navigate to the
67+
<a href="https://github.com/firebase/firebase-admin-go/actions/runs/${{github.run_id}}">failed workflow</a>.
68+
continue-on-error: true
69+
70+
- name: Send email on cancelled
71+
if: cancelled()
72+
uses: firebase/firebase-admin-node/.github/actions/send-email@master
73+
with:
74+
api-key: ${{ secrets.OSS_BOT_MAILGUN_KEY }}
75+
domain: ${{ secrets.OSS_BOT_MAILGUN_DOMAIN }}
76+
from: 'GitHub <admin-github@${{ secrets.OSS_BOT_MAILGUN_DOMAIN }}>'
77+
to: ${{ secrets.FIREBASE_ADMIN_GITHUB_EMAIL }}
78+
subject: 'Nightly build ${{github.run_id}} of ${{github.repository}} cancelled!'
79+
html: >
80+
<b>Nightly workflow ${{github.run_id}} cancelled on: ${{github.repository}}</b>
81+
<br /><br />Navigate to the
82+
<a href="https://github.com/firebase/firebase-admin-go/actions/runs/${{github.run_id}}">cancelled workflow</a>.
83+
continue-on-error: true

auth/auth.go

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"time"
2626

2727
"firebase.google.com/go/v4/internal"
28+
"golang.org/x/oauth2"
29+
"google.golang.org/api/option"
2830
"google.golang.org/api/transport"
2931
)
3032

@@ -37,6 +39,7 @@ const (
3739

3840
// SDK-generated error codes
3941
idTokenRevoked = "ID_TOKEN_REVOKED"
42+
userDisabled = "USER_DISABLED"
4043
sessionCookieRevoked = "SESSION_COOKIE_REVOKED"
4144
tenantIDMismatch = "TENANT_ID_MISMATCH"
4245
)
@@ -46,6 +49,10 @@ var reservedClaims = []string{
4649
"exp", "firebase", "iat", "iss", "jti", "nbf", "nonce", "sub",
4750
}
4851

52+
var emulatorToken = &oauth2.Token{
53+
AccessToken: "owner",
54+
}
55+
4956
// Client is the interface for the Firebase auth service.
5057
//
5158
// Client facilitates generating custom JWT tokens for Firebase clients, and verifying ID tokens issued
@@ -113,7 +120,15 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
113120
return nil, err
114121
}
115122

116-
transport, _, err := transport.NewHTTPClient(ctx, conf.Opts...)
123+
var opts []option.ClientOption
124+
if isEmulator {
125+
ts := oauth2.StaticTokenSource(emulatorToken)
126+
opts = append(opts, option.WithTokenSource(ts))
127+
} else {
128+
opts = append(opts, conf.Opts...)
129+
}
130+
131+
transport, _, err := transport.NewHTTPClient(ctx, opts...)
117132
if err != nil {
118133
return nil, err
119134
}
@@ -288,14 +303,14 @@ func (c *baseClient) withTenantID(tenantID string) *baseClient {
288303
// These keys get cached up to 24 hours, and therefore the RPC overhead gets amortized
289304
// over many invocations of this function.
290305
//
291-
// This does not check whether or not the token has been revoked. Use `VerifyIDTokenAndCheckRevoked()`
306+
// This does not check whether or not the token has been revoked or disabled. Use `VerifyIDTokenAndCheckRevoked()`
292307
// when a revocation check is needed.
293308
func (c *baseClient) VerifyIDToken(ctx context.Context, idToken string) (*Token, error) {
294309
return c.verifyIDToken(ctx, idToken, false)
295310
}
296311

297312
// VerifyIDTokenAndCheckRevoked verifies the provided ID token, and additionally checks that the
298-
// token has not been revoked.
313+
// token has not been revoked or disabled.
299314
//
300315
// Unlike `VerifyIDToken()`, this function must make an RPC call to perform the revocation check.
301316
// Developers are advised to take this additional overhead into consideration when including this
@@ -304,7 +319,7 @@ func (c *baseClient) VerifyIDTokenAndCheckRevoked(ctx context.Context, idToken s
304319
return c.verifyIDToken(ctx, idToken, true)
305320
}
306321

307-
func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRevoked bool) (*Token, error) {
322+
func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRevokedOrDisabled bool) (*Token, error) {
308323
decoded, err := c.idTokenVerifier.VerifyToken(ctx, idToken, c.isEmulator)
309324
if err != nil {
310325
return nil, err
@@ -320,21 +335,11 @@ func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRev
320335
}
321336
}
322337

323-
if c.isEmulator || checkRevoked {
324-
revoked, err := c.checkRevoked(ctx, decoded)
338+
if c.isEmulator || checkRevokedOrDisabled {
339+
err = c.checkRevokedOrDisabled(ctx, decoded, idTokenRevoked, "ID token has been revoked")
325340
if err != nil {
326341
return nil, err
327342
}
328-
329-
if revoked {
330-
return nil, &internal.FirebaseError{
331-
ErrorCode: internal.InvalidArgument,
332-
String: "ID token has been revoked",
333-
Ext: map[string]interface{}{
334-
authErrorCode: idTokenRevoked,
335-
},
336-
}
337-
}
338343
}
339344

340345
return decoded, nil
@@ -347,11 +352,18 @@ func IsTenantIDMismatch(err error) bool {
347352

348353
// IsIDTokenRevoked checks if the given error was due to a revoked ID token.
349354
//
350-
// When IsIDTokenRevoked returns true, IsIDTokenInvalid is guranteed to return true.
355+
// When IsIDTokenRevoked returns true, IsIDTokenInvalid is guaranteed to return true.
351356
func IsIDTokenRevoked(err error) bool {
352357
return hasAuthErrorCode(err, idTokenRevoked)
353358
}
354359

360+
// IsUserDisabled checks if the given error was due to a disabled ID token
361+
//
362+
// When IsUserDisabled returns true, IsIDTokenInvalid is guaranteed to return true.
363+
func IsUserDisabled(err error) bool {
364+
return hasAuthErrorCode(err, userDisabled)
365+
}
366+
355367
// VerifySessionCookie verifies the signature and payload of the provided Firebase session cookie.
356368
//
357369
// VerifySessionCookie accepts a signed JWT token string, and verifies that it is current, issued for the
@@ -371,7 +383,7 @@ func (c *Client) VerifySessionCookie(ctx context.Context, sessionCookie string)
371383
}
372384

373385
// VerifySessionCookieAndCheckRevoked verifies the provided session cookie, and additionally checks that the
374-
// cookie has not been revoked.
386+
// cookie has not been revoked and the user has not been disabled.
375387
//
376388
// Unlike `VerifySessionCookie()`, this function must make an RPC call to perform the revocation check.
377389
// Developers are advised to take this additional overhead into consideration when including this
@@ -380,46 +392,55 @@ func (c *Client) VerifySessionCookieAndCheckRevoked(ctx context.Context, session
380392
return c.verifySessionCookie(ctx, sessionCookie, true)
381393
}
382394

383-
func (c *Client) verifySessionCookie(ctx context.Context, sessionCookie string, checkRevoked bool) (*Token, error) {
395+
func (c *Client) verifySessionCookie(ctx context.Context, sessionCookie string, checkRevokedOrDisabled bool) (*Token, error) {
384396
decoded, err := c.cookieVerifier.VerifyToken(ctx, sessionCookie, c.isEmulator)
385397
if err != nil {
386398
return nil, err
387399
}
388400

389-
if c.isEmulator || checkRevoked {
390-
revoked, err := c.checkRevoked(ctx, decoded)
401+
if c.isEmulator || checkRevokedOrDisabled {
402+
err := c.checkRevokedOrDisabled(ctx, decoded, sessionCookieRevoked, "session cookie has been revoked")
391403
if err != nil {
392404
return nil, err
393405
}
394-
395-
if revoked {
396-
return nil, &internal.FirebaseError{
397-
ErrorCode: internal.InvalidArgument,
398-
String: "session cookie has been revoked",
399-
Ext: map[string]interface{}{
400-
authErrorCode: sessionCookieRevoked,
401-
},
402-
}
403-
}
404406
}
405407

406408
return decoded, nil
407409
}
408410

409411
// IsSessionCookieRevoked checks if the given error was due to a revoked session cookie.
410412
//
411-
// When IsSessionCookieRevoked returns true, IsSessionCookieInvalid is guranteed to return true.
413+
// When IsSessionCookieRevoked returns true, IsSessionCookieInvalid is guaranteed to return true.
412414
func IsSessionCookieRevoked(err error) bool {
413415
return hasAuthErrorCode(err, sessionCookieRevoked)
414416
}
415417

416-
func (c *baseClient) checkRevoked(ctx context.Context, token *Token) (bool, error) {
418+
// checkRevokedOrDisabled checks whether the input token has been revoked or disabled.
419+
func (c *baseClient) checkRevokedOrDisabled(ctx context.Context, token *Token, errCode string, errMessage string) error {
417420
user, err := c.GetUser(ctx, token.UID)
418421
if err != nil {
419-
return false, err
422+
return err
420423
}
424+
if user.Disabled {
425+
return &internal.FirebaseError{
426+
ErrorCode: internal.InvalidArgument,
427+
String: "user has been disabled",
428+
Ext: map[string]interface{}{
429+
authErrorCode: userDisabled,
430+
},
431+
}
421432

422-
return token.IssuedAt*1000 < user.TokensValidAfterMillis, nil
433+
}
434+
if token.IssuedAt*1000 < user.TokensValidAfterMillis {
435+
return &internal.FirebaseError{
436+
ErrorCode: internal.InvalidArgument,
437+
String: errMessage,
438+
Ext: map[string]interface{}{
439+
authErrorCode: errCode,
440+
},
441+
}
442+
}
443+
return nil
423444
}
424445

425446
func hasAuthErrorCode(err error, code string) bool {

0 commit comments

Comments
 (0)