Dieser Eintrag beschreibt das allgemeine OIDC-Auto-Provisioning von BISO. Die kantonsspezifische Genfer Umsetzung (GINA) inkl. der vollständigen Konfiguration ist unter Kanton Genf: OIDC/GINA-Benutzerprovisionierung dokumentiert.
Beim Single-Sign-On (SSO) authentifiziert ein externer Identity-Provider (IdP) den Benutzer. BISO soll den Benutzer dann automatisch anlegen und bei jedem Login synchronisieren (Identität, Gruppen, Rollen/Rechte), sodass kein separater BISO-Login-Screen und keine manuelle Benutzerpflege nötig sind. Das Verhalten ist als allgemeines Framework implementiert und wird pro Kunde über eine Delegate-Klasse konkretisiert.
mod_auth_openidc beendet den OIDC-Handshake (siehe
docker/dev/apache-000-oidc.conf) und übergibt die Claims des Benutzers als
$_SERVER-Variablen (OIDC_CLAIM_*, nach interner Weiterleitung auch
REDIRECT_OIDC_CLAIM_*) sowie das Access-Token (OIDC_access_token).AuthService::authCheck() die Methode
remoteUserAuth() auf (sobald oidc.auto_provision = true – oder remote_user_auth = true
für den separaten REMOTE_USER-/Kerberos-Pfad).oidc.auto_provision = true, dann:OidcClaims-Objekt aus $_SERVER gebaut,OidcUserProvisioner-Instanz — der BisoDIProvider
wählt anhand des Params kunde die kundenspezifische Subklasse (z.B.
GeOidcUserProvisioner), sonst die Basisklasse,provision($claims) auf. Diese Methode
reichert – falls oidc.userinfo_endpoint gesetzt ist – die Claims zuerst über den
userinfo-Endpoint an (Rollen + saubere Identität), findet oder erstellt
danach Login + Benutzer und bildet die Rollen auf BISO-Gruppen/Flags ab,setupSession() (bzw. setupSessionPartial(), wenn der
Login mehrere Benutzer/Seats hat – dann zeigt die SPA das bestehende
Mehrfach-Benutzer-Auswahlfenster).SESSION.benutzer direkt ins Hauptpanel –
ohne separaten Login-Screen.| Klasse | Aufgabe |
|---|---|
backend/logic/OidcClaims.php |
Normalisiert die OIDC_CLAIM_*-Variablen; get()/getList(); accessToken() liefert das Bearer-Token; merge() fügt userinfo-Claims hinzu. |
backend/logic/OidcUserInfoClient.php |
Kleiner Guzzle-Client: GET userinfo mit Authorization: Bearer <token>, JSON-Parsing. |
backend/logic/OidcUserProvisioner.php |
Basis-Delegate mit dem generischen Find-or-Create-/Sync-Ablauf und überschreibbaren Hooks. |
backend/service/AuthService.php |
remoteUserAuth() – Einstiegspunkt, Session-Aufbau. |
Überschreibbare Hooks auf OidcUserProvisioner (pro Kunde):
extractUsername() – welcher Claim wird login.benutzername (der sub-Claim).findLogin() / createLogin() – Login finden/erstellen.enrichClaimsFromUserInfo() – userinfo-Aufruf + Merge (generisch, per Config aktiv).provisionSeats() – erzeugt die Benutzer-"Seats" (Standard: genau ein Benutzer).createBenutzer() / syncBenutzer() – Benutzer anlegen / Identität (Person) syncen.syncLogin() – Login-Daten syncen (Standard: nichts).mapRolesToGroups() / mapRolesToFlags() – Rollen → Gruppen/Flags.findOrCreatePerson() / syncPersonIdentity() – verknüpfte Person finden/erstellen
und deren Name/Vorname/E-Mail aktuell halten.Ein Login kann in BISO mehrere Benutzer besitzen. Das Framework nutzt dies für
das Konzept eines Seats: pro Rolle/Service kann ein eigener Benutzer mit eigener
Institution, eigenen Gruppen und Default-Werten angelegt werden.
setupSessionPartial()); die SPA zeigt
das bestehende Mehrfach-Benutzer-Auswahlfenster, in dem der Benutzer den Seat
wählt (unterschieden u.a. über die Institution). Es ist keine eigene Zusatz-UI
nötig.Manche IdP liefern die Rollen nicht in den Front-Channel-Claims. In diesem Fall holt
enrichClaimsFromUserInfo() sie per HTTP:
oidc.userinfo_endpoint mit dem Bearer-Token des Benutzers. Dieses Token
wird aus dem von Apache bereitgestellten OIDC_access_token wiederverwendet
(OidcClaims::accessToken()), d.h. kein zusätzliches Client-Secret nötig.roles) wird in die Claims gemergt; die Rollen landen unter
oidc.roles_claim.oidc.userinfo_endpoint leer, entfällt der Aufruf und die Rollen werden aus dem
Claim oidc.roles_claim gelesen.Fehler-Policy: Schlägt der userinfo-Aufruf fehl, bleibt ein bestehender Benutzer unangetastet (Login gelingt mit den aktuellen Rechten – nie „Rechte wegwischen" bei einer Störung), während ein neuer Login abgelehnt wird (Rollen nicht bestimmbar).
Bei jedem Login (wenn oidc.sync_existing = true):
Benutzer deaktiviert (aktiv=false) – er gewährt keinen Zugriff mehr, die
Daten bleiben jedoch erhalten.Login-Datensatz.oidc.sync_existing = false bedeutet „nur anlegen": bestehende Benutzer werden nach dem
ersten Login nicht mehr verändert. Neue Benutzer werden immer voll provisioniert.
Param::set('kunde', 'xy').backend/logic/XyOidcUserProvisioner.php erstellen:class XyOidcUserProvisioner extends OidcUserProvisioner {
protected function mapRolesToGroups(OidcClaims $claims): array { /* ... */ }
protected function mapRolesToFlags(OidcClaims $claims): array { /* ... */ }
}
BisoDIProvider einen case für den Kunden ergänzen:case Param::KUNDE_XY:
return new XyOidcUserProvisioner();
config.php dieser Installation oidc.auto_provision = true
(und ggf. oidc.userinfo_endpoint) setzen.Ein vollständiges Beispiel ist die Genfer Umsetzung, siehe Kanton Genf: OIDC/GINA-Benutzerprovisionierung.
In der config.php der jeweiligen Installation:
Config::set('oidc.auto_provision', true); // aktiviert OIDC-Auto-Provisioning (Find-or-Create aus den Claims)
Config::set('oidc.sync_existing', true); // bestehende Benutzer bei jedem Login re-synchronisieren
Config::set('oidc.debug_claims', false); // normalisierte Claims protokollieren (nur Dev/Test)
Config::set('oidc.roles_claim', 'roles'); // Name des Claims/userinfo-Felds mit den Rollen
// Optional: Rollen aus einem userinfo-Endpoint holen (wenn nicht in den Claims):
Config::set('oidc.userinfo_endpoint', ''); // z.B. 'https://.../oauth2/userinfo'; leer = deaktiviert
oidc.auto_provision = true genügt, um den Provisioning-Pfad zu aktivieren.
remote_user_auth gehört zu einem separaten SSO-Mechanismus (REMOTE_USER/Kerberos über
Config remote_user) und ist für OIDC nicht erforderlich.
Der aktive Kunde wird wie üblich über Param::set('kunde', '<kunde>') gewählt; darüber
liefert der BisoDIProvider die passende OidcUserProvisioner-Instanz.
Das Provisioning protokolliert in einen eigenen oidc-Log-Kanal (Start, angelegte
Login/Benutzer, Sync vs. Create-only, gemappte Gruppen/Flags, Fehler, etablierte
Session). Eigene Datei über einen oidc-Eintrag in gaia.logging (config.php):
'oidc' => [
'type' => 'file',
'level' => 'DEBUG',
'logfile' => Config::get('tmpdir') . "/biso-oidc.log",
],
Fehlt der oidc-Kanal, landen die Meldungen automatisch im main-Log.
Siehe auch: Login, Benutzer, Berater, Institutionen, Mitarbeiter und Prüfen von Rollen.