Repository navigation
feat: OIDC group→role mapping, per-provider scopes and groups claim - #73
Merged
Merged
Conversation
OIDC providers gain four config fields: scopes (extra OAuth scopes past
the base openid/profile/email set, deduplicated), groupsClaim (the
ID-token claim carrying group memberships, default "groups"),
roleMappings (per-role IdP group lists; most privileged match wins,
admin > operator > viewer), and defaultRole (fallback when nothing
matches: viewer/operator/admin, or deny to refuse the login with 403).
When roleMappings is set the IdP becomes authoritative: every login
re-syncs users.role and the cluster-wide ('*') role binding in one
transaction, leaving namespace-scoped bindings alone. Providers without
mappings keep the existing behavior — new users start as viewer and
manual promotions survive re-login. validateAuth rejects the new fields
on the local provider, malformed scope tokens, blank claims, unknown
default roles, defaultRole without mappings, and empty mapping groups.
Covered by extractGroups/computeRole table tests, fake-IdP flow tests
(first-login mapping, demotion resync, manual-promotion persistence,
deny, AuthCodeURL scopes), and validateAuth cases.
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The IdP-authoritative role resync could lock an install out of user administration: if the sole admin's group mapping stopped granting a manager role, their own login would demote them. syncUserRole now mirrors the manual users handler's guard (RoleGrantsUserManagement / UserManagesUsers / UserManagerCount, count <= 1) and skips the role write — login still succeeds, stored role kept — with a slog warning. Covered by fake-IdP tests for both the skip (sole admin keeps admin) and the normal demotion when a second user-manager exists. Also notes in docs/oidc.md that the legacy Helm-flag provider has no group->role mapping support. Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The add-provider form in Admin Settings -> Authentication now exposes the group->role mapping fields the API accepts: extra OAuth scopes (space- or comma-separated), the groups claim (placeholder "groups"), a Role mapping subsection with comma-separated Admin/Operator/Viewer group lists (highest matching role wins; roles re-sync on every login while any mapping is set), and a Default role select whose Deny sign-in option refuses unmatched logins. Empty inputs serialize to absent fields (never [""]), group names are trimmed, and the Default role select stays locked until a mapping exists since the API rejects defaultRole without roleMappings. AuthProvider in lib/config.ts gains the optional scopes/groupsClaim/roleMappings/defaultRole fields, and the section tests cover field rendering, the exact saved JSON payload including deny, and a stored provider's mapping fields surviving an unrelated save. Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
TestHandleCallback_RoleMappingResync demoted an admin who was the test DB's only user-manager, so the new lockout guard (correctly) skipped the demotion and the operator/operator expectations went stale. Seed a second admin before the logins — mirroring the guard-inverse test — so the demotion path applies again; assertions unchanged. The other resync tests are unaffected: every remaining resolveOrLinkUser call site uses syncRole=false, the deny test never reaches an existing user, and the two guard tests cover skip/apply explicitly. Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the main OIDC gap for beta.6: IdP groups can now drive Gameplane roles.
API
scopes(extra scopes beyond openid/profile/email, deduped),groupsClaim(defaultgroups),roleMappings(admin/operator/viewergroup lists),defaultRole(""|viewer|operator|admin|deny).denyreturns a neutral 403 (login-privacy rule respected —/auth/providersdoes not expose the new fields pre-auth).users.role+ the'*'-namespace binding (namespace-scoped bindings untouched). No mappings → existing behavior unchanged.validateAuthrejects the new fields onkind=localand validates scope tokens, role enum, and group lists.Web
Tests
Design: Pencil node
L0cAF(Authentication screen role-mapping section) on branchchore/design-beta6-screens.🤖 Generated with Claude Code