""" 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)}" )