@@ -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,23 @@ 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_not_invalid_in_emulator = [
429
+ 'WrongKid' ,
430
+ 'FutureToken' ,
431
+ 'ExpiredToken'
432
+ ]
433
+
434
+ def _assert_valid_token (self , id_token , app ):
435
+ claims = auth .verify_id_token (id_token , app = app )
413
436
assert claims ['admin' ] is True
414
437
assert claims ['uid' ] == claims ['sub' ]
415
438
assert claims ['firebase' ]['sign_in_provider' ] == 'provider'
416
439
440
+ @pytest .mark .parametrize ('id_token' , valid_tokens .values (), ids = list (valid_tokens ))
441
+ def test_valid_token (self , user_mgt_app , id_token ):
442
+ _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
443
+ self ._assert_valid_token (id_token , app = user_mgt_app )
444
+
417
445
def test_valid_token_with_tenant (self , user_mgt_app ):
418
446
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
419
447
claims = auth .verify_id_token (TEST_ID_TOKEN_WITH_TENANT , app = user_mgt_app )
@@ -458,8 +486,12 @@ def test_invalid_arg(self, user_mgt_app, id_token):
458
486
auth .verify_id_token (id_token , app = user_mgt_app )
459
487
assert 'Illegal ID token provided' in str (excinfo .value )
460
488
461
- @pytest .mark .parametrize ('id_token' , invalid_tokens .values (), ids = list (invalid_tokens ))
462
- def test_invalid_token (self , user_mgt_app , id_token ):
489
+ @pytest .mark .parametrize ('id_token_key' , list (invalid_tokens ))
490
+ def test_invalid_token (self , user_mgt_app , id_token_key ):
491
+ id_token = self .invalid_tokens [id_token_key ]
492
+ if _is_emulated () and id_token_key in self .tokens_not_invalid_in_emulator :
493
+ self ._assert_valid_token (id_token , user_mgt_app )
494
+ return
463
495
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
464
496
with pytest .raises (auth .InvalidIdTokenError ) as excinfo :
465
497
auth .verify_id_token (id_token , app = user_mgt_app )
@@ -469,6 +501,9 @@ def test_invalid_token(self, user_mgt_app, id_token):
469
501
def test_expired_token (self , user_mgt_app ):
470
502
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
471
503
id_token = self .invalid_tokens ['ExpiredToken' ]
504
+ if _is_emulated ():
505
+ self ._assert_valid_token (id_token , user_mgt_app )
506
+ return
472
507
with pytest .raises (auth .ExpiredIdTokenError ) as excinfo :
473
508
auth .verify_id_token (id_token , app = user_mgt_app )
474
509
assert isinstance (excinfo .value , auth .InvalidIdTokenError )
@@ -506,6 +541,10 @@ def test_custom_token(self, auth_app):
506
541
507
542
def test_certificate_request_failure (self , user_mgt_app ):
508
543
_overwrite_cert_request (user_mgt_app , testutils .MockRequest (404 , 'not found' ))
544
+ if _is_emulated ():
545
+ # Shouldn't fetch certificates in emulator mode.
546
+ self ._assert_valid_token (TEST_ID_TOKEN , app = user_mgt_app )
547
+ return
509
548
with pytest .raises (auth .CertificateFetchError ) as excinfo :
510
549
auth .verify_id_token (TEST_ID_TOKEN , app = user_mgt_app )
511
550
assert 'Could not fetch certificates' in str (excinfo .value )
@@ -540,20 +579,27 @@ class TestVerifySessionCookie:
540
579
'IDToken' : TEST_ID_TOKEN ,
541
580
}
542
581
582
+ cookies_not_invalid_in_emulator = [
583
+ 'WrongKid' ,
584
+ 'FutureCookie' ,
585
+ 'ExpiredCookie'
586
+ ]
587
+
588
+ def _assert_valid_cookie (self , cookie , app , check_revoked = False ):
589
+ claims = auth .verify_session_cookie (cookie , app = app , check_revoked = check_revoked )
590
+ assert claims ['admin' ] is True
591
+ assert claims ['uid' ] == claims ['sub' ]
592
+
543
593
@pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
544
594
def test_valid_cookie (self , user_mgt_app , cookie ):
545
595
_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' ]
596
+ self ._assert_valid_cookie (cookie , user_mgt_app )
549
597
550
598
@pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
551
599
def test_valid_cookie_check_revoked (self , user_mgt_app , cookie ):
552
600
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
553
601
_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' ]
602
+ self ._assert_valid_cookie (cookie , app = user_mgt_app , check_revoked = True )
557
603
558
604
@pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
559
605
def test_revoked_cookie_check_revoked (self , user_mgt_app , revoked_tokens , cookie ):
@@ -567,9 +613,7 @@ def test_revoked_cookie_check_revoked(self, user_mgt_app, revoked_tokens, cookie
567
613
def test_revoked_cookie_does_not_check_revoked (self , user_mgt_app , revoked_tokens , cookie ):
568
614
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
569
615
_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' ]
616
+ self ._assert_valid_cookie (cookie , app = user_mgt_app , check_revoked = False )
573
617
574
618
@pytest .mark .parametrize ('cookie' , INVALID_JWT_ARGS .values (), ids = list (INVALID_JWT_ARGS ))
575
619
def test_invalid_args (self , user_mgt_app , cookie ):
@@ -578,8 +622,12 @@ def test_invalid_args(self, user_mgt_app, cookie):
578
622
auth .verify_session_cookie (cookie , app = user_mgt_app )
579
623
assert 'Illegal session cookie provided' in str (excinfo .value )
580
624
581
- @pytest .mark .parametrize ('cookie' , invalid_cookies .values (), ids = list (invalid_cookies ))
582
- def test_invalid_cookie (self , user_mgt_app , cookie ):
625
+ @pytest .mark .parametrize ('cookie_key' , list (invalid_cookies ))
626
+ def test_invalid_cookie (self , user_mgt_app , cookie_key ):
627
+ cookie = self .invalid_cookies [cookie_key ]
628
+ if _is_emulated () and cookie_key in self .cookies_not_invalid_in_emulator :
629
+ self ._assert_valid_cookie (cookie , user_mgt_app )
630
+ return
583
631
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
584
632
with pytest .raises (auth .InvalidSessionCookieError ) as excinfo :
585
633
auth .verify_session_cookie (cookie , app = user_mgt_app )
@@ -589,6 +637,9 @@ def test_invalid_cookie(self, user_mgt_app, cookie):
589
637
def test_expired_cookie (self , user_mgt_app ):
590
638
_overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
591
639
cookie = self .invalid_cookies ['ExpiredCookie' ]
640
+ if _is_emulated ():
641
+ self ._assert_valid_cookie (cookie , user_mgt_app )
642
+ return
592
643
with pytest .raises (auth .ExpiredSessionCookieError ) as excinfo :
593
644
auth .verify_session_cookie (cookie , app = user_mgt_app )
594
645
assert isinstance (excinfo .value , auth .InvalidSessionCookieError )
@@ -621,6 +672,10 @@ def test_custom_token(self, auth_app):
621
672
622
673
def test_certificate_request_failure (self , user_mgt_app ):
623
674
_overwrite_cert_request (user_mgt_app , testutils .MockRequest (404 , 'not found' ))
675
+ if _is_emulated ():
676
+ # Shouldn't fetch certificates in emulator mode.
677
+ auth .verify_session_cookie (TEST_SESSION_COOKIE , app = user_mgt_app )
678
+ return
624
679
with pytest .raises (auth .CertificateFetchError ) as excinfo :
625
680
auth .verify_session_cookie (TEST_SESSION_COOKIE , app = user_mgt_app )
626
681
assert 'Could not fetch certificates' in str (excinfo .value )
@@ -637,9 +692,11 @@ def test_certificate_caching(self, user_mgt_app, httpserver):
637
692
verifier .cookie_verifier .cert_url = httpserver .url
638
693
verifier .id_token_verifier .cert_url = httpserver .url
639
694
verifier .verify_session_cookie (TEST_SESSION_COOKIE )
640
- assert len (httpserver .requests ) == 1
695
+ # No requests should be made in emulated mode
696
+ request_count = 0 if _is_emulated () else 1
697
+ assert len (httpserver .requests ) == request_count
641
698
# Subsequent requests should not fetch certs from the server
642
699
verifier .verify_session_cookie (TEST_SESSION_COOKIE )
643
- assert len (httpserver .requests ) == 1
700
+ assert len (httpserver .requests ) == request_count
644
701
verifier .verify_id_token (TEST_ID_TOKEN )
645
- assert len (httpserver .requests ) == 1
702
+ assert len (httpserver .requests ) == request_count
0 commit comments