fix(redis): Pool-Rollout vervollständigen + TOTP-Lockout fail-closed mit 503
Redis-Review deckte auf, dass der Pool-Fix vom letzten Commit nur totp_login/kiosk_security erreichte. Login/Refresh (auth_service.py) und PIN/NFC/QR-Kiosk-Login (kiosk_auth_service.py) öffneten weiterhin pro Request eine neue aioredis-Verbindung. Zusätzlich nutzten kiosk_session_service.py und public_stamp_session_service.py den *sync* Redis-Client aus async-Code – blockierender Socket-Call im Event-Loop bei jedem Kiosk-/Stempel-Request. Alle auf get_async_redis() umgestellt. TOTP-Lockout wirft jetzt 503 statt eines ungefangenen 500 bei Redis-Ausfall (RedisError explizit gefangen, eigene HTTPExceptions unberührt). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015Ahyx6D3r7G1EuAc42nezn
This commit is contained in:
+15
-10
@@ -318,19 +318,24 @@ async def totp_login(
|
||||
if not user.totp_enabled or not user.totp_secret:
|
||||
raise HTTPException(400, "2FA nicht aktiv")
|
||||
|
||||
from redis.exceptions import RedisError
|
||||
|
||||
redis_client = get_async_redis()
|
||||
# M-5: Lockout-Check vor TOTP-Verifikation
|
||||
await _check_totp_lockout(user_id, redis_client)
|
||||
try:
|
||||
# M-5: Lockout-Check vor TOTP-Verifikation
|
||||
await _check_totp_lockout(user_id, redis_client)
|
||||
|
||||
plain_secret = _totp_plain(user)
|
||||
totp = pyotp.TOTP(plain_secret or "")
|
||||
if not totp.verify(data.code, valid_window=1):
|
||||
# M-5: Fehlversuch zählen
|
||||
await _record_totp_failure(user_id, redis_client)
|
||||
raise HTTPException(400, "Ungültiger Code")
|
||||
plain_secret = _totp_plain(user)
|
||||
totp = pyotp.TOTP(plain_secret or "")
|
||||
if not totp.verify(data.code, valid_window=1):
|
||||
# M-5: Fehlversuch zählen
|
||||
await _record_totp_failure(user_id, redis_client)
|
||||
raise HTTPException(400, "Ungültiger Code")
|
||||
|
||||
# M-5: Erfolg → Fehlversuche zurücksetzen
|
||||
await _clear_totp_failures(user_id, redis_client)
|
||||
# M-5: Erfolg → Fehlversuche zurücksetzen
|
||||
await _clear_totp_failures(user_id, redis_client)
|
||||
except RedisError as exc:
|
||||
raise HTTPException(503, "2FA-Login vorübergehend nicht verfügbar (Redis).") from exc
|
||||
|
||||
from datetime import datetime, timezone
|
||||
user.last_login = datetime.now(timezone.utc)
|
||||
|
||||
Reference in New Issue
Block a user