feat: implement Phase 1 hardening
- Verify JWT signatures via JWKS in auth.py - Fix broken frontend auth button references - Add Pydantic Settings for env validation (RETENTION_DAYS, CORS_ORIGINS) - Create MongoDB indexes + TTL on startup - Add /health endpoint and CORS middleware - Escape regex input in event queries - Fix dedupe() return calculation in maintenance.py - Replace basic logging with structured structlog JSON logs - Update README and add ROADMAP.md
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import time
|
||||
import logging
|
||||
import structlog
|
||||
from typing import Optional, Set
|
||||
|
||||
import requests
|
||||
from fastapi import Depends, HTTPException, Header
|
||||
from jose import jwt
|
||||
from jose.jwk import construct
|
||||
|
||||
from config import (
|
||||
AUTH_ENABLED,
|
||||
@@ -15,7 +16,7 @@ from config import (
|
||||
)
|
||||
|
||||
JWKS_CACHE = {"exp": 0, "keys": []}
|
||||
logger = logging.getLogger("aoc.auth")
|
||||
logger = structlog.get_logger("aoc.auth")
|
||||
|
||||
|
||||
def _get_jwks():
|
||||
@@ -48,9 +49,18 @@ def _allowed(claims: dict, allowed_roles: Set[str], allowed_groups: Set[str]) ->
|
||||
|
||||
def _decode_token(token: str, jwks):
|
||||
try:
|
||||
# Unverified decode to accept tokens from single-app setups without strict signing validation.
|
||||
claims = jwt.get_unverified_claims(token)
|
||||
header = jwt.get_unverified_header(token)
|
||||
kid = header.get("kid")
|
||||
key_dict = next((k for k in jwks if k.get("kid") == kid), None)
|
||||
if not key_dict:
|
||||
raise HTTPException(status_code=401, detail="Invalid token: signing key not found")
|
||||
|
||||
key = construct(key_dict)
|
||||
decode_kwargs = {"algorithms": ["RS256"]}
|
||||
if AUTH_CLIENT_ID:
|
||||
decode_kwargs["audience"] = AUTH_CLIENT_ID
|
||||
claims = jwt.decode(token, key, **decode_kwargs)
|
||||
|
||||
tid = claims.get("tid")
|
||||
iss = claims.get("iss", "")
|
||||
if AUTH_TENANT_ID and tid and tid != AUTH_TENANT_ID:
|
||||
@@ -61,7 +71,7 @@ def _decode_token(token: str, jwks):
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as exc:
|
||||
logger.warning("Token parse failed: %s", exc)
|
||||
logger.warning("Token verification failed", error=str(exc))
|
||||
raise HTTPException(status_code=401, detail="Invalid token")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user