shinkan-jinkendo/backend/tests/test_auth_hardening.py

52 lines
1.5 KiB
Python
Raw Normal View History

"""Login-Sperre, TOTP und Medien-Grant ohne Datenbank."""
from __future__ import annotations
import os
os.environ.setdefault("SKIP_DB_MIGRATE", "1")
os.environ.setdefault("REQUIRE_ADMIN_TOTP", "0")
import pytest
from fastapi.testclient import TestClient
from main import app
from media_grant import issue_media_grant, profile_id_from_media_grant
from totp_auth import generate_totp_secret, totp_code, verify_totp
import time
@pytest.fixture
def client() -> TestClient:
return TestClient(app)
def test_totp_accepts_current_code() -> None:
secret = generate_totp_secret()
code = totp_code(secret, int(time.time()) // 30)
assert verify_totp(secret, code)
assert not verify_totp(secret, "000000") or code == "000000"
def test_media_grant_rejects_session_shaped_token() -> None:
assert profile_id_from_media_grant("not-a-media-grant") is None
token, _exp = issue_media_grant(42, ttl_seconds=60)
assert profile_id_from_media_grant(token) == 42
assert profile_id_from_media_grant(token + "x") is None
def test_change_password_requires_current_password() -> None:
from pydantic import ValidationError
from models import ChangePasswordRequest
with pytest.raises(ValidationError):
ChangePasswordRequest.model_validate({"pin": "neuespasswort"})
def test_login_rejects_oversized_password(client: TestClient) -> None:
response = client.post(
"/api/auth/login",
json={"email": "trainer@example.com", "password": "x" * 200},
)
assert response.status_code == 422