117 lines
4.3 KiB
Python
117 lines
4.3 KiB
Python
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
|