diff --git a/tests/test_auth_sessions.py b/tests/test_auth_sessions.py index 9e95dedf..725e336b 100644 --- a/tests/test_auth_sessions.py +++ b/tests/test_auth_sessions.py @@ -130,6 +130,48 @@ class TestSessionInvalidation(unittest.TestCase): # Should not raise +class TestHmacMigrationBridge(unittest.TestCase): + """Verify the 32→64-char HMAC migration bridge in verify_session(). + + When create_session() was changed from hexdigest()[:32] to hexdigest(), + existing session cookies with 32-char signatures needed to remain valid. + These tests lock down the dual-length acceptance so a future refactor + doesn't accidentally drop it. + + These can be removed once session TTLs have expired (~30 days from the + deploy date of fix 3/3). + """ + + def setUp(self): + auth._sessions.clear() + + def test_legacy_truncated_sig_still_validates(self): + """A cookie signed with the old 32-char truncation must still verify. + + Simulates a session created by a pre-upgrade build where + hexdigest()[:32] was used. After upgrade to full 64-char HMAC, + this cookie must still be accepted (migration bridge). + """ + token = auth.secrets.token_hex(32) + auth._sessions[token] = time.time() + 3600 + legacy_sig = auth.hmac.new( + auth._signing_key(), token.encode(), auth.hashlib.sha256 + ).hexdigest()[:32] + cookie = f"{token}.{legacy_sig}" + self.assertTrue(auth.verify_session(cookie)) + + def test_full_sig_rejects_forged_prefix(self): + """A forged 32-char sig that is NOT the HMAC prefix must be rejected. + + Ensures the len(sig) == 32 guard prevents blind acceptance of + arbitrary short signatures. + """ + token = auth.secrets.token_hex(32) + auth._sessions[token] = time.time() + 3600 + forged = "a" * 32 + self.assertFalse(auth.verify_session(f"{token}.{forged}")) + + if __name__ == "__main__": unittest.main()