ifixkart-backend/Backend/app/core/permissions/RoleChecker.py

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