impersonate
This commit is contained in:
parent
3ee86fedc7
commit
f1807aead4
4 changed files with 102 additions and 11 deletions
|
@ -294,6 +294,10 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage
|
|||
if (identity == null) {
|
||||
throw new RuntimeException("Identity of admin is not set for permission query");
|
||||
}
|
||||
return evaluatePermission(resource, scope, resourceServer, identity);
|
||||
}
|
||||
|
||||
public boolean evaluatePermission(Resource resource, Scope scope, ResourceServer resourceServer, Identity identity) {
|
||||
RealmModel oldRealm = session.getContext().getRealm();
|
||||
try {
|
||||
session.getContext().setRealm(realm);
|
||||
|
|
|
@ -43,5 +43,7 @@ public interface UserPermissionManagement {
|
|||
|
||||
Policy mapRolesPermission();
|
||||
|
||||
Policy impersonatePermission();
|
||||
Policy adminImpersonatingPermission();
|
||||
|
||||
Policy userImpersonatedPermission();
|
||||
}
|
||||
|
|
|
@ -18,12 +18,13 @@ package org.keycloak.services.resources.admin.permissions;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.common.UserModelIdentity;
|
||||
import org.keycloak.authorization.identity.Identity;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.model.Scope;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.ImpersonationConstants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -47,9 +48,11 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
private static final Logger logger = Logger.getLogger(UserPermissions.class);
|
||||
public static final String MAP_ROLES_SCOPE="map-roles";
|
||||
public static final String IMPERSONATE_SCOPE="impersonate";
|
||||
public static final String USER_IMPERSONATED_SCOPE="user-impersonated";
|
||||
public static final String MANAGE_GROUP_MEMBERSHIP_SCOPE="manage-group-membership";
|
||||
public static final String MAP_ROLES_PERMISSION_USERS = "map-roles.permission.users";
|
||||
public static final String IMPERSONATE_PERMISSION_USERS = "impersonate.permission.users";
|
||||
public static final String ADMIN_IMPERSONATING_PERMISSION = "admin-impersonating.permission.users";
|
||||
public static final String USER_IMPERSONATED_PERMISSION = "user-impersonated.permission.users";
|
||||
public static final String MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS = "manage-group-membership.permission.users";
|
||||
public static final String MANAGE_PERMISSION_USERS = "manage.permission.users";
|
||||
public static final String VIEW_PERMISSION_USERS = "view.permission.users";
|
||||
|
@ -75,6 +78,7 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
Scope viewScope = root.realmViewScope();
|
||||
Scope mapRolesScope = root.initializeRealmScope(MAP_ROLES_SCOPE);
|
||||
Scope impersonateScope = root.initializeRealmScope(IMPERSONATE_SCOPE);
|
||||
Scope userImpersonatedScope = root.initializeRealmScope(USER_IMPERSONATED_SCOPE);
|
||||
Scope manageGroupMembershipScope = root.initializeRealmScope(MANAGE_GROUP_MEMBERSHIP_SCOPE);
|
||||
|
||||
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||
|
@ -86,6 +90,7 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
scopeset.add(mapRolesScope);
|
||||
scopeset.add(impersonateScope);
|
||||
scopeset.add(manageGroupMembershipScope);
|
||||
scopeset.add(userImpersonatedScope);
|
||||
usersResource.updateScopes(scopeset);
|
||||
}
|
||||
Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
|
||||
|
@ -104,9 +109,13 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
if (membershipPermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, usersResource, manageGroupMembershipScope);
|
||||
}
|
||||
Policy impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(IMPERSONATE_PERMISSION_USERS, server.getId());
|
||||
Policy impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
|
||||
if (impersonatePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, IMPERSONATE_PERMISSION_USERS, usersResource, impersonateScope);
|
||||
Helper.addEmptyScopePermission(authz, server, ADMIN_IMPERSONATING_PERMISSION, usersResource, impersonateScope);
|
||||
}
|
||||
impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
|
||||
if (impersonatePermission == null) {
|
||||
Helper.addEmptyScopePermission(authz, server, USER_IMPERSONATED_PERMISSION, usersResource, userImpersonatedScope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,7 +126,7 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission().getId());
|
||||
scopes.put(MAP_ROLES_SCOPE, mapRolesPermission().getId());
|
||||
scopes.put(MANAGE_GROUP_MEMBERSHIP_SCOPE, manageGroupMembershipPermission().getId());
|
||||
scopes.put(IMPERSONATE_SCOPE, impersonatePermission().getId());
|
||||
scopes.put(IMPERSONATE_SCOPE, adminImpersonatingPermission().getId());
|
||||
return scopes;
|
||||
}
|
||||
|
||||
|
@ -166,7 +175,12 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
}
|
||||
policy = impersonatePermission();
|
||||
policy = adminImpersonatingPermission();
|
||||
if (policy == null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
}
|
||||
policy = userImpersonatedPermission();
|
||||
if (policy == null) {
|
||||
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
|
||||
|
@ -215,9 +229,15 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
|
||||
|
||||
@Override
|
||||
public Policy impersonatePermission() {
|
||||
public Policy adminImpersonatingPermission() {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(IMPERSONATE_PERMISSION_USERS, server.getId());
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy userImpersonatedPermission() {
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
return authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
|
||||
}
|
||||
|
||||
|
||||
|
@ -451,7 +471,34 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
|
||||
@Override
|
||||
public boolean canImpersonate(UserModel user) {
|
||||
return canImpersonate();
|
||||
if (!canImpersonate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Identity userIdentity = new UserModelIdentity(root.realm, user);
|
||||
if (!root.isAdminSameRealm()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ResourceServer server = root.realmResourceServer();
|
||||
if (server == null) return true;
|
||||
|
||||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||
if (resource == null) return true;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
|
||||
if (policy == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||
// if no policies attached to permission then just do default behavior
|
||||
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Scope scope = root.realmScope(USER_IMPERSONATED_SCOPE);
|
||||
return root.evaluatePermission(resource, scope, server, userIdentity);
|
||||
|
||||
}
|
||||
|
||||
|
@ -469,7 +516,7 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
|||
Resource resource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
|
||||
if (resource == null) return false;
|
||||
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(IMPERSONATE_PERMISSION_USERS, server.getId());
|
||||
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
|
||||
if (policy == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.authorization.model.Resource;
|
|||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
|
@ -160,6 +161,19 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
|
|||
{
|
||||
permissions.clients().setPermissionsEnabled(client1, true);
|
||||
}
|
||||
// setup Users impersonate policy
|
||||
{
|
||||
ClientModel realmManagementClient = realm.getClientByClientId("realm-management");
|
||||
RoleModel adminRole = realmManagementClient.getRole(AdminRoles.REALM_ADMIN);
|
||||
permissions.users().setPermissionsEnabled(true);
|
||||
ResourceServer server = permissions.realmResourceServer();
|
||||
Policy adminPolicy = permissions.roles().rolePolicy(server, adminRole);
|
||||
adminPolicy.setLogic(Logic.NEGATIVE);
|
||||
Policy permission = permissions.users().userImpersonatedPermission();
|
||||
permission.addAssociatedPolicy(adminPolicy);
|
||||
permission.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -183,6 +197,11 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
|
|||
session.userCredentialManager().updateCredential(realm, nomapAdmin, UserCredentialModel.password("password"));
|
||||
nomapAdmin.grantRole(adminRole);
|
||||
|
||||
UserModel anotherAdmin = session.users().addUser(realm, "anotherAdmin");
|
||||
anotherAdmin.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, anotherAdmin, UserCredentialModel.password("password"));
|
||||
anotherAdmin.grantRole(adminRole);
|
||||
|
||||
UserModel authorizedUser = session.users().addUser(realm, "authorized");
|
||||
authorizedUser.setEnabled(true);
|
||||
session.userCredentialManager().updateCredential(realm, authorizedUser, UserCredentialModel.password("password"));
|
||||
|
@ -372,6 +391,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
|
|||
testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
|
||||
|
||||
UserRepresentation user1 = adminClient.realm(TEST).users().search("user1").get(0);
|
||||
UserRepresentation anotherAdmin = adminClient.realm(TEST).users().search("anotherAdmin").get(0);
|
||||
UserRepresentation groupMember = adminClient.realm(TEST).users().search("groupMember").get(0);
|
||||
RoleRepresentation realmRole = adminClient.realm(TEST).roles().get("realm-role").toRepresentation();
|
||||
List<RoleRepresentation> realmRoleSet = new LinkedList<>();
|
||||
|
@ -384,6 +404,24 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
|
|||
List<RoleRepresentation> clientRoleSet = new LinkedList<>();
|
||||
clientRoleSet.add(clientRole);
|
||||
|
||||
// test illegal impersonation
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "nomap-admin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
realmClient.realm(TEST).users().get(user1.getId()).impersonate();
|
||||
realmClient.close(); // just in case of cookie settings
|
||||
realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
TEST, "nomap-admin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
|
||||
try {
|
||||
realmClient.realm(TEST).users().get(anotherAdmin.getId()).impersonate();
|
||||
Assert.fail("should fail with forbidden exception");
|
||||
} catch (ClientErrorException e) {
|
||||
Assert.assertEquals(e.getResponse().getStatus(), 403);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
|
||||
|
|
Loading…
Reference in a new issue