|
19 | 19 | import json |
20 | 20 | import os |
21 | 21 | import time |
| 22 | +from unittest import mock |
22 | 23 |
|
23 | 24 | from google.auth import crypt |
24 | 25 | from google.auth import jwt |
@@ -562,17 +563,34 @@ def test_expired_token(self, user_mgt_app): |
562 | 563 |
|
563 | 564 | def test_expired_token_with_tolerance(self, user_mgt_app): |
564 | 565 | _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) |
565 | | - id_token = self.invalid_tokens['ExpiredTokenShort'] |
| 566 | + id_token_encoded = self.invalid_tokens['ExpiredTokenShort'] |
566 | 567 | if _is_emulated(): |
567 | | - self._assert_valid_token(id_token, user_mgt_app) |
| 568 | + # Emulator mode doesn't perform the same time checks, skip advanced mocking |
| 569 | + self._assert_valid_token(id_token_encoded, user_mgt_app) |
568 | 570 | return |
569 | | - claims = auth.verify_id_token(id_token, app=user_mgt_app, |
570 | | - clock_skew_seconds=60) |
| 571 | + |
| 572 | + # Decode the token to get its actual 'exp' timestamp |
| 573 | + # Ensure 'google.auth.jwt' is available for jwt.decode |
| 574 | + # This might require `from google.auth import jwt` if not already present |
| 575 | + decoded_token = jwt.decode(id_token_encoded, verify=False) |
| 576 | + exp_timestamp = decoded_token['exp'] |
| 577 | + |
| 578 | + # Valid case: mock utcnow to be exactly at exp + clock_skew (boundary of validity) |
| 579 | + # The token should be considered valid here. |
| 580 | + mock_now_valid = datetime.datetime.utcfromtimestamp(exp_timestamp + 60) |
| 581 | + with mock.patch('google.auth._helpers.utcnow', return_value=mock_now_valid): |
| 582 | + claims = auth.verify_id_token(id_token_encoded, app=user_mgt_app, |
| 583 | + clock_skew_seconds=60) |
571 | 584 | assert claims['admin'] is True |
572 | 585 | assert claims['uid'] == claims['sub'] |
573 | | - with pytest.raises(auth.ExpiredIdTokenError): |
574 | | - auth.verify_id_token(id_token, app=user_mgt_app, |
575 | | - clock_skew_seconds=20) |
| 586 | + |
| 587 | + # Expired case: mock utcnow to be 1 second after exp + clock_skew (just expired) |
| 588 | + # The token should be considered expired here. |
| 589 | + mock_now_expired = datetime.datetime.utcfromtimestamp(exp_timestamp + 20 + 1) |
| 590 | + with mock.patch('google.auth._helpers.utcnow', return_value=mock_now_expired): |
| 591 | + with pytest.raises(auth.ExpiredIdTokenError): |
| 592 | + auth.verify_id_token(id_token_encoded, app=user_mgt_app, |
| 593 | + clock_skew_seconds=20) |
576 | 594 |
|
577 | 595 | def test_project_id_option(self): |
578 | 596 | app = firebase_admin.initialize_app( |
@@ -741,17 +759,34 @@ def test_expired_cookie(self, user_mgt_app): |
741 | 759 |
|
742 | 760 | def test_expired_cookie_with_tolerance(self, user_mgt_app): |
743 | 761 | _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) |
744 | | - cookie = self.invalid_cookies['ExpiredCookieShort'] |
| 762 | + cookie_encoded = self.invalid_cookies['ExpiredCookieShort'] |
745 | 763 | if _is_emulated(): |
746 | | - self._assert_valid_cookie(cookie, user_mgt_app) |
| 764 | + # Emulator mode doesn't perform the same time checks, skip advanced mocking |
| 765 | + self._assert_valid_cookie(cookie_encoded, user_mgt_app) |
747 | 766 | return |
748 | | - claims = auth.verify_session_cookie(cookie, app=user_mgt_app, check_revoked=False, |
749 | | - clock_skew_seconds=59) |
| 767 | + |
| 768 | + # Decode the token to get its actual 'exp' timestamp |
| 769 | + decoded_cookie = jwt.decode(cookie_encoded, verify=False) |
| 770 | + exp_timestamp = decoded_cookie['exp'] |
| 771 | + |
| 772 | + # Valid case: mock utcnow to be exactly at exp + clock_skew (boundary of validity) |
| 773 | + # The cookie should be considered valid here. |
| 774 | + mock_now_valid = datetime.datetime.utcfromtimestamp(exp_timestamp + 59) |
| 775 | + with mock.patch('google.auth._helpers.utcnow', return_value=mock_now_valid): |
| 776 | + claims = auth.verify_session_cookie( |
| 777 | + cookie_encoded, app=user_mgt_app, check_revoked=False, |
| 778 | + clock_skew_seconds=59) # This clock_skew is used by google.auth.jwt |
750 | 779 | assert claims['admin'] is True |
751 | 780 | assert claims['uid'] == claims['sub'] |
752 | | - with pytest.raises(auth.ExpiredSessionCookieError): |
753 | | - auth.verify_session_cookie(cookie, app=user_mgt_app, check_revoked=False, |
754 | | - clock_skew_seconds=29) |
| 781 | + |
| 782 | + # Expired case: mock utcnow to be 1 second after exp + clock_skew (just expired) |
| 783 | + # The cookie should be considered expired here. |
| 784 | + mock_now_expired = datetime.datetime.utcfromtimestamp(exp_timestamp + 29 + 1) |
| 785 | + with mock.patch('google.auth._helpers.utcnow', return_value=mock_now_expired): |
| 786 | + with pytest.raises(auth.ExpiredSessionCookieError): |
| 787 | + auth.verify_session_cookie( |
| 788 | + cookie_encoded, app=user_mgt_app, check_revoked=False, |
| 789 | + clock_skew_seconds=29) # This clock_skew is used by google.auth.jwt |
755 | 790 |
|
756 | 791 | def test_project_id_option(self): |
757 | 792 | app = firebase_admin.initialize_app( |
|
0 commit comments