"""FastAPI dependency functions for authentication and authorization.""" from collections.abc import Callable from typing import Any from fastapi import HTTPException, Request, status def require_admin_role(request: Request) -> None: """Dependency to require admin role""" auth = getattr(request.state, "auth", None) if not auth: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Authentication required" ) auth.require_role("admin") def require_reviewer_role(request: Request) -> None: """Dependency to require reviewer role""" auth = getattr(request.state, "auth", None) if not auth: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Authentication required" ) auth.require_any_role(["admin", "reviewer"]) def get_current_tenant(request: Request) -> str | None: """Extract tenant ID from user context or headers""" # This could be extracted from JWT claims, user groups, or custom headers # For now, we'll use a simple mapping from user to tenant user = getattr(request.state, "user", None) if not user: return None # Simple tenant extraction - in production this would be more sophisticated # Could be from JWT claims, database lookup, or group membership roles = getattr(request.state, "roles", []) for role in roles: if role.startswith("tenant:"): return str(role.split(":", 1)[1]) # Check for explicit tenant header (useful for testing/API keys) tenant_header = request.headers.get("X-Tenant-ID") if tenant_header: return tenant_header # Default tenant for development return "default" # Dependency functions for FastAPI def get_current_user() -> Callable[[Request], dict[str, Any]]: """FastAPI dependency to get current user""" def _get_current_user(request: Request) -> dict[str, Any]: user = getattr(request.state, "user", None) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Authentication required", ) return { "sub": user, "email": getattr(request.state, "email", ""), "roles": getattr(request.state, "roles", []), } return _get_current_user def get_tenant_id() -> Callable[[Request], str]: """FastAPI dependency to get tenant ID""" def _get_tenant_id(request: Request) -> str: tenant_id = get_current_tenant(request) if not tenant_id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Tenant ID required" ) return tenant_id return _get_tenant_id