@@ -76,13 +76,18 @@ def _merge_jwt_claims(defaults, overrides):
76
76
77
77
def verify_custom_token (custom_token , expected_claims , tenant_id = None ):
78
78
assert isinstance (custom_token , bytes )
79
- token = google .oauth2 .id_token .verify_token (
80
- custom_token ,
81
- testutils .MockRequest (200 , MOCK_PUBLIC_CERTS ),
82
- _token_gen .FIREBASE_AUDIENCE )
79
+ expected_email = MOCK_SERVICE_ACCOUNT_EMAIL
80
+ if _is_emulated ():
81
+ expected_email = _token_gen .AUTH_EMULATOR_EMAIL
82
+ token = jwt .decode (custom_token , verify = False )
83
+ else :
84
+ token = google .oauth2 .id_token .verify_token (
85
+ custom_token ,
86
+ testutils .MockRequest (200 , MOCK_PUBLIC_CERTS ),
87
+ _token_gen .FIREBASE_AUDIENCE )
83
88
assert token ['uid' ] == MOCK_UID
84
- assert token ['iss' ] == MOCK_SERVICE_ACCOUNT_EMAIL
85
- assert token ['sub' ] == MOCK_SERVICE_ACCOUNT_EMAIL
89
+ assert token ['iss' ] == expected_email
90
+ assert token ['sub' ] == expected_email
86
91
if tenant_id is None :
87
92
assert 'tenant_id' not in token
88
93
else :
@@ -141,7 +146,15 @@ def _overwrite_iam_request(app, request):
141
146
client = auth ._get_client (app )
142
147
client ._token_generator .request = request
143
148
144
- @pytest .fixture (scope = 'module' , params = [{'emulated' : False }, {'emulated' : True }])
149
+
150
+ def _is_emulated ():
151
+ emulator_host = os .getenv (EMULATOR_HOST_ENV_VAR , '' )
152
+ return emulator_host and '//' not in emulator_host
153
+
154
+
155
+ # These fixtures are set to the default function scope as the emulator environment variable bleeds
156
+ # over when in module scope.
157
+ @pytest .fixture (params = [{'emulated' : False }, {'emulated' : True }])
145
158
def auth_app (request ):
146
159
"""Returns an App initialized with a mock service account credential.
147
160
@@ -157,7 +170,7 @@ def auth_app(request):
157
170
firebase_admin .delete_app (app )
158
171
monkeypatch .undo ()
159
172
160
- @pytest .fixture (scope = 'module' , params = [{'emulated' : False }, {'emulated' : True }])
173
+ @pytest .fixture (params = [{'emulated' : False }, {'emulated' : True }])
161
174
def user_mgt_app (request ):
162
175
monkeypatch = testutils .new_monkeypatch ()
163
176
if request .param ['emulated' ]:
@@ -230,6 +243,12 @@ def test_invalid_params(self, auth_app, values):
230
243
auth .create_custom_token (user , claims , app = auth_app )
231
244
232
245
def test_noncert_credential (self , user_mgt_app ):
246
+ if _is_emulated ():
247
+ # Should work fine with the emulator, so do a condensed version of
248
+ # test_sign_with_iam below.
249
+ custom_token = auth .create_custom_token (MOCK_UID , app = user_mgt_app ).decode ()
250
+ self ._verify_signer (custom_token , _token_gen .AUTH_EMULATOR_EMAIL )
251
+ return
233
252
with pytest .raises (ValueError ):
234
253
auth .create_custom_token (MOCK_UID , app = user_mgt_app )
235
254
@@ -304,7 +323,7 @@ def test_sign_with_discovery_failure(self):
304
323
def _verify_signer (self , token , signer ):
305
324
segments = token .split ('.' )
306
325
assert len (segments ) == 3
307
- body = json . loads ( base64 . b64decode ( segments [ 1 ]). decode () )
326
+ body = jwt . decode (token , verify = False )
308
327
assert body ['iss' ] == signer
309
328
assert body ['sub' ] == signer
310
329
@@ -406,14 +425,24 @@ class TestVerifyIdToken:
406
425
'BadFormatToken' : 'foobar'
407
426
}
408
427
409
- @pytest .mark .parametrize ('id_token' , valid_tokens .values (), ids = list (valid_tokens ))
410
- def test_valid_token (self , user_mgt_app , id_token ):
411
- _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
412
- claims = auth .verify_id_token (id_token , app = user_mgt_app )
428
+ tokens_accepted_in_emulator = [
429
+ 'NoKid' ,
430
+ 'WrongKid' ,
431
+ 'FutureToken' ,
432
+ 'ExpiredToken'
433
+ ]
434
+
435
+ def _assert_valid_token (self , id_token , app ):
436
+ claims = auth .verify_id_token (id_token , app = app )
413
437
assert claims ['admin' ] is True
414
438
assert claims ['uid' ] == claims ['sub' ]
415
439
assert claims ['firebase' ]['sign_in_provider' ] == 'provider'
416
440
441
+ @pytest .mark .parametrize ('id_token' , valid_tokens .values (), ids = list (valid_tokens ))
442
+ def test_valid_token (self , user_mgt_app , id_token ):
443
+ _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
444
+ self ._assert_valid_token (id_token , app = user_mgt_app )
445
+
417
446
def test_valid_token_with_tenant (self , user_mgt_app ):
418
447
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
419
448
claims = auth .verify_id_token (TEST_ID_TOKEN_WITH_TENANT , app = user_mgt_app )
@@ -458,8 +487,12 @@ def test_invalid_arg(self, user_mgt_app, id_token):
458
487
auth .verify_id_token (id_token , app = user_mgt_app )
459
488
assert 'Illegal ID token provided' in str (excinfo .value )
460
489
461
- @pytest .mark .parametrize ('id_token' , invalid_tokens .values (), ids = list (invalid_tokens ))
462
- def test_invalid_token (self , user_mgt_app , id_token ):
490
+ @pytest .mark .parametrize ('id_token_key' , list (invalid_tokens ))
491
+ def test_invalid_token (self , user_mgt_app , id_token_key ):
492
+ id_token = self .invalid_tokens [id_token_key ]
493
+ if _is_emulated () and id_token_key in self .tokens_accepted_in_emulator :
494
+ self ._assert_valid_token (id_token , user_mgt_app )
495
+ return
463
496
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
464
497
with pytest .raises (auth .InvalidIdTokenError ) as excinfo :
465
498
auth .verify_id_token (id_token , app = user_mgt_app )
@@ -469,6 +502,9 @@ def test_invalid_token(self, user_mgt_app, id_token):
469
502
def test_expired_token (self , user_mgt_app ):
470
503
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
471
504
id_token = self .invalid_tokens ['ExpiredToken' ]
505
+ if _is_emulated ():
506
+ self ._assert_valid_token (id_token , user_mgt_app )
507
+ return
472
508
with pytest .raises (auth .ExpiredIdTokenError ) as excinfo :
473
509
auth .verify_id_token (id_token , app = user_mgt_app )
474
510
assert isinstance (excinfo .value , auth .InvalidIdTokenError )
@@ -506,6 +542,10 @@ def test_custom_token(self, auth_app):
506
542
507
543
def test_certificate_request_failure (self , user_mgt_app ):
508
544
_overwrite_cert_request (user_mgt_app , testutils .MockRequest (404 , 'not found' ))
545
+ if _is_emulated ():
546
+ # Shouldn't fetch certificates in emulator mode.
547
+ self ._assert_valid_token (TEST_ID_TOKEN , app = user_mgt_app )
548
+ return
509
549
with pytest .raises (auth .CertificateFetchError ) as excinfo :
510
550
auth .verify_id_token (TEST_ID_TOKEN , app = user_mgt_app )
511
551
assert 'Could not fetch certificates' in str (excinfo .value )
@@ -540,20 +580,28 @@ class TestVerifySessionCookie:
540
580
'IDToken' : TEST_ID_TOKEN ,
541
581
}
542
582
583
+ cookies_accepted_in_emulator = [
584
+ 'NoKid' ,
585
+ 'WrongKid' ,
586
+ 'FutureCookie' ,
587
+ 'ExpiredCookie'
588
+ ]
589
+
590
+ def _assert_valid_cookie (self , cookie , app , check_revoked = False ):
591
+ claims = auth .verify_session_cookie (cookie , app = app , check_revoked = check_revoked )
592
+ assert claims ['admin' ] is True
593
+ assert claims ['uid' ] == claims ['sub' ]
594
+
543
595
@pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
544
596
def test_valid_cookie (self , user_mgt_app , cookie ):
545
597
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
546
- claims = auth .verify_session_cookie (cookie , app = user_mgt_app )
547
- assert claims ['admin' ] is True
548
- assert claims ['uid' ] == claims ['sub' ]
598
+ self ._assert_valid_cookie (cookie , user_mgt_app )
549
599
550
600
@pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
551
601
def test_valid_cookie_check_revoked (self , user_mgt_app , cookie ):
552
602
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
553
603
_instrument_user_manager (user_mgt_app , 200 , MOCK_GET_USER_RESPONSE )
554
- claims = auth .verify_session_cookie (cookie , app = user_mgt_app , check_revoked = True )
555
- assert claims ['admin' ] is True
556
- assert claims ['uid' ] == claims ['sub' ]
604
+ self ._assert_valid_cookie (cookie , app = user_mgt_app , check_revoked = True )
557
605
558
606
@pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
559
607
def test_revoked_cookie_check_revoked (self , user_mgt_app , revoked_tokens , cookie ):
@@ -567,9 +615,7 @@ def test_revoked_cookie_check_revoked(self, user_mgt_app, revoked_tokens, cookie
567
615
def test_revoked_cookie_does_not_check_revoked (self , user_mgt_app , revoked_tokens , cookie ):
568
616
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
569
617
_instrument_user_manager (user_mgt_app , 200 , revoked_tokens )
570
- claims = auth .verify_session_cookie (cookie , app = user_mgt_app , check_revoked = False )
571
- assert claims ['admin' ] is True
572
- assert claims ['uid' ] == claims ['sub' ]
618
+ self ._assert_valid_cookie (cookie , app = user_mgt_app , check_revoked = False )
573
619
574
620
@pytest .mark .parametrize ('cookie' , INVALID_JWT_ARGS .values (), ids = list (INVALID_JWT_ARGS ))
575
621
def test_invalid_args (self , user_mgt_app , cookie ):
@@ -578,8 +624,12 @@ def test_invalid_args(self, user_mgt_app, cookie):
578
624
auth .verify_session_cookie (cookie , app = user_mgt_app )
579
625
assert 'Illegal session cookie provided' in str (excinfo .value )
580
626
581
- @pytest .mark .parametrize ('cookie' , invalid_cookies .values (), ids = list (invalid_cookies ))
582
- def test_invalid_cookie (self , user_mgt_app , cookie ):
627
+ @pytest .mark .parametrize ('cookie_key' , list (invalid_cookies ))
628
+ def test_invalid_cookie (self , user_mgt_app , cookie_key ):
629
+ cookie = self .invalid_cookies [cookie_key ]
630
+ if _is_emulated () and cookie_key in self .cookies_accepted_in_emulator :
631
+ self ._assert_valid_cookie (cookie , user_mgt_app )
632
+ return
583
633
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
584
634
with pytest .raises (auth .InvalidSessionCookieError ) as excinfo :
585
635
auth .verify_session_cookie (cookie , app = user_mgt_app )
@@ -589,6 +639,9 @@ def test_invalid_cookie(self, user_mgt_app, cookie):
589
639
def test_expired_cookie (self , user_mgt_app ):
590
640
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
591
641
cookie = self .invalid_cookies ['ExpiredCookie' ]
642
+ if _is_emulated ():
643
+ self ._assert_valid_cookie (cookie , user_mgt_app )
644
+ return
592
645
with pytest .raises (auth .ExpiredSessionCookieError ) as excinfo :
593
646
auth .verify_session_cookie (cookie , app = user_mgt_app )
594
647
assert isinstance (excinfo .value , auth .InvalidSessionCookieError )
@@ -621,6 +674,10 @@ def test_custom_token(self, auth_app):
621
674
622
675
def test_certificate_request_failure (self , user_mgt_app ):
623
676
_overwrite_cert_request (user_mgt_app , testutils .MockRequest (404 , 'not found' ))
677
+ if _is_emulated ():
678
+ # Shouldn't fetch certificates in emulator mode.
679
+ auth .verify_session_cookie (TEST_SESSION_COOKIE , app = user_mgt_app )
680
+ return
624
681
with pytest .raises (auth .CertificateFetchError ) as excinfo :
625
682
auth .verify_session_cookie (TEST_SESSION_COOKIE , app = user_mgt_app )
626
683
assert 'Could not fetch certificates' in str (excinfo .value )
@@ -637,9 +694,11 @@ def test_certificate_caching(self, user_mgt_app, httpserver):
637
694
verifier .cookie_verifier .cert_url = httpserver .url
638
695
verifier .id_token_verifier .cert_url = httpserver .url
639
696
verifier .verify_session_cookie (TEST_SESSION_COOKIE )
640
- assert len (httpserver .requests ) == 1
697
+ # No requests should be made in emulated mode
698
+ request_count = 0 if _is_emulated () else 1
699
+ assert len (httpserver .requests ) == request_count
641
700
# Subsequent requests should not fetch certs from the server
642
701
verifier .verify_session_cookie (TEST_SESSION_COOKIE )
643
- assert len (httpserver .requests ) == 1
702
+ assert len (httpserver .requests ) == request_count
644
703
verifier .verify_id_token (TEST_ID_TOKEN )
645
- assert len (httpserver .requests ) == 1
704
+ assert len (httpserver .requests ) == request_count
0 commit comments