Add impersonate-members scope to group resource type

Closes #38566

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2025-04-07 11:56:27 -03:00 committed by GitHub
parent e730d8bec5
commit 87430fc181
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 188 additions and 92 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -7,22 +7,22 @@ Different from the regular Role-Based Access Control Mechanism provided through
(<<_master_realm_access_control, Master realm access control>>), this feature provides a more fine-grained control over
how realm resources can be accessed and managed based on a well-defined set of operations that can be performed on them.
By relying on a Policy-Based Access Control, server administrators can define permissions to realm resources such as users,
groups, and clients, using different policy types, or access control methods, so that a realm administrator is limited to
By relying on a Policy-Based Access Control, server administrators can define permissions to realm resources such as users,
groups, and clients, using different policy types, or access control methods, so that a realm administrator is limited to
access a subset of realm resources and their operations.
Here are some key points to understand about fine-grained admin permissions:
* Fine grained admin permissions are only available within <<_per_realm_admin_permissions, dedicated admin consoles>> or
* Fine grained admin permissions are only available within <<_per_realm_admin_permissions, dedicated admin consoles>> or
realm-specific admin APIs and administrators defined within those realms. You cannot define cross-realm fine grained permissions.
* Fine grained admin permissions are used to grant additional permissions. You cannot override the default behavior of the
* Fine grained admin permissions are used to grant additional permissions. You cannot override the default behavior of the
built-in admin roles.
* Fine-grained admin permissions V2 do not support federated resources. This restriction is a known limitation under consideration
* Fine-grained admin permissions V2 do not support federated resources. This restriction is a known limitation under consideration
for future improvement.
[NOTE]
====
To maximize the effectiveness of fine-grained admin permissions while minimizing the impact of broad admin roles,
To maximize the effectiveness of fine-grained admin permissions while minimizing the impact of broad admin roles,
it is recommended to assign the *query-clients*, *query-groups*, and *query-users* roles (along with roles required
for realm management) to allow querying. All other administrative access could be managed through fine-grained permissions.
See <<_realm_access_control, Accessing a Realm Admin Console as a Realm Administrator>> for more information.
@ -30,26 +30,26 @@ See <<_realm_access_control, Accessing a Realm Admin Console as a Realm Administ
==== Understanding the Realm Resource Types
In a realm, you can manage different types of resources such as users, groups, clients, client scopes, roles, and so on.
As a realm administrator, you are constantly managing these resources to manage your identities and how they authenticate
In a realm, you can manage different types of resources such as users, groups, clients, client scopes, roles, and so on.
As a realm administrator, you are constantly managing these resources to manage your identities and how they authenticate
and authorize to a realm and your applications.
Each realm resource supports a well-defined set of management operations, or actions, that can be performed on them,
such as view, manage, and resource-specific operations such as view-members if you take groups as an example.
This feature provides the necessary mechanisms to enforce access to a well-defined set of realm resources, limited to:
This feature provides the necessary mechanisms to enforce access controls when managing realm resources, limited to:
* Users
* Groups
* Clients
* Roles
When managing permissions for a specific realm resource type, you can choose to do it for all resources of a given resource
type, such as users, or for a specific realm resource, such as a specific user or set of users in the realm.
It allows you to manage permissions for all resources of a given resource type, such as all users in a realm, or
for a specific realm resource, such as a specific user or set of users in the realm.
Each realm resource supports a well-defined set of management operations, or actions, that can be performed on them,
such as view, manage, and resource-specific operations such as view-members if you take groups as an example.
===== Users Resource Type
The *Users* realm resource type represents the users in a realm. You can manage permissions for users based on the following
The *Users* realm resource type represents the users in a realm. You can manage permissions for users based on the following
set of management operations:
[cols="30%,70%"]
@ -65,17 +65,16 @@ set of management operations:
[NOTE]
====
- An administrator must have explicit permission assigned for each operation to perform the corresponding action. For example,
assigning only *manage* without *view* will prevent the user from being visible.
- The *view* operation also considers group-related permissions, specifically *view-members* for viewing group members.
The evaluation takes permissions for specific resources (specific user permissions and specific group permissions) first.
- The *view* operation also considers group-related permissions, specifically *view-members* for viewing group members.
The evaluation takes permissions for specific resources (specific user permissions and specific group permissions) first.
See <<_resolving-conflicting-permissions, Resolving Conflicting Permissions>> for more information.
- Similarly, the *manage* operation takes *manage-members* into account when managing group members.
- The *manage* operation takes *manage-members* into account when managing group members.
- The *impersonate* operation takes *impersonate-members* into account when managing group members.
====
===== Groups Resource Type
The *Groups* realm resource type represents the groups in a realm. You can manage permissions for groups based on the following
The *Groups* realm resource type represents the groups in a realm. You can manage permissions for groups based on the following
set of management operations:
[cols="30%,70%"]
@ -84,23 +83,22 @@ set of management operations:
| *view* | Defines if a realm administrator can view groups.
| *manage* | Defines if a realm administrator can manage groups.
| *view-members* | Defines if a realm administrator can view group members.
| *view-members* | Defines if a realm administrator can view group members.
| *manage-members* | Defines if a realm administrator can manage group members.
| *impersonate-members* | Defines if a realm administrator can impersonate group members.
| *manage-membership* | Defines if a realm administrator can add or remove members from groups.
|===
[NOTE]
====
- An administrator must have explicit permission assigned for each operation to perform the corresponding action. For example,
assigning only *manage* without *view* will prevent the group from being visible.
- The *view-members* and *manage-members* operations apply to the entire group hierarchy. In other words, if an administrator has
permission to manage members of a group, they can also manage members of all its subgroups. This can be prevented by
- The *view-members* and *manage-members* operations apply to the entire group hierarchy. In other words, if an administrator has
permission to manage members of a group, they can also manage members of all its subgroups. This can be prevented by
explicitly denying permission for specific subgroups.
====
===== Clients Resource Type
The *Clients* realm resource type represents the clients in a realm. You can manage permissions for clients based on the following
The *Clients* realm resource type represents the clients in a realm. You can manage permissions for clients based on the following
set of management operations:
[cols="30%,70%"]
@ -110,17 +108,15 @@ set of management operations:
| *view* | Defines if a realm administrator can view clients.
| *manage* | Defines if a realm administrator can manage clients.
| *map-roles* | Defines if a realm administrator can assign any role defined by a client (or multiple clients) to a user.
| *map-roles-composite* | Defines if a realm administrator can assign any role defined by a client (or multiple clients) as a composite to
| *map-roles-composite* | Defines if a realm administrator can assign any role defined by a client (or multiple clients) as a composite to
another role.
| *map-roles-client-scope* | Defines if a realm administrator can assign any role defined by a client (or multiple clients) to the scope of
| *map-roles-client-scope* | Defines if a realm administrator can assign any role defined by a client (or multiple clients) to the scope of
another client.
|===
[NOTE]
====
- An administrator must have explicit permission assigned for each operation to perform the corresponding action. For example,
assigning only *manage* without *view* will prevent the client from being visible.
- The *map-roles* operation does not grant the ability to manage users or assign roles arbitrarily; the administrator must also
- The *map-roles* operation does not grant the ability to manage users or assign roles arbitrarily; the administrator must also
have user role mapping permissions.
====
@ -133,15 +129,15 @@ The *Roles* realm resource type represents the roles in a realm. You can manage
| *Operation* | *Description*
| *map-role* | Defines if a realm administrator can assign a role (or multiple roles) to a user.
| *map-role-composite* | Defines if a realm administrator can assign a role (or multiple roles) as a composite to another role.
| *map-role-composite* | Defines if a realm administrator can assign a role (or multiple roles) as a composite to another role.
| *map-role-client-scope* | Defines if a realm administrator can apply a role (or multiple roles) to an another clients scope.
|===
[NOTE]
====
* The *map-role* operation does not grant the ability to manage users or assign roles arbitrarily; the administrator must also have
user role mapping permissions.
* When mapping client roles, if an administrator has permission to *map-roles*, *map-roles-composite*, or *map-roles-client-scope* for
* The *map-role* operation does not grant the ability to manage users or assign roles arbitrarily; the administrator must also have
user role mapping permissions.
* When mapping client roles, if an administrator has permission to *map-roles*, *map-roles-composite*, or *map-roles-client-scope* for
a client, permissions for specific roles within that client are not evaluated.
====
@ -161,28 +157,67 @@ image:images/fine-grain-permissions-tab.png[Fine grain permissions tab]
==== Managing Permissions
The *Permissions* tab provides an overview of all active permissions within a realm. From here, administrators can create,
The *Permissions* tab provides an overview of all active permissions within a realm. From here, administrators can create,
update, delete, or search for permissions.
The *Policies* tab allows administrators to define conditions using different access control methods (*policy type*) to determine whether
a permission should be granted to an administrator attempting to access a specific resource performing some operation. It also
supports basic searching capability, based on policy `name` and its `type`. Fine-grained admin permissions were implemented on top of
Authorization services. Read more about link:{authorizationguide_link}#_policy_overview[Managing policies] in the Authorization services
documentation.
To create a permission, click on the `Create permission` button and select the resource type you want to protect.
image:images/select-resource-type.png[Selecting a resource type to protect]
Once you select the resource type, you can now define how access should be enforced for a set of one or more resources of the selected type:
image:images/create-permission.png[Creating a permission]
When managing a permission you can define the following settings:
* *Name*: A unique name for the permission. The name should also not conflict with any policy name
* *Description*: An optional description to better describe what the permission is about
* *Authorization scopes*: A set of one or more scopes representing the operations you want to protect for the selected resource type.
An administrator must have explicit permission assigned for each operation to perform the corresponding action. For example,
assigning only *manage* without *view* will prevent the user from being visible.
* *Enforce access to*: Defines if the permission should enforce access to all resources of the selected type or to specific resources in a realm.
* *Policies*: Defines a set of one or more policies that should be evaluated to grant or deny access to the selected resource(s).
==== Managing Policies
The *Policies* tab allows administrators to define conditions using different access control methods to determine whether
a permission should be granted to an administrator attempting to perform operations on a realm resource. When managing permissions,
you must associate at least a single policy to grant or deny access to a realm resource.
Policies are basically conditions that will evaluate to either a `GRANT` or a `DENY`. Their outcome will decide whether
a permission should be granted or denied. A permission is only granted if all its associated policies evaluate to a `GRANT`.
Otherwise, the permission is denied and a realm administrator will not be able to access the protected resource.
{project_name} provides a set of built-in policies that you can choose from:
image:images/select-policy-type.png[Selecting a policy type]
For more details about each policy type, take a look at link:{authorizationguide_link}#_policy_overview[Managing policies].
==== Evaluating Permissions
The *Evaluation* tab provides a testing environment where administrators can verify that permissions are correctly enforcing access
control as expected.
The administrator could see what permissions were involved in evaluation and what the outcome is by specifying a `username` of a user they
want to verify, *Resource type*, resource (usermane of a *User* in this case) and optionally an authorization scope.
image:images/fine-grain-evaluation.png[Fine grained permissions evaluation tab]
In the example above it is visible that the user `myadmin`, can *manage* user `user-1`. There is also information what permissions were involved
in the evaluation, what outcome it had and what scopes were granted or denied.
===== Defining permissions for viewing realm resources
IMPORTANT: When listing or searching for realm resources (such as clients, groups, or users) via the Admin Console or Admin API, {project_name}
evaluates permissions that contain the *view* scope for the specific resource. For this operation, only role, user, and group policy types are
considered, while other policy types are ignored due to partial evaluation performed at the database level. Because of this, only policies that
reference the resource directly—whether through user association, group membership, or role assignment—are found and permissions assiciated with
those are used for evaluation.
When listing or searching for realm resources (such as clients, groups, or users) via the Admin Console or Admin API, {project_name}
evaluates permissions that contain the *view* scope for the specific resource. For this operation, only role, user, and group policy types are
considered, while other policy types are ignored due to partial evaluation performed at the database level. Because of this, only policies that
reference the resource directly—whether through user association, group membership, or role assignment—are found and permissions associated with
those are used to filter the resources.
When checking whether an admin can view a specific user, all policy types are taken into account.
The partial evaluation mechanism helps identify and load relevant permissions from the database by using the resource
identifiers that the realm administrator has permission to "view". These identifiers are then applied in the subsequent
database query to fetch the actual stream of resources. Partial evaluation is supported for non-federated resources, which
The partial evaluation mechanism helps identify and load relevant permissions from the database by using the resource
identifiers that the realm administrator has permission to "view". These identifiers are then applied in the subsequent
database query to fetch the actual stream of resources. Partial evaluation is not supported for federated resources, which
is a limitation of the current implementation.
===== Searching Permissions
@ -193,37 +228,24 @@ The Admin Console provides several ways to search for permissions, supporting th
* Search for permissions of a specific resource type, such as *Users*
* Search for permissions of a specific resource type that apply to a particular resource (such as *Users* resource type for user `myadmin`).
* Search for permissions of a specific resource type with a given scope (such as *Users* resource type permissions with the *manage* scope).
* Search for permissions of a specific resource type that apply to a particular resource and have a specific scope (such as *Users* resource
* Search for permissions of a specific resource type that apply to a particular resource and have a specific scope (such as *Users* resource
type permissions with the *manage* scope for user `myadmin`).
image:images/fine-grain-search.png[Fine grained permissions search]
==== Evaluating Permissions
The *Evaluation* tab provides a testing environment where administrators can verify that permissions are correctly enforcing access
control as expected.
The administrator could see what permissions were involved in evaluation and what the outcome is by specifying a `username` of a user they
want to verify, *Resource type*, resource (usermane of a *User* in this case) and optionally an authorization scope.
image:images/fine-grain-evaluation.png[Fine grained permissions evaluation tab]
In the example above it is visible that the user `myadmin`, can *manage* user `user-1`. There is also information what permissions were involved
in the evaluation, what outcome it had and what scopes were granted or denied.
[[_resolving-conflicting-permissions]]
===== Resolving conflicting permissions
Permissions can have multiple policies associated with them. As the authorization model evolves, it is common for some policies within a permission or
Permissions can have multiple policies associated with them. As the authorization model evolves, it is common for some policies within a permission or
even different permissions related to a specific resource to conflict.
The evaluation outcome will be "denied" whenever any permission is evaluated to "DENY." If there are multiple permissions related to the same resource,
The evaluation outcome will be "denied" whenever any permission is evaluated to "DENY." If there are multiple permissions related to the same resource,
all of them must grant access in order for the outcome to be "granted."
IMPORTANT: Fine-grained admin permissions allow you to set up permissions for individual resources or for the resource type itself (such as all users,
all groups, and so on.). If a permission or permissions related to a specific resource exist, the "all-resource" permission is *NOT* taken into account
during evaluation. If no specific permission exists, the fallback is to the "all-resource" permission. This approach helps address scenarios like
allowing members of the `realm-admins` group to manage members of realm groups, but preventing them from managing members of the `realm-admins` group
IMPORTANT: Fine-grained admin permissions allow you to set up permissions for individual resources or for the resource type itself (such as all users,
all groups, and so on.). If a permission or permissions related to a specific resource exist, the "all-resource" permission is *NOT* taken into account
during evaluation. If no specific permission exists, the fallback is to the "all-resource" permission. This approach helps address scenarios like
allowing members of the `realm-admins` group to manage members of realm groups, but preventing them from managing members of the `realm-admins` group
themselves.
*View and Manage users and group members*
@ -232,7 +254,7 @@ When evaluating *view* or *manage* permissions for users the group *view-members
The evaluation follows:
* Specific user/group permissions take precedence over broader all-resource permissions.
* If multiple permissions apply to a given user or group (such as multiple user-specific permissions, or a permission covering a set of
* If multiple permissions apply to a given user or group (such as multiple user-specific permissions, or a permission covering a set of
users/groups where the user is member of), all of them are evaluated, and all of them must grant access for the outcome to be GRANTED.
* If no user/group-specific permissions exist, the evaluation falls back to all-resource permissions ("all-users", "all-groups").
* When both all-users and all-groups permissions exist, both must grant access for the outcome to be GRANTED.
@ -241,35 +263,35 @@ The evaluation follows:
[[_realm_access_control]]
==== Accessing a Realm Admin Console as a Realm Administrator
Realm administrators can access a dedicated realm-specific Admin Console, which allows them to manage resources within their assigned realm.
Realm administrators can access a dedicated realm-specific Admin Console, which allows them to manage resources within their assigned realm.
This is separate from the main Keycloak Admin Console, which is typically used by server administrators.
For more details on dedicated realm admin consoles and available roles, refer to: <<_per_realm_admin_permissions, Dedicated admin consoles>>.
To access the Admin Console, a realm administrator must have at least one of the following roles assigned, depending on the resources they
To access the Admin Console, a realm administrator must have at least one of the following roles assigned, depending on the resources they
need to administer:
- *query-users* Required to query realm users.
- *query-groups* Required to query realm groups.
- *query-clients* Required to query realm clients.
- *query-users* Required to query realm users.
- *query-groups* Required to query realm groups.
- *query-clients* Required to query realm clients.
If an administrator is responsible for multiple resource types (such as both users and groups), they must have all corresponding "query-*"
If an administrator is responsible for multiple resource types (such as both users and groups), they must have all corresponding "query-*"
roles assigned.
These roles enable basic access to query resources but do not grant permission to view or modify them. To configure more fine-grained
These roles enable basic access to query resources but do not grant permission to view or modify them. To configure more fine-grained
administrative access, additional permissions must be granted using fine-grained admin permissions.
===== Granting Administrative Roles to a Realm Administrator
A realm administrators access must be configured by someone with permission to assign administrative roles. At a minimum, the administrator
must have:
A realm administrators access must be configured by someone with permission to assign administrative roles. At a minimum, the administrator
must have:
- The appropriate "query-*" roles, depending on the resource types they need to administer.
Beyond these foundational roles, *fine-grained admin permissions* can be used to define specific administrative capabilities. While fine-grained
Beyond these foundational roles, *fine-grained admin permissions* can be used to define specific administrative capabilities. While fine-grained
permissions allow for more granular control over access, they cannot override the default behavior of built-in admin roles.
This means that if an respective admin role is assigned to a realm administrator, permission evaluation will be bypassed, and access will be
granted.
This means that if an respective admin role is assigned to a realm administrator, permission evaluation will be bypassed, and access will be
granted.
====== Roles and Permission relationship
@ -280,14 +302,14 @@ If a realm admin is assigned one or more admin roles, it prevents the permission
|===
| *Admin Role* | *Description*
| *query-users* | A realm administrator can see the *Users* section in Admin Console and can search for users in the realm.
| *query-users* | A realm administrator can see the *Users* section in Admin Console and can search for users in the realm.
It does not grant the ability to *view* users.
| *query-groups* | A realm administrator can see the *Groups* section in Admin Console and can search for groups in the realm.
| *query-groups* | A realm administrator can see the *Groups* section in Admin Console and can search for groups in the realm.
It does not grant the ability to *view* groups.
| *query-clients* | A realm administrator can see the *Clients* section in Admin Console and can search for clients in the realm.
| *query-clients* | A realm administrator can see the *Clients* section in Admin Console and can search for clients in the realm.
It does not grant the ability to *view* clients.
| *view-users* | A realm administrator can *view* all users and groups in the realm.
| *manage-users* | A realm administrator can *view*, *map-roles*, *manage-group-membership* and *manage* all users in the realm,
| *manage-users* | A realm administrator can *view*, *map-roles*, *manage-group-membership* and *manage* all users in the realm,
as well as *view*, *manage-membership* and *manage* groups in the realm.
| *impersonation* | A realm administrator can *impersonate* all users in the realm.
| *view-clients* | A realm administrator can *view* all clients in the realm.
@ -296,7 +318,7 @@ If a realm admin is assigned one or more admin roles, it prevents the permission
==== Understanding some common use cases
Consider a situation where an administrator wants to allow a group of administrators to manage all users in the realm except those that
Consider a situation where an administrator wants to allow a group of administrators to manage all users in the realm except those that
belong to the administrators group. This example includes a `test` realm and a `test-admins` group.
===== Allow manage users by group of administrators
@ -356,3 +378,8 @@ Let's exlude the members of the group itself, so that `test-admins` cannot manag
- Assign a "Group Policy" targeting `test-admins` to it.
- Create another "Group Permission" with the *view-members* and *manage-members* scopes for specific group, select all subgroups of the `mygroup`.
- Create negative "Group Policy" for `test-admins` and assign it to the "subgroups" permission.
===== Allow impersonating members of a specific group
- Create a "Group Permission" with the *impersonate-members* for specific group `mygroup`.
- Assign a "Group Policy" targeting `mygroup-helpdesk` to it.

View File

@ -122,6 +122,7 @@ Due to fundamental changes in the permission model, **automatic migration from V
* Permission model changes:
** The *user-impersonated* user permission has been _removed_.
** The *configure* client permission has been _removed_. With the introduction of explicit operation scoping in V2, the distinction between manage and configure became ambiguous.
** The *user-impersonated* user permission has been _removed_. Instead, you can use the `impersonate-members` scope of the `Groups` resource type to allow or deny impersonation of group members.
* Flexible resource scoping:
** Unlike V1, where permissions were granted either to *a single resource* (for clients, groups, and roles) or *all resources* (for users), V2 introduces greater flexibility.
** Administrators can now define permissions for:

View File

@ -83,6 +83,7 @@ public class AdminPermissionsSchema extends AuthorizationSchema {
public static final String MANAGE_MEMBERSHIP = "manage-membership";
public static final String MANAGE_MEMBERS = "manage-members";
public static final String VIEW_MEMBERS = "view-members";
public static final String IMPERSONATE_MEMBERS = "impersonate-members";
// role specific scopes
public static final String MAP_ROLE = "map-role";
@ -95,9 +96,9 @@ public class AdminPermissionsSchema extends AuthorizationSchema {
public static final String MANAGE_GROUP_MEMBERSHIP = "manage-group-membership";
public static final ResourceType CLIENTS = new ResourceType(CLIENTS_RESOURCE_TYPE, Set.of(MANAGE, MAP_ROLES, MAP_ROLES_CLIENT_SCOPE, MAP_ROLES_COMPOSITE, VIEW));
public static final ResourceType GROUPS = new ResourceType(GROUPS_RESOURCE_TYPE, Set.of(MANAGE, VIEW, MANAGE_MEMBERSHIP, MANAGE_MEMBERS, VIEW_MEMBERS));
public static final ResourceType GROUPS = new ResourceType(GROUPS_RESOURCE_TYPE, Set.of(MANAGE, VIEW, MANAGE_MEMBERSHIP, MANAGE_MEMBERS, VIEW_MEMBERS, IMPERSONATE_MEMBERS));
public static final ResourceType ROLES = new ResourceType(ROLES_RESOURCE_TYPE, Set.of(MAP_ROLE, MAP_ROLE_CLIENT_SCOPE, MAP_ROLE_COMPOSITE));
public static final ResourceType USERS = new ResourceType(USERS_RESOURCE_TYPE, Set.of(MANAGE, VIEW, IMPERSONATE, MAP_ROLES, MANAGE_GROUP_MEMBERSHIP), Map.of(VIEW, Set.of(VIEW_MEMBERS), MANAGE, Set.of(MANAGE_MEMBERS)), GROUPS.getType());
public static final ResourceType USERS = new ResourceType(USERS_RESOURCE_TYPE, Set.of(MANAGE, VIEW, IMPERSONATE, MAP_ROLES, MANAGE_GROUP_MEMBERSHIP), Map.of(VIEW, Set.of(VIEW_MEMBERS), MANAGE, Set.of(MANAGE_MEMBERS), IMPERSONATE, Set.of(IMPERSONATE_MEMBERS)), GROUPS.getType());
public static final AdminPermissionsSchema SCHEMA = new AdminPermissionsSchema();
private final PartialEvaluator partialEvaluator = new PartialEvaluator();

View File

@ -25,10 +25,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.keycloak.authorization.AdminPermissionsSchema.GROUPS_RESOURCE_TYPE;
import static org.keycloak.authorization.AdminPermissionsSchema.IMPERSONATE;
import static org.keycloak.authorization.AdminPermissionsSchema.IMPERSONATE_MEMBERS;
import static org.keycloak.authorization.AdminPermissionsSchema.MANAGE;
import static org.keycloak.authorization.AdminPermissionsSchema.MANAGE_GROUP_MEMBERSHIP;
import static org.keycloak.authorization.AdminPermissionsSchema.MANAGE_MEMBERS;
import static org.keycloak.authorization.AdminPermissionsSchema.MANAGE_MEMBERSHIP;
import static org.keycloak.authorization.AdminPermissionsSchema.USERS_RESOURCE_TYPE;
import static org.keycloak.authorization.AdminPermissionsSchema.VIEW;
import static org.keycloak.authorization.AdminPermissionsSchema.VIEW_MEMBERS;
@ -64,6 +67,9 @@ public class GroupResourceTypeEvaluationTest extends AbstractPermissionTest {
@InjectUser(ref = "alice")
ManagedUser userAlice;
@InjectUser(ref = "jdoe")
ManagedUser userJdoe;
@InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, client = "myclient", user = "myadmin")
Keycloak realmAdminClient;
@ -380,6 +386,67 @@ public class GroupResourceTypeEvaluationTest extends AbstractPermissionTest {
} catch (ForbiddenException expected) {}
}
@Test
public void testImpersonateMembers() {
UserRepresentation myadmin = realm.admin().users().search("myadmin").get(0);
UserPolicyRepresentation allowMyAdminPermission = createUserPolicy(realm, client, "Only My Admin User Policy", myadmin.getId());
// my admin should not be able to manage yet
try {
realmAdminClient.realm(realm.getName()).users().get(userAlice.getId()).impersonate();
fail("Expected Exception wasn't thrown.");
} catch (Exception ex) {
assertThat(ex, instanceOf(ForbiddenException.class));
}
// allow my admin to impersonate members of the group where Alice is member of
createGroupPermission(topGroup, Set.of(IMPERSONATE_MEMBERS), allowMyAdminPermission);
realmAdminClient.realm(realm.getName()).users().get(userAlice.getId()).impersonate();
realmAdminClient.tokenManager().logout();
}
@Test
public void testImpersonateMembersFromChildGroups() {
// my admin should not be able to manage yet
try {
realmAdminClient.realm(realm.getName()).users().get(userJdoe.getId()).impersonate();
fail("Expected Exception wasn't thrown.");
} catch (Exception ex) {
assertThat(ex, instanceOf(ForbiddenException.class));
}
GroupRepresentation subGroup = new GroupRepresentation();
subGroup.setName("testSubGroup");
String testGroupId = ApiUtil.handleCreatedResponse(realm.admin().groups().add(subGroup));
subGroup.setId(testGroupId);
realm.admin().groups().group(topGroup.getId()).subGroup(subGroup).close();
realm.admin().users().get(userJdoe.getId()).joinGroup(subGroup.getId());
assertTrue(userJdoe.admin().groups().stream().map(GroupRepresentation::getName).allMatch(subGroup.getName()::equals));
// allow my admin to impersonate members of the group and its children
UserRepresentation myadmin = realm.admin().users().search("myadmin").get(0);
UserPolicyRepresentation allowMyAdminPermission = createUserPolicy(realm, client, "Only My Admin User Policy", myadmin.getId());
createGroupPermission(topGroup, Set.of(IMPERSONATE_MEMBERS), allowMyAdminPermission);
realmAdminClient.realm(realm.getName()).users().get(userJdoe.getId()).impersonate();
realmAdminClient.tokenManager().logout();
UserPolicyRepresentation denyPolicy = createUserPolicy(Logic.NEGATIVE, realm, client, "Deny My Admin User Policy", myadmin.getId());
createPermission(client, userAlice.getId(), USERS_RESOURCE_TYPE, Set.of(IMPERSONATE), denyPolicy);
try {
realmAdminClient.realm(realm.getName()).users().get(userAlice.getId()).impersonate();
fail("Expected Exception wasn't thrown.");
} catch (Exception ex) {
assertThat(ex, instanceOf(ForbiddenException.class));
} finally {
realmAdminClient.tokenManager().logout();
}
realmAdminClient.realm(realm.getName()).users().get(userJdoe.getId()).impersonate();
realmAdminClient.tokenManager().logout();
}
private ScopePermissionRepresentation createAllGroupsPermission(UserPolicyRepresentation policy, Set<String> scopes) {
return createAllPermission(client, AdminPermissionsSchema.GROUPS_RESOURCE_TYPE, policy, scopes);
}