from fastapi import Depends, HTTPException, Request, status from fastapi.security import OAuth2PasswordBearer from sqlalchemy.orm import Session from sqlalchemy import select from app.core.database.db_session import get_db from app.core.Token import verify_access_token from app.models.UserModel import User from app.models.RoleModel import Role from app.models.PermissionModel import Permission, RolePermission from app.core.config.Config import settings oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token", auto_error=False) def get_current_user( request: Request, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db) ) -> User: # 🛡️ MCP INTERNAL BYPASS client_key = request.headers.get("X-API-KEY") if client_key and client_key == settings.PUBLIC_API_KEY: # Create virtual Role and User object virtual_role = Role(role_id="virtual-admin-role", role_name="Admin", role_prefix="ADM") virtual_user = User( user_id="internal-mcp", email="mcp@steelonix.in", first_name="MCP", last_name="Platform", display_name="MCP Platform", role_id="virtual-admin-role", role=virtual_role, is_active=True ) if hasattr(request.state, "db_session"): request.state.db_session.info["user_id"] = "internal-mcp" from app.core.middleware.audit_context import user_id_var user_id_var.set("internal-mcp") return virtual_user if not token: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing Authorization token", headers={"WWW-Authenticate": "Bearer"} ) payload = verify_access_token(token) user_id = payload.get("sub") if not user_id: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token claims", headers={"WWW-Authenticate": "Bearer"} ) # Query user with active state check stmt = select(User).where(User.user_id == user_id, User.deleted_at.is_(None)) user = db.execute(stmt).scalar_one_or_none() if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found", headers={"WWW-Authenticate": "Bearer"} ) if not user.is_active or user.is_locked: raise HTTPException(status_code=403, detail="User account is inactive or locked") if hasattr(request.state, "db_session"): request.state.db_session.info["user_id"] = user.user_id from app.core.middleware.audit_context import user_id_var user_id_var.set(user.user_id) return user class RoleChecker: def __init__(self, allowed_roles: list[str]): self.allowed_roles = [r.lower() for r in allowed_roles] def __call__(self, current_user: User = Depends(get_current_user)) -> User: user_role = current_user.role.role_name.lower() if user_role not in self.allowed_roles: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You do not have permission to access this resource" ) return current_user class PermissionChecker: def __init__(self, permission_code: str): self.permission_code = permission_code def __call__( self, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ) -> User: # Super Admin bypass if current_user.role.role_name.lower() == "super admin" or current_user.user_id == "internal-mcp": return current_user # Query permission link stmt = ( select(RolePermission) .join(Permission, Permission.permission_id == RolePermission.permission_id) .where( RolePermission.role_id == current_user.role_id, Permission.permission_code == self.permission_code, Permission.is_active.is_(True) ) ) has_permission = db.execute(stmt).scalar_one_or_none() if not has_permission: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"Missing required permission: {self.permission_code}" ) return current_user