jogosultsági szintek RBAC beállítva tesztelve

This commit is contained in:
Roo
2026-06-25 20:41:49 +00:00
parent 52011606ff
commit 36109fc722
242 changed files with 8672 additions and 2237 deletions

View File

@@ -13,7 +13,6 @@ from app.models.identity import User, UserRole # JAVÍTVA: Új Identity modell
from app.models.marketplace.organization import OrgRole, OrganizationMember
from app.core.config import settings
from app.core.translation_helper import t # Translation helper
from app.core.capabilities import SYSTEM_CAPABILITIES_MATRIX, role_has_capability
logger = logging.getLogger(__name__)
@@ -157,25 +156,6 @@ def check_min_rank(role_key: str):
return True
return rank_checker
async def get_current_admin(
current_user: User = Depends(get_current_user)
) -> User:
"""
Csak admin/moderátor/superadmin szerepkörrel rendelkező felhasználók számára.
"""
# A UserRole Enum értékeit használjuk (RBAC Phase 1)
allowed_roles = {
UserRole.SUPERADMIN,
UserRole.ADMIN,
UserRole.MODERATOR,
}
if current_user.role not in allowed_roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=t("AUTH.INSUFFICIENT_ADMIN_PERMISSIONS")
)
return current_user
# ═══════════════════════════════════════════════════════════════════════════════
# RBAC Phase 1.5: Staff & Flexible Role Dependencies
@@ -210,108 +190,10 @@ async def get_current_staff(
return current_user
def RequireRole(allowed_roles: List[UserRole], target_org_id: Optional[int] = None):
"""
🎯 Flexible role-checking dependency factory with scope-based access.
Accepts a list of UserRole values. If the current user's role is
in the list, access is granted. Otherwise, 403 Forbidden.
When target_org_id is provided, the RBACService is automatically
invoked to check if the staff member has scope-based access to
that specific organization.
Usage:
# Simple role check
@router.get("/admin/sales")
async def sales_dashboard(
current_user: User = Depends(get_current_user),
_ = Depends(RequireRole([UserRole.SUPERADMIN, UserRole.SALES_REP]))
):
# Scope-based access check
@router.get("/admin/organizations/{org_id}")
async def get_organization(
org_id: int,
current_user: User = Depends(get_current_user),
_ = Depends(RequireRole(
[UserRole.SUPERADMIN, UserRole.ADMIN, UserRole.SALES_REP],
target_org_id=org_id # ← triggers scope check
))
):
"""
async def role_checker(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> bool:
# 1. Check if the user's role is in the allowed list
if current_user.role not in allowed_roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="AUTH.INSUFFICIENT_PERMISSIONS"
)
# 2. If target_org_id is provided, perform scope-based access check
if target_org_id is not None:
from app.services.rbac_service import rbac_service
try:
await rbac_service.check_admin_access(
db=db,
user=current_user,
action="VIEW_DATA", # Generic read access for the dependency
target_org_id=target_org_id,
)
except PermissionError as e:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=str(e)
)
return True
return role_checker
# ═══════════════════════════════════════════════════════════════════════════════
# RBAC Phase 2: Capability Dependencies (Kapuőrök)
# ═══════════════════════════════════════════════════════════════════════════════
def RequireSystemCapability(capability_name: str):
"""
🎯 Rendszerszintű képesség-ellenőrző dependency.
Használat:
@router.get("/admin/users")
async def list_users(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
_ = Depends(RequireSystemCapability("can_manage_users"))
):
Logika:
1. Ha a user SUPERADMIN → azonnal átengedi (True).
2. Egyébként lekéri a user role-ját, és ellenőrzi a
SYSTEM_CAPABILITIES_MATRIX-ból, hogy a kért capability True-e.
3. Ha nincs meg a capability → 403 Forbidden.
"""
async def system_capability_checker(
current_user: User = Depends(get_current_user),
) -> bool:
# SUPERADMIN mindent visz
if current_user.role == UserRole.SUPERADMIN:
return True
# Ellenőrizzük a SYSTEM_CAPABILITIES_MATRIX-ból
role_key = current_user.role.value # pl. "ADMIN", "MODERATOR", "USER"
if not role_has_capability(role_key, capability_name):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"SYSTEM_CAPABILITY_DENIED: A '{capability_name}' képesség nem elérhető a '{role_key}' szerepkör számára."
)
return True
return system_capability_checker
def RequireOrgCapability(capability_name: str):
"""
🎯 Szervezeti képesség-ellenőrző dependency.
@@ -391,4 +273,69 @@ def RequireOrgCapability(capability_name: str):
return True
return org_capability_checker
return org_capability_checker
# ═══════════════════════════════════════════════════════════════════════════════
# RBAC Phase 2: DB-Driven Permission Code Dependency (RequirePermission)
# ═══════════════════════════════════════════════════════════════════════════════
def RequirePermission(permission_code: str):
"""
🎯 DB-driven permission code dependency factory.
Queries the system.role_permissions table (via RBACService.get_role_permissions)
to check if the current user's role has the specified permission code granted.
SUPERADMIN bypass: If the user's role rank is 100 (SUPERADMIN), access is
granted immediately without a database lookup.
Usage:
@router.get("/admin/sensitive-data")
async def get_sensitive_data(
current_user: User = Depends(get_current_user),
_ = Depends(RequirePermission("fleet:view")),
):
Args:
permission_code: The permission code to check (e.g., "fleet:view", "user:create")
Returns:
A dependency callable that returns the current_user if permission is granted,
or raises HTTPException(403) if denied.
"""
async def permission_checker(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db),
) -> User:
# ── SUPERADMIN bypass ──
# SUPERADMIN has rank 100 → bypass all permission checks
if current_user.role == UserRole.SUPERADMIN:
return current_user
# ── Resolve role_id ──
# Use the DB-driven role_id if available, otherwise fall back to
# the legacy UserRole enum for backward compatibility
role_id = getattr(current_user, 'role_id', None)
if role_id is None:
# Fallback: SUPERADMIN already handled above, so this is a non-admin
# user without a role_id assigned yet. Deny access.
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Missing permission: {permission_code}. No role_id assigned to user."
)
# ── Query permissions from DB ──
from app.services.rbac_service import rbac_service
user_permissions = await rbac_service.get_role_permissions(db, role_id)
# ── Check the specific permission ──
if permission_code not in user_permissions:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Missing permission: {permission_code}"
)
return current_user
return permission_checker