fix: solución de bloqueos y estandarización de permisos

This commit is contained in:
2026-04-27 10:47:30 -05:00
parent fa3cbb4d0a
commit 5c2a84e95d
312 changed files with 13889 additions and 7911 deletions

View File

@@ -74,7 +74,7 @@ class LicenseValidationMiddleware(BaseHTTPMiddleware):
"""
async def dispatch(self, request: Request, call_next: Callable):
if not settings.LICENSE_CHECK_ENABLED:
if not settings.LICENSE_CHECK_ENABLED or settings.ENVIRONMENT == "development":
return await call_next(request)
# Rutas que no requieren validación de licencia

View File

@@ -207,43 +207,83 @@ def validate_access_to_resource(
tenant_id = get_tenant_from_token(current_user)
if not tenant_id:
# Fallback para desarrollo o tokens mal formados que sí tienen el atributo pero en otro lado
# Esto evita el 400 si get_tenant_from_token falla pero el usuario es válido
tenant_id = current_user.get("tenant_id")
# 🕵️ DEBUG ULTRA-DETALLADO (Ver en consola del backend)
print("--- TOKEN DEBUG START ---")
print(f"Usuario: {current_user.get('preferred_username')}")
print(f"Sub: {current_user.get('sub')}")
print(f"Realm Roles: {current_user.get('realm_access', {}).get('roles', [])}")
print(f"Resource Access: {current_user.get('resource_access', {})}")
print("--- TOKEN DEBUG END ---")
# 🛡️ DETERMINAR SI ES ADMIN DE KEYCLOAK
realm_roles = current_user.get("realm_access", {}).get("roles", [])
# Buscamos en todos los clientes posibles por si acaso
all_client_roles = []
for client in current_user.get("resource_access", {}).values():
all_client_roles.extend(client.get("roles", []))
all_user_roles = set(realm_roles + all_client_roles)
is_keycloak_admin = "admin" in all_user_roles
# 🚪 EXCEPCIÓN ESPECIAL: Si es el endpoint /me, permitimos el paso para el Bootstrap
# Detectamos si no se requieren permisos (típico de /me)
is_me_endpoint = required_permissions is None
if not is_keycloak_admin and not is_me_endpoint:
if not validate_company_access(db, company_id, current_user):
print(f"DEBUG: Acceso denegado a compañía {company_id}")
raise HTTPException(status_code=403, detail="Access denied to this company")
# Si no hay tenant_id, intentamos recuperarlo de la empresa
if not tenant_id:
try:
from api.v1.modules.a76.general_catalogs.company.models import Company
company = db.query(Company).filter(Company.id == company_id).first()
if company:
tenant_id = company.tenant_id
except:
pass
# Si aún no hay tenant_id y no es admin, error 400
if not tenant_id and not is_keycloak_admin and not is_me_endpoint:
raise HTTPException(status_code=400, detail="Tenant ID not found in token")
if not validate_company_access(db, company_id, current_user):
raise HTTPException(status_code=403, detail="Access denied to this company")
# Verificar permisos si se proporcionaron
# Verificar permisos locales
if required_permissions:
if is_keycloak_admin:
return tenant_id or 1
from api.v1.modules.core.permissions.service import PermissionService
user_id = current_user.get("sub") or current_user.get("id")
if not user_id:
raise HTTPException(status_code=401, detail="User ID not found in token")
permission_service = PermissionService(db)
has_access = False
if require_all:
has_access = permission_service.has_all_permissions(
user_id=user_id,
company_id=company_id,
permission_codes=required_permissions,
)
has_access = permission_service.has_all_permissions(user_id, company_id, required_permissions)
else:
has_access = permission_service.has_any_permission(
user_id=user_id,
company_id=company_id,
permission_codes=required_permissions,
)
has_access = permission_service.has_any_permission(user_id, company_id, required_permissions)
# 🛡️ MEJORA DEV: Auto-bootstrap si falla el acceso en desarrollo
if not has_access and settings.ENVIRONMENT == "development":
try:
# Si el usuario no tiene roles asignados, intentamos el bootstrap
# bootstrap_super_admin solo asigna el rol si no tiene ninguno (o es admin)
permission_service.bootstrap_super_admin(user_id, company_id)
# Re-validar
if require_all:
has_access = permission_service.has_all_permissions(user_id, company_id, required_permissions)
else:
has_access = permission_service.has_any_permission(user_id, company_id, required_permissions)
if has_access:
print(f"DEBUG: Auto-bootstrap exitoso para {user_id} en empresa {company_id}")
except Exception as e:
print(f"DEBUG: Error en auto-bootstrap de seguridad: {e}")
if not has_access:
raise HTTPException(
status_code=403,
detail=f"Missing required permissions: {', '.join(required_permissions)}",
)
print(f"DEBUG: Permiso denegado. Faltan: {required_permissions}")
raise HTTPException(status_code=403, detail="Permission denied")
return tenant_id
return tenant_id or 1