Skip to content

Optimize composite realm role mappings - #51565

Open
PRAHLAD09-dev wants to merge 2 commits into
keycloak:mainfrom
PRAHLAD09-dev:fix/GH-51531-composite-realm-role-mappings
Open

Optimize composite realm role mappings#51565
PRAHLAD09-dev wants to merge 2 commits into
keycloak:mainfrom
PRAHLAD09-dev:fix/GH-51531-composite-realm-role-mappings

Conversation

@PRAHLAD09-dev

Copy link
Copy Markdown

RoleMapperResource#getCompositeRealmRoleMappings() currently iterates over all realm roles and calls roleMapper.hasRole() for each role.

This can become expensive when a user has a large number of effective role mappings, particularly when roles are inherited through groups or composite roles.

The client-role variant already uses RoleUtils.getDeepRoleMappings() to resolve effective mappings. This PR applies the same approach to the realm-role variant and filters the resolved mappings to realm roles.

Changes

  • Replace the per-role roleMapper.hasRole() lookup with RoleUtils.getDeepRoleMappings().
  • Filter the resolved mappings using RoleUtils.isRealmRole().
  • Add regression coverage for direct composite roles and group-inherited roles.

Closes #51531

@PRAHLAD09-dev
PRAHLAD09-dev requested a review from a team as a code owner August 9, 2026 06:35
Copilot AI balanced review requested due to automatic review settings August 9, 2026 06:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Optimizes effective realm-role resolution by computing deep mappings once.

Changes:

  • Uses RoleUtils.getDeepRoleMappings().
  • Filters mappings to realm roles.
  • Adds user and group-inheritance regression tests.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
RoleMapperResource.java Optimizes effective realm-role lookup.
CompositeRealmRoleMappingsTest.java Adds endpoint regression coverage.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +216 to +217
return RoleUtils.getDeepRoleMappings(roleMapper).stream()
.filter(r -> RoleUtils.isRealmRole(r, realm))

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — confirmed GroupAdapter.hasRole() walks the parent chain but RoleUtils.getDeepRoleMappings() doesn't for GroupModel. Fixed by walking the parent chain explicitly in getCompositeRealmRoleMappings() when roleMapper is a GroupModel, then expanding composites via RoleUtils.expandCompositeRoles(). Pushed.

Comment on lines +137 to +139
try (Response r = realm.users().create(UserBuilder.create().username("USER_4").build())) {
user4Id = ApiUtil.getCreatedId(r);
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, missed that fresh users get default-roles-{realm} (which composites in offline_access/uma_authorization). Added cleanup in @testsetup to strip it from all test users before assigning the roles under test, so the exact-size assertions hold. Pushed.

Comment on lines +208 to +209
@Test
public void testNoClientRoleLeaksIntoRealmResults() {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point, the test wasn't actually exercising the filter. Added a real client + client role assigned to USER_1 in the fixture so testNoClientRoleLeaksIntoRealmResults() now fails if the realm-role filter is removed. Pushed.

Copilot AI review requested due to automatic review settings August 9, 2026 10:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java:223

  • The new group-inheritance test invokes the user endpoint, so roleMapper is a UserModel and this GroupModel branch is never exercised. Add coverage through groups().group(childGroupId).roles().realmLevel().listEffective() to verify that a child group's result still includes roles inherited from its parent.
        if (roleMapper instanceof GroupModel group) {
            // GroupModel.hasRole() (the semantics this endpoint previously relied on)
            // walks the parent-group chain, but RoleUtils.getDeepRoleMappings() only
            // expands a group's own direct mappings. Walk the chain explicitly here
            // to preserve parent-group role inheritance for the group endpoint.

tests/base/src/test/java/org/keycloak/tests/admin/user/CompositeRealmRoleMappingsTest.java:63

  • These functional assertions would also pass with the previous per-realm-role hasRole() implementation, so they do not actually guard the #51531 scalability regression. Add a query/invocation-count test proving that adding unrelated realm roles does not increase endpoint work (for example, by asserting this path does not call realm.getRolesStream() or roleMapper.hasRole()).
 * Regression coverage for #51531: the realm variant previously iterated
 * realm.getRolesStream().filter(roleMapper::hasRole), which is O(C x M x D)
 * and was especially expensive for group-inherited roles. The fix mirrors
 * the client-role fix from #47157 by using RoleUtils.getDeepRoleMappings().

Signed-off-by: Prahlad Bhakat <prahladbhakat05@gmail.com>
…est fixtures per review

Signed-off-by: Prahlad Bhakat <prahladbhakat05@gmail.com>
@PRAHLAD09-dev
PRAHLAD09-dev force-pushed the fix/GH-51531-composite-realm-role-mappings branch from 59f0e81 to d1cd163 Compare August 9, 2026 10:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Composite realm role mappings endpoint does not scale with the number of realm roles — the #47157 fix was applied only to the client variant

2 participants