Skip to content

Feature: agregar login con Active Directory (LDAP) manteniendo JWT interno

Agustín Cantero requested to merge feature/auth-active-directory into dev

Qué

Agrega POST /auth/ad, un método de login alternativo que autentica usuario y contraseña contra el controlador de dominio de Active Directory (LDAP) y, si el atributo mail de esa cuenta coincide con un funcionario o estudiante ya existente en SIENEP, emite el mismo JWT que el resto de los logins. No da de alta cuentas nuevas.

Por qué

A pedido del área de Infraestructura, que necesita que los usuarios puedan loguearse con sus credenciales del dominio en vez de (o además de) la contraseña local de SIENEP. Se siguió el mismo patrón ya usado para el login con Google (GoogleIdTokenVerifierService → Facade sobre el SDK externo, y AuthService solo resuelve la cuenta local por email) en vez de inventar un flujo nuevo: ActiveDirectoryVerifierService es un Facade equivalente sobre ActiveDirectoryLdapAuthenticationProvider, y la resolución de cuenta que antes vivía dentro de loginConGoogle() se extrajo a loginConIdentidadExterna() para que ambos flujos la compartan.

Un detalle donde sí se aparta de Google: acá un login exitoso saca a la cuenta de PENDIENTE_DE_ACTIVACION. Con Google eso no pasaba porque la contraseña temporal local podía seguir siendo relevante; con AD no tiene sentido, la contraseña temporal nunca interviene en este flujo, así que dejar la cuenta pendiente solo forzaría una pantalla de cambio de contraseña que un usuario de AD no va a usar nunca.

Cambios

  • ActiveDirectoryVerifierService (nuevo): recibe usuario/contraseña, autentica contra AD y devuelve el mail ya verificado, o vacío si las credenciales son inválidas. Distingue credenciales rechazadas de AD no configurado/inalcanzable, lanzando 503 en este último caso en vez de disfrazarlo de contraseña incorrecta.
  • AuthService.loginConAd() + loginConIdentidadExterna(): resuelve la cuenta local por email, valida que no esté bloqueada/inactiva, activa la cuenta si estaba pendiente (solo en el flujo de AD) y emite el JWT. Refactor comparte esta lógica con loginConGoogle().
  • AuthController: nuevo endpoint POST /auth/ad + AdLoginRequestDTO (usuario, contrasenia).
  • pom.xml: nueva dependencia spring-security-ldap.
  • application.properties / .env.example: nuevas variables AD_LDAP_URL, AD_DOMAIN, AD_ROOT_DN.

Acción requerida en el deploy

Ninguna migración de base de datos. Para habilitar el login por AD hay que cargar estas tres variables de entorno en el ambiente:

AD_LDAP_URL=ldap://10.0.50.19:389
AD_DOMAIN=corp.UTEC-Durazno.grupo01
AD_ROOT_DN=dc=corp,dc=UTEC-Durazno,dc=grupo01

Mientras no estén las tres cargadas, POST /auth/ad responde 503 sin romper nada del resto del sistema, se puede deployar antes de tener esos datos y activarlo después.

Cómo probar

Sin AD real (unit/integration, no necesita Docker):

./mvnw test -Dtest=ActiveDirectoryVerifierServiceTest,AuthServiceTest,AuthControllerTest

Cubre autenticación exitosa, credenciales rechazadas, AD no configurado (503), cuenta de AD sin atributo mail, cuenta local inactiva/bloqueada y la activación de cuentas PENDIENTE_DE_ACTIVACION.

Contra el AD real:

  1. Completar en .env (copiado de .env.example) las tres variables de arriba.
  2. Confirmar que exista un Funcionario o Estudiante en SIENEP cuyo email coincida (case-insensitive) con el atributo mail de la cuenta de AD a usar.
  3. Levantar la app y probar:
    curl -X POST http://localhost:8080/auth/ad \
      -H "Content-Type: application/json" \
      -d '{"usuario": "<sAMAccountName>", "contrasenia": "<contraseña-del-dominio>"}'
  4. Validar: credenciales correctas → 200 + JWT (y la cuenta pasa a ACTIVO si estaba pendiente); contraseña incorrecta → 401; usuario de AD sin cuenta correspondiente en SIENEP → 401; variables vacías o controlador inalcanzable → 503; cuenta SIENEP bloqueada → 403.

Merge request reports

Loading