8000 Allow extending fine-grained admin permissions for groups to their children by baptistegh · Pull Request #55019 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content

Allow extending fine-grained admin permissions for groups to their children - #55019

Open
baptistegh wants to merge 5 commits into
keycloak:mainfrom
baptistegh:43865-group-permission-extend-children
Open

baptistegh wants to merge 5 commits into
keycloak:mainfrom
baptistegh:43865-group-permission-extend-children

Conversation

@baptistegh
@baptistegh baptistegh commented Nov 10, 2026 •
Copy link
Copy Markdown

Closes #43865

Decisions

  • Opt-in flag: existing permissions keep their behavior, so there is no upgrade impact. The flag is rejected for resource types other than Groups, for permissions without specific groups, and outside admin permissions.
  • Most specific wins: a subgroup's own permission for a scope always decides that scope. Otherwise the closest extended parent decides, so a subgroup can be extended to override its parent. An inherited permission only decides the scopes not already decided lower down, even if it has more scopes.
  • Non-extended permissions are local: for group scopes (view, manage, manage-membership), a permission without the option only applies to its own groups and does not stop the inheritance. An admin can therefore be granted a subgroup while being denied its parent. This is intentional, so that only extended permissions take part in inheritance, and it is documented with an example.
  • Member scopes: for view-members and the other member scopes, a deny from any parent wins. User evaluation already applies the member scopes of every ancestor permission, extended or not, so once a member scope is inherited from an extended parent, the non-extended permissions of the other parents are evaluated too. This keeps group member checks, user checks and user search consistent, and the option stays opt-in: without an extended parent, group checks are unchanged.
  • Search: group and user search include inherited permissions, so members of subgroups now appear in user search and count when view-members is extended (partially add 8000 resses Unable to view childgroup users with view-members permission on the parent group #16966).
  • Permissions that do not reference the admin: partial evaluation only returns the permissions whose policies reference the current admin, so the other extended permissions are evaluated with the same logic, because a policy denying another admin grants access to the current one. When none of their policies can be partially evaluated (e.g. a group policy for a group the admin is not a member of, or a client policy), they neither grant nor deny access to the descendants in search, as for permissions that are not extended, rather than hiding them.
  • No cost without the option: the parent walk and the search expansion are skipped when no extended permission exists in the realm.

Known limitations

  • Search walks each extended group's subtree with one query per subgroup, so its cost grows with the hierarchy. A single recursive query is not portable through JPA across the supported databases.
  • hasExtendChildrenPermissions loads the group permissions of the realm to check for the option. A query filtering on the config key could replace it later if needed.
  • Search does not include groups granted only by a negative policy targeting someone else, or by a client policy, since partial evaluation does not support them. This already happens without the option, so I left it out of scope.
  • A permission without policies (only possible through the REST API) is not returned by findByResourceType, so search ignores it while direct checks treat it as the group's own permission. For member scopes, the members of that group can appear in user search while being denied when accessed directly. I did not change the shared named query for this edge case; it is documented with the recommendation to associate at least one policy with every permission.

Testing

GroupResourceTypeExtendChildrenTest (53 tests) covers validation, precedence, member scopes and their composition with user evaluation, group, role and aggregated policies (including negative policies targeting others), several extended permissions on the same group, moving groups in and out of an extended hierarchy, user search and count, all member scopes (manage-membership, impersonate-members, delegate-members, manage-membership-of-members), disabling or removing an extended permission, permissions for several groups, and deeper hierarchies with siblings. Two Playwright tests cover the permission form. All 327 tests in org.keycloak.tests.admin.authz.fgap pass with the embedded server.

🤖 Generated with Claude Code

…ildren

Adds an opt-in "Extend to children" option (extendChildren in the REST API) to admin permissions for specific groups. When enabled, the permission also applies to all the subgroups of the selected groups, including subgroups created later, so that the administration of a group hierarchy can be delegated.

A subgroup's own permission for a scope takes precedence over inherited ones. For group scopes, the closest ancestor with an extended permission decides. For member scopes, a deny from any extended ancestor wins, consistently with the existing member scope cascading. Inherited permissions are also taken into account when searching groups and users.

Closes keycloak#43865

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Baptiste Gouhoury <gouhoury.baptiste@gmail.com>
When evaluating users, the member scopes of any ancestor permission, extended or not, already protect the members of a group. Group checks and searches only considered extended permissions, so a deny without extend children on an intermediate group was ignored for the members of its subgroups in group member checks and user searches, while users were denied when accessed directly.

Once a member scope is inherited from an extended ancestor, the permissions of the other ancestors for that scope are now also evaluated, and an inherited grant no longer reaches the descendants of a group whose own permission denies.

Also adds tests for the composition with user evaluation and documents the inheritance through groups with a permission that is not extended and the behavior of permissions without policies.

Closes keycloak#43865

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Baptiste Gouhoury <gouhoury.baptiste@gmail.com>
@baptistegh
baptistegh marked this pull request as ready for review November 11, 2026 16:44
@baptistegh
baptistegh requested review from a team as code owners November 11, 2026 16:44
Copilot AI balanced review requested due to automatic review settings November 11, 2026 16:44
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.

🟡 Changes recommended

An unresolved authorization flaw exposes descendant members in search/count despite ancestor denies, and resource UUIDs bypass validation of invalid extendChildren settings.

2 open issues
What changed in this PR

Adds opt-in inheritance for fine-grained group admin permissions, allowing delegated administrators to manage existing and newly created subgroups without separate grants.

Changes:

  • Adds API support, persistence, and validation for extendChildren.
  • Implements inherited permission evaluation and expands group and user searches.
  • Adds an Admin Console switch, integration and UI tests, and documentation.
File Description
tests/​base/​src/​test/​java/​org/​keycloak/​tests/​admin/​authz/​fgap/​GroupResourceTypeExtendChildrenTest.java Tests inheritance, precedence, validation, and search.
server-spi-private/​src/​main/​java/​org/​keycloak/​authorization/​fgap/​evaluation/​partial/​ScopeRestrictedPolicy.java Restricts inherited permissions to applicable scopes.
server-spi-private/​src/​main/​java/​org/​keycloak/​authorization/​fgap/​evaluation/​partial/​PartialEvaluator.java Integrates inheritance into search filtering and separates cache contexts.
server-spi-private/​src/​main/​java/​org/​keycloak/​authorization/​fgap/​evaluation/​partial/​GroupResourceTypePolicyEvaluator.java Evaluates ancestor permissions for group access.
server-spi-private/​src/​main/​java/​org/​keycloak/​authorization/​fgap/​evaluation/​partial/​ExtendChildrenPartialEvaluator.java Resolves inherited search allowances and denials.
server-spi-private/​src/​main/​java/​org/​keycloak/​authorization/​fgap/​evaluation/​FGAPPolicyEvaluator.java Registers group-specific evaluation.
server-spi-private/​src/​main/​java/​org/​keycloak/​authorization/​fgap/​evaluation/​FGAPEvaluation.java Gives inherited grants precedence over all-groups permissions.
server-spi-private/​src/​main/​java/​org/​keycloak/​authorization/​fgap/​AdminPermissionsSchema.java Validates and detects extended permissions.
js/​libs/​keycloak-admin-client/​src/​defs/​policyRepresentation.ts Exposes the flag in the TypeScript client.
js/​apps/​admin-ui/​test/​permissions/​main.spec.ts Tests switch visibility and persistence.
js/​apps/​admin-ui/​src/​permissions-configuration/​resource-types/​ResourceType.tsx Adds the group permission switch.
js/​apps/​admin-ui/​maven-resources/​theme/​keycloak.v2/​admin/​messages/​messages_en.properties Adds explanatory help text.
docs/​documentation/​server_admin/​topics/​admin-console-permissions/​fine-grain-v2.adoc Documents inheritance rules and limitations.
docs/​documentation/​release_notes/​topics/​27_0_0.adoc Announces group hierarchy delegation.
core/​src/​main/​java/​org/​keycloak/​representations/​idm/​authorization/​ScopePermissionRepresentation.java Adds the nullable API property.
authz/​policy/​common/​src/​main/​java/​org/​keycloak/​authorization/​policy/​provider/​permission/​ScopePolicyProviderFactory.java Persists and serializes the flag.

Review effort: Balanced

A member scope grant extended from a group was propagated to its descendants in group and user searches even when the group itself or one of its ancestors had a permission denying that scope, while direct checks denied the members. The grant is no longer propagated in that case.

Also rejects extending permissions to children when the resource for all groups is referenced by the id of its authorization resource, which was accepted and then silently treated as not extended.

Closes keycloak#43865

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Baptiste Gouhoury <gouhoury.baptiste@gmail.com>
Copilot AI balanced review requested due to automatic review settings November 11, 2026 17:15
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.

🟡 Changes recommended

The evaluator treats missing permissions as denials even though permissions are filtered by the current admin, incorrectly hiding descendants from authorized group search results.

1 open issue
2 resolved since last review

Review effort: Balanced

The permissions returned by the policy providers during partial evaluation only include those whose policies reference the current admin. Extended permissions missing from them were considered as denying access, although a permission whose policy denies another admin grants access during direct evaluation, so their descendants were wrongly hidden from searches.

These permissions are now evaluated with the same logic as the others. When none of their policies can be partially evaluated, they neither grant nor deny access to the descendants, as for permissions that are not extended, instead of hiding them.

Also adds tests for other policy types, several extended permissions on the same group, moving groups, user counts, the remaining member scopes, disabling or removing an extended permission, permissions for several groups, and deeper hierarchies.

Closes keycloak#43865

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Baptiste Gouhoury <gouhoury.baptiste@gmail.com>
Copilot AI balanced review requested due to automatic review settings November 11, 2026 20:20
@baptistegh
Copy link
Copy Markdown
Author

While adding more tests I hit two gaps in search. They aren't caused by this PR, they also happen without extend children:

  • A permission whose policy is negative and targets someone else (for example "deny Bob") grants access when checked directly, but search only shows the group if another permission grants it too. Search only looks at permissions whose policies reference the current admin.
  • Client policies can't be evaluated in search at all, so permissions that only use them are ignored there.

In the extended case, if search can't decide a permission, it now just falls back to the other permissions instead of hiding the subgroups. I didn't try to fix the two gaps themselves since they're outside the scope of this PR, but I can open a separate issue if that helps.

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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.

🟡 Changes recommended

Critical flaws in scope filtering, deny propagation, and persisted inheritance flags cause inconsistent access decisions and can silently re-enable subtree permissions.

3 open issues
1 resolved since last review

Review effort: Balanced

return;
}

policyConsumer.accept(unclaimed.size() == policy.getScopes().size() ? policy : new ScopeRestrictedPolicy(policy, unclaimed));
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.

This comes from UserResourceTypePolicyEvaluator, which this PR doesn't change.

…pecific groups

The flag was kept when a client unaware of it updated a permission without sending it. After changing an extended permission to all groups, the flag was hidden but still stored, so changing it back to specific groups without sending the flag silently extended it to their subgroups again.

The flag is now removed once the permission no longer targets specific groups.

Closes keycloak#43865

Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Baptiste Gouhoury <gouhoury
10000
.baptiste@gmail.com>
Copilot AI balanced review requested due to automatic review settings November 12, 2026 07: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.

🔵 Needs a closer look

Human assessment is needed because the help text conflates group- and member-scope precedence, potentially misleading administrators about ancestor denies overriding closer member-scope grants.

1 open issue
2 resolved since last review

Review effort: Balanced

@baptistegh
Copy link
Copy Markdown
Author

Hi @vramik,

I answered the last Copilot thread.

This PR is ready for review on my end.

@vramik
vramik commented Nov 12, 2026
Copy link
Copy Markdown
Contributor

Thanks for the update and for marking it ready, @baptistegh. I've started going through the changes — the evolution across the 5 commits looks solid so far. I need a bit more time to finish the full review. I should get back to you by the end of next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add "extend to children" capability for group permissions in FGAP v2

3 participants

0