diff --git a/tests/test_tenant_mgt.py b/tests/test_tenant_mgt.py index 224fdcc1..018892e3 100644 --- a/tests/test_tenant_mgt.py +++ b/tests/test_tenant_mgt.py @@ -15,6 +15,7 @@ """Test cases for the firebase_admin.tenant_mgt module.""" import json +import unittest.mock from urllib import parse import pytest @@ -29,6 +30,7 @@ from firebase_admin import _utils from tests import testutils from tests import test_token_gen +from tests.test_token_gen import MOCK_CURRENT_TIME, MOCK_CURRENT_TIME_UTC GET_TENANT_RESPONSE = """{ @@ -964,6 +966,17 @@ def _assert_saml_provider_config(self, provider_config, want_id='saml.provider') class TestVerifyIdToken: + def setup_method(self): + self.time_patch = unittest.mock.patch('time.time', return_value=MOCK_CURRENT_TIME) + self.mock_time = self.time_patch.start() + self.utcnow_patch = unittest.mock.patch( + 'google.auth.jwt._helpers.utcnow', return_value=MOCK_CURRENT_TIME_UTC) + self.mock_utcnow = self.utcnow_patch.start() + + def teardown_method(self): + self.time_patch.stop() + self.utcnow_patch.stop() + def test_valid_token(self, tenant_mgt_app): client = tenant_mgt.auth_for_tenant('test-tenant', app=tenant_mgt_app) client._token_verifier.request = test_token_gen.MOCK_REQUEST @@ -997,6 +1010,17 @@ def tenant_aware_custom_token_app(): class TestCreateCustomToken: + def setup_method(self): + self.time_patch = unittest.mock.patch('time.time', return_value=MOCK_CURRENT_TIME) + self.mock_time = self.time_patch.start() + self.utcnow_patch = unittest.mock.patch( + 'google.auth.jwt._helpers.utcnow', return_value=MOCK_CURRENT_TIME_UTC) + self.mock_utcnow = self.utcnow_patch.start() + + def teardown_method(self): + self.time_patch.stop() + self.utcnow_patch.stop() + def test_custom_token(self, tenant_aware_custom_token_app): client = tenant_mgt.auth_for_tenant('test-tenant', app=tenant_aware_custom_token_app) diff --git a/tests/test_token_gen.py b/tests/test_token_gen.py index 536a5ec9..fe0b28db 100644 --- a/tests/test_token_gen.py +++ b/tests/test_token_gen.py @@ -19,6 +19,7 @@ import json import os import time +import unittest.mock from google.auth import crypt from google.auth import jwt @@ -36,6 +37,9 @@ from tests import testutils +MOCK_CURRENT_TIME = 1500000000 +MOCK_CURRENT_TIME_UTC = datetime.datetime.fromtimestamp( + MOCK_CURRENT_TIME, tz=datetime.timezone.utc) MOCK_UID = 'user1' MOCK_CREDENTIAL = credentials.Certificate( testutils.resource_filename('service_account.json')) @@ -105,16 +109,17 @@ def verify_custom_token(custom_token, expected_claims, tenant_id=None): for key, value in expected_claims.items(): assert value == token['claims'][key] -def _get_id_token(payload_overrides=None, header_overrides=None): +def _get_id_token(payload_overrides=None, header_overrides=None, current_time=MOCK_CURRENT_TIME): signer = crypt.RSASigner.from_string(MOCK_PRIVATE_KEY) headers = { 'kid': 'mock-key-id-1' } + now = int(current_time if current_time is not None else time.time()) payload = { 'aud': MOCK_CREDENTIAL.project_id, 'iss': 'https://securetoken.google.com/' + MOCK_CREDENTIAL.project_id, - 'iat': int(time.time()) - 100, - 'exp': int(time.time()) + 3600, + 'iat': now - 100, + 'exp': now + 3600, 'sub': '1234567890', 'admin': True, 'firebase': { @@ -127,12 +132,13 @@ def _get_id_token(payload_overrides=None, header_overrides=None): payload = _merge_jwt_claims(payload, payload_overrides) return jwt.encode(signer, payload, header=headers) -def _get_session_cookie(payload_overrides=None, header_overrides=None): +def _get_session_cookie( + payload_overrides=None, header_overrides=None, current_time=MOCK_CURRENT_TIME): payload_overrides = payload_overrides or {} if 'iss' not in payload_overrides: payload_overrides['iss'] = 'https://session.firebase.google.com/{0}'.format( MOCK_CREDENTIAL.project_id) - return _get_id_token(payload_overrides, header_overrides) + return _get_id_token(payload_overrides, header_overrides, current_time=current_time) def _instrument_user_manager(app, status, payload): client = auth._get_client(app) @@ -205,7 +211,7 @@ def env_var_app(request): @pytest.fixture(scope='module') def revoked_tokens(): mock_user = json.loads(testutils.resource('get_user.json')) - mock_user['users'][0]['validSince'] = str(int(time.time())+100) + mock_user['users'][0]['validSince'] = str(MOCK_CURRENT_TIME + 100) return json.dumps(mock_user) @pytest.fixture(scope='module') @@ -218,7 +224,7 @@ def user_disabled(): def user_disabled_and_revoked(): mock_user = json.loads(testutils.resource('get_user.json')) mock_user['users'][0]['disabled'] = True - mock_user['users'][0]['validSince'] = str(int(time.time())+100) + mock_user['users'][0]['validSince'] = str(MOCK_CURRENT_TIME + 100) return json.dumps(mock_user) @@ -420,6 +426,17 @@ def test_unexpected_response(self, user_mgt_app): class TestVerifyIdToken: + def setup_method(self): + self.time_patch = unittest.mock.patch('time.time', return_value=MOCK_CURRENT_TIME) + self.time_patch.start() + self.utcnow_patch = unittest.mock.patch( + 'google.auth.jwt._helpers.utcnow', return_value=MOCK_CURRENT_TIME_UTC) + self.utcnow_patch.start() + + def teardown_method(self): + self.time_patch.stop() + self.utcnow_patch.stop() + valid_tokens = { 'BinaryToken': TEST_ID_TOKEN, 'TextToken': TEST_ID_TOKEN.decode('utf-8'), @@ -435,14 +452,14 @@ class TestVerifyIdToken: 'EmptySubject': _get_id_token({'sub': ''}), 'IntSubject': _get_id_token({'sub': 10}), 'LongStrSubject': _get_id_token({'sub': 'a' * 129}), - 'FutureToken': _get_id_token({'iat': int(time.time()) + 1000}), + 'FutureToken': _get_id_token({'iat': MOCK_CURRENT_TIME + 1000}), 'ExpiredToken': _get_id_token({ - 'iat': int(time.time()) - 10000, - 'exp': int(time.time()) - 3600 + 'iat': MOCK_CURRENT_TIME - 10000, + 'exp': MOCK_CURRENT_TIME - 3600 }), 'ExpiredTokenShort': _get_id_token({ - 'iat': int(time.time()) - 10000, - 'exp': int(time.time()) - 30 + 'iat': MOCK_CURRENT_TIME - 10000, + 'exp': MOCK_CURRENT_TIME - 30 }), 'BadFormatToken': 'foobar' } @@ -618,6 +635,17 @@ def test_certificate_request_failure(self, user_mgt_app): class TestVerifySessionCookie: + def setup_method(self): + self.time_patch = unittest.mock.patch('time.time', return_value=MOCK_CURRENT_TIME) + self.time_patch.start() + self.utcnow_patch = unittest.mock.patch( + 'google.auth.jwt._helpers.utcnow', return_value=MOCK_CURRENT_TIME_UTC) + self.utcnow_patch.start() + + def teardown_method(self): + self.time_patch.stop() + self.utcnow_patch.stop() + valid_cookies = { 'BinaryCookie': TEST_SESSION_COOKIE, 'TextCookie': TEST_SESSION_COOKIE.decode('utf-8'), @@ -633,14 +661,14 @@ class TestVerifySessionCookie: 'EmptySubject': _get_session_cookie({'sub': ''}), 'IntSubject': _get_session_cookie({'sub': 10}), 'LongStrSubject': _get_session_cookie({'sub': 'a' * 129}), - 'FutureCookie': _get_session_cookie({'iat': int(time.time()) + 1000}), + 'FutureCookie': _get_session_cookie({'iat': MOCK_CURRENT_TIME + 1000}), 'ExpiredCookie': _get_session_cookie({ - 'iat': int(time.time()) - 10000, - 'exp': int(time.time()) - 3600 + 'iat': MOCK_CURRENT_TIME - 10000, + 'exp': MOCK_CURRENT_TIME - 3600 }), 'ExpiredCookieShort': _get_session_cookie({ - 'iat': int(time.time()) - 10000, - 'exp': int(time.time()) - 30 + 'iat': MOCK_CURRENT_TIME - 10000, + 'exp': MOCK_CURRENT_TIME - 30 }), 'BadFormatCookie': 'foobar', 'IDToken': TEST_ID_TOKEN, @@ -792,6 +820,17 @@ def test_certificate_request_failure(self, user_mgt_app): class TestCertificateCaching: + def setup_method(self): + self.time_patch = unittest.mock.patch('time.time', return_value=MOCK_CURRENT_TIME) + self.time_patch.start() + self.utcnow_patch = unittest.mock.patch( + 'google.auth.jwt._helpers.utcnow', return_value=MOCK_CURRENT_TIME_UTC) + self.utcnow_patch.start() + + def teardown_method(self): + self.time_patch.stop() + self.utcnow_patch.stop() + def test_certificate_caching(self, user_mgt_app, httpserver): httpserver.serve_content(MOCK_PUBLIC_CERTS, 200, headers={'Cache-Control': 'max-age=3600'}) verifier = _token_gen.TokenVerifier(user_mgt_app) @@ -810,6 +849,18 @@ def test_certificate_caching(self, user_mgt_app, httpserver): class TestCertificateFetchTimeout: + def setup_method(self): + self.time_patch = unittest.mock.patch('time.time', return_value=MOCK_CURRENT_TIME) + self.time_patch.start() + self.utcnow_patch = unittest.mock.patch( + 'google.auth.jwt._helpers.utcnow', return_value=MOCK_CURRENT_TIME_UTC) + self.utcnow_patch.start() + + def teardown_method(self): + self.time_patch.stop() + self.utcnow_patch.stop() + testutils.cleanup_apps() + timeout_configs = [ ({'httpTimeout': 4}, 4), ({'httpTimeout': None}, None), @@ -852,6 +903,3 @@ def _instrument_session(self, app): recorder = [] request.session.mount('https://', testutils.MockAdapter(MOCK_PUBLIC_CERTS, 200, recorder)) return recorder - - def teardown_method(self): - testutils.cleanup_apps()