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