keycloak-aplcache

fine grain tests

5/8/2017 2:48:51 PM

Changes

testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java 260(+0 -260)

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/ManagementPermissionReference.java b/core/src/main/java/org/keycloak/representations/idm/ManagementPermissionReference.java
new file mode 100644
index 0000000..22550d6
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ManagementPermissionReference.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ManagementPermissionReference {
+    private boolean enabled;
+    private String resource;
+    private Map<String, String> scopePermissions;
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public String getResource() {
+        return resource;
+    }
+
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+
+    public Map<String, String> getScopePermissions() {
+        return scopePermissions;
+    }
+
+    public void setScopePermissions(Map<String, String> scopePermissions) {
+        this.scopePermissions = scopePermissions;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/permissions/MgmtPermissions.java b/services/src/main/java/org/keycloak/authorization/admin/permissions/MgmtPermissions.java
index 098c263..84aa631 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/permissions/MgmtPermissions.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/permissions/MgmtPermissions.java
@@ -25,7 +25,9 @@ import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.admin.AdminAuth;
@@ -47,7 +49,8 @@ public class MgmtPermissions {
     public MgmtPermissions(KeycloakSession session, RealmModel realm) {
         this.session = session;
         this.realm = realm;
-        AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
+        KeycloakSessionFactory keycloakSessionFactory = session.getKeycloakSessionFactory();
+        AuthorizationProviderFactory factory = (AuthorizationProviderFactory) keycloakSessionFactory.getProviderFactory(AuthorizationProvider.class);
         this.authz = factory.create(session, realm);
     }
     public MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
@@ -57,10 +60,11 @@ public class MgmtPermissions {
     }
 
     public boolean isAdminSameRealm() {
-        return realm.getId().equals(auth.getRealm().getId());
+        return auth == null || realm.getId().equals(auth.getRealm().getId());
     }
 
     public RealmAuth getRealmAuth() {
+        if (auth == null) return null;
         RealmManager realmManager = new RealmManager(session);
         if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
             return new RealmAuth(auth, realm.getMasterAdminClient());
@@ -71,7 +75,7 @@ public class MgmtPermissions {
 
     public Identity identity() {
         if (identity != null) return identity;
-        if (auth.getClient().getClientId().equals(Constants.REALM_MANAGEMENT_CLIENT_ID)) {
+        if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)) {
             this.identity = new UserModelIdentity(realm, auth.getUser());
 
         } else {
@@ -80,11 +84,17 @@ public class MgmtPermissions {
         return this.identity;
     }
 
+    public void setIdentity(UserModel user) {
+        this.identity = new UserModelIdentity(realm, user);
+    }
+
 
     public RoleMgmtPermissions roles() {
         return new RoleMgmtPermissions(session, realm, authz, this);
     }
 
+    public UsersPermissions users() { return new UsersPermissions(session, realm, authz, this); }
+
     public ResourceServer findOrCreateResourceServer(ClientModel client) {
         ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
         if (server == null) {
diff --git a/services/src/main/java/org/keycloak/authorization/admin/permissions/RoleMgmtPermissions.java b/services/src/main/java/org/keycloak/authorization/admin/permissions/RoleMgmtPermissions.java
index a745d56..4924131 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/permissions/RoleMgmtPermissions.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/permissions/RoleMgmtPermissions.java
@@ -29,6 +29,7 @@ import org.keycloak.authorization.permission.ResourcePermission;
 import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
 import org.keycloak.authorization.policy.evaluation.DecisionResult;
 import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.authorization.store.ResourceStore;
 import org.keycloak.authorization.util.Permissions;
 import org.keycloak.models.AdminRoles;
 import org.keycloak.models.ClientModel;
@@ -59,16 +60,7 @@ public class RoleMgmtPermissions {
     }
 
     public boolean isPermissionsEnabled(RoleModel role) {
-        ClientModel client = getRoleClient(role);
-        ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
-        if (server == null) return false;
-
-        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
-        if (resource == null) return false;
-
-        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
-
-        return policy != null;
+        return mapRolePermission(role) != null;
     }
 
     public void setPermissionsEnabled(RoleModel role, boolean enable) {
@@ -79,8 +71,7 @@ public class RoleMgmtPermissions {
            }
            createResource(role);
        } else {
-           ClientModel client = getRoleClient(role);
-           ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+           ResourceServer server = resourceServer(role);
            if (server == null) return;
            Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
            if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
@@ -89,6 +80,44 @@ public class RoleMgmtPermissions {
        }
     }
 
+    public Policy mapRolePermission(RoleModel role) {
+        ResourceServer server = resourceServer(role);
+        if (server == null) return null;
+
+        Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
+        if (resource == null) return null;
+
+        Policy policy =  authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
+        return authz.getStoreFactory().getPolicyStore().findById(policy.getId(), server.getId());
+    }
+
+    public Resource resource(RoleModel role) {
+        ResourceStore resourceStore = authz.getStoreFactory().getResourceStore();
+        ResourceServer server = resourceServer(role);
+        if (server == null) return null;
+        Resource resource =  resourceStore.findByName(getRoleResourceName(role), server.getId());
+        if (resource == null) return null;
+        return resourceStore.findById(resource.getId(), server.getId());
+    }
+
+    public ResourceServer resourceServer(RoleModel role) {
+        ClientModel client = getRoleClient(role);
+        return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+    }
+
+    /**
+     * Is admin allowed to map this role?  In Authz terms, does the user have the "map-role" scope for the role's Authz resource?
+     *
+     * This method is hardcoded to return TRUE if any of these conditions are met:
+     * - The admin is from the master realm managing a different realm
+     * - If the Authz objects are not set up correctly for this role (resource server, resource, permission)
+     * - If the role's mapRole permission does not have a policy associated with it.
+     *
+     * Otherwise, it will use the Authz policy engine to resolve this answer.
+     *
+     * @param role
+     * @return
+     */
     public boolean canMapRole(RoleModel role) {
         if (!root.isAdminSameRealm()) {
             return true;
@@ -101,22 +130,27 @@ public class RoleMgmtPermissions {
             return true; // if no policies applied, just ignore
         }
 
-
-        Identity identity = root.identity();
-
-        EvaluationContext context = new DefaultEvaluationContext(identity, session);
-        DecisionResult decisionCollector = new DecisionResult();
-        Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), resourceServer.getId());
-        Scope mapRoleScope = getMapRoleScope(resourceServer);
-
-        List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
-        PermissionEvaluator from = authz.evaluators().from(permissions, context);
-        from.evaluate(decisionCollector);
-        if (!decisionCollector.completed()) {
-            logger.error("Failed to run map role policy check", decisionCollector.getError());
-            return false;
+        RealmModel oldRealm = session.getContext().getRealm();
+        try {
+            session.getContext().setRealm(realm);
+            Identity identity = root.identity();
+
+            EvaluationContext context = new DefaultEvaluationContext(identity, session);
+            DecisionResult decisionCollector = new DecisionResult();
+            Resource roleResource = resource(role);
+            Scope mapRoleScope = getMapRoleScope(resourceServer);
+
+            List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
+            PermissionEvaluator from = authz.evaluators().from(permissions, context);
+            from.evaluate(decisionCollector);
+            if (!decisionCollector.completed()) {
+                logger.error("Failed to run map role policy check", decisionCollector.getError());
+                return false;
+            }
+            return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
+        } finally {
+            session.getContext().setRealm(oldRealm);
         }
-        return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
     }
 
 
@@ -130,12 +164,12 @@ public class RoleMgmtPermissions {
         return client;
     }
 
-    public Policy getManageUsersPolicy(ResourceServer server) {
+    public Policy manageUsersPolicy(ResourceServer server) {
         RoleModel role = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).getRole(AdminRoles.MANAGE_USERS);
-        return getRolePolicy(server, role);
+        return rolePolicy(server, role);
     }
 
-    public Policy getRolePolicy(ResourceServer server, RoleModel role) {
+    public Policy rolePolicy(ResourceServer server, RoleModel role) {
         String policyName = Helper.getRolePolicyName(role);
         Policy policy = authz.getStoreFactory().getPolicyStore().findByName(policyName, server.getId());
         if (policy != null) return policy;
diff --git a/services/src/main/java/org/keycloak/authorization/admin/permissions/UsersPermissions.java b/services/src/main/java/org/keycloak/authorization/admin/permissions/UsersPermissions.java
index c198885..3f6b72a 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/permissions/UsersPermissions.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/permissions/UsersPermissions.java
@@ -30,14 +30,13 @@ import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
 import org.keycloak.authorization.policy.evaluation.DecisionResult;
 import org.keycloak.authorization.policy.evaluation.EvaluationContext;
 import org.keycloak.authorization.util.Permissions;
+import org.keycloak.models.AdminRoles;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
-import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.resources.admin.AdminAuth;
 import org.keycloak.services.resources.admin.RealmAuth;
 
 import java.util.HashSet;
@@ -45,11 +44,16 @@ import java.util.List;
 import java.util.Set;
 
 /**
+ * Manages default policies for all users.
+ *
+ *
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 public class UsersPermissions {
     private static final Logger logger = Logger.getLogger(UsersPermissions.class);
+    public static final String MANAGE_PERMISSION_USERS = "manage.permission.users";
+    public static final String USERS_RESOURCE = "Users";
     protected final KeycloakSession session;
     protected final RealmModel realm;
     protected final AuthorizationProvider authz;
@@ -70,45 +74,44 @@ public class UsersPermissions {
             manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
 
         }
-        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
         if (usersResource == null) {
-            usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
+            usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
         }
-        Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
         if (policy == null) {
             Set<Scope> scopeset = new HashSet<>();
             scopeset.add(manageScope);
             usersResource.updateScopes(scopeset);
-            Policy manageUsersPolicy = root.roles().getManageUsersPolicy(server);
-            Helper.addScopePermission(authz, server, "manage.permission.users", usersResource, manageScope, manageUsersPolicy);
+            Policy manageUsersPolicy = root.roles().manageUsersPolicy(server);
+            Helper.addScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope, manageUsersPolicy);
         }
     }
 
     public boolean isPermissionsEnabled() {
-        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
-        ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+        ResourceServer server = resourceServer();
         if (server == null) return false;
 
-        Resource resource =  authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
         if (resource == null) return false;
 
-        Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
 
         return policy != null;
     }
 
-    public void setPermissionsEnabled(RoleModel role, boolean enable) {
+    public void setPermissionsEnabled(boolean enable) {
         ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
         if (enable) {
             initialize();
         } else {
             ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
             if (server == null) return;
-            Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+            Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
             if (usersResource == null) {
                 authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
             }
-            Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+            Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
             if (policy == null) {
                 authz.getStoreFactory().getPolicyStore().delete(policy.getId());
 
@@ -117,9 +120,9 @@ public class UsersPermissions {
     }
 
     private Resource getUsersResource(ResourceServer server) {
-        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
         if (usersResource == null) {
-            usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
+            usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
         }
         return usersResource;
     }
@@ -138,51 +141,108 @@ public class UsersPermissions {
         return root.findOrCreateResourceServer(client);
     }
 
-    private boolean canManageDefault() {
+    private boolean canManageDefault(UserModel admin) {
         RealmAuth auth = root.getRealmAuth();
-        auth.init(RealmAuth.Resource.USER);
-        return auth.hasManage();
+        if (auth != null) {
+            auth.init(RealmAuth.Resource.USER);
+            return auth.hasManage();
+        } else {
+            ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+            RoleModel manageUsers = client.getRole(AdminRoles.MANAGE_USERS);
+            return admin.hasRole(manageUsers);
+        }
+
+    }
+
+    public boolean canManage() {
+        if (root.getRealmAuth() == null) {
+            throw new NullPointerException("Realm auth null");
+        }
+        return canManage(root.getRealmAuth().getAuth().getUser());
+    }
+
+    public Resource resource() {
+        ResourceServer server = resourceServer();
+        if (server == null) return null;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return null;
+        return  authz.getStoreFactory().getResourceStore().findById(resource.getId(), server.getId());
 
     }
 
-    public boolean canManage(UserModel user) {
+    /**
+     * Is admin allowed to manage users?  In Authz terms, does the admin have the "map-role" scope for the role's Authz resource?
+     *
+     * This method will follow the old default behavior (does the admin have the manage-users role) if any of these conditions
+     * are met.:
+     * - The admin is from the master realm managing a different realm
+     * - If the Authz objects are not set up correctly for the Users resource in Authz
+     * - The "manage" permission for the Users resource has an empty associatedPolicy list.
+     *
+     * Otherwise, it will use the Authz policy engine to resolve this answer.
+     *
+     * @param admin
+     * @return
+     */
+    public boolean canManage(UserModel admin) {
         if (!root.isAdminSameRealm()) {
-            return canManageDefault();
+            return canManageDefault(admin);
         }
 
-        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
-        ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
-        if (server == null) return canManageDefault();
+        ResourceServer server = resourceServer();
+        if (server == null) return canManageDefault(admin);
 
-        Resource resource =  authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
-        if (resource == null) return canManageDefault();
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return canManageDefault(admin);
 
-        Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
         if (policy == null) {
-            return canManageDefault();
+            return canManageDefault(admin);
         }
 
         Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
         // if no policies attached to permission then just do default behavior
         if (associatedPolicies == null || associatedPolicies.isEmpty()) {
-            return canManageDefault();
+            return canManageDefault(admin);
         }
 
-        Identity identity = root.identity();
-        EvaluationContext context = new DefaultEvaluationContext(identity, session);
-        DecisionResult decisionCollector = new DecisionResult();
-        ResourceServer resourceServer = getRealmManagementResourceServer();
-        Resource roleResource = authz.getStoreFactory().getResourceStore().findByName("Users", resourceServer.getId());
-        Scope manageScope = getManageScope(resourceServer);
-
-        List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, manageScope);
-        PermissionEvaluator from = authz.evaluators().from(permissions, context);
-        from.evaluate(decisionCollector);
-        if (!decisionCollector.completed()) {
-            logger.error("Failed to run Users manage check", decisionCollector.getError());
-            return false;
+        RealmModel oldRealm = session.getContext().getRealm();
+        try {
+            session.getContext().setRealm(realm);
+            Identity identity = root.identity();
+            EvaluationContext context = new DefaultEvaluationContext(identity, session);
+            DecisionResult decisionCollector = new DecisionResult();
+            ResourceServer resourceServer = getRealmManagementResourceServer();
+            Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, resourceServer.getId());
+            Scope manageScope = getManageScope(resourceServer);
+
+            List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, manageScope);
+            PermissionEvaluator from = authz.evaluators().from(permissions, context);
+            from.evaluate(decisionCollector);
+            if (!decisionCollector.completed()) {
+                logger.error("Failed to run Users manage check", decisionCollector.getError());
+                return false;
+            }
+            return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
+        } finally {
+            session.getContext().setRealm(oldRealm);
         }
-        return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
 
     }
+
+    public ResourceServer resourceServer() {
+        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        return authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+    }
+
+    public Policy managePermission() {
+        ResourceServer server = resourceServer();
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
+        // have to do this because findByName returns a Jpa Entity todo change when fixed
+        return authz.getStoreFactory().getPolicyStore().findById(policy.getId(), server.getId());
+
+    }
+
+
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 89b0a33..db24956 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -328,7 +328,7 @@ public class ClientResource {
 
     @Path("roles")
     public RoleContainerResource getRoleContainerResource() {
-        return new RoleContainerResource(uriInfo, realm, auth, client, adminEvent);
+        return new RoleContainerResource(session, uriInfo, realm, auth, client, adminEvent);
     }
 
     /**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java
index 3d7d4cd..8cc456f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.logging.Logger;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.authorization.admin.permissions.MgmtPermissions;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
@@ -30,6 +31,7 @@ import org.keycloak.models.RoleModel;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.ForbiddenException;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -63,6 +65,8 @@ public class ClientRoleMappingsResource {
     protected ClientModel client;
     protected AdminEventBuilder adminEvent;
     private UriInfo uriInfo;
+    private RoleMapperResource.ManageResourcePermissionCheck manageResourcePermissionCheck;
+
 
     public ClientRoleMappingsResource(UriInfo uriInfo, KeycloakSession session, RealmModel realm, RealmAuth auth, RoleMapperModel user, ClientModel client, AdminEventBuilder adminEvent) {
         this.uriInfo = uriInfo;
@@ -74,6 +78,12 @@ public class ClientRoleMappingsResource {
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING);
     }
 
+    public void setManageCheck(RoleMapperResource.ManageResourcePermissionCheck mapperPermissions) {
+        this.manageResourcePermissionCheck = mapperPermissions;
+    }
+
+
+
     /**
      * Get client-level role mappings for the user, and the app
      *
@@ -157,6 +167,17 @@ public class ClientRoleMappingsResource {
         return mappings;
     }
 
+    private void checkManagePermission() {
+        if (manageResourcePermissionCheck == null) {
+            auth.requireManage();
+        } else {
+            if (!manageResourcePermissionCheck.canManage()) {
+                throw new ForbiddenException();
+            }
+        }
+    }
+
+
     /**
      * Add client-level roles to the user role mapping
      *
@@ -165,7 +186,7 @@ public class ClientRoleMappingsResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addClientRoleMapping(List<RoleRepresentation> roles) {
-        auth.requireManage();
+        checkManagePermission();
 
         if (user == null || client == null) {
             throw new NotFoundException("Not found");
@@ -176,21 +197,28 @@ public class ClientRoleMappingsResource {
             if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                 throw new NotFoundException("Role not found");
             }
+            checkMapRolePermission(roleModel);
             user.grantRole(roleModel);
         }
         adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
 
     }
 
-    /**
-     * Delete client-level roles from user role mapping
-     *
-     * @param roles
-     */
+    private void checkMapRolePermission(RoleModel roleModel) {
+        if (!new MgmtPermissions(session, realm, auth.getAuth()).roles().canMapRole(roleModel)) {
+            throw new ForbiddenException();
+        }
+    }
+
+        /**
+         * Delete client-level roles from user role mapping
+         *
+         * @param roles
+         */
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     public void deleteClientRoleMapping(List<RoleRepresentation> roles) {
-        auth.requireManage();
+        checkManagePermission();
 
         if (user == null || client == null) {
             throw new NotFoundException("Not found");
@@ -205,6 +233,7 @@ public class ClientRoleMappingsResource {
                     ClientModel client = (ClientModel) roleModel.getContainer();
                     if (!client.getId().equals(this.client.getId())) continue;
                 }
+                checkMapRolePermission(roleModel);
                 user.deleteRoleMapping(roleModel);
                 roles.add(ModelToRepresentation.toRepresentation(roleModel));
             }
@@ -216,6 +245,7 @@ public class ClientRoleMappingsResource {
                     throw new NotFoundException("Role not found");
                 }
 
+                checkMapRolePermission(roleModel);
                 try {
                     user.deleteRoleMapping(roleModel);
                 } catch (ModelException me) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 146ef86..4585e16 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -23,6 +23,9 @@ import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.Config;
 import org.keycloak.KeyPairVerifier;
+import org.keycloak.authorization.admin.permissions.MgmtPermissions;
+import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions;
+import org.keycloak.authorization.admin.permissions.UsersPermissions;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.common.VerificationException;
 import org.keycloak.common.util.PemUtils;
@@ -44,6 +47,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.cache.CacheRealmProvider;
 import org.keycloak.models.cache.UserCache;
@@ -61,6 +65,7 @@ import org.keycloak.representations.idm.ComponentRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.ManagementPermissionReference;
 import org.keycloak.representations.idm.PartialImportRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
@@ -132,7 +137,6 @@ public class RealmAdminResource {
         this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM);
 
         auth.init(RealmAuth.Resource.REALM);
-        auth.requireAny();
     }
 
     /**
@@ -234,7 +238,7 @@ public class RealmAdminResource {
      */
     @Path("roles")
     public RoleContainerResource getRoleContainerResource() {
-        return new RoleContainerResource(uriInfo, realm, auth, realm, adminEvent);
+        return new RoleContainerResource(session, uriInfo, realm, auth, realm, adminEvent);
     }
 
     /**
@@ -360,6 +364,51 @@ public class RealmAdminResource {
         return users;
     }
 
+    @NoCache
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("users-management-permissions")
+    public ManagementPermissionReference getUserMgmtPermissions() {
+        auth.requireView();
+
+        MgmtPermissions permissions = new MgmtPermissions(session, realm);
+        if (permissions.users().isPermissionsEnabled()) {
+            return toUsersMgmtRef(permissions);
+        } else {
+            return new ManagementPermissionReference();
+        }
+
+    }
+
+    @PUT
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    @NoCache
+    @Path("users-management-permissions")
+    public ManagementPermissionReference setUsersManagementPermissionsEnabled(ManagementPermissionReference ref) {
+        auth.requireManage();
+
+        MgmtPermissions permissions = new MgmtPermissions(session, realm);
+        permissions.users().setPermissionsEnabled(ref.isEnabled());
+        if (ref.isEnabled()) {
+            return toUsersMgmtRef(permissions);
+        } else {
+            return new ManagementPermissionReference();
+        }
+    }
+
+
+    public static ManagementPermissionReference toUsersMgmtRef(MgmtPermissions permissions) {
+        ManagementPermissionReference ref = new ManagementPermissionReference();
+        ref.setEnabled(true);
+        ref.setResource(permissions.users().resource().getId());
+        Map<String, String> scopes = new HashMap<>();
+        scopes.put(MgmtPermissions.MANAGE_SCOPE, permissions.users().managePermission().getId());
+        ref.setScopePermissions(scopes);
+        return ref;
+    }
+
+
     @Path("user-storage")
     public UserStorageProviderResource userStorage() {
         UserStorageProviderResource fed = new UserStorageProviderResource(realm, auth, adminEvent);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
index 1f19b64..9d3e100 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
@@ -19,6 +19,8 @@ package org.keycloak.services.resources.admin;
 import org.jboss.logging.Logger;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.authorization.admin.permissions.MgmtPermissions;
+import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
@@ -26,6 +28,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.ManagementPermissionReference;
 import org.keycloak.representations.idm.RoleRepresentation;
 
 import javax.ws.rs.Consumes;
@@ -39,7 +42,9 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -244,4 +249,63 @@ public class RoleByIdResource extends RoleResource {
         deleteComposites(adminEvent, uriInfo, roles, role);
     }
 
+    /**
+     * Return object stating whether role Authoirzation permissions have been initialized or not and a reference
+     *
+     *
+     * @param id
+     * @return
+     */
+    @Path("{role-id}/management/permissions")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference getManagementPermissions(final @PathParam("role-id") String id) {
+        auth.requireView();
+
+        RoleModel role = getRoleModel(id);
+
+        MgmtPermissions permissions = new MgmtPermissions(session, realm);
+        if (!permissions.roles().isPermissionsEnabled(role)) {
+            return new ManagementPermissionReference();
+        }
+        return toMgmtRef(role, permissions);
+    }
+
+    public static ManagementPermissionReference toMgmtRef(RoleModel role, MgmtPermissions permissions) {
+        ManagementPermissionReference ref = new ManagementPermissionReference();
+        ref.setEnabled(true);
+        ref.setResource(permissions.roles().resource(role).getId());
+        Map<String, String> scopes = new HashMap<>();
+        scopes.put(RoleMgmtPermissions.MAP_ROLE_SCOPE, permissions.roles().mapRolePermission(role).getId());
+        ref.setScopePermissions(scopes);
+        return ref;
+    }
+
+    /**
+     * Return object stating whether role Authoirzation permissions have been initialized or not and a reference
+     *
+     *
+     * @param id
+     * @return initialized manage permissions reference
+     */
+    @Path("{role-id}/management/permissions")
+    @PUT
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-id") String id, ManagementPermissionReference ref) {
+        auth.requireManage();
+
+        RoleModel role = getRoleModel(id);
+
+        MgmtPermissions permissions = new MgmtPermissions(session, realm);
+        permissions.roles().setPermissionsEnabled(role, ref.isEnabled());
+        if (ref.isEnabled()) {
+            return toMgmtRef(role, permissions);
+        } else {
+            return new ManagementPermissionReference();
+        }
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index 47f9c64..94e4def 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -19,14 +19,18 @@ package org.keycloak.services.resources.admin;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.authorization.admin.permissions.MgmtPermissions;
+import org.keycloak.authorization.admin.permissions.RoleMgmtPermissions;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.representations.idm.ManagementPermissionReference;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.services.ErrorResponse;
 
@@ -44,7 +48,9 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -58,14 +64,16 @@ public class RoleContainerResource extends RoleResource {
     protected RoleContainerModel roleContainer;
     private AdminEventBuilder adminEvent;
     private UriInfo uriInfo;
+    private KeycloakSession session;
 
-    public RoleContainerResource(UriInfo uriInfo, RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) {
+    public RoleContainerResource(KeycloakSession session, UriInfo uriInfo, RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) {
         super(realm);
         this.uriInfo = uriInfo;
         this.realm = realm;
         this.auth = auth;
         this.roleContainer = roleContainer;
         this.adminEvent = adminEvent;
+        this.session = session;
     }
 
     /**
@@ -355,4 +363,67 @@ public class RoleContainerResource extends RoleResource {
         deleteComposites(adminEvent, uriInfo, roles, role);
     }
 
+    /**
+     * Return object stating whether role Authoirzation permissions have been initialized or not and a reference
+     *
+     *
+     * @param roleName
+     * @return
+     */
+    @Path("{role-name}/management/permissions")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference getManagementPermissions(final @PathParam("role-name") String roleName) {
+        auth.requireView();
+
+        if (roleContainer == null) {
+            throw new NotFoundException("Could not find client");
+        }
+
+        RoleModel role = roleContainer.getRole(roleName);
+        if (role == null) {
+            throw new NotFoundException("Could not find role");
+        }
+
+        MgmtPermissions permissions = new MgmtPermissions(session, realm);
+        if (!permissions.roles().isPermissionsEnabled(role)) {
+            return new ManagementPermissionReference();
+        }
+        return RoleByIdResource.toMgmtRef(role, permissions);
+    }
+
+    /**
+     * Return object stating whether role Authoirzation permissions have been initialized or not and a reference
+     *
+     *
+     * @param roleName
+     * @return initialized manage permissions reference
+     */
+    @Path("{role-name}/management/permissions")
+    @PUT
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference setManagementPermissionsEnabled(final @PathParam("role-name") String roleName, ManagementPermissionReference ref) {
+        auth.requireManage();
+
+        if (roleContainer == null) {
+            throw new NotFoundException("Could not find client");
+        }
+
+        RoleModel role = roleContainer.getRole(roleName);
+        if (role == null) {
+            throw new NotFoundException("Could not find role");
+        }
+
+        if (ref.isEnabled()) {
+            MgmtPermissions permissions = new MgmtPermissions(session, realm);
+            permissions.roles().setPermissionsEnabled(role, ref.isEnabled());
+            return RoleByIdResource.toMgmtRef(role, permissions);
+        } else {
+            return new ManagementPermissionReference();
+        }
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java
index 5b7af1f..51b1847 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.logging.Logger;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.authorization.admin.permissions.MgmtPermissions;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
@@ -33,6 +34,7 @@ import org.keycloak.representations.idm.ClientMappingsRepresentation;
 import org.keycloak.representations.idm.MappingsRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.ForbiddenException;
 import org.keycloak.services.managers.RealmManager;
 
 import javax.ws.rs.Consumes;
@@ -64,6 +66,17 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 public class RoleMapperResource {
+
+    /**
+     * RoleMapperResource is reused bewteen GroupResource and UserResource to manage role mappings.
+     * We don't know what type of resource we're managing here (user or group), so we don't know how to query the policy engine to determine
+     * if an action is allowed.
+     *
+     */
+    public interface ManageResourcePermissionCheck {
+        boolean canManage();
+    }
+
     protected static final Logger logger = Logger.getLogger(RoleMapperResource.class);
 
     protected RealmModel realm;
@@ -74,6 +87,8 @@ public class RoleMapperResource {
 
     private AdminEventBuilder adminEvent;
 
+    private ManageResourcePermissionCheck manageResourcePermissionCheck;
+
     @Context
     protected ClientConnection clientConnection;
 
@@ -94,6 +109,9 @@ public class RoleMapperResource {
 
     }
 
+    public void setManageCheck(ManageResourcePermissionCheck mapperPermissions) {
+        this.manageResourcePermissionCheck = mapperPermissions;
+    }
 
     /**
      * Get role mappings
@@ -224,7 +242,7 @@ public class RoleMapperResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addRealmRoleMappings(List<RoleRepresentation> roles) {
-        auth.requireManage();
+        checkManagePermission();
 
         if (roleMapper == null) {
             throw new NotFoundException("User not found");
@@ -237,12 +255,23 @@ public class RoleMapperResource {
             if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                 throw new NotFoundException("Role not found");
             }
+            checkMapRolePermission(roleModel);
             roleMapper.grantRole(roleModel);
         }
 
         adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
     }
 
+    private void checkManagePermission() {
+        if (manageResourcePermissionCheck == null) {
+            auth.requireManage();
+        } else {
+            if (!manageResourcePermissionCheck.canManage()) {
+                throw new ForbiddenException();
+            }
+        }
+    }
+
     /**
      * Delete realm-level role mappings
      *
@@ -252,7 +281,7 @@ public class RoleMapperResource {
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     public void deleteRealmRoleMappings(List<RoleRepresentation> roles) {
-        auth.requireManage();
+        checkManagePermission();
 
         if (roleMapper == null) {
             throw new NotFoundException("User not found");
@@ -264,6 +293,7 @@ public class RoleMapperResource {
             roles = new LinkedList<>();
 
             for (RoleModel roleModel : roleModels) {
+                checkMapRolePermission(roleModel);
                 roleMapper.deleteRoleMapping(roleModel);
                 roles.add(ModelToRepresentation.toRepresentation(roleModel));
             }
@@ -274,7 +304,7 @@ public class RoleMapperResource {
                 if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                     throw new NotFoundException("Role not found");
                 }
-
+                checkMapRolePermission(roleModel);
                 try {
                     roleMapper.deleteRoleMapping(roleModel);
                 } catch (ModelException me) {
@@ -290,10 +320,20 @@ public class RoleMapperResource {
 
     }
 
+    private void checkMapRolePermission(RoleModel roleModel) {
+        if (!new MgmtPermissions(session, realm, auth.getAuth()).roles().canMapRole(roleModel)) {
+            throw new ForbiddenException();
+        }
+    }
+
     @Path("clients/{client}")
     public ClientRoleMappingsResource getUserClientRoleMappingsResource(@PathParam("client") String client) {
         ClientModel clientModel = realm.getClientById(client);
-        return new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper, clientModel, adminEvent);
+        ClientRoleMappingsResource resource = new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper, clientModel, adminEvent);
+        resource.setManageCheck(() -> {
+            return new MgmtPermissions(session, realm, auth.getAuth()).users().canManage();
+        });
+        return resource;
 
     }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 3259982..3e4cfef 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -22,6 +22,7 @@ import org.jboss.resteasy.spi.BadRequestException;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.authentication.RequiredActionProvider;
+import org.keycloak.authorization.admin.permissions.MgmtPermissions;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.common.Profile;
 import org.keycloak.common.util.Time;
@@ -48,9 +49,7 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.credential.PasswordUserCredentialModel;
 import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.provider.ProviderFactory;
@@ -723,6 +722,9 @@ public class UsersResource {
         UserModel user = session.users().getUserById(id, realm);
 
         RoleMapperResource resource =  new RoleMapperResource(realm, auth, user, adminEvent);
+        resource.setManageCheck(() -> {
+            return new MgmtPermissions(session, realm, auth.getAuth()).users().canManage();
+        });
         ResteasyProviderFactory.getInstance().injectProperties(resource);
         return resource;
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java
index c1869d7..a8d8089 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/AdminClientUtil.java
@@ -42,6 +42,15 @@ import static org.keycloak.testsuite.util.IOUtil.PROJECT_BUILD_DIRECTORY;
 public class AdminClientUtil {
 
     public static Keycloak createAdminClient(boolean ignoreUnknownProperties) throws Exception {
+        String realmName = MASTER;
+        String username = ADMIN;
+        String password = ADMIN;
+        String clientId = Constants.ADMIN_CLI_CLIENT_ID;
+        String clientSecret = null;
+        return createAdminClient(ignoreUnknownProperties, realmName, username, password, clientId, clientSecret);
+    }
+
+    public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String realmName, String username, String password, String clientId, String clientSecret) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
         SSLContext ssl = null;
         if ("true".equals(System.getProperty("auth.server.ssl.required"))) {
             File trustore = new File(PROJECT_BUILD_DIRECTORY, "dependency/keystore/keycloak.truststore");
@@ -62,7 +71,7 @@ public class AdminClientUtil {
         }
 
         return Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
-                MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID, null, ssl, jacksonProvider);
+                realmName, username, password, clientId, clientSecret, ssl, jacksonProvider);
     }
 
     public static Keycloak createAdminClient() throws Exception {
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
new file mode 100644
index 0000000..add91cc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.admin;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.authorization.admin.permissions.MgmtPermissions;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.DecisionEffect;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
+import org.keycloak.testsuite.util.AdminClientUtil;
+
+import javax.ws.rs.ClientErrorException;
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.core.Response;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
+import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+//@Ignore
+public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation testRealmRep = new RealmRepresentation();
+        testRealmRep.setId(TEST);
+        testRealmRep.setRealm(TEST);
+        testRealmRep.setEnabled(true);
+        testRealms.add(testRealmRep);
+    }
+
+    public static void setupPolices(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        MgmtPermissions permissions = new MgmtPermissions(session, realm);
+        RoleModel realmRole = realm.addRole("realm-role");
+        RoleModel realmRole2 = realm.addRole("realm-role2");
+        ClientModel client1 = realm.addClient("role-namespace");
+        RoleModel client1Role = client1.addRole("client-role");
+
+        RoleModel mapperRole = realm.addRole("mapper");
+        RoleModel managerRole = realm.addRole("manager");
+        RoleModel compositeRole = realm.addRole("composite-role");
+        compositeRole.addCompositeRole(mapperRole);
+        compositeRole.addCompositeRole(managerRole);
+
+        // realm-role and role-namespace.client-role will have a role policy associated with their map-role permission
+        {
+            permissions.roles().setPermissionsEnabled(realmRole, true);
+            Policy mapRolePermission = permissions.roles().mapRolePermission(realmRole);
+            ResourceServer server = permissions.roles().resourceServer(realmRole);
+            Policy mapperPolicy = permissions.roles().rolePolicy(server, mapperRole);
+            mapRolePermission.addAssociatedPolicy(mapperPolicy);
+        }
+
+        {
+            permissions.roles().setPermissionsEnabled(client1Role, true);
+            Policy mapRolePermission = permissions.roles().mapRolePermission(client1Role);
+            ResourceServer server = permissions.roles().resourceServer(client1Role);
+            Policy mapperPolicy = permissions.roles().rolePolicy(server, mapperRole);
+            mapRolePermission.addAssociatedPolicy(mapperPolicy);
+        }
+
+        // realmRole2 will have an empty map-role policy
+        {
+            permissions.roles().setPermissionsEnabled(realmRole2, true);
+        }
+
+        // setup Users manage policies
+        {
+            permissions.users().setPermissionsEnabled(true);
+            ResourceServer server = permissions.users().resourceServer();
+            Policy managerPolicy = permissions.roles().rolePolicy(server, managerRole);
+            Policy permission = permissions.users().managePermission();
+            permission.addAssociatedPolicy(managerPolicy);
+            permission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        }
+
+    }
+
+    public static void setupUsers(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        ClientModel client = realm.getClientByClientId("role-namespace");
+        RoleModel realmRole = realm.getRole("realm-role");
+        RoleModel realmRole2 = realm.getRole("realm-role2");
+        RoleModel clientRole = client.getRole("client-role");
+        RoleModel mapperRole = realm.getRole("mapper");
+        RoleModel managerRole = realm.getRole("manager");
+        RoleModel compositeRole = realm.getRole("composite-role");
+
+        UserModel authorizedUser = session.users().addUser(realm, "authorized");
+        authorizedUser.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, authorizedUser, UserCredentialModel.password("password"));
+        authorizedUser.grantRole(mapperRole);
+        authorizedUser.grantRole(managerRole);
+
+        UserModel authorizedComposite = session.users().addUser(realm, "authorizedComposite");
+        authorizedComposite.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, authorizedComposite, UserCredentialModel.password("password"));
+        authorizedComposite.grantRole(compositeRole);
+
+        UserModel unauthorizedUser = session.users().addUser(realm, "unauthorized");
+        unauthorizedUser.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, unauthorizedUser, UserCredentialModel.password("password"));
+
+        UserModel unauthorizedMapper = session.users().addUser(realm, "unauthorizedMapper");
+        unauthorizedMapper.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, unauthorizedMapper, UserCredentialModel.password("password"));
+        unauthorizedMapper.grantRole(managerRole);
+
+        UserModel user1 = session.users().addUser(realm, "user1");
+        user1.setEnabled(true);
+        UserModel user2 = session.users().addUser(realm, "user2");
+        user2.setEnabled(true);
+        UserModel user3 = session.users().addUser(realm, "user3");
+        user3.setEnabled(true);
+        UserModel user4 = session.users().addUser(realm, "user4");
+        user4.setEnabled(true);
+
+    }
+
+    public static void evaluateLocally(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        RoleModel realmRole = realm.getRole("realm-role");
+        RoleModel realmRole2 = realm.getRole("realm-role2");
+        ClientModel client = realm.getClientByClientId("role-namespace");
+        RoleModel clientRole = client.getRole("client-role");
+
+        // test authorized
+        {
+            UserModel user = session.users().getUserByUsername("authorized", realm);
+            MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
+            permissionsForAdmin.setIdentity(user);
+            Assert.assertTrue(permissionsForAdmin.users().canManage(user));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
+        }
+        // test composite role
+        {
+            UserModel user = session.users().getUserByUsername("authorizedComposite", realm);
+            MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
+            permissionsForAdmin.setIdentity(user);
+            Assert.assertTrue(permissionsForAdmin.users().canManage(user));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
+        }
+
+        // test unauthorized
+        {
+            UserModel user = session.users().getUserByUsername("unauthorized", realm);
+            MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
+            permissionsForAdmin.setIdentity(user);
+            Assert.assertFalse(permissionsForAdmin.users().canManage(user));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole));
+
+            // will result to true because realmRole2 does not have any policies attached to this permission
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
+        }
+        // test unauthorized mapper
+        {
+            UserModel user = session.users().getUserByUsername("unauthorizedMapper", realm);
+            MgmtPermissions permissionsForAdmin = new MgmtPermissions(session, realm);
+            permissionsForAdmin.setIdentity(user);
+            Assert.assertTrue(permissionsForAdmin.users().canManage(user));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole));
+            // will result to true because realmRole2 does not have any policies attached to this permission
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole2));
+        }
+
+    }
+
+
+    protected boolean isImportAfterEachMethod() {
+        return true;
+    }
+
+
+    @Test
+    public void testUI() throws Exception {
+        testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
+        testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
+        Thread.sleep(1000000000);
+    }
+
+    @Test
+    public void testEvaluationLocal() throws Exception {
+        testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
+        testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
+        testingClient.server().run(FineGrainAdminUnitTest::evaluateLocally);
+    }
+
+    @Test
+    public void testRestEvaluation() throws Exception {
+        testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
+        testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
+
+        UserRepresentation user1 = adminClient.realm(TEST).users().search("user1").get(0);
+        UserRepresentation user2 = adminClient.realm(TEST).users().search("user2").get(0);
+        UserRepresentation user3 = adminClient.realm(TEST).users().search("user3").get(0);
+        UserRepresentation user4 = adminClient.realm(TEST).users().search("user4").get(0);
+        RoleRepresentation realmRole = adminClient.realm(TEST).roles().get("realm-role").toRepresentation();
+        List<RoleRepresentation> realmRoleSet = new LinkedList<>();
+        realmRoleSet.add(realmRole);
+        RoleRepresentation realmRole2 = adminClient.realm(TEST).roles().get("realm-role2").toRepresentation();
+        List<RoleRepresentation> realmRole2Set = new LinkedList<>();
+        realmRole2Set.add(realmRole);
+        ClientRepresentation client = adminClient.realm(TEST).clients().findByClientId("role-namespace").get(0);
+        RoleRepresentation clientRole = adminClient.realm(TEST).clients().get(client.getId()).roles().get("client-role").toRepresentation();
+        List<RoleRepresentation> clientRoleSet = new LinkedList<>();
+        clientRoleSet.add(clientRole);
+
+
+        {
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "authorized", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
+            List<RoleRepresentation> roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
+            Assert.assertTrue(roles.stream().anyMatch((r) -> {
+                return r.getName().equals("realm-role");
+            }));
+            realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().remove(realmRoleSet);
+            roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
+            Assert.assertTrue(roles.stream().noneMatch((r) -> {
+                return r.getName().equals("realm-role");
+            }));
+
+            realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
+            roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+            Assert.assertTrue(roles.stream().anyMatch((r) -> {
+                return r.getName().equals("client-role");
+            }));
+            realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
+            roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+            Assert.assertTrue(roles.stream().noneMatch((r) -> {
+                return r.getName().equals("client-role");
+            }));
+            realmClient.close();
+        }
+
+        {
+            Keycloak realmClient= AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "authorizedComposite", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
+            List<RoleRepresentation> roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
+            Assert.assertTrue(roles.stream().anyMatch((r) -> {
+                return r.getName().equals("realm-role");
+            }));
+            realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().remove(realmRoleSet);
+            roles = adminClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAll();
+            Assert.assertTrue(roles.stream().noneMatch((r) -> {
+                return r.getName().equals("realm-role");
+            }));
+
+            realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
+            roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+            Assert.assertTrue(roles.stream().anyMatch((r) -> {
+                return r.getName().equals("client-role");
+            }));
+            realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
+            roles = adminClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+            Assert.assertTrue(roles.stream().noneMatch((r) -> {
+                return r.getName().equals("client-role");
+            }));
+        }
+        {
+            Keycloak realmClient= AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "unauthorized", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            try {
+                realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+        }
+        {
+            Keycloak realmClient= AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "unauthorizedMapper", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            try {
+                realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().add(realmRoleSet);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+        }
+
+    }
+
+
+}
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index dc4ef93..175e39e 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -1290,8 +1290,13 @@ disable-credentials=Disable Credentials
 credential-reset-actions=Credential Reset
 ldap-mappers=LDAP Mappers
 create-ldap-mapper=Create LDAP mapper
-
-
+map-role-mgmt-scope-description=Policies that decide if an admin can map this role to a user or group
+manage-mgmt-scope-description=Policies that decide if an admin can manage this resource or resources
+permissions-enabled-role=Permissions Enabled
+permissions-enabled-role.tooltip=Whether or not to enable fine grain permissions for this role.  Disabling will delete all current permissions that have been set up.
+manage-permissions-role.tooltip=Fine grain permissions for managing roles.  For example, you can define different policies for who is allowed to map a role.
+lookup=Lookup
+manage-permissions-users.tooltip=Fine grain permssions for managing all users in realm.  You can define different policies for who is allowed to manage users in the realm.
 
 
 
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/app.js b/themes/src/main/resources/theme/base/admin/resources/js/app.js
index 5f58e88..58db5a0 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -2345,6 +2345,24 @@ module.directive('kcTabsAuthentication', function () {
     }
 });
 
+module.directive('kcTabsRole', function () {
+    return {
+        scope: true,
+        restrict: 'E',
+        replace: true,
+        templateUrl: resourceUrl + '/templates/kc-tabs-role.html'
+    }
+});
+
+module.directive('kcTabsClientRole', function () {
+    return {
+        scope: true,
+        restrict: 'E',
+        replace: true,
+        templateUrl: resourceUrl + '/templates/kc-tabs-client-role.html'
+    }
+});
+
 module.directive('kcTabsUser', function () {
     return {
         scope: true,
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
index ecb008d..7b61a3c 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
@@ -373,7 +373,41 @@ module.config(['$routeProvider', function ($routeProvider) {
             }
         },
         controller: 'ResourceServerPolicyAggregateDetailCtrl'
-    });
+    }).when('/realms/:realm/roles/:role/permissions', {
+        templateUrl : resourceUrl + '/partials/authz/mgmt/realm-role-permissions.html',
+        resolve : {
+            realm : function(RealmLoader) {
+                return RealmLoader();
+            },
+            role : function(RoleLoader) {
+                return RoleLoader();
+            }
+        },
+        controller : 'RealmRolePermissionsCtrl'
+    }).when('/realms/:realm/clients/:client/roles/:role/permissions', {
+        templateUrl : resourceUrl + '/partials/authz/mgmt/client-role-permissions.html',
+        resolve : {
+            realm : function(RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            },
+            role : function(RoleLoader) {
+                return RoleLoader();
+            }
+        },
+        controller : 'ClientRolePermissionsCtrl'
+    }).when('/realms/:realm/users-permissions', {
+        templateUrl : resourceUrl + '/partials/authz/mgmt/users-permissions.html',
+        resolve : {
+            realm : function(RealmLoader) {
+                return RealmLoader();
+            }
+        },
+        controller : 'UsersPermissionsCtrl'
+    })
+    ;
 }]);
 
 module.directive('kcTabsResourceServer', function () {
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
index 5d8d462..f9a9ca5 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
@@ -2353,4 +2353,61 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
 
         $scope.authzRequest.userId = user.id;
     }
-});
\ No newline at end of file
+});
+
+module.controller('RealmRolePermissionsCtrl', function($scope, $http, $route, $location, realm, role, RoleManagementPermissions, Client, Notifications) {
+    console.log('RealmRolePermissionsCtrl');
+    $scope.role = role;
+    $scope.realm = realm;
+    RoleManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) {
+        $scope.permissions = data;
+    });
+    Client.query({realm: realm.realm, clientId: 'realm-management'}, function(data) {
+        $scope.realmManagementClientId = data[0].id;
+    });
+    $scope.setEnabled = function() {
+        var param = { enabled: $scope.permissions.enabled};
+        RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param, function(data) {
+            $scope.permissions = data;
+        })
+    };
+
+
+});
+module.controller('ClientRolePermissionsCtrl', function($scope, $http, $route, $location, realm, client, role, RoleManagementPermissions, Client, Notifications) {
+    console.log('RealmRolePermissionsCtrl');
+    $scope.client = client;
+    $scope.role = role;
+    $scope.realm = realm;
+    RoleManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) {
+        $scope.permissions = data;
+    });
+    $scope.setEnabled = function() {
+        var param = { enabled: $scope.permissions.enabled};
+        RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param, function(data) {
+            $scope.permissions = data;
+        })
+    };
+
+
+});
+
+module.controller('UsersPermissionsCtrl', function($scope, $http, $route, $location, realm, UsersManagementPermissions, Client, Notifications) {
+    console.log('UsersPermissionsCtrl');
+    $scope.realm = realm;
+    UsersManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) {
+        $scope.permissions = data;
+    });
+    Client.query({realm: realm.realm, clientId: 'realm-management'}, function(data) {
+        $scope.realmManagementClientId = data[0].id;
+    });
+    $scope.setEnabled = function() {
+        var param = { enabled: $scope.permissions.enabled};
+        UsersManagementPermissions.update({realm: realm.realm, role:role.id}, param, function(data) {
+            $scope.permissions = data;
+        })
+    };
+
+
+});
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index bcb0d0c..4f2a62f 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -1326,6 +1326,21 @@ module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevoca
 });
 
 
+module.controller('RoleTabCtrl', function(Dialog, $scope, Current, Notifications, $location) {
+    $scope.removeRole = function() {
+        Dialog.confirmDelete($scope.role.name, 'role', function() {
+            RoleById.remove({
+                realm: realm.realm,
+                role: $scope.role.id
+            }, function () {
+                $route.reload();
+                Notifications.success("The role has been deleted.");
+            });
+        });
+    };
+});
+
+
 module.controller('RoleListCtrl', function($scope, $route, Dialog, Notifications, realm, roles, RoleById, filterFilter) {
     $scope.realm = realm;
     $scope.roles = roles;
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/services.js b/themes/src/main/resources/theme/base/admin/resources/js/services.js
index fe09ebb..679a3c9 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -841,6 +841,28 @@ module.factory('Role', function($resource) {
     });
 });
 
+module.factory('RoleManagementPermissions', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/management/permissions', {
+        realm : '@realm',
+        role : '@role'
+    }, {
+        update: {
+            method: 'PUT'
+        }
+    });
+});
+
+module.factory('UsersManagementPermissions', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/users-management-permissions', {
+        realm : '@realm'
+    }, {
+        update: {
+            method: 'PUT'
+        }
+    });
+});
+
+
 module.factory('RoleById', function($resource) {
     return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role', {
         realm : '@realm',
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html
new file mode 100644
index 0000000..d2d6c14
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html
@@ -0,0 +1,41 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles">{{:: 'roles' | translate}}</a></li>
+        <li>{{role.name}}</li>
+    </ol>
+
+    <kc-tabs-client-role></kc-tabs-client-role>
+
+    <form class=form-horizontal" name="enableForm" novalidate kc-read-only="!access.manageAuthorization">
+        <fieldset class="border-top">
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="permissionsEnabled">{{:: 'permissions-enabled-role' | translate}}</label>
+            <div class="col-md-6">
+                <input ng-model="permissions.enabled" ng-click="setEnabled()" name="permissionsEnabled" id="permissionsEnabled" ng-disabled="!access.manageAuthorization" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+            </div>
+            <kc-tooltip>{{:: 'permissions-enabled-role.tooltip' | translate}}</kc-tooltip>
+        </div>
+        </fieldset>
+    </form>
+    <table class="datatable table table-striped table-bordered dataTable no-footer" data-ng-show="permissions.enabled">
+        <thead>
+        <tr>
+            <th>{{:: 'scope-name' | translate}}</th>
+            <th>{{:: 'description' | translate}}</th>
+            <th colspan="2">{{:: 'actions' | translate}}</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="(scopeName, scopeId) in permissions.scopePermissions">
+            <td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+            <td translate="{{scopeName}}-mgmt-scope-description"></td>
+            <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/scope/{{scopeId}}">{{:: 'edit' | translate}}</td>
+        </tr>
+        </tbody>
+    </table>
+
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html
new file mode 100644
index 0000000..860f20f
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html
@@ -0,0 +1,39 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/roles">{{:: 'roles' | translate}}</a></li>
+        <li>{{role.name}}</li>
+    </ol>
+
+    <kc-tabs-role></kc-tabs-role>
+
+    <form class=form-horizontal" name="enableForm" novalidate kc-read-only="!access.manageAuthorization">
+        <fieldset class="border-top">
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="permissionsEnabled">{{:: 'permissions-enabled' | translate}}</label>
+            <div class="col-md-6">
+                <input ng-model="permissions.enabled" ng-click="setEnabled()" name="permissionsEnabled" id="permissionsEnabled" ng-disabled="!access.manageAuthorization" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+            </div>
+            <kc-tooltip>{{:: 'permissions-enabled.tooltip' | translate}}</kc-tooltip>
+        </div>
+        </fieldset>
+    </form>
+    <table class="datatable table table-striped table-bordered dataTable no-footer" data-ng-show="permissions.enabled">
+        <thead>
+        <tr>
+            <th>{{:: 'scope-name' | translate}}</th>
+            <th>{{:: 'description' | translate}}</th>
+            <th colspan="2">{{:: 'actions' | translate}}</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="(scopeName, scopeId) in permissions.scopePermissions">
+            <td><a href="#/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+            <td translate="{{scopeName}}-mgmt-scope-description"></td>
+            <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{:: 'edit' | translate}}</td>
+        </tr>
+        </tbody>
+    </table>
+
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/users-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/users-permissions.html
new file mode 100644
index 0000000..03420d0
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/users-permissions.html
@@ -0,0 +1,35 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <kc-tabs-users></kc-tabs-users>
+
+    <form class=form-horizontal" name="enableForm" novalidate kc-read-only="!access.manageAuthorization">
+        <fieldset class="border-top">
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="permissionsEnabled">{{:: 'permissions-enabled' | translate}}</label>
+            <div class="col-md-6">
+                <input ng-model="permissions.enabled" ng-click="setEnabled()" name="permissionsEnabled" id="permissionsEnabled" ng-disabled="!access.manageAuthorization" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+            </div>
+            <kc-tooltip>{{:: 'permissions-enabled.tooltip' | translate}}</kc-tooltip>
+        </div>
+        </fieldset>
+    </form>
+    <table class="datatable table table-striped table-bordered dataTable no-footer" data-ng-show="permissions.enabled">
+        <thead>
+        <tr>
+            <th>{{:: 'scope-name' | translate}}</th>
+            <th>{{:: 'description' | translate}}</th>
+            <th colspan="2">{{:: 'actions' | translate}}</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="(scopeName, scopeId) in permissions.scopePermissions">
+            <td><a href="#/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+            <td translate="{{scopeName}}-mgmt-scope-description"></td>
+            <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{:: 'edit' | translate}}</td>
+        </tr>
+        </tbody>
+    </table>
+
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html
index de1a763..9c3e215 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-role-detail.html
@@ -8,9 +8,7 @@
         <li data-ng-hide="create">{{role.name}}</li>
     </ol>
 
-    <h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
-    <h1 data-ng-hide="create">{{role.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create && access.manageClients" 
-    	data-ng-hide="changed" data-ng-click="remove()"></i></h1>
+    <kc-tabs-client-role></kc-tabs-client-role>
 
     <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients">
 
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
index 97acab8..3bcaa66 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
@@ -6,9 +6,7 @@
         <li data-ng-show="create">{{:: 'add-role' | translate}}</li>
     </ol>
 
-    <h1 data-ng-hide="create">{{role.name|capitalize}} <i id="removeRole" class="pficon pficon-delete clickable" data-ng-show="!create && access.manageRealm" 
-    	data-ng-hide="changed" data-ng-click="remove()"></i></h1>
-    <h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
+    <kc-tabs-role></kc-tabs-role>
 
     <form class="form-horizontal clearfix" name="realmForm" novalidate kc-read-only="!access.manageRealm">
         <fieldset>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-list.html
index 4864acf..f1dd03b 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-list.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-list.html
@@ -1,5 +1,6 @@
 <div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2" ng-init="init()">
-    <h1>{{:: 'users' | translate}}</h1>
+
+    <kc-tabs-users></kc-tabs-users>
 
     <table class="table table-striped table-bordered">
         <caption data-ng-show="users" class="hidden">{{:: 'table-of-realm-users' | translate}}</caption>
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client-role.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client-role.html
new file mode 100755
index 0000000..9637186
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client-role.html
@@ -0,0 +1,13 @@
+<div data-ng-controller="RoleTabCtrl">
+    <h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
+    <h1 data-ng-hide="create">{{role.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create && access.manageClients"
+                                                         data-ng-hide="changed" data-ng-click="remove()"></i></h1>
+
+    <ul class="nav nav-tabs" data-ng-show="!create">
+        <li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
+        <li ng-class="{active: path[6] && path[6] == 'permissions'}">
+            <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
+            <kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
+        </li>
+    </ul>
+</div>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-role.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-role.html
new file mode 100755
index 0000000..5c2d71d
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-role.html
@@ -0,0 +1,13 @@
+<div data-ng-controller="RoleTabCtrl">
+    <h1 data-ng-hide="create">{{role.name|capitalize}} <i id="removeRole" class="pficon pficon-delete clickable" data-ng-show="!create && access.manageRealm"
+    	data-ng-hide="changed" data-ng-click="remove()"></i></h1>
+    <h1 data-ng-show="create">{{:: 'add-role' | translate}}</h1>
+
+    <ul class="nav nav-tabs" data-ng-show="!create">
+        <li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
+        <li ng-class="{active: path[4] == 'permissions'}">
+            <a href="#/realms/{{realm.realm}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
+            <kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
+        </li>
+    </ul>
+</div>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-users.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-users.html
new file mode 100755
index 0000000..8cc17ea
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-users.html
@@ -0,0 +1,11 @@
+<div >
+    <h1>{{:: 'users' | translate}}</h1>
+
+    <ul class="nav nav-tabs">
+        <li ng-class="{active: path[2] == 'users'}"><a href="#/realms/{{realm.realm}}/users">{{:: 'lookup' | translate}}</a></li>
+        <li ng-class="{active: path[2] == 'users-permissions'}">
+            <a href="#/realms/{{realm.realm}}/users-permissions">{{:: 'authz-permissions' | translate}}</a>
+            <kc-tooltip>{{:: 'manage-permissions-users.tooltip' | translate}}</kc-tooltip>
+        </li>
+    </ul>
+</div>
\ No newline at end of file