@@ -76,13 +76,18 @@ def _merge_jwt_claims(defaults, overrides):
7676
7777def verify_custom_token (custom_token , expected_claims , tenant_id = None ):
7878 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 )
8388 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
8691 if tenant_id is None :
8792 assert 'tenant_id' not in token
8893 else :
@@ -141,7 +146,15 @@ def _overwrite_iam_request(app, request):
141146 client = auth ._get_client (app )
142147 client ._token_generator .request = request
143148
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 }])
145158def auth_app (request ):
146159 """Returns an App initialized with a mock service account credential.
147160
@@ -157,7 +170,7 @@ def auth_app(request):
157170 firebase_admin .delete_app (app )
158171 monkeypatch .undo ()
159172
160- @pytest .fixture (scope = 'module' , params = [{'emulated' : False }, {'emulated' : True }])
173+ @pytest .fixture (params = [{'emulated' : False }, {'emulated' : True }])
161174def user_mgt_app (request ):
162175 monkeypatch = testutils .new_monkeypatch ()
163176 if request .param ['emulated' ]:
@@ -230,6 +243,12 @@ def test_invalid_params(self, auth_app, values):
230243 auth .create_custom_token (user , claims , app = auth_app )
231244
232245 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
233252 with pytest .raises (ValueError ):
234253 auth .create_custom_token (MOCK_UID , app = user_mgt_app )
235254
@@ -304,7 +323,7 @@ def test_sign_with_discovery_failure(self):
304323 def _verify_signer (self , token , signer ):
305324 segments = token .split ('.' )
306325 assert len (segments ) == 3
307- body = json . loads ( base64 . b64decode ( segments [ 1 ]). decode () )
326+ body = jwt . decode (token , verify = False )
308327 assert body ['iss' ] == signer
309328 assert body ['sub' ] == signer
310329
@@ -406,14 +425,23 @@ class TestVerifyIdToken:
406425 'BadFormatToken' : 'foobar'
407426 }
408427
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 )
413436 assert claims ['admin' ] is True
414437 assert claims ['uid' ] == claims ['sub' ]
415438 assert claims ['firebase' ]['sign_in_provider' ] == 'provider'
416439
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+
417445 def test_valid_token_with_tenant (self , user_mgt_app ):
418446 _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
419447 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):
458486 auth .verify_id_token (id_token , app = user_mgt_app )
459487 assert 'Illegal ID token provided' in str (excinfo .value )
460488
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
463495 _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
464496 with pytest .raises (auth .InvalidIdTokenError ) as excinfo :
465497 auth .verify_id_token (id_token , app = user_mgt_app )
@@ -469,6 +501,9 @@ def test_invalid_token(self, user_mgt_app, id_token):
469501 def test_expired_token (self , user_mgt_app ):
470502 _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
471503 id_token = self .invalid_tokens ['ExpiredToken' ]
504+ if _is_emulated ():
505+ self ._assert_valid_token (id_token , user_mgt_app )
506+ return
472507 with pytest .raises (auth .ExpiredIdTokenError ) as excinfo :
473508 auth .verify_id_token (id_token , app = user_mgt_app )
474509 assert isinstance (excinfo .value , auth .InvalidIdTokenError )
@@ -506,6 +541,10 @@ def test_custom_token(self, auth_app):
506541
507542 def test_certificate_request_failure (self , user_mgt_app ):
508543 _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
509548 with pytest .raises (auth .CertificateFetchError ) as excinfo :
510549 auth .verify_id_token (TEST_ID_TOKEN , app = user_mgt_app )
511550 assert 'Could not fetch certificates' in str (excinfo .value )
@@ -540,20 +579,27 @@ class TestVerifySessionCookie:
540579 'IDToken' : TEST_ID_TOKEN ,
541580 }
542581
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+
543593 @pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
544594 def test_valid_cookie (self , user_mgt_app , cookie ):
545595 _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 )
549597
550598 @pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
551599 def test_valid_cookie_check_revoked (self , user_mgt_app , cookie ):
552600 _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
553601 _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 )
557603
558604 @pytest .mark .parametrize ('cookie' , valid_cookies .values (), ids = list (valid_cookies ))
559605 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
567613 def test_revoked_cookie_does_not_check_revoked (self , user_mgt_app , revoked_tokens , cookie ):
568614 _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
569615 _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 )
573617
574618 @pytest .mark .parametrize ('cookie' , INVALID_JWT_ARGS .values (), ids = list (INVALID_JWT_ARGS ))
575619 def test_invalid_args (self , user_mgt_app , cookie ):
@@ -578,8 +622,12 @@ def test_invalid_args(self, user_mgt_app, cookie):
578622 auth .verify_session_cookie (cookie , app = user_mgt_app )
579623 assert 'Illegal session cookie provided' in str (excinfo .value )
580624
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
583631 _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
584632 with pytest .raises (auth .InvalidSessionCookieError ) as excinfo :
585633 auth .verify_session_cookie (cookie , app = user_mgt_app )
@@ -589,6 +637,9 @@ def test_invalid_cookie(self, user_mgt_app, cookie):
589637 def test_expired_cookie (self , user_mgt_app ):
590638 _overwrite_cert_request (user_mgt_app , MOCK_REQUEST )
591639 cookie = self .invalid_cookies ['ExpiredCookie' ]
640+ if _is_emulated ():
641+ self ._assert_valid_cookie (cookie , user_mgt_app )
642+ return
592643 with pytest .raises (auth .ExpiredSessionCookieError ) as excinfo :
593644 auth .verify_session_cookie (cookie , app = user_mgt_app )
594645 assert isinstance (excinfo .value , auth .InvalidSessionCookieError )
@@ -621,6 +672,10 @@ def test_custom_token(self, auth_app):
621672
622673 def test_certificate_request_failure (self , user_mgt_app ):
623674 _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
624679 with pytest .raises (auth .CertificateFetchError ) as excinfo :
625680 auth .verify_session_cookie (TEST_SESSION_COOKIE , app = user_mgt_app )
626681 assert 'Could not fetch certificates' in str (excinfo .value )
@@ -637,9 +692,11 @@ def test_certificate_caching(self, user_mgt_app, httpserver):
637692 verifier .cookie_verifier .cert_url = httpserver .url
638693 verifier .id_token_verifier .cert_url = httpserver .url
639694 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
641698 # Subsequent requests should not fetch certs from the server
642699 verifier .verify_session_cookie (TEST_SESSION_COOKIE )
643- assert len (httpserver .requests ) == 1
700+ assert len (httpserver .requests ) == request_count
644701 verifier .verify_id_token (TEST_ID_TOKEN )
645- assert len (httpserver .requests ) == 1
702+ assert len (httpserver .requests ) == request_count
0 commit comments