4545INVALID_STRINGS = [None , '' , 0 , 1 , True , False , list (), tuple (), dict ()]
4646INVALID_BOOLS = [None , '' , 'foo' , 0 , 1 , list (), tuple (), dict ()]
4747INVALID_DICTS = [None , 'foo' , 0 , 1 , True , False , list (), tuple ()]
48+ INVALID_POSITIVE_NUMS = [None , 'foo' , 0 , - 1 , True , False , list (), tuple (), dict ()]
49+
4850
4951MOCK_GET_USER_RESPONSE = testutils .resource ('get_user.json' )
5052MOCK_LIST_USERS_RESPONSE = testutils .resource ('list_users.json' )
5153
54+ def _revoked_tokens_response ():
55+ mock_user = json .loads (testutils .resource ('get_user.json' ))
56+ mock_user ['users' ][0 ]['validSince' ] = str (int (time .time ())+ 100 )
57+ return json .dumps (mock_user )
58+
59+ MOCK_GET_USER_REVOKED_TOKENS_RESPONSE = _revoked_tokens_response ()
5260
5361class AuthFixture (object ):
5462 def __init__ (self , name = None ):
@@ -60,14 +68,13 @@ def __init__(self, name=None):
6068 def create_custom_token (self , * args ):
6169 if self .app :
6270 return auth .create_custom_token (* args , app = self .app )
63- else :
64- return auth .create_custom_token (* args )
71+ return auth .create_custom_token (* args )
6572
66- def verify_id_token (self , * args ):
73+ # Using **kwargs to pass along the check_revoked if passed.
74+ def verify_id_token (self , * args , ** kwargs ):
6775 if self .app :
68- return auth .verify_id_token (* args , app = self .app )
69- else :
70- return auth .verify_id_token (* args )
76+ return auth .verify_id_token (* args , app = self .app , ** kwargs )
77+ return auth .verify_id_token (* args , ** kwargs )
7178
7279def setup_module ():
7380 firebase_admin .initialize_app (MOCK_CREDENTIAL )
@@ -160,7 +167,6 @@ def get_id_token(payload_overrides=None, header_overrides=None):
160167
161168TEST_ID_TOKEN = get_id_token ()
162169
163-
164170class TestCreateCustomToken (object ):
165171
166172 valid_args = {
@@ -244,8 +250,42 @@ def test_valid_token(self, authtest, id_token):
244250 assert claims ['admin' ] is True
245251 assert claims ['uid' ] == claims ['sub' ]
246252
247- @pytest .mark .parametrize ('id_token' , invalid_tokens .values (),
248- ids = list (invalid_tokens ))
253+ @pytest .mark .parametrize ('id_token' , valid_tokens .values (), ids = list (valid_tokens ))
254+ def test_valid_token_check_revoked (self , user_mgt_app , id_token ):
255+ _instrument_user_manager (user_mgt_app , 200 , MOCK_GET_USER_RESPONSE )
256+ claims = auth .verify_id_token (id_token , app = user_mgt_app , check_revoked = True )
257+ assert claims ['admin' ] is True
258+ assert claims ['uid' ] == claims ['sub' ]
259+
260+ @pytest .mark .parametrize ('id_token' , valid_tokens .values (), ids = list (valid_tokens ))
261+ def test_revoked_token_check_revoked (self , user_mgt_app , id_token ):
262+ _instrument_user_manager (user_mgt_app , 200 , MOCK_GET_USER_REVOKED_TOKENS_RESPONSE )
263+
264+ with pytest .raises (auth .AuthError ) as excinfo :
265+ auth .verify_id_token (id_token , app = user_mgt_app , check_revoked = True )
266+
267+ assert excinfo .value .code == 'ID_TOKEN_REVOKED'
268+ assert str (excinfo .value ) == 'The Firebase ID token has been revoked.'
269+
270+ @pytest .mark .parametrize ('id_token' , valid_tokens .values (), ids = list (valid_tokens ))
271+ def test_revoked_token_do_not_check_revoked (self , user_mgt_app , id_token ):
272+ _instrument_user_manager (user_mgt_app , 200 , MOCK_GET_USER_REVOKED_TOKENS_RESPONSE )
273+ claims = auth .verify_id_token (id_token , app = user_mgt_app , check_revoked = False )
274+ assert claims ['admin' ] is True
275+ assert claims ['uid' ] == claims ['sub' ]
276+
277+ def test_revoke_refresh_tokens (self , user_mgt_app ):
278+ _ , recorder = _instrument_user_manager (user_mgt_app , 200 , '{"localId":"testuser"}' )
279+ before_time = time .time ()
280+ auth .revoke_refresh_tokens ('testuser' , app = user_mgt_app )
281+ after_time = time .time ()
282+
283+ request = json .loads (recorder [0 ].body .decode ())
284+ assert request ['localId' ] == 'testuser'
285+ assert int (request ['validSince' ]) >= int (before_time )
286+ assert int (request ['validSince' ]) <= int (after_time )
287+
288+ @pytest .mark .parametrize ('id_token' , invalid_tokens .values (), ids = list (invalid_tokens ))
249289 def test_invalid_token (self , authtest , id_token ):
250290 with pytest .raises (ValueError ):
251291 authtest .verify_id_token (id_token )
@@ -283,7 +323,8 @@ def test_certificate_request_failure(self, authtest):
283323
284324@pytest .fixture (scope = 'module' )
285325def user_mgt_app ():
286- app = firebase_admin .initialize_app (testutils .MockCredential (), name = 'userMgt' )
326+ app = firebase_admin .initialize_app (testutils .MockCredential (), name = 'userMgt' ,
327+ options = {'projectId' : 'mock-project-id' })
287328 yield app
288329 firebase_admin .delete_app (app )
289330
@@ -305,7 +346,7 @@ def _check_user_record(user, expected_uid='testuser'):
305346 assert user .photo_url == 'http://www.example.com/testuser/photo.png'
306347 assert user .disabled is False
307348 assert user .email_verified is True
308- assert user .user_metadata .creation_timestamp == 1234567890
349+ assert user .user_metadata .creation_timestamp == 1234567890000
309350 assert user .user_metadata .last_sign_in_timestamp is None
310351 assert user .provider_id == 'firebase'
311352
@@ -594,6 +635,11 @@ def test_invalid_property(self):
594635 with pytest .raises (ValueError ):
595636 auth .update_user ('user' , unsupported = 'arg' )
596637
638+ @pytest .mark .parametrize ('arg' , INVALID_POSITIVE_NUMS )
639+ def test_invalid_valid_since (self , arg ):
640+ with pytest .raises (ValueError ):
641+ auth .update_user ('user' , valid_since = arg )
642+
597643 def test_update_user (self , user_mgt_app ):
598644 user_mgt , recorder = _instrument_user_manager (user_mgt_app , 200 , '{"localId":"testuser"}' )
599645 user_mgt .update_user ('testuser' )
@@ -630,6 +676,12 @@ def test_update_user_error(self, user_mgt_app):
630676 assert excinfo .value .code == _user_mgt .USER_UPDATE_ERROR
631677 assert '{"error":"test"}' in str (excinfo .value )
632678
679+ def test_update_user_valid_since (self , user_mgt_app ):
680+ user_mgt , recorder = _instrument_user_manager (user_mgt_app , 200 , '{"localId":"testuser"}' )
681+ user_mgt .update_user ('testuser' , valid_since = 1 )
682+ request = json .loads (recorder [0 ].body .decode ())
683+ assert request == {'localId' : 'testuser' , 'validSince' : 1 }
684+
633685
634686class TestSetCustomUserClaims (object ):
635687
0 commit comments