151 lines
5.8 KiB
Python
151 lines
5.8 KiB
Python
"""
|
|
Standardized Permission Classes
|
|
Provides consistent permission checking across all endpoints
|
|
"""
|
|
from rest_framework import permissions
|
|
from rest_framework.exceptions import PermissionDenied
|
|
|
|
|
|
class IsAuthenticatedAndActive(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires user to be authenticated and active
|
|
Base permission for most endpoints
|
|
"""
|
|
def has_permission(self, request, view):
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if not request.user or not request.user.is_authenticated:
|
|
logger.warning(f"[IsAuthenticatedAndActive] DENIED: User not authenticated")
|
|
return False
|
|
|
|
# Check if user is active
|
|
if hasattr(request.user, 'is_active'):
|
|
is_active = request.user.is_active
|
|
if is_active:
|
|
logger.info(f"[IsAuthenticatedAndActive] ALLOWED: User {request.user.email} is active")
|
|
else:
|
|
logger.warning(f"[IsAuthenticatedAndActive] DENIED: User {request.user.email} is inactive")
|
|
return is_active
|
|
|
|
logger.info(f"[IsAuthenticatedAndActive] ALLOWED: User {request.user.email} (no is_active check)")
|
|
return True
|
|
|
|
|
|
class HasTenantAccess(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires user to belong to the tenant/account
|
|
Ensures tenant isolation
|
|
Superusers, developers, and system account users bypass this check.
|
|
|
|
CRITICAL: Every authenticated user MUST have an account.
|
|
The middleware sets request.account from request.user.account.
|
|
If a user doesn't have an account, it's a data integrity issue.
|
|
"""
|
|
def has_permission(self, request, view):
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if not request.user or not request.user.is_authenticated:
|
|
logger.warning(f"[HasTenantAccess] DENIED: User not authenticated")
|
|
return False
|
|
|
|
# SIMPLIFIED LOGIC: Every authenticated user MUST have an account
|
|
# Middleware already set request.account from request.user.account
|
|
# Just verify it exists
|
|
if not hasattr(request.user, 'account'):
|
|
logger.warning(f"[HasTenantAccess] DENIED: User {request.user.email} has no account attribute")
|
|
return False
|
|
|
|
try:
|
|
# Access the account to trigger any lazy loading
|
|
user_account = request.user.account
|
|
if not user_account:
|
|
logger.warning(f"[HasTenantAccess] DENIED: User {request.user.email} has NULL account")
|
|
return False
|
|
|
|
# Success - user has a valid account
|
|
logger.info(f"[HasTenantAccess] ALLOWED: User {request.user.email} has account {user_account.name} (ID: {user_account.id})")
|
|
return True
|
|
except (AttributeError, Exception) as e:
|
|
# User doesn't have account relationship - data integrity issue
|
|
logger.warning(f"[HasTenantAccess] DENIED: User {request.user.email} account access failed: {e}")
|
|
return False
|
|
|
|
|
|
class IsViewerOrAbove(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires viewer, editor, admin, or owner role
|
|
For read-only operations
|
|
"""
|
|
def has_permission(self, request, view):
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if not request.user or not request.user.is_authenticated:
|
|
logger.warning(f"[IsViewerOrAbove] DENIED: User not authenticated")
|
|
return False
|
|
|
|
# Check user role
|
|
if hasattr(request.user, 'role'):
|
|
role = request.user.role
|
|
# viewer, editor, admin, owner all have access
|
|
allowed = role in ['viewer', 'editor', 'admin', 'owner']
|
|
if allowed:
|
|
logger.info(f"[IsViewerOrAbove] ALLOWED: User {request.user.email} has role {role}")
|
|
else:
|
|
logger.warning(f"[IsViewerOrAbove] DENIED: User {request.user.email} has invalid role {role}")
|
|
return allowed
|
|
|
|
# If no role system, allow authenticated users
|
|
logger.info(f"[IsViewerOrAbove] ALLOWED: User {request.user.email} (no role system)")
|
|
return True
|
|
|
|
|
|
class IsEditorOrAbove(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires editor, admin, or owner role
|
|
For content operations
|
|
"""
|
|
def has_permission(self, request, view):
|
|
if not request.user or not request.user.is_authenticated:
|
|
return False
|
|
|
|
# Check user role
|
|
if hasattr(request.user, 'role'):
|
|
role = request.user.role
|
|
# editor, admin, owner have access
|
|
return role in ['editor', 'admin', 'owner']
|
|
|
|
# If no role system, allow authenticated users
|
|
return True
|
|
|
|
|
|
class IsAdminOrOwner(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires admin or owner role only
|
|
OR user belongs to aws-admin account
|
|
For settings, keys, billing operations
|
|
"""
|
|
def has_permission(self, request, view):
|
|
if not request.user or not request.user.is_authenticated:
|
|
return False
|
|
|
|
# Check if user belongs to aws-admin account (case-insensitive)
|
|
if hasattr(request.user, 'account') and request.user.account:
|
|
account_name = getattr(request.user.account, 'name', None)
|
|
account_slug = getattr(request.user.account, 'slug', None)
|
|
if account_name and account_name.lower() == 'aws admin':
|
|
return True
|
|
if account_slug == 'aws-admin':
|
|
return True
|
|
|
|
# Check user role
|
|
if hasattr(request.user, 'role'):
|
|
role = request.user.role
|
|
# admin, owner have access
|
|
return role in ['admin', 'owner']
|
|
|
|
# If no role system, deny by default for security
|
|
return False
|