feat: Implement user-tenant relationship management with CRUD operations and access control
This commit is contained in:
@@ -49,7 +49,10 @@ class AuthService:
|
||||
try:
|
||||
# Verificar que el tenant existe
|
||||
from api.v1.modules.a76.tenants.service import TenantService
|
||||
from api.v1.modules.a76.user_tenant.service import UserTenantService
|
||||
|
||||
tenant_service = TenantService(self.db)
|
||||
user_tenant_service = UserTenantService(self.db)
|
||||
tenant = tenant_service.get_tenant_by_slug(login_data.tenant_slug)
|
||||
|
||||
if not tenant:
|
||||
@@ -73,7 +76,59 @@ class AuthService:
|
||||
grant_type=["password"]
|
||||
)
|
||||
|
||||
logger.info(f"User logged in: {login_data.username} (tenant: {tenant.slug})")
|
||||
# Obtener información del usuario y verificar acceso al tenant
|
||||
user_info = keycloak_client.userinfo(token_response["access_token"])
|
||||
user_id = user_info.get("sub")
|
||||
|
||||
if user_id:
|
||||
# Verificar si el usuario tiene acceso a este tenant
|
||||
has_access = user_tenant_service.user_has_access_to_tenant(user_id, tenant.id)
|
||||
|
||||
if not has_access:
|
||||
logger.warning(f"User {user_id} tried to access tenant {tenant.id} without permission")
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="You don't have access to this tenant"
|
||||
)
|
||||
|
||||
# Actualizar el tenant_id del usuario en Keycloak basado en el slug usado
|
||||
try:
|
||||
# Crear instancia de KeycloakAdmin para actualizar atributos
|
||||
keycloak_admin = KeycloakAdmin(
|
||||
server_url=settings.KEYCLOAK_SERVER_URL,
|
||||
username=settings.KEYCLOAK_ADMIN_USERNAME,
|
||||
password=settings.KEYCLOAK_ADMIN_PASSWORD,
|
||||
realm_name=tenant.keycloak_realm,
|
||||
user_realm_name="master",
|
||||
verify=True
|
||||
)
|
||||
|
||||
# Obtener los datos actuales del usuario para no sobrescribirlos
|
||||
current_user = keycloak_admin.get_user(user_id)
|
||||
|
||||
# Obtener los atributos actuales o crear un dict vacío
|
||||
current_attributes = current_user.get("attributes", {})
|
||||
|
||||
# Actualizar solo los atributos de tenant
|
||||
current_attributes["tenant_id"] = [str(tenant.id)]
|
||||
current_attributes["tenant_slug"] = [tenant.slug]
|
||||
|
||||
# Actualizar el usuario enviando TODOS los campos para evitar que se borren
|
||||
update_payload = {
|
||||
"email": current_user.get("email"),
|
||||
"firstName": current_user.get("firstName"),
|
||||
"lastName": current_user.get("lastName"),
|
||||
"enabled": current_user.get("enabled", True),
|
||||
"emailVerified": current_user.get("emailVerified", False),
|
||||
"attributes": current_attributes
|
||||
}
|
||||
|
||||
keycloak_admin.update_user(user_id=user_id, payload=update_payload)
|
||||
logger.info(f"Updated tenant_id={tenant.id} for user {login_data.username}")
|
||||
|
||||
except Exception as e:
|
||||
# No queremos que falle el login si no se puede actualizar el atributo
|
||||
logger.warning(f"Could not update tenant_id attribute: {str(e)}")
|
||||
|
||||
return TokenResponseDTO(
|
||||
access_token=token_response["access_token"],
|
||||
@@ -249,6 +304,29 @@ class AuthService:
|
||||
# El rol 'user' no existe, no es un error crítico
|
||||
logger.warning(f"Could not assign 'user' role: {str(e)}")
|
||||
|
||||
# Agregar el usuario al tenant en la base de datos
|
||||
try:
|
||||
from api.v1.modules.a76.user_tenant.service import UserTenantService
|
||||
user_tenant_service = UserTenantService(self.db)
|
||||
user_tenant_service.add_user_to_tenant(
|
||||
keycloak_user_id=user_id,
|
||||
tenant_id=tenant.id,
|
||||
role="user" # Rol por defecto
|
||||
)
|
||||
logger.info(f"Added user {user_id} to tenant {tenant.id} in database")
|
||||
except Exception as e:
|
||||
# Si falla, hacer rollback del usuario en Keycloak
|
||||
logger.error(f"Failed to add user to tenant in database: {str(e)}")
|
||||
try:
|
||||
keycloak_admin.delete_user(user_id)
|
||||
logger.info(f"Rolled back user creation in Keycloak")
|
||||
except:
|
||||
pass
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Failed to register user in database"
|
||||
)
|
||||
|
||||
logger.info(f"User registered: {register_data.username} (tenant: {tenant.slug}, user_id: {user_id})")
|
||||
|
||||
return RegisterResponseDTO(
|
||||
|
||||
Reference in New Issue
Block a user