Files
igny8/MULTI-TENANCY-FIXES-DEC-2025.md
IGNY8 VPS (Salman) 7a35981038 feat(multi-tenancy): implement critical fixes for orphaned users and permissions
- Simplified HasTenantAccess permission logic to ensure every authenticated user has an account.
- Added fallback to system account for OpenAI settings in AI configuration.
- Allowed any authenticated user to check task progress in IntegrationSettingsViewSet.
- Created a script to identify and fix orphaned users without accounts.
- Updated error response handling in business endpoints for clarity.
2025-12-10 09:51:06 +00:00

5.8 KiB

CRITICAL MULTI-TENANCY FIXES - December 10, 2025

PROBLEM SUMMARY

Users are unable to use business features (auto_cluster, automation, etc.) despite being authenticated. The error is "Account is required" or permission denied.

ROOT CAUSE

The system has structural issues in the multi-tenancy implementation:

1. User Model Allows NULL Accounts

File: backend/igny8_core/auth/models.py (line 644)

account = models.ForeignKey('igny8_core_auth.Account', 
                           on_delete=models.CASCADE, 
                           null=True,      # ❌ WRONG
                           blank=True,     # ❌ WRONG
                           ...)

Problem: Users can exist without accounts (orphaned users). When middleware sets request.account from request.user.account, it becomes None for orphaned users.

Impact: ALL business endpoints that check request.account fail.

2. HasTenantAccess Permission Too Complex

File: backend/igny8_core/api/permissions.py (lines 24-67)

Problem: The permission class had unnecessary fallback logic and unclear flow:

  • Checked request.account
  • Fell back to request.user.account
  • Compared if they match
  • Returned False on ANY exception

Impact: Added complexity made debugging hard. If user has no account, access is denied silently.

3. Business Endpoints Explicitly Check request.account

File: backend/igny8_core/modules/planner/views.py (line 633)

account = getattr(request, 'account', None)
if not account:
    return error_response(error='Account is required', ...)

Problem: Direct dependency on request.account. If middleware fails to set it, feature breaks.

Impact: Auto-cluster and other AI functions fail with "Account is required".

FIXES APPLIED

Fix 1: Simplified HasTenantAccess Permission

File: backend/igny8_core/api/permissions.py

Change: Removed fallback logic. Made it clear: authenticated users MUST have accounts.

# 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'):
    return False

try:
    user_account = request.user.account
    if not user_account:
        return False
    return True
except (AttributeError, Exception):
    return False

Fix 2: Task Progress Permission

File: backend/igny8_core/modules/system/integration_views.py (line 900)

Change: Allowed any authenticated user to check task progress (not just system accounts).

@action(..., permission_classes=[IsAuthenticatedAndActive])
def task_progress(self, request, task_id=None):

Fix 3: AI Settings Fallback

File: backend/igny8_core/ai/settings.py

Change: Added fallback to system account (aws-admin) for OpenAI settings when user account doesn't have them configured.

Fix 4: Error Response Parameter

File: backend/igny8_core/modules/planner/views.py

Change: Fixed error_response() call - changed invalid extra_data parameter to debug_info.

REQUIRED ACTIONS

🔴 CRITICAL: Fix Orphaned Users

  1. Run the fix script:

    cd /data/app/igny8/backend
    python3 fix_orphaned_users.py
    
  2. The script will:

    • Find users with account = NULL
    • Create accounts for them OR delete them
    • Report results

🔴 CRITICAL: Make Account Field Required

After fixing orphaned users, update the User model:

File: backend/igny8_core/auth/models.py (line 644)

Change:

# BEFORE
account = models.ForeignKey(..., null=True, blank=True, ...)

# AFTER
account = models.ForeignKey(..., null=False, blank=False, ...)

Then create and run migration:

cd /data/app/igny8/backend
python3 manage.py makemigrations
python3 manage.py migrate

VERIFICATION

After fixes, verify:

  1. Check no orphaned users:

    cd /data/app/igny8/backend
    python3 manage.py shell -c "
    from igny8_core.auth.models import User
    orphaned = User.objects.filter(account__isnull=True).count()
    print(f'Orphaned users: {orphaned}')
    "
    

    Expected: Orphaned users: 0

  2. Test auto-cluster:

    • Login as normal user
    • Select 5+ keywords
    • Click "Auto Cluster"
    • Should work without "Account is required" error
  3. Test task progress:

    • Start any AI function
    • Progress modal should show real-time updates
    • No "403 Forbidden" errors

ARCHITECTURE PRINCIPLES ESTABLISHED

  1. NO NULL ACCOUNTS: Every user MUST have an account. Period.

  2. NO FALLBACKS: If request.user.account is None, it's a data integrity issue, not a code issue.

  3. CLEAR FLOW:

    • User registers → Account created → User.account set
    • User logs in → Middleware sets request.account from user.account
    • Permission checks → Verify request.user.account exists
    • Business logic → Use request.account directly
  4. FAIL FAST: Don't hide errors with fallbacks. If account is missing, raise error.

FILES MODIFIED

  1. backend/igny8_core/api/permissions.py - Simplified HasTenantAccess
  2. backend/igny8_core/modules/system/integration_views.py - Fixed task_progress permission
  3. backend/igny8_core/ai/settings.py - Added system account fallback for AI settings
  4. backend/igny8_core/modules/planner/views.py - Fixed error_response call

FILES CREATED

  1. backend/fix_orphaned_users.py - Script to fix orphaned users
  2. MULTI-TENANCY-FIXES-DEC-2025.md - This document

NEXT STEPS

  1. Run orphaned users fix script
  2. Make User.account field required (migration)
  3. Test all business features
  4. Update documentation to reflect "no fallbacks" principle
  5. Add database constraints to prevent orphaned users

Date: December 10, 2025
Status: FIXES APPLIED - VERIFICATION PENDING
Priority: CRITICAL