From 1420180be72a5b790d6052592e5042d3d269b341 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Sat, 6 Jun 2026 21:55:13 +0200 Subject: [PATCH] feat(07.4-02): add fgp validation block to get_current_user in deps/auth.py - Add `import hmac` to deps/auth.py imports block - Insert fgp check after user_nbf block: extract fgp_claim from payload, skip if empty (migration grace for pre-7.4 tokens, D-06), recompute fgp_actual via auth_service._compute_fgp, compare with hmac.compare_digest - Mismatch raises HTTP 401 "Token fingerprint mismatch" (D-03) - Block placed outside try/except (pure computation, no I/O, no fail-open) --- backend/deps/auth.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backend/deps/auth.py b/backend/deps/auth.py index ad6a5e2..248a422 100644 --- a/backend/deps/auth.py +++ b/backend/deps/auth.py @@ -20,6 +20,7 @@ Usage in route handlers: ): ... """ +import hmac import logging import uuid @@ -84,6 +85,24 @@ async def get_current_user( _logger.warning("Redis user_nbf check failed (fail-open): %s", exc) # ── end user_nbf check ────────────────────────────────────────────────────── + # ── fgp check (D-06, Phase 7.4) ──────────────────────────────────────────── + # Validates the fgp claim embedded by create_access_token. Empty claim means + # the token predates Phase 7.4 — allow gracefully (migration window, D-06). + # NOT wrapped in try/except: _compute_fgp is pure computation with no I/O. + fgp_claim = payload.get("fgp", "") + if fgp_claim: + fgp_actual = auth_service._compute_fgp( + request.headers.get("User-Agent", ""), + request.headers.get("Accept-Language", ""), + ) + if not hmac.compare_digest(fgp_claim, fgp_actual): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Token fingerprint mismatch", + headers={"WWW-Authenticate": "Bearer"}, + ) + # ── end fgp check ─────────────────────────────────────────────────────────── + try: user_uuid = uuid.UUID(payload["sub"]) except (KeyError, ValueError) as exc: