Files
calminer/tests/test_security.py

79 lines
2.1 KiB
Python

from __future__ import annotations
import secrets
from datetime import timedelta
import pytest
from services.security import (
JWTSettings,
TokenDecodeError,
TokenExpiredError,
TokenTypeMismatchError,
create_access_token,
create_refresh_token,
decode_access_token,
hash_password,
verify_password,
)
@pytest.fixture()
def jwt_settings() -> JWTSettings:
"""Provide a unique JWTSettings instance per test with random secret."""
return JWTSettings(secret_key=secrets.token_urlsafe(32))
def test_hash_password_round_trip() -> None:
password = secrets.token_urlsafe(16)
hashed = hash_password(password)
assert hashed != password
assert verify_password(password, hashed)
assert not verify_password("incorrect", hashed)
def test_verify_password_handles_malformed_hash() -> None:
assert not verify_password("secret", "not-a-valid-hash")
def test_access_token_roundtrip(jwt_settings: JWTSettings) -> None:
token = create_access_token(
"user-id-123",
jwt_settings,
scopes=("read", "write"),
extra_claims={"custom": "value"},
)
payload = decode_access_token(token, jwt_settings)
assert payload.sub == "user-id-123"
assert payload.type == "access"
assert payload.scopes == ["read", "write"]
def test_refresh_token_type_mismatch(jwt_settings: JWTSettings) -> None:
token = create_refresh_token("user-id-456", jwt_settings)
with pytest.raises(TokenTypeMismatchError):
decode_access_token(token, jwt_settings)
def test_decode_expired_token(jwt_settings: JWTSettings) -> None:
expired_token = create_access_token(
"user-id-789",
jwt_settings,
expires_delta=timedelta(seconds=-5),
)
with pytest.raises(TokenExpiredError):
decode_access_token(expired_token, jwt_settings)
def test_decode_tampered_token(jwt_settings: JWTSettings) -> None:
token = create_access_token("user-id-321", jwt_settings)
tampered = token[:-1] + ("a" if token[-1] != "a" else "b")
with pytest.raises(TokenDecodeError):
decode_access_token(tampered, jwt_settings)