Aller au contenu

Ouverture de session unique

L’ouverture de session unique permet à un fournisseur d’identité (IdP) externe de décider qui peut se connecter à votre serveur Control Center. Deux protocoles sont pris en charge — SAML 2.0 et OpenID Connect — et les deux aboutissent au même endroit : un identifiant d’appareil fraîchement créé, impossible à distinguer d’une invitation ou d’un appairage par code QR partout en aval.

Les connexions SAML sont intermédiées par le navigateur. L’IdP n’ouvre jamais de connexion vers votre serveur ; c’est le navigateur de l’utilisateur qui transporte tout :

browser ──> /saml/login ──> IdP ──POST SAMLResponse──> /saml/acs
│ verify
▼
provision user (maybe)
│
▼
browser handoff: device PSK in the URL
fragment (never a query parameter)

Parce que le navigateur sert de courrier, un serveur derrière un NAT fonctionne très bien pour les connexions : localhost, LAN, Tailscale, VPN ou tunnel font tous l’affaire — seul le navigateur de l’utilisateur doit joindre l’URL ACS. Le relais WebSocket qu’utilise le contrôle à distance par téléphone ne peut pas transporter l’aller-retour HTTP, et c’est pourquoi les points d’entrée SSO ciblent toujours l’origine HTTP du serveur.

OpenID Connect suit la même forme avec un aller-retour code d’autorisation + PKCE ; les revendications sont lues depuis le point de terminaison de jeton de l’émetteur par TLS, de sorte que le navigateur ne fournit jamais de données d’identité.

Control Center répartit délibérément les responsabilités :

Élément Emplacement Responsabilité
natif cc_saml packages/cc_natives/native/saml/ vérification XML-DSig, canonicalisation, validation du profil SAML — déléguées à la crate saml en pur Rust épinglée, derrière une ABI C sans état
SamlService / OidcService cc_server_core l’état de connexion (suivi des requêtes en attente, déduplication des rejeux), les réglages de politique de validation, l’appel de provisionnement partagé
SsoProvisioner cc_server_core trouver ou créer l’utilisateur, épingler le sujet du fournisseur, accorder les appartenances selon la politique d’ajout automatique de membres
ScimService cc_server_core la surface de poussée SCIM 2.0 (cycle de vie de provisionnement et de déprovisionnement)
SsoSettingsService cc_server_core les lignes de connexion enregistrées, la réapplication à chaud, le jeton SCIM

Il n’existe délibérément aucune solution de repli cryptographique SAML en pur Dart : la vérification XML-DSig et la canonicalisation écrites à la main sont exactement là où logent les vulnérabilités d’enveloppement de signature ; l’absence de la bibliothèque cc_saml fait donc échouer à la fois la connexion SAML et le démarrage du serveur. Le natif est sans état par conception — l’état inter-requêtes vit dans les services Dart, à usage unique et de courte durée.

À l’intérieur du natif vérifié et du service, dans l’ordre :

  1. la signature de l’assertion (toujours exigée ; celle de l’enveloppe de réponse est facultative selon la configuration) — structurellement résistante à l’enveloppement de signature, parce que la charge utile validée est liée à l’élément vérifié,
  2. l’émetteur correspond à l’IdP configuré,
  3. l’audience désigne ce fournisseur de service,
  4. la destination est notre URL ACS,
  5. InResponseTo correspond à un AuthnRequest en attente que nous avons émis (les réponses non sollicitées, initiées par l’IdP, sont désactivées par défaut),
  6. les fenêtres de durée de vie tiennent dans le décalage d’horloge (90 s par défaut) et
  7. l’identifiant d’assertion n’a jamais été vu auparavant (cache anti-rejeu).

Les échecs reviennent sous forme de codes typés — signature, expiré, audience, destination, émetteur, correspondance de requête — et les points de terminaison répondent par des erreurs génériques, de sorte qu’un attaquant n’apprend rien sur la raison de l’échec d’une falsification.

La première connexion SSO épingle sur le compte le sujet immuable du fournisseur (issuer plus SAML NameID / OIDC sub, ou SCIM externalId). À partir de là, c’est le sujet — et non le courriel — qui identifie la connexion. Si quelqu’un d’autre présente plus tard le même courriel depuis le même IdP ou un autre, le compte épinglé le refuse. C’est ce qui empêche un courriel recyclé chez un fournisseur de devenir une prise de contrôle de compte.

Le provisionnement JIT se produit à la connexion (SsoProvisioner). SCIM est une surface de poussée distincte (ScimService) qui épingle le même sujet sur la ligne d’utilisateur ; il n’accorde pas d’appartenances à des espaces de travail. Le déprovisionnement — SCIM active: false ou DELETE — refuse si le compte est propriétaire d’un espace de travail (transférez d’abord). Sinon, il révoque d’abord chaque identifiant d’appareil (les sessions tombent en quelques secondes grâce à la surveillance des appareils), retire chaque appartenance à un espace de travail et marque le compte comme désactivé. La ligne d’utilisateur survit : l’attribution est permanente. La réactivation rétablit la connexion, mais ne réaccorde jamais les appartenances.

  • La correspondance groupe→rôle se fait à la connexion à partir des attributs SAML / des revendications OIDC — les groupes poussés par SCIM ne sont pas stockés.
  • Le rôle de propriétaire est inatteignable depuis le SSO — ni comme rôle par défaut, ni par une correspondance de groupes.
  • Le relais WebSocket n’est jamais un canal SSO ; les téléphones qui ne joignent le serveur que par le relais ne peuvent pas effectuer d’aller-retour de navigateur contre lui.