fix(auth): normalize IdP group names before matching scope mappings - #1713
Open
AmirF194 wants to merge 1 commit into
Open
fix(auth): normalize IdP group names before matching scope mappings#1713AmirF194 wants to merge 1 commit into
AmirF194 wants to merge 1 commit into
Conversation
Keycloak's Group Membership mapper can emit the full group path (e.g. "/mcp-admins") instead of the bare name. Scope mappings are seeded without the leading slash, so filter_session_groups, its Design C helper _filter_by_scope_mappings, and map_groups_to_scopes all compared the prefixed claim against the unslashed mapping and matched nothing, silently dropping the group's scopes. Normalize group names at the comparison points, mirroring _normalize_server_name, which already handles the identical slash mismatch for server names. Refs agentic-community#1689
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Root cause
_normalize_server_name(auth_server/server.py) strips leading/trailingslashes so a scope entry written as
/cloudflare-docsstill matches arequest for
cloudflare-docs. Group names never got the same treatment, soevery comparison point matched verbatim:
group_filter.py::_filter_by_scope_mappings(Design C):[g for g in groups if g in mapped]group_filter.py::filter_session_groups(Design B):[g for g in groups if g in allowed]server.py::map_groups_to_scopes, which callsget_group_mappings_bulk(groups)(a MongoDB$inagainst unslashed storedgroup_mappings) and falls back to the same exact-match lookup againstSCOPES_CONFIGKeycloak's Group Membership mapper emits the full group path (
/mcp-admins)when "Full group path" is enabled, while scope mappings are seeded without
the leading slash. A user in that group then silently resolves to zero
scopes for it, both in the session (dropped by the login-time filter) and on
every subsequent authorization check.
Fix
Added a small
_normalize_group_namehelper (same logic as_normalize_server_name: strip surrounding slashes) at each comparisonpoint:
filter_session_groupsnormalizes the incoming groups once, before eitherthe Design B allowlist or the Design C scope-derived branch; the allowlist
and the scope-mapped set are normalized too, so both sides agree.
map_groups_to_scopesnormalizes itsgroupsargument before callingget_group_mappings_bulkand before the in-memory fallback lookup, whichcovers all five call sites of this function.
Scope
This addresses the normalization gap only (the first half of #1689). The
issue also asks for the group filter to log dropped group names, not just
counts, plus a documentation note on the bearer-token/session asymmetry;
neither is touched here, so this is
Refs #1689rather thanFixes #1689.Verification
matching an unslashed mapping, allowlist entry, and the bulk scope query),
confirmed failing against unmodified
auth_server/group_filter.pyandauth_server/server.pyand passing against this branch, in a cleanpython:3.14-slimcontainer.tests/auth_server/suite: 820 passed, no regressions, samecontainer.
ruff check,ruff format --check, and the repo's scopedmypyinvocation(
--ignore-missing-imports --no-strict-optionalonregistry|auth_server)all clean;
banditreports no new findings.container); this diff touches only
auth_server/, and its own testsexercise every changed line.