164 lines
5.0 KiB
Python
164 lines
5.0 KiB
Python
"""
|
|
Permission Decorators - Function decorators for permission checks
|
|
"""
|
|
|
|
from functools import wraps
|
|
from typing import List, Callable, Union
|
|
from fastapi import HTTPException, status
|
|
|
|
from .engine import PermissionEngine
|
|
from .permissions import ScopeType
|
|
|
|
|
|
def requires_permission(
|
|
permission: str,
|
|
scope: ScopeType = ScopeType.GLOBAL,
|
|
user_param: str = "current_user"
|
|
):
|
|
"""
|
|
Decorator to require a specific permission.
|
|
|
|
Usage:
|
|
@requires_permission("vm:create")
|
|
async def create_vm(current_user: User, ...):
|
|
...
|
|
"""
|
|
def decorator(func: Callable):
|
|
@wraps(func)
|
|
async def async_wrapper(*args, **kwargs):
|
|
user = kwargs.get(user_param)
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="User not found in request"
|
|
)
|
|
|
|
PermissionEngine.check_permission(user, permission, scope)
|
|
return await func(*args, **kwargs)
|
|
|
|
@wraps(func)
|
|
def sync_wrapper(*args, **kwargs):
|
|
user = kwargs.get(user_param)
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="User not found in request"
|
|
)
|
|
|
|
PermissionEngine.check_permission(user, permission, scope)
|
|
return func(*args, **kwargs)
|
|
|
|
# Return appropriate wrapper based on function type
|
|
import asyncio
|
|
if asyncio.iscoroutinefunction(func):
|
|
return async_wrapper
|
|
return sync_wrapper
|
|
|
|
return decorator
|
|
|
|
|
|
def requires_any_permission(
|
|
permissions: List[str],
|
|
scope: ScopeType = ScopeType.GLOBAL,
|
|
user_param: str = "current_user"
|
|
):
|
|
"""
|
|
Decorator to require any one of the listed permissions.
|
|
|
|
Usage:
|
|
@requires_any_permission(["vm:create", "lxc:create"])
|
|
async def create_instance(current_user: User, ...):
|
|
...
|
|
"""
|
|
def decorator(func: Callable):
|
|
@wraps(func)
|
|
async def async_wrapper(*args, **kwargs):
|
|
user = kwargs.get(user_param)
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="User not found in request"
|
|
)
|
|
|
|
if not PermissionEngine.has_any_permission(user, permissions):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail=f"Permission denied: requires one of {permissions}"
|
|
)
|
|
|
|
return await func(*args, **kwargs)
|
|
|
|
@wraps(func)
|
|
def sync_wrapper(*args, **kwargs):
|
|
user = kwargs.get(user_param)
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="User not found in request"
|
|
)
|
|
|
|
if not PermissionEngine.has_any_permission(user, permissions):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail=f"Permission denied: requires one of {permissions}"
|
|
)
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
import asyncio
|
|
if asyncio.iscoroutinefunction(func):
|
|
return async_wrapper
|
|
return sync_wrapper
|
|
|
|
return decorator
|
|
|
|
|
|
def requires_all_permissions(
|
|
permissions: List[str],
|
|
scope: ScopeType = ScopeType.GLOBAL,
|
|
user_param: str = "current_user"
|
|
):
|
|
"""
|
|
Decorator to require all of the listed permissions.
|
|
|
|
Usage:
|
|
@requires_all_permissions(["vm:view", "vm:update"])
|
|
async def update_vm(current_user: User, ...):
|
|
...
|
|
"""
|
|
def decorator(func: Callable):
|
|
@wraps(func)
|
|
async def async_wrapper(*args, **kwargs):
|
|
user = kwargs.get(user_param)
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="User not found in request"
|
|
)
|
|
|
|
for perm in permissions:
|
|
PermissionEngine.check_permission(user, perm, scope)
|
|
|
|
return await func(*args, **kwargs)
|
|
|
|
@wraps(func)
|
|
def sync_wrapper(*args, **kwargs):
|
|
user = kwargs.get(user_param)
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="User not found in request"
|
|
)
|
|
|
|
for perm in permissions:
|
|
PermissionEngine.check_permission(user, perm, scope)
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
import asyncio
|
|
if asyncio.iscoroutinefunction(func):
|
|
return async_wrapper
|
|
return sync_wrapper
|
|
|
|
return decorator
|