Ga naar inhoud

Eenmalige aanmelding

Eenmalige aanmelding laat een externe identiteitsprovider (IdP) beslissen wie zich mag aanmelden bij je Control Center-server. Er worden twee protocollen ondersteund — SAML 2.0 en OpenID Connect — en beide komen op hetzelfde punt uit: een nieuw uitgegeven apparaatinloggegeven dat stroomafwaarts nergens te onderscheiden is van een uitnodiging of een QR-koppeling.

SAML-aanmeldingen verlopen via de browser. De IdP opent nooit zelf een verbinding naar je server; de browser van de gebruiker draagt alles:

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

Omdat de browser als bode fungeert, werkt een server achter NAT prima voor aanmeldingen: localhost, LAN, Tailscale, VPN of een tunnel voldoen allemaal — alleen de browser van de gebruiker hoeft de ACS-URL te bereiken. De WebSocket-relay waarvan de telefoonafstandsbediening gebruikmaakt, kan de HTTP-roundtrip niet dragen; daarom richten SSO-toegangspunten zich altijd op de HTTP-origin van de server.

OpenID Connect volgt dezelfde vorm met een roundtrip van autorisatiecode + PKCE; claims worden via TLS gelezen van het token-endpoint van de issuer, dus de browser levert helemaal geen identiteitsgegevens aan.

Control Center verdeelt de verantwoordelijkheid bewust:

Onderdeel Waar Verantwoordelijk voor
native cc_saml packages/cc_natives/native/saml/ verificatie van XML-DSig, canonicalisatie, validatie van het SAML-profiel — gedelegeerd aan de vastgepinde pure-Rust crate saml achter een staatloze C-ABI
SamlService / OidcService cc_server_core aanmeldstatus (trackers voor openstaande requests, replay-deduplicatie), instellingen van het validatiebeleid, de gedeelde provisioneringsaanroep
SsoProvisioner cc_server_core de gebruiker opzoeken of aanmaken, het subject van de provider vastzetten, lidmaatschappen verlenen volgens het auto-member-beleid
ScimService cc_server_core het push-oppervlak van SCIM 2.0 (levenscyclus van provisioneren en deprovisioneren)
SsoSettingsService cc_server_core de opgeslagen verbindingsrijen, live opnieuw toepassen, het SCIM-token

Er is bewust geen SAML-cryptofallback in puur Dart: met de hand geschreven XML-DSig/canonicalisatie is precies de plek waar signature-wrapping-kwetsbaarheden zitten, dus een ontbrekende cc_saml-bibliotheek weigert zowel de SAML-aanmelding als het opstarten van de server. De native is bewust staatloos — status over requests heen leeft in de Dart-services, eenmalig bruikbaar en kortlevend.

In de geverifieerde native en de service, in deze volgorde:

  1. de handtekening van de assertion (altijd vereist; die van de antwoordenvelop is optioneel per configuratie) — structureel bestand tegen signature wrapping, doordat de gevalideerde payload aan het geverifieerde element is gebonden,
  2. de issuer overeenkomt met de geconfigureerde IdP,
  3. de audience deze serviceprovider vermeldt,
  4. de destination onze ACS-URL is,
  5. InResponseTo overeenkomt met een openstaand AuthnRequest dat wij hebben uitgegeven (ongevraagde, door de IdP geïnitieerde antwoorden staan standaard uit),
  6. de levensduurvensters binnen de klokafwijking vallen (standaard 90 s) en
  7. de assertion-id nooit eerder is gezien (replay-cache).

Fouten komen terug als getypeerde codes — signature, expired, audience, destination, issuer, request-match — en de endpoints antwoorden met algemene fouten, zodat een aanvaller niets leert over waarom een vervalsing is mislukt.

De eerste SSO-aanmelding zet het onveranderlijke subject van de provider (issuer plus SAML-NameID / OIDC-sub, of SCIM externalId) vast op het account. Vanaf dat moment identificeert het subject de aanmelding, niet het e-mailadres. Biedt iemand later hetzelfde e-mailadres aan, van dezelfde of een andere IdP, dan weigert het vastgezette account. Dat voorkomt dat een gerecycled e-mailadres bij een provider een accountovername wordt.

JIT-provisionering gebeurt bij het aanmelden (SsoProvisioner). SCIM is een apart push-oppervlak (ScimService) dat hetzelfde subject op de gebruikersrij vastzet; werkruimtelidmaatschappen verleent het niet. Deprovisioneren — SCIM active: false of DELETE — weigert als het account eigenaar van een werkruimte is (draag eerst over). Anders trekt het eerst elk apparaatinloggegeven in (sessies verdwijnen binnen enkele seconden via de apparaatwatch), verwijdert het elk werkruimtelidmaatschap en stempelt het account als gedeactiveerd. De gebruikersrij blijft bestaan: toeschrijving is permanent. Reactivering herstelt de aanmelding, maar verleent nooit opnieuw lidmaatschappen.

  • De toewijzing groep→rol gebeurt bij het aanmelden op basis van de SAML-attributen / OIDC-claims — via push aangeleverde SCIM-groepen worden niet opgeslagen.
  • De rol eigenaar is via SSO niet te bereiken — niet als standaardrol en niet via een groepstoewijzing.
  • De WebSocket-relay is nooit een SSO-kanaal; telefoons die de server alleen via de relay bereiken, kunnen daar geen browser-roundtrip tegen afronden.