apac-ops-bot/backend/app/core/rbac.py
SamoilenkoVadym b284cadb86 Add test user authentication and RBAC admin panel
Implemented simple authentication for testing and admin panel for user management:

Backend:
- Add simple email/password login for test users (admin@test.local, user@test.local)
- Implement RBAC (Role-Based Access Control) with Permission enum
- Create admin endpoints for user management and system analytics
- Add bcrypt password hashing for test users
- Create script to generate test users in database

Frontend:
- Add SimpleLogin component for test authentication
- Create AdminPanel with user management and system analytics
- Add role-based navigation (Admin tab visible only for admins)
- Update AuthContext to support both MSAL and simple login
- Add API methods for admin operations

Features:
- Admins can view all users, manage roles, activate/deactivate accounts
- Admins can view system-wide analytics (users, conversations, tokens, costs)
- Regular users only see their own chats and usage
- Role badges in UI show user role (user/admin/superadmin)

Note: Simple authentication is for testing only. Production uses Azure AD MSAL.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-27 20:05:54 +00:00

146 lines
4 KiB
Python

"""
Role-Based Access Control (RBAC) utilities
"""
from enum import Enum
from typing import List
from fastapi import HTTPException, status
class UserRole(str, Enum):
"""User roles for RBAC"""
USER = "user"
ADMIN = "admin"
SUPERADMIN = "superadmin"
class Permission(str, Enum):
"""System permissions"""
# User permissions
READ_OWN_PROFILE = "read_own_profile"
UPDATE_OWN_PROFILE = "update_own_profile"
# Chat permissions
READ_OWN_CHATS = "read_own_chats"
CREATE_CHAT = "create_chat"
UPDATE_OWN_CHAT = "update_own_chat"
DELETE_OWN_CHAT = "delete_own_chat"
# Token usage permissions
READ_OWN_USAGE = "read_own_usage"
# Admin permissions
READ_ALL_USERS = "read_all_users"
UPDATE_USER_ROLE = "update_user_role"
READ_ALL_CHATS = "read_all_chats"
READ_ALL_USAGE = "read_all_usage"
VIEW_ANALYTICS = "view_analytics"
MANAGE_SYSTEM = "manage_system"
# Role to permissions mapping
ROLE_PERMISSIONS = {
UserRole.USER: [
Permission.READ_OWN_PROFILE,
Permission.UPDATE_OWN_PROFILE,
Permission.READ_OWN_CHATS,
Permission.CREATE_CHAT,
Permission.UPDATE_OWN_CHAT,
Permission.DELETE_OWN_CHAT,
Permission.READ_OWN_USAGE,
],
UserRole.ADMIN: [
# All user permissions
Permission.READ_OWN_PROFILE,
Permission.UPDATE_OWN_PROFILE,
Permission.READ_OWN_CHATS,
Permission.CREATE_CHAT,
Permission.UPDATE_OWN_CHAT,
Permission.DELETE_OWN_CHAT,
Permission.READ_OWN_USAGE,
# Admin permissions
Permission.READ_ALL_USERS,
Permission.UPDATE_USER_ROLE,
Permission.READ_ALL_CHATS,
Permission.READ_ALL_USAGE,
Permission.VIEW_ANALYTICS,
],
UserRole.SUPERADMIN: [
# All permissions
Permission.READ_OWN_PROFILE,
Permission.UPDATE_OWN_PROFILE,
Permission.READ_OWN_CHATS,
Permission.CREATE_CHAT,
Permission.UPDATE_OWN_CHAT,
Permission.DELETE_OWN_CHAT,
Permission.READ_OWN_USAGE,
Permission.READ_ALL_USERS,
Permission.UPDATE_USER_ROLE,
Permission.READ_ALL_CHATS,
Permission.READ_ALL_USAGE,
Permission.VIEW_ANALYTICS,
Permission.MANAGE_SYSTEM,
]
}
def check_permission(user_role: str, required_permission: Permission) -> bool:
"""
Check if a user role has a specific permission
Args:
user_role: User's role
required_permission: Permission to check
Returns:
True if user has permission, False otherwise
"""
try:
role = UserRole(user_role)
permissions = ROLE_PERMISSIONS.get(role, [])
return required_permission in permissions
except ValueError:
return False
def require_permission(user_role: str, required_permission: Permission) -> None:
"""
Raise exception if user doesn't have required permission
Args:
user_role: User's role
required_permission: Permission to check
Raises:
HTTPException: If user doesn't have permission
"""
if not check_permission(user_role, required_permission):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Permission denied. Required permission: {required_permission.value}"
)
def require_role(user_role: str, required_roles: List[UserRole]) -> None:
"""
Raise exception if user doesn't have one of the required roles
Args:
user_role: User's role
required_roles: List of acceptable roles
Raises:
HTTPException: If user doesn't have required role
"""
try:
role = UserRole(user_role)
if role not in required_roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Access denied. Required roles: {[r.value for r in required_roles]}"
)
except ValueError:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid user role"
)