* feat(auth): OIDC role mapping + login policy — phase 2 (#798) Role mapping: configurable dot-path roles claim (Keycloak realm_access.roles, Authentik/Pocket ID groups, Entra roles), IdP-value → PicPeak-role mapping table validated against the roles table, re-evaluated on every SSO login with highest-priority-wins on multiple matches. The last active super_admin is never demoted. Optional require-mapped-role policy refuses logins whose token maps to no role (sso_error=no_role). Login policy: oidc_disable_local_login makes the API refuse password logins (403 LOCAL_LOGIN_DISABLED) and the login page render SSO-only; only effective while SSO is enabled+configured, and OIDC_BREAK_GLASS=true always re-opens local login. Public settings expose the EFFECTIVE flag only. Settings UI: Role-mapping card (claim path, mapping rows editor, strict toggle) and Login-policy card with break-glass hint, EN+DE. 14 new integration tests over the mock IdP. * fix(auth): harden phase-2 review findings (#798) - memoize the scrypt-derived OIDC key and serve /public/settings from a 10s-TTL flag cache — the unauthenticated endpoint no longer pays a 13-key config read + blocking scryptSync per request (login route still checks uncached) - make the last-super-admin demotion guard atomic (FOR UPDATE on the active super rows) — concurrent mapped callbacks could previously both count 2 and demote both supers - own-property lookup in role mapping: IdP values like `constructor` now count as unmapped instead of corrupting the roles query - SsoTab clears oidc_disable_local_login in the same save that turns SSO off — the full-form payload otherwise hit the server-side 400 * fix(auth): guarantee break-glass reachability for SSO-only mode (#798) - wire OIDC_BREAK_GLASS and OIDC_ENCRYPTION_KEY through the quick-start docker-compose.yml env allowlist (production compose already passes .env via env_file) and document both in .env.example - refuse enabling oidc_disable_local_login unless an active local-password super_admin exists: OIDC_BREAK_GLASS only re-opens the password route, which OIDC-owned accounts can never use, and settings.edit is super_admin-only — an all-OIDC instance would be unrecoverable during an IdP outage * fix(auth): close SSO-only lockout gaps from review round 3 (#798) - role sync never demotes the last active LOCAL-password super_admin (an OIDC-owned super does not count as break-glass), and isLocalLoginDisabled() disarms itself when no such account remains — self-healing against manual demotion/deactivation/deletion paths - the local-super save-time check now validates the MERGED state, so re-enabling SSO with a stored disable flag is checked too - ALL oidc_* keys are reserved from the generic settings upserts/reads (prefix match) — policy and mapping invariants can only go through the validated PUT /sso - /admin/login/mfa re-checks the policy so an mfa_pending token minted before the flip cannot complete into a local session --------- Co-authored-by: Paul Nothaft <[email protected]>
This commit is contained in:
co-authored by
Paul Nothaft
parent
ad326da35c
commit
f8a95d29d2
@@ -2119,7 +2119,27 @@
|
||||
"testOk": "Discovery erfolgreich — Issuer ist erreichbar: {{issuer}}",
|
||||
"testFailed": "Discovery fehlgeschlagen",
|
||||
"saved": "SSO-Einstellungen gespeichert",
|
||||
"saveError": "SSO-Einstellungen konnten nicht gespeichert werden"
|
||||
"saveError": "SSO-Einstellungen konnten nicht gespeichert werden",
|
||||
"roleMapping": {
|
||||
"title": "Rollen-Mapping",
|
||||
"intro": "Weisen Sie PicPeak-Rollen aus einem Rollen- oder Gruppen-Claim im ID-Token zu. Rollen werden bei jeder SSO-Anmeldung neu ausgewertet — der IdP wird zur führenden Quelle.",
|
||||
"enabled": "Rollen-Mapping aktivieren",
|
||||
"enabledHint": "Aus: Bestehende Admins behalten ihre Rolle, neue Benutzer erhalten die Standardrolle oben.",
|
||||
"claim": "Rollen-Claim (Punkt-Pfad)",
|
||||
"claimHint": "Keycloak: realm_access.roles · Authentik: groups · Entra ID: roles oder groups",
|
||||
"mappings": "Zuordnungen (IdP-Wert → PicPeak-Rolle)",
|
||||
"noMappings": "Noch keine Zuordnungen — ohne Zuordnung erhält keine Anmeldung eine Rolle vom IdP.",
|
||||
"idpValuePlaceholder": "IdP-Rolle oder -Gruppe, z. B. picpeak-admins",
|
||||
"addMapping": "Zuordnung hinzufügen",
|
||||
"requireRole": "Zugeordnete Rolle für die Anmeldung verlangen",
|
||||
"requireRoleHint": "SSO-Anmeldungen ohne zugeordnete Rolle werden abgelehnt — nur Mitglieder der zugeordneten IdP-Gruppen kommen hinein. Der letzte aktive Super Admin wird durch das Mapping nie herabgestuft."
|
||||
},
|
||||
"policy": {
|
||||
"title": "Anmelde-Richtlinie",
|
||||
"disableLocalLogin": "Lokale Passwort-Anmeldung deaktivieren",
|
||||
"disableLocalLoginHint": "Die Anmeldeseite zeigt nur noch den SSO-Button und die API lehnt Passwort-Anmeldungen ab. Nur möglich, solange SSO aktiviert ist; wird SSO deaktiviert, ist die Passwort-Anmeldung automatisch wieder möglich.",
|
||||
"breakGlassHint": "Ausgesperrt, weil der IdP down oder falsch konfiguriert ist? Setzen Sie die Umgebungsvariable OIDC_BREAK_GLASS=true am Backend und starten Sie neu — die Passwort-Anmeldung ist sofort wieder möglich."
|
||||
}
|
||||
}
|
||||
},
|
||||
"branding": {
|
||||
@@ -3749,13 +3769,15 @@
|
||||
},
|
||||
"ssoDivider": "oder",
|
||||
"ssoSignIn": "Mit SSO anmelden",
|
||||
"ssoOnlyHint": "Die Passwort-Anmeldung ist auf dieser Instanz deaktiviert — melden Sie sich über Ihren Identity Provider an.",
|
||||
"ssoErrors": {
|
||||
"config": "SSO ist falsch konfiguriert — prüfen Sie die SSO-Einstellungen oder melden Sie sich mit E-Mail und Passwort an.",
|
||||
"state": "Die SSO-Anmeldung ist abgelaufen oder wurde manipuliert. Bitte erneut versuchen.",
|
||||
"idp": "Der Identity Provider hat die Anmeldung abgelehnt. Bitte erneut versuchen oder E-Mail und Passwort verwenden.",
|
||||
"inactive": "Ihr Admin-Konto ist deaktiviert.",
|
||||
"not_provisioned": "Kein Admin-Konto passt zu Ihrer SSO-Identität. Bitten Sie einen Administrator um eine Einladung.",
|
||||
"no_email": "Ihr Identity Provider hat keine E-Mail-Adresse geliefert — es kann kein Konto erstellt werden."
|
||||
"no_email": "Ihr Identity Provider hat keine E-Mail-Adresse geliefert — es kann kein Konto erstellt werden.",
|
||||
"no_role": "Ihr Identity Provider hat keine Rolle geliefert, die dieser Instanz zugeordnet ist — bitten Sie einen Administrator, Sie einer zugeordneten Gruppe hinzuzufügen."
|
||||
}
|
||||
},
|
||||
"cssTemplates": {
|
||||
|
||||
@@ -1666,7 +1666,27 @@
|
||||
"testOk": "Discovery succeeded — issuer is reachable: {{issuer}}",
|
||||
"testFailed": "Discovery failed",
|
||||
"saved": "SSO settings saved",
|
||||
"saveError": "Failed to save SSO settings"
|
||||
"saveError": "Failed to save SSO settings",
|
||||
"roleMapping": {
|
||||
"title": "Role mapping",
|
||||
"intro": "Assign PicPeak roles from a role or group claim in the ID token. Roles are re-evaluated on every SSO login — the IdP becomes the source of truth.",
|
||||
"enabled": "Enable role mapping",
|
||||
"enabledHint": "Off: existing admins keep their role and new users get the default role above.",
|
||||
"claim": "Roles claim (dot-path)",
|
||||
"claimHint": "Keycloak: realm_access.roles · Authentik: groups · Entra ID: roles or groups",
|
||||
"mappings": "Mappings (IdP value → PicPeak role)",
|
||||
"noMappings": "No mappings yet — without one, no login gets a role from the IdP.",
|
||||
"idpValuePlaceholder": "IdP role or group, e.g. picpeak-admins",
|
||||
"addMapping": "Add mapping",
|
||||
"requireRole": "Require a mapped role to sign in",
|
||||
"requireRoleHint": "Refuse SSO logins whose token maps to no role — only members of the mapped IdP groups get in. The last active Super Admin is never demoted by mapping."
|
||||
},
|
||||
"policy": {
|
||||
"title": "Login policy",
|
||||
"disableLocalLogin": "Disable local password login",
|
||||
"disableLocalLoginHint": "The login page shows only the SSO button and the API refuses password logins. Only possible while SSO is enabled; turning SSO off restores password login automatically.",
|
||||
"breakGlassHint": "Locked out because the IdP is down or misconfigured? Set the environment variable OIDC_BREAK_GLASS=true on the backend and restart — password login comes back immediately."
|
||||
}
|
||||
}
|
||||
},
|
||||
"analytics": {
|
||||
@@ -3635,13 +3655,15 @@
|
||||
},
|
||||
"ssoDivider": "or",
|
||||
"ssoSignIn": "Sign in with SSO",
|
||||
"ssoOnlyHint": "Password login is disabled on this instance — sign in through your identity provider.",
|
||||
"ssoErrors": {
|
||||
"config": "SSO is misconfigured — check the SSO settings or sign in with email and password.",
|
||||
"state": "The SSO sign-in expired or was tampered with. Please try again.",
|
||||
"idp": "The identity provider rejected the sign-in. Please try again or use email and password.",
|
||||
"inactive": "Your admin account is deactivated.",
|
||||
"not_provisioned": "No admin account matches your SSO identity. Ask an administrator to invite you.",
|
||||
"no_email": "Your identity provider supplied no email address — an account cannot be created."
|
||||
"no_email": "Your identity provider supplied no email address — an account cannot be created.",
|
||||
"no_role": "Your identity provider granted no role that is mapped to this instance — ask an administrator to add you to a mapped group."
|
||||
}
|
||||
},
|
||||
"slideshow": {
|
||||
|
||||
Reference in New Issue
Block a user