Inicio de sesión único
El inicio de sesión único permite que un proveedor de identidad (IdP) externo decida quién puede iniciar sesión en tu servidor de Control Center. Se admiten dos protocolos —SAML 2.0 y OpenID Connect— y ambos terminan en el mismo lugar: una credencial de dispositivo recién emitida que, en todo lo que viene después, es indistinguible de una invitación o de un emparejamiento por QR.
La forma de un inicio de sesión
Sección titulada «La forma de un inicio de sesión»Los inicios de sesión SAML están mediados por el navegador. El IdP nunca abre una conexión con tu servidor; el navegador del usuario lo transporta todo:
browser ──> /saml/login ──> IdP ──POST SAMLResponse──> /saml/acs │ verify ▼ provision user (maybe) │ ▼ browser handoff: device PSK in the URL fragment (never a query parameter)Como el navegador es el mensajero, un servidor detrás de NAT funciona sin problema para los inicios de sesión: localhost, la LAN, Tailscale, una VPN o un túnel sirven igual — solo el navegador del usuario debe alcanzar la URL de ACS. El relevo WebSocket que usa el control remoto desde el teléfono no puede transportar el ciclo HTTP de ida y vuelta, y por eso los puntos de entrada de SSO siempre apuntan al origen HTTP del servidor.
OpenID Connect sigue la misma forma con un ciclo de código de autorización + PKCE; las reclamaciones se leen del endpoint de tokens del emisor a través de TLS, así que el navegador nunca aporta datos de identidad.
Los adaptadores
Sección titulada «Los adaptadores»Control Center reparte la responsabilidad de forma deliberada:
| Pieza | Dónde | Se encarga de |
|---|---|---|
cc_saml native |
packages/cc_natives/native/saml/ |
verificación XML-DSig, canonicalización y validación del perfil SAML — delegadas en el crate saml de Rust puro fijado tras una ABI de C sin estado |
SamlService / OidcService |
cc_server_core |
el estado del inicio de sesión (rastreadores de solicitudes pendientes, deduplicación de repeticiones), los parámetros de la política de validación y la llamada de aprovisionamiento compartida |
SsoProvisioner |
cc_server_core |
buscar o crear al usuario, fijar el sujeto del proveedor y conceder pertenencias según la política de miembro automático |
ScimService |
cc_server_core |
la superficie de envío SCIM 2.0 (ciclo de vida de aprovisionamiento/desaprovisionamiento) |
SsoSettingsService |
cc_server_core |
las filas de conexión guardadas, la reaplicación en vivo y el token SCIM |
Deliberadamente no hay ninguna alternativa de criptografía SAML en Dart
puro: la canonicalización/XML-DSig hecha a mano es justo donde viven las
vulnerabilidades de envoltura de firma, así que la ausencia de la biblioteca
cc_saml rechaza tanto el inicio de sesión SAML como el arranque del servidor.
El componente nativo no tiene estado por diseño: el estado entre solicitudes
vive en los servicios Dart, de un solo uso y de vida corta.
Qué verifica un inicio de sesión
Sección titulada «Qué verifica un inicio de sesión»Dentro del nativo verificado y del servicio, en este orden:
- la firma de la aserción (siempre obligatoria; la del sobre de respuesta es opcional según la configuración) — resistente por diseño a la envoltura de firma, porque la carga útil validada está vinculada al elemento verificado,
- el emisor coincide con el IdP configurado,
- la audiencia nombra a este proveedor de servicio,
- el destino es nuestra URL de ACS,
InResponseTocoincide con una AuthnRequest pendiente que emitimos (las respuestas no solicitadas iniciadas por el IdP están desactivadas de forma predeterminada),- las ventanas de vigencia se mantienen dentro del desfase de reloj (90 s de forma predeterminada) y
- el id de aserción no se ha visto nunca antes (caché de repeticiones).
Los fallos se devuelven como códigos tipados —firma, expirado, audiencia, destino, emisor, coincidencia de solicitud— y los endpoints responden con errores genéricos, así que un atacante no aprende nada sobre por qué falló una falsificación.
Cuentas y fijación del sujeto
Sección titulada «Cuentas y fijación del sujeto»El primer inicio de sesión SSO fija el sujeto inmutable del proveedor
(issuer más el NameID de SAML / sub de OIDC, o el externalId de SCIM) en la
cuenta. A partir de entonces, es el sujeto —no el correo electrónico— el que
identifica el inicio de sesión. Si otra persona presenta después el mismo
correo desde el mismo IdP o desde otro, la cuenta fijada la rechaza. Esto es lo
que impide que un correo reciclado en un proveedor se convierta en una toma de
control de la cuenta.
Aprovisionamiento y desaprovisionamiento
Sección titulada «Aprovisionamiento y desaprovisionamiento»El aprovisionamiento JIT ocurre al iniciar sesión (SsoProvisioner). SCIM es
una superficie de envío aparte (ScimService) que fija el mismo sujeto en la
fila del usuario; no concede pertenencias a espacios de trabajo. El
desaprovisionamiento —active: false o DELETE de SCIM— se niega si la cuenta
es propietaria de un espacio de trabajo (transfiere la propiedad primero). De
lo contrario, revoca primero todas las credenciales de dispositivo (las
sesiones caen en cuestión de segundos gracias a la vigilancia de dispositivos),
elimina todas las pertenencias a espacios de trabajo y marca la cuenta como
desactivada. La fila del usuario sobrevive: la atribución es permanente. La
reactivación restaura el inicio de sesión, pero nunca vuelve a conceder
pertenencias.
Lo que queda fuera
Sección titulada «Lo que queda fuera»- La asignación de grupos→roles ocurre al iniciar sesión a partir de los atributos SAML / las reclamaciones OIDC; los grupos SCIM enviados no se almacenan.
- El rol de propietario es inalcanzable desde SSO, ni como rol predeterminado ni mediante una asignación de grupos.
- El relevo WebSocket nunca es un canal de SSO; los teléfonos que solo llegan al servidor por el relevo no pueden completar un ciclo de ida y vuelta por el navegador contra él.