"""API dependencies for authentication, authorization, and tenant resolution.""" from typing import Annotated from uuid import UUID from fastapi import Depends, HTTPException, Header, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from sqlalchemy.orm import Session from app.database import get_db from app.core.security import decode_token from app.models.user import User from app.models.tenant import Tenant from app.core.permissions import has_permission security = HTTPBearer() async def get_current_user( credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)], db: Session = Depends(get_db), ) -> User: """Validate JWT and return current user.""" try: payload = decode_token(credentials.credentials) user_id = UUID(payload["sub"]) except Exception: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials", headers={"WWW-Authenticate": "Bearer"}, ) user = db.query(User).filter(User.id == user_id).first() if not user or user.status != "active": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found or inactive", ) return user async def get_current_tenant( x_tenant_id: Annotated[UUID, Header(..., alias="X-Tenant-ID")], user: User = Depends(get_current_user), ) -> Tenant: """Validate user has access to the specified tenant.""" if user.tenant_id != x_tenant_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied to this tenant", ) return user.tenant class RequirePermission: """Dependency factory for permission checking.""" def __init__(self, permission: str): self.permission = permission async def __call__(self, user: User = Depends(get_current_user)) -> User: user_perms = set() for role in user.roles: user_perms.update(role.permissions) if not has_permission(user_perms, self.permission): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"Missing permission: {self.permission}", ) return user # Common permission dependencies RequireAdmin = Depends(RequirePermission("users.update")) RequireUserRead = Depends(RequirePermission("users.read")) RequireTenantManage = Depends(RequirePermission("tenants.manage")) RequireBillingRead = Depends(RequirePermission("billing.read")) RequireAuditRead = Depends(RequirePermission("audit.read")) RequireReportCreate = Depends(RequirePermission("reports.create")) RequireApiKeyCreate = Depends(RequirePermission("api_keys.create"))