Skip to content

Commit 33968af

Browse files
committed
add tests for new jwt_leeway
1 parent 2f515c9 commit 33968af

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

tests/test_session.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import concurrent.futures
22
from datetime import datetime, timezone
3+
import time
34
from unittest.mock import AsyncMock, Mock, patch
45

56
import jwt
@@ -477,6 +478,174 @@ def test_refresh_success_with_aud_claim(
477478

478479
assert isinstance(response, RefreshWithSessionCookieSuccessResponse)
479480

481+
@with_jwks_mock
482+
def test_authenticate_with_slightly_expired_jwt_fails_without_leeway(
483+
self, session_constants, mock_user_management
484+
):
485+
# Create a token that's expired by 5 seconds
486+
current_time = int(time.time())
487+
488+
# Create token claims with exp 5 seconds in the past
489+
token_claims = {
490+
**session_constants["TEST_TOKEN_CLAIMS"],
491+
"exp": current_time - 5, # Expired by 5 seconds
492+
"iat": current_time - 60, # Issued 60 seconds ago
493+
}
494+
495+
slightly_expired_token = jwt.encode(
496+
token_claims,
497+
session_constants["PRIVATE_KEY"],
498+
algorithm="RS256",
499+
)
500+
501+
# Prepare sealed session data with the slightly expired token
502+
session_data = Session.seal_data(
503+
{
504+
"access_token": slightly_expired_token,
505+
"user": session_constants["TEST_USER"],
506+
},
507+
session_constants["COOKIE_PASSWORD"],
508+
)
509+
510+
# With default leeway=0, authentication should fail
511+
session = Session(
512+
user_management=mock_user_management,
513+
client_id=session_constants["CLIENT_ID"],
514+
session_data=session_data,
515+
cookie_password=session_constants["COOKIE_PASSWORD"],
516+
jwt_leeway=0,
517+
)
518+
519+
response = session.authenticate()
520+
assert response.authenticated is False
521+
assert response.reason == AuthenticateWithSessionCookieFailureReason.INVALID_JWT
522+
523+
@with_jwks_mock
524+
def test_authenticate_with_slightly_expired_jwt_succeeds_with_leeway(
525+
self, session_constants, mock_user_management
526+
):
527+
# Create a token that's expired by 5 seconds
528+
current_time = int(time.time())
529+
530+
# Create token claims with exp 5 seconds in the past
531+
token_claims = {
532+
**session_constants["TEST_TOKEN_CLAIMS"],
533+
"exp": current_time - 5, # Expired by 5 seconds
534+
"iat": current_time - 60, # Issued 60 seconds ago
535+
}
536+
537+
slightly_expired_token = jwt.encode(
538+
token_claims,
539+
session_constants["PRIVATE_KEY"],
540+
algorithm="RS256",
541+
)
542+
543+
# Prepare sealed session data with the slightly expired token
544+
session_data = Session.seal_data(
545+
{
546+
"access_token": slightly_expired_token,
547+
"user": session_constants["TEST_USER"],
548+
},
549+
session_constants["COOKIE_PASSWORD"],
550+
)
551+
552+
# With leeway=10, authentication should succeed
553+
session = Session(
554+
user_management=mock_user_management,
555+
client_id=session_constants["CLIENT_ID"],
556+
session_data=session_data,
557+
cookie_password=session_constants["COOKIE_PASSWORD"],
558+
jwt_leeway=10, # 10 seconds leeway
559+
)
560+
561+
response = session.authenticate()
562+
assert response.authenticated is True
563+
assert response.session_id == session_constants["TEST_TOKEN_CLAIMS"]["sid"]
564+
565+
@with_jwks_mock
566+
def test_authenticate_with_significantly_expired_jwt_fails_without_leeway(
567+
self, session_constants, mock_user_management
568+
):
569+
# Create a token that's expired by 60 seconds
570+
current_time = int(time.time())
571+
572+
# Create token claims with exp 60 seconds in the past
573+
token_claims = {
574+
**session_constants["TEST_TOKEN_CLAIMS"],
575+
"exp": current_time - 60, # Expired by 60 seconds
576+
"iat": current_time - 120, # Issued 120 seconds ago
577+
}
578+
579+
significantly_expired_token = jwt.encode(
580+
token_claims,
581+
session_constants["PRIVATE_KEY"],
582+
algorithm="RS256",
583+
)
584+
585+
# Prepare sealed session data with the significantly expired token
586+
session_data = Session.seal_data(
587+
{
588+
"access_token": significantly_expired_token,
589+
"user": session_constants["TEST_USER"],
590+
},
591+
session_constants["COOKIE_PASSWORD"],
592+
)
593+
594+
# With default leeway=0, authentication should fail
595+
session = Session(
596+
user_management=mock_user_management,
597+
client_id=session_constants["CLIENT_ID"],
598+
session_data=session_data,
599+
cookie_password=session_constants["COOKIE_PASSWORD"],
600+
jwt_leeway=0,
601+
)
602+
603+
response = session.authenticate()
604+
assert response.authenticated is False
605+
assert response.reason == AuthenticateWithSessionCookieFailureReason.INVALID_JWT
606+
607+
@with_jwks_mock
608+
def test_authenticate_with_significantly_expired_jwt_fails_with_insufficient_leeway(
609+
self, session_constants, mock_user_management
610+
):
611+
# Create a token that's expired by 60 seconds
612+
current_time = int(time.time())
613+
614+
# Create token claims with exp 60 seconds in the past
615+
token_claims = {
616+
**session_constants["TEST_TOKEN_CLAIMS"],
617+
"exp": current_time - 60, # Expired by 60 seconds
618+
"iat": current_time - 120, # Issued 120 seconds ago
619+
}
620+
621+
significantly_expired_token = jwt.encode(
622+
token_claims,
623+
session_constants["PRIVATE_KEY"],
624+
algorithm="RS256",
625+
)
626+
627+
# Prepare sealed session data with the significantly expired token
628+
session_data = Session.seal_data(
629+
{
630+
"access_token": significantly_expired_token,
631+
"user": session_constants["TEST_USER"],
632+
},
633+
session_constants["COOKIE_PASSWORD"],
634+
)
635+
636+
# With leeway=10, authentication should still fail (not enough leeway)
637+
session = Session(
638+
user_management=mock_user_management,
639+
client_id=session_constants["CLIENT_ID"],
640+
session_data=session_data,
641+
cookie_password=session_constants["COOKIE_PASSWORD"],
642+
jwt_leeway=10, # 10 seconds leeway is not enough for 60 seconds expiration
643+
)
644+
645+
response = session.authenticate()
646+
assert response.authenticated is False
647+
assert response.reason == AuthenticateWithSessionCookieFailureReason.INVALID_JWT
648+
480649

481650
class TestAsyncSession(SessionFixtures):
482651
@pytest.mark.asyncio

0 commit comments

Comments
 (0)