gateway/modules/routes/routeRbac.py
2025-12-07 13:48:39 +01:00

161 lines
5.2 KiB
Python

"""
RBAC routes for the backend API.
Implements endpoints for role-based access control permissions.
"""
from fastapi import APIRouter, HTTPException, Depends, Query, Request
from typing import Optional
import logging
from modules.security.auth import getCurrentUser, limiter
from modules.datamodels.datamodelUam import User, UserPermissions, AccessLevel
from modules.datamodels.datamodelRbac import AccessRuleContext
from modules.interfaces.interfaceDbAppObjects import getInterface
# Configure logger
logger = logging.getLogger(__name__)
router = APIRouter(
prefix="/api/rbac",
tags=["RBAC"],
responses={404: {"description": "Not found"}}
)
@router.get("/permissions", response_model=UserPermissions)
@limiter.limit("60/minute")
async def getPermissions(
request: Request,
context: str = Query(..., description="Context type: DATA, UI, or RESOURCE"),
item: Optional[str] = Query(None, description="Item identifier (table name, UI path, or resource path)"),
currentUser: User = Depends(getCurrentUser)
) -> UserPermissions:
"""
Get RBAC permissions for the current user for a specific context and item.
Query Parameters:
- context: Context type (DATA, UI, or RESOURCE)
- item: Optional item identifier. For DATA: table name (e.g., "UserInDB"),
For UI: cascading string (e.g., "playground.voice.settings"),
For RESOURCE: cascading string (e.g., "ai.model.anthropic")
Returns:
- UserPermissions object with view, read, create, update, delete permissions
Examples:
- GET /api/rbac/permissions?context=DATA&item=UserInDB
- GET /api/rbac/permissions?context=UI&item=playground.voice.settings
- GET /api/rbac/permissions?context=RESOURCE&item=ai.model.anthropic
"""
try:
# Validate context
try:
accessContext = AccessRuleContext(context.upper())
except ValueError:
raise HTTPException(
status_code=400,
detail=f"Invalid context '{context}'. Must be one of: DATA, UI, RESOURCE"
)
# Get interface and RBAC permissions
interface = getInterface(currentUser)
if not interface.rbac:
raise HTTPException(
status_code=500,
detail="RBAC interface not available"
)
# Get permissions
permissions = interface.rbac.getUserPermissions(
currentUser,
accessContext,
item or ""
)
return permissions
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting RBAC permissions: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Failed to get permissions: {str(e)}"
)
@router.get("/rules", response_model=list)
@limiter.limit("30/minute")
async def getAccessRules(
request: Request,
roleLabel: Optional[str] = Query(None, description="Filter by role label"),
context: Optional[str] = Query(None, description="Filter by context (DATA, UI, RESOURCE)"),
item: Optional[str] = Query(None, description="Filter by item identifier"),
currentUser: User = Depends(getCurrentUser)
) -> list:
"""
Get access rules with optional filters.
Only returns rules that the current user has permission to view.
Query Parameters:
- roleLabel: Optional role label filter
- context: Optional context filter (DATA, UI, RESOURCE)
- item: Optional item filter
Returns:
- List of AccessRule objects
"""
try:
# Get interface
interface = getInterface(currentUser)
# Check if user has permission to view access rules
# For now, only sysadmin can view rules
if not interface.rbac:
raise HTTPException(
status_code=500,
detail="RBAC interface not available"
)
# Check permission - only sysadmin can view rules
permissions = interface.rbac.getUserPermissions(
currentUser,
AccessRuleContext.DATA,
"AccessRule"
)
if not permissions.view or permissions.read == AccessLevel.NONE:
raise HTTPException(
status_code=403,
detail="No permission to view access rules"
)
# Parse context if provided
accessContext = None
if context:
try:
accessContext = AccessRuleContext(context.upper())
except ValueError:
raise HTTPException(
status_code=400,
detail=f"Invalid context '{context}'. Must be one of: DATA, UI, RESOURCE"
)
# Get rules
rules = interface.getAccessRules(
roleLabel=roleLabel,
context=accessContext,
item=item
)
# Convert to dict for JSON serialization
return [rule.model_dump() for rule in rules]
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting access rules: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Failed to get access rules: {str(e)}"
)