keycloak-uncached

impersonate

6/25/2017 12:28:37 PM

Details

diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
index ffcc0f0..2df4953 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
@@ -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);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionManagement.java
index d4184ed..d465378 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionManagement.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionManagement.java
@@ -43,5 +43,7 @@ public interface UserPermissionManagement {
 
     Policy mapRolesPermission();
 
-    Policy impersonatePermission();
+    Policy adminImpersonatingPermission();
+
+    Policy userImpersonatedPermission();
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissions.java
index 46a9d01..80bf07f 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissions.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissions.java
@@ -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(ADMIN_IMPERSONATING_PERMISSION, server.getId());
+    }
+
+    @Override
+    public Policy userImpersonatedPermission() {
         ResourceServer server = root.realmResourceServer();
-        return authz.getStoreFactory().getPolicyStore().findByName(IMPERSONATE_PERMISSION_USERS, server.getId());
+        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;
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
index b8edcf8..452e81f 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
@@ -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(),