From f2c7d6bbe15ffe2ab59509e536675f49d3d68858 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 20:14:47 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Auto=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs_src/security/tutorial004_an_py310.py | 4 +- tests/test_invariant_tutorial004_an_py310.py | 82 +++++++++++++------- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py index d5c4deda5..f09ada5bd 100644 --- a/docs_src/security/tutorial004_an_py310.py +++ b/docs_src/security/tutorial004_an_py310.py @@ -11,7 +11,9 @@ from pydantic import BaseModel # to get a string like this run: # openssl rand -hex 32 -SECRET_KEY = os.getenv("SECRET_KEY", "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7") +SECRET_KEY = os.getenv( + "SECRET_KEY", "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" +) ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 diff --git a/tests/test_invariant_tutorial004_an_py310.py b/tests/test_invariant_tutorial004_an_py310.py index 0e31c85f8..78641e6e3 100644 --- a/tests/test_invariant_tutorial004_an_py310.py +++ b/tests/test_invariant_tutorial004_an_py310.py @@ -1,47 +1,69 @@ -import pytest -import sys +import base64 +import json import os +import sys from datetime import datetime, timedelta -import json -import base64 + +import pytest # Add the project root to sys.path to import the module -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../.."))) from docs_src.security.tutorial004_an_py310 import decode_and_validate_token -@pytest.mark.parametrize("token_payload", [ - # Exact exploit case: token with expired timestamp - json.dumps({"user_id": "admin", "exp": int((datetime.utcnow() - timedelta(hours=1)).timestamp())}), - - # Boundary case: token with no expiration claim - json.dumps({"user_id": "attacker"}), - - # Valid input: token with future expiration - json.dumps({"user_id": "user123", "exp": int((datetime.utcnow() + timedelta(hours=1)).timestamp())}), - - # Adversarial case: token with malformed expiration (string instead of int) - json.dumps({"user_id": "evil", "exp": "never"}), - - # Adversarial case: token with far future expiration (beyond reasonable bounds) - json.dumps({"user_id": "admin", "exp": int((datetime.utcnow() + timedelta(days=365*10)).timestamp())}), -]) + +@pytest.mark.parametrize( + "token_payload", + [ + # Exact exploit case: token with expired timestamp + json.dumps( + { + "user_id": "admin", + "exp": int((datetime.utcnow() - timedelta(hours=1)).timestamp()), + } + ), + # Boundary case: token with no expiration claim + json.dumps({"user_id": "attacker"}), + # Valid input: token with future expiration + json.dumps( + { + "user_id": "user123", + "exp": int((datetime.utcnow() + timedelta(hours=1)).timestamp()), + } + ), + # Adversarial case: token with malformed expiration (string instead of int) + json.dumps({"user_id": "evil", "exp": "never"}), + # Adversarial case: token with far future expiration (beyond reasonable bounds) + json.dumps( + { + "user_id": "admin", + "exp": int((datetime.utcnow() + timedelta(days=365 * 10)).timestamp()), + } + ), + ], +) def test_jwt_expiration_validation_invariant(token_payload): """Invariant: JWT tokens must be rejected if expired or lacking proper expiration validation.""" - + # Create a simple JWT-like token (header.payload.signature) - header = base64.urlsafe_b64encode(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()).rstrip(b'=') - payload = base64.urlsafe_b64encode(token_payload.encode()).rstrip(b'=') - signature = base64.urlsafe_b64encode(b"fakesignature").rstrip(b'=') + header = base64.urlsafe_b64encode( + json.dumps({"alg": "HS256", "typ": "JWT"}).encode() + ).rstrip(b"=") + payload = base64.urlsafe_b64encode(token_payload.encode()).rstrip(b"=") + signature = base64.urlsafe_b64encode(b"fakesignature").rstrip(b"=") token = f"{header.decode()}.{payload.decode()}.{signature.decode()}" - + try: result = decode_and_validate_token(token) # If token is accepted, it must have a valid future expiration payload_dict = json.loads(token_payload) - assert "exp" in payload_dict, "Token without expiration claim should be rejected" + assert "exp" in payload_dict, ( + "Token without expiration claim should be rejected" + ) assert isinstance(payload_dict["exp"], int), "Expiration must be integer" - assert payload_dict["exp"] > int(datetime.utcnow().timestamp()), "Token expiration must be in future" - except Exception as e: + assert payload_dict["exp"] > int(datetime.utcnow().timestamp()), ( + "Token expiration must be in future" + ) + except Exception: # Any validation failure is acceptable - the invariant holds - assert True \ No newline at end of file + assert True