feat(auth): OIDC/Keycloak SSO-Login (additiv) — v1.2.91
SSO per OpenID Connect (Authorization Code + PKCE) zusätzlich zum lokalen Login.
- Regeln: kein Auto-Provisioning (E-Mail muss als User existieren), Rolle aus DB (nie aus Token), lokaler Login+TOTP unangetastet.
- Migration 0040: oidc_settings (Singleton, client_secret_enc via secrets.Box) + users.oidc_subject.
- internal/services/oidc: Settings-Repo (write-only Secret) + lazy go-oidc Client (testbarer Authenticator-Seam).
- internal/handlers/oidc.go: GET/PUT /oidc/settings (admin), GET /auth/oidc/{settings,login,callback}. Flow-State (state/PKCE/nonce) stateless im 5-min signierten HttpOnly-Cookie (SameSite=Lax). email_verified erzwungen, opportunistisches sub-Linking, Session via setSessionCookie+Signer.
- session.SignBlob/VerifyBlob; users.Get/SetOIDCSubject; main.go-Wiring.
- Frontend: App.tsx /auth/me-Bootstrap (für Cookie-Session nach Callback), Login-SSO-Button + sso_error, Settings OIDC-Card, i18n de/en.
- Tests (guarded EG_FWTEST_DSN): Secret-Roundtrip + Callback (Rolle-aus-DB, no_account, disabled, unverified, nonce, state).
Deps: go-oidc/v3, x/oauth2. Scope v1: nur Login (kein SLO/Refresh).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -289,6 +289,24 @@
|
||||
"forgotPassword": "Passwort vergessen?",
|
||||
"viewerBadge": "Nur lesen",
|
||||
"viewerHint": "Dieser Account hat die Rolle Betrachter — Änderungen sind gesperrt. Ein Admin kann die Rolle anpassen.",
|
||||
"sso": {
|
||||
"login": "Mit SSO anmelden",
|
||||
"err": {
|
||||
"no_account": "Kein EdgeGuard-Konto für diese E-Mail. Bitte wende dich an einen Administrator.",
|
||||
"disabled": "Dieses Konto ist deaktiviert.",
|
||||
"unverified": "Die E-Mail-Adresse ist beim Identity-Provider nicht verifiziert.",
|
||||
"state": "Sicherheitsprüfung fehlgeschlagen (State). Bitte erneut versuchen.",
|
||||
"nonce": "Sicherheitsprüfung fehlgeschlagen (Nonce). Bitte erneut versuchen.",
|
||||
"token": "Das Token vom Identity-Provider konnte nicht verifiziert werden.",
|
||||
"exchange": "Code-Austausch mit dem Identity-Provider fehlgeschlagen.",
|
||||
"expired": "Die Anmeldesitzung ist abgelaufen. Bitte erneut versuchen.",
|
||||
"denied": "Anmeldung beim Identity-Provider abgebrochen.",
|
||||
"subject_mismatch": "Die Identität passt nicht zum hinterlegten Konto.",
|
||||
"config": "SSO ist nicht korrekt konfiguriert.",
|
||||
"server": "Interner Fehler bei der SSO-Anmeldung.",
|
||||
"generic": "SSO-Anmeldung fehlgeschlagen."
|
||||
}
|
||||
},
|
||||
"totp": {
|
||||
"prompt": "Bitte gib den 6-stelligen Code aus deiner Authenticator-App ein.",
|
||||
"verify": "Code bestätigen",
|
||||
@@ -907,6 +925,24 @@
|
||||
"configPreviewBtn": "Vorschau laden",
|
||||
"configPreviewHint": "Rendert die gewählte Service-Config aus dem aktuellen DB-State. Nur Lesezugriff — es wird nichts auf Disk geschrieben oder neu geladen.",
|
||||
"configCopied": "Config in Zwischenablage kopiert",
|
||||
"oidc": {
|
||||
"title": "Single Sign-On (OIDC)",
|
||||
"intro": "SSO-Login per OpenID Connect (z. B. Keycloak), zusätzlich zum lokalen Login. Anmeldung gelingt nur für bereits angelegte Benutzer; die Rolle wird in EdgeGuard verwaltet.",
|
||||
"enabled": "SSO aktiviert",
|
||||
"issuerUrl": "Issuer-URL",
|
||||
"issuerHint": "Basis-URL des Realms, z. B. https://keycloak.example.com/realms/edgeguard",
|
||||
"clientId": "Client-ID",
|
||||
"clientSecret": "Client-Secret",
|
||||
"secretSet": "Gespeichert — leer lassen, um es unverändert zu lassen.",
|
||||
"secretUnset": "Noch kein Secret gespeichert.",
|
||||
"scopes": "Scopes",
|
||||
"emailClaim": "E-Mail-Claim",
|
||||
"buttonLabel": "Button-Beschriftung",
|
||||
"redirectUri": "Redirect-URI",
|
||||
"redirectHint": "Diese URL im Keycloak-Client als gültige Redirect-URI eintragen (pro Cluster-Node die jeweilige FQDN).",
|
||||
"saved": "OIDC-Einstellungen gespeichert",
|
||||
"saveFailed": "Speichern der OIDC-Einstellungen fehlgeschlagen"
|
||||
},
|
||||
"passwordCardTitle": "Admin-Passwort ändern",
|
||||
"currentPassword": "Aktuelles Passwort",
|
||||
"newPassword": "Neues Passwort",
|
||||
@@ -1287,6 +1323,7 @@
|
||||
"common": {
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"or": "oder",
|
||||
"save": "Speichern",
|
||||
"cancel": "Abbrechen",
|
||||
"loading": "Lädt …",
|
||||
|
||||
Reference in New Issue
Block a user