Improve SGU logon resilience and client UX
This commit is contained in:
@@ -52,6 +52,16 @@ digits of the requested `AD` identity before any scraped metadata is trusted.
|
||||
Missing metadata does not clear existing AD values and never changes the
|
||||
password outcome.
|
||||
|
||||
Human-readable SGU values are decoded with BOM/header/meta detection, strict
|
||||
UTF-8 validation, and a Windows-1252 fallback for the legacy portal. Names and
|
||||
titles are normalized with Spanish-aware casing; particles such as `de`, `del`
|
||||
and `de la` remain lowercase and Unicode accents are preserved. Values that
|
||||
still contain the Unicode replacement character are not written to AD.
|
||||
|
||||
When `RemoteDesktopGroupDn` is configured, the broker also adds each successfully
|
||||
synchronized SGU user to that dedicated AD security group. The laboratory
|
||||
Windows client maps the group into its local **Remote Desktop Users** group.
|
||||
|
||||
The managed hierarchy is rooted at `OU=Usuarios-SGU`: `Docentes`, `Alumnos`,
|
||||
and `Administrativos` are direct child OUs beneath it.
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# Operación del SGU Authentication Broker
|
||||
|
||||
## Dónde se ejecuta
|
||||
|
||||
En el laboratorio, el broker se ejecuta en el controlador de dominio Windows
|
||||
Server:
|
||||
|
||||
| Elemento | Valor |
|
||||
|---|---|
|
||||
| Equipo | `WIN-1AIQMMA1EPR.lci.lasalle.mx` |
|
||||
| Servicio | `SGUAuthBroker` / `SGU Authentication Broker` |
|
||||
| Ejecutable | `C:\Program Files\SGU\AuthBroker\SGU.AuthBroker.exe` |
|
||||
| Configuración | `C:\Program Files\SGU\AuthBroker\appsettings.Production.json` |
|
||||
| Endpoint cliente | `https://sgu-auth.lci.lasalle.mx:8443/v1/authenticate` |
|
||||
| Salud | `https://sgu-auth.lci.lasalle.mx:8443/health/live` |
|
||||
| Transporte | HTTPS 1.1 con certificado de cliente obligatorio (mTLS) |
|
||||
|
||||
El Credential Provider no se comunica directamente con Active Directory ni
|
||||
conserva una contraseña. Envía la clave y la contraseña originales al broker;
|
||||
el broker valida SGU, actualiza la cuenta de dominio y devuelve solamente el
|
||||
dominio y el nombre de usuario canónico.
|
||||
|
||||
## Comprobación rápida
|
||||
|
||||
Ejecutar como administrador en Windows Server:
|
||||
|
||||
```powershell
|
||||
Get-CimInstance Win32_Service -Filter "Name='SGUAuthBroker'" |
|
||||
Select-Object Name, State, StartMode, PathName, ProcessId
|
||||
|
||||
Get-NetTCPConnection -LocalPort 8443 -State Listen
|
||||
Get-NetFirewallRule -DisplayName 'SGU Authentication Broker (mTLS)'
|
||||
sc.exe qfailure SGUAuthBroker
|
||||
```
|
||||
|
||||
Desde un cliente que tenga el certificado mTLS:
|
||||
|
||||
```powershell
|
||||
Invoke-WebRequest `
|
||||
-Uri https://sgu-auth.lci.lasalle.mx:8443/health/live `
|
||||
-CertificateThumbprint CLIENT_CERT_THUMBPRINT
|
||||
```
|
||||
|
||||
Una petición sin un certificado cliente válido debe ser rechazada durante TLS.
|
||||
Eso es comportamiento esperado, no una caída del servicio.
|
||||
|
||||
## Timeouts y recuperación
|
||||
|
||||
- El Credential Provider espera hasta **20 segundos** por el broker.
|
||||
- El broker espera hasta **15 segundos** por SGU. Un portal que normalmente
|
||||
tarda alrededor de seis segundos queda dentro del margen sin bloquear LogonUI
|
||||
indefinidamente.
|
||||
- El instalador configura recuperación del servicio con reinicios a los 5, 15
|
||||
y 60 segundos y reinicia el contador de fallos después de 24 horas.
|
||||
- Si el broker o SGU no está disponible, el Credential Provider entrega la
|
||||
contraseña intacta a Windows. AD o el caché de inicio de sesión de Windows aún
|
||||
debe validarla; el fallback no concede acceso por sí mismo.
|
||||
|
||||
Reiniciar o volver a desplegar el servicio produce una interrupción breve en un
|
||||
laboratorio con una sola instancia. Antes de una demostración, comprobar
|
||||
`Running` y el listener 8443.
|
||||
|
||||
## Diagnóstico
|
||||
|
||||
```powershell
|
||||
Get-WinEvent -FilterHashtable @{
|
||||
LogName='Application'
|
||||
StartTime=(Get-Date).AddHours(-1)
|
||||
} | Where-Object ProviderName -eq 'SGU Authentication Broker' |
|
||||
Select-Object TimeCreated, LevelDisplayName, Id, Message
|
||||
|
||||
Get-Content 'C:\Program Files\SGU\AuthBroker\appsettings.Production.json' -Raw |
|
||||
ConvertFrom-Json |
|
||||
Select-Object -ExpandProperty Broker
|
||||
```
|
||||
|
||||
Nunca habilitar registro de cuerpos HTTP: contienen la contraseña durante la
|
||||
solicitud. Los certificados, no las contraseñas, proporcionan la identidad entre
|
||||
el cliente y el broker.
|
||||
@@ -0,0 +1,60 @@
|
||||
# ADR 0001: no usar Redis como caché de contraseñas
|
||||
|
||||
- Estado: aceptado
|
||||
- Alcance: autenticación SGU y fallback sin conexión
|
||||
|
||||
## Contexto
|
||||
|
||||
SGU puede tardar varios segundos o quedar temporalmente fuera de servicio. Se
|
||||
consideró instalar Redis persistente en el mismo Windows Server que hospeda el
|
||||
broker y Active Directory, almacenando un hash con sal/clave o una contraseña
|
||||
cifrada.
|
||||
|
||||
## Decisión
|
||||
|
||||
No se almacenarán contraseñas, contraseñas cifradas, hashes, HMAC ni otros
|
||||
verificadores de contraseña en Redis. Tampoco se instalará Redis en el
|
||||
controlador de dominio.
|
||||
|
||||
El mecanismo de continuidad es el ya proporcionado por Windows:
|
||||
|
||||
1. una autenticación SGU exitosa sincroniza la contraseña original a AD;
|
||||
2. AD valida esa contraseña mientras el controlador es accesible;
|
||||
3. Windows conserva su verificador de inicio de sesión de dominio para equipos
|
||||
desconectados;
|
||||
4. si SGU o el broker no responde, el Credential Provider entrega la misma
|
||||
credencial a Windows y deja que AD/LSA decidan.
|
||||
|
||||
## Motivos
|
||||
|
||||
- Un hash no permite recuperar la contraseña original. Comparar la contraseña
|
||||
presentada contra otro verificador solo duplicaría el material atacable que
|
||||
ya mantienen AD y Windows.
|
||||
- Una contraseña cifrada es un secreto reversible; colocar la clave de descifrado
|
||||
junto al broker convierte el caché en una bóveda de credenciales reutilizables.
|
||||
- Un caché persistente aceptaría durante más tiempo una contraseña revocada y
|
||||
añadiría una tercera fuente de verdad entre SGU y AD.
|
||||
- Redis persistente escribe RDB/AOF a disco. La documentación de Redis recomienda
|
||||
controles adicionales como TLS, ACL y cifrado del lado cliente.
|
||||
- Redis Open Source no tiene un servicio Windows nativo propio; Redis documenta
|
||||
Memurai o WSL para Windows. Ninguna opción debe ampliar la superficie de ataque
|
||||
de un controlador de dominio.
|
||||
- Microsoft recomienda reducir el software instalado en controladores de dominio
|
||||
y tratarlos como sistemas sensibles de propósito único.
|
||||
|
||||
Referencias:
|
||||
|
||||
- <https://learn.microsoft.com/en-us/troubleshoot/windows-server/user-profiles-and-logon/cached-domain-logon-information>
|
||||
- <https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/securing-domain-controllers-against-attack>
|
||||
- <https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/>
|
||||
- <https://redis.io/docs/latest/operate/oss_and_stack/install/archive/install-redis/install-redis-on-windows/>
|
||||
- <https://redis.io/docs/latest/operate/rs/security/recommended-security-practices/>
|
||||
|
||||
## Alternativa permitida en el futuro
|
||||
|
||||
Redis podría ser útil para metadatos no secretos —nombre normalizado,
|
||||
dependencia, puesto o control de tasa distribuido— si existe más de una instancia
|
||||
del broker. En ese caso debe ejecutarse en un servidor miembro o VM Linux
|
||||
separada, usar TLS y ACL, tener TTL corto y nunca participar en la decisión de
|
||||
aceptar una contraseña. Con una sola instancia, un caché en memoria es más
|
||||
simple y no añade otra dependencia al inicio de sesión.
|
||||
@@ -80,6 +80,7 @@ certificate thumbprint:
|
||||
-PublishPath C:\Deploy\broker `
|
||||
-ServerCertificateSubject sgu-auth.lci.lasalle.mx `
|
||||
-AllowedClientThumbprints CLIENT_CERT_THUMBPRINT `
|
||||
-RemoteDesktopGroupDn 'CN=SG-Laboratorio-Usuarios-RDP,OU=Laboratorio,DC=lci,DC=lasalle,DC=mx' `
|
||||
-CreateMissingOus `
|
||||
-DisableCertificateRevocationCheckForLab
|
||||
```
|
||||
@@ -88,6 +89,8 @@ Verify the service and managed OUs:
|
||||
|
||||
```powershell
|
||||
Get-Service SGUAuthBroker
|
||||
Get-NetTCPConnection -LocalPort 8443 -State Listen
|
||||
sc.exe qfailure SGUAuthBroker
|
||||
Get-ADOrganizationalUnit -Filter * -SearchBase 'OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx'
|
||||
```
|
||||
|
||||
@@ -116,6 +119,7 @@ On Windows 10:
|
||||
-BrokerEndpoint https://sgu-auth.lci.lasalle.mx:8443/v1/authenticate `
|
||||
-ClientCertificateThumbprint CLIENT_CERT_THUMBPRINT `
|
||||
-ServerCertificateThumbprint SERVER_CERT_THUMBPRINT `
|
||||
-TimeoutSeconds 20 `
|
||||
-InstallDotNetRuntime `
|
||||
-DotNetRuntimeInstallerPath C:\SGUDeploy\prerequisites\dotnet-runtime-10.0.11-win-x64.exe
|
||||
```
|
||||
@@ -124,6 +128,18 @@ Use Lithnet's `Invoke-CredUI` test utility when available, or lock the VM and
|
||||
select **Acceso institucional SGU** under sign-in options. Keep the built-in
|
||||
Windows password tile visible.
|
||||
|
||||
Before testing through Hyper-V Enhanced Session/RDP, enable the dedicated lab
|
||||
group and Windows PowerShell Remoting:
|
||||
|
||||
```powershell
|
||||
.\Enable-LabRemoteAccess.ps1 `
|
||||
-RemoteDesktopPrincipal 'LCI\SG-Laboratorio-Usuarios-RDP' `
|
||||
-EnableAdministrativeFirewallGroups
|
||||
```
|
||||
|
||||
See [`windows-client-onboarding.md`](windows-client-onboarding.md) for domain
|
||||
join, RDP, WinRM, firewall, and error `0xC000015B` diagnostics.
|
||||
|
||||
## 6. Required end-to-end cases
|
||||
|
||||
1. Online valid `DO`, `AL`, and `AD` logons; verify each OU.
|
||||
|
||||
@@ -52,6 +52,12 @@ infrastructure:
|
||||
to Windows. Windows must still validate it against AD or the cached domain
|
||||
verifier, so this does not grant access without the last synchronized password.
|
||||
|
||||
Redis is deliberately not used for password continuity. A second persistent
|
||||
password verifier duplicates attackable credential material, while a reversible
|
||||
encrypted password becomes a credential vault. AD and Windows cached domain
|
||||
logon already implement the required last-known-password behavior. See
|
||||
[`decisions/0001-no-password-cache.md`](decisions/0001-no-password-cache.md).
|
||||
|
||||
The installer never registers a Credential Provider filter and never disables
|
||||
Microsoft's password, PIN, smart-card, or Windows Hello providers.
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# Alta de un equipo Windows en el laboratorio LCI
|
||||
|
||||
Esta guía configura un Windows 10/11 Pro o Enterprise para el dominio, RDP con
|
||||
NLA y PowerShell Remoting. Está pensada para la red aislada del laboratorio; no
|
||||
abre estos servicios en el perfil de red pública.
|
||||
|
||||
## 1. Prerrequisitos
|
||||
|
||||
- Una cuenta con permiso para unir equipos al dominio.
|
||||
- DNS primario del adaptador apuntando al controlador de dominio
|
||||
`192.168.50.10`.
|
||||
- Conectividad con `lci.lasalle.mx` y hora sincronizada.
|
||||
- Windows Pro, Enterprise o Education para actuar como host RDP.
|
||||
|
||||
```powershell
|
||||
Get-NetAdapter
|
||||
Set-DnsClientServerAddress -InterfaceAlias 'Ethernet' `
|
||||
-ServerAddresses 192.168.50.10
|
||||
Resolve-DnsName -Type SRV _ldap._tcp.dc._msdcs.lci.lasalle.mx
|
||||
```
|
||||
|
||||
## 2. Unir el equipo al dominio
|
||||
|
||||
Abrir Windows PowerShell como administrador. El prompt solicita la contraseña
|
||||
de forma interactiva y evita ponerla en el historial:
|
||||
|
||||
```powershell
|
||||
$domainCredential = Get-Credential -UserName 'LCI\Administrator'
|
||||
Add-Computer `
|
||||
-DomainName 'lci.lasalle.mx' `
|
||||
-Credential $domainCredential `
|
||||
-Restart
|
||||
```
|
||||
|
||||
Después del reinicio:
|
||||
|
||||
```powershell
|
||||
(Get-CimInstance Win32_ComputerSystem) |
|
||||
Select-Object Name, Domain, PartOfDomain
|
||||
```
|
||||
|
||||
## 3. Habilitar acceso remoto
|
||||
|
||||
El grupo de dominio `LCI\SG-Laboratorio-Usuarios-RDP` es el único principal de
|
||||
usuarios SGU agregado al grupo local **Remote Desktop Users**. El broker agrega
|
||||
automáticamente a ese grupo cada cuenta que sincroniza; no concede permisos de
|
||||
administrador.
|
||||
|
||||
Copiar `scripts\Enable-LabRemoteAccess.ps1` al equipo y ejecutar. El bypass se
|
||||
limita a este proceso y no cambia la directiva persistente del equipo:
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass `
|
||||
-File .\Enable-LabRemoteAccess.ps1 `
|
||||
-RemoteDesktopPrincipal 'LCI\SG-Laboratorio-Usuarios-RDP' `
|
||||
-EnableAdministrativeFirewallGroups
|
||||
```
|
||||
|
||||
El script realiza de forma idempotente lo siguiente:
|
||||
|
||||
- habilita RDP y conserva Network Level Authentication;
|
||||
- habilita las reglas RDP solo para el perfil Domain;
|
||||
- autoriza el grupo SGU dedicado;
|
||||
- habilita Windows PowerShell Remoting/WinRM;
|
||||
- opcionalmente habilita administración remota de servicios, eventos y WMI,
|
||||
también limitada al perfil Domain.
|
||||
|
||||
PowerShell Direct de Hyper-V no requiere abrir puertos en la VM y sigue siendo
|
||||
la opción preferida para recuperación administrativa.
|
||||
|
||||
## 4. Instalar el Credential Provider
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass `
|
||||
-File .\Install-CredentialProvider.ps1 `
|
||||
-PublishPath C:\SGUDeploy\credential-provider `
|
||||
-BrokerEndpoint https://sgu-auth.lci.lasalle.mx:8443/v1/authenticate `
|
||||
-ClientCertificateThumbprint CLIENT_CERT_THUMBPRINT `
|
||||
-ServerCertificateThumbprint SERVER_CERT_THUMBPRINT `
|
||||
-TimeoutSeconds 20
|
||||
```
|
||||
|
||||
Los binarios se guardan en un subdirectorio `versions` identificado por su
|
||||
contenido. De esta forma se puede preparar una actualización aunque
|
||||
`LogonUI.exe` todavía tenga cargada la DLL anterior; el reinicio obligatorio
|
||||
activa la nueva versión.
|
||||
|
||||
Bloquear el equipo, abrir **Sign-in options** y elegir el icono azul con llave
|
||||
del acceso SGU. El proveedor de contraseña de Microsoft debe permanecer visible.
|
||||
|
||||
## 5. Verificación
|
||||
|
||||
```powershell
|
||||
Get-Service TermService, WinRM
|
||||
Get-LocalGroupMember -Group 'Remote Desktop Users'
|
||||
Test-WSMan localhost
|
||||
Test-NetConnection sgu-auth.lci.lasalle.mx -Port 8443
|
||||
```
|
||||
|
||||
Desde otro equipo administrador:
|
||||
|
||||
```powershell
|
||||
Test-WSMan NOMBRE-DEL-EQUIPO
|
||||
Enter-PSSession -ComputerName NOMBRE-DEL-EQUIPO -Credential LCI\Administrator
|
||||
mstsc.exe /v:NOMBRE-DEL-EQUIPO
|
||||
```
|
||||
|
||||
El mensaje “the user has not been granted the requested logon type” con evento
|
||||
4625, `LogonType=10` y estado `0xC000015B` indica autorización RDP, no una
|
||||
contraseña incorrecta. Comprobar que la cuenta pertenece a
|
||||
`SG-Laboratorio-Usuarios-RDP` y que ese grupo aparece en **Remote Desktop Users**.
|
||||
Las directivas de grupo de dominio prevalecen sobre la política local.
|
||||
|
||||
Microsoft documenta este derecho en:
|
||||
<https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-userrights#allowlogonthroughremotedesktop>
|
||||
y PowerShell Remoting en:
|
||||
<https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting>.
|
||||
Reference in New Issue
Block a user