keycloak-aplcache

Changes

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

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
index cc9e54b..a7ca83e 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
@@ -65,6 +65,7 @@ public class ClientRepresentation {
     private Boolean useTemplateScope;
     private Boolean useTemplateMappers;
     private ResourceServerRepresentation authorizationSettings;
+    private Map<String, Boolean> access;
 
 
     public String getId() {
@@ -366,4 +367,12 @@ public class ClientRepresentation {
     public void setAuthorizationSettings(ResourceServerRepresentation authorizationSettings) {
         this.authorizationSettings = authorizationSettings;
     }
+
+    public Map<String, Boolean> getAccess() {
+        return access;
+    }
+
+    public void setAccess(Map<String, Boolean> access) {
+        this.access = access;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/GroupRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/GroupRepresentation.java
index 180db64..9c96970 100755
--- a/core/src/main/java/org/keycloak/representations/idm/GroupRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/GroupRepresentation.java
@@ -34,6 +34,7 @@ public class GroupRepresentation {
     protected List<String> realmRoles;
     protected Map<String, List<String>> clientRoles;
     protected List<GroupRepresentation> subGroups;
+    private Map<String, Boolean> access;
 
     public String getId() {
         return id;
@@ -97,4 +98,12 @@ public class GroupRepresentation {
     public void setSubGroups(List<GroupRepresentation> subGroups) {
         this.subGroups = subGroups;
     }
+
+    public Map<String, Boolean> getAccess() {
+        return access;
+    }
+
+    public void setAccess(Map<String, Boolean> access) {
+        this.access = access;
+    }
 }
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/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
index 2a4ec62..4dcea95 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
@@ -62,6 +62,7 @@ public class UserRepresentation {
     protected List<SocialLinkRepresentation> socialLinks;
 
     protected List<String> groups;
+    private Map<String, Boolean> access;
 
     public String getSelf() {
         return self;
@@ -264,4 +265,12 @@ public class UserRepresentation {
     public void setDisableableCredentialTypes(Set<String> disableableCredentialTypes) {
         this.disableableCredentialTypes = disableableCredentialTypes;
     }
+
+    public Map<String, Boolean> getAccess() {
+        return access;
+    }
+
+    public void setAccess(Map<String, Boolean> access) {
+        this.access = access;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/JsonWebToken.java b/core/src/main/java/org/keycloak/representations/JsonWebToken.java
index e499271..04071b6 100755
--- a/core/src/main/java/org/keycloak/representations/JsonWebToken.java
+++ b/core/src/main/java/org/keycloak/representations/JsonWebToken.java
@@ -141,6 +141,7 @@ public class JsonWebToken implements Serializable {
     }
 
     public boolean hasAudience(String audience) {
+        if (this.audience == null) return false;
         for (String a : this.audience) {
             if (a.equals(audience)) {
                 return true;
diff --git a/core/src/test/java/org/keycloak/RSAVerifierTest.java b/core/src/test/java/org/keycloak/RSAVerifierTest.java
index 58e1f38..e606e35 100755
--- a/core/src/test/java/org/keycloak/RSAVerifierTest.java
+++ b/core/src/test/java/org/keycloak/RSAVerifierTest.java
@@ -234,13 +234,16 @@ public class RSAVerifierTest {
     public void testTokenAuth() throws Exception {
         token = new AccessToken();
         token.subject("CN=Client")
-                .issuer("domain")
+                .issuer("http://localhost:8080/auth/realms/demo")
                 .addAccess("service").addRole("admin").verifyCaller(true);
+        token.setEmail("bill@jboss.org");
 
         String encoded = new JWSBuilder()
                 .jsonContent(token)
                 .rsa256(idpPair.getPrivate());
 
+        System.out.println("token size: " + encoded.length());
+
         AccessToken v = null;
         try {
             v = verifySkeletonKeyToken(encoded);
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientsResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientsResource.java
index 47b4db4..3c8552e 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientsResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientsResource.java
@@ -48,6 +48,10 @@ public interface ClientsResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
+    public List<ClientRepresentation> findAll(@QueryParam("viewableOnly") boolean viewableOnly);
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
     public List<ClientRepresentation> findByClientId(@QueryParam("clientId") String clientId);
 
 
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
index 9ee63b6..fabdd9c 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
@@ -59,12 +59,6 @@ public class ResourceServerEntity {
     @Column(name = "POLICY_ENFORCE_MODE")
     private PolicyEnforcementMode policyEnforcementMode = PolicyEnforcementMode.ENFORCING;
 
-    @OneToMany(mappedBy = "resourceServer")
-    private List<ResourceEntity> resources;
-
-    @OneToMany (mappedBy = "resourceServer")
-    private List<ScopeEntity> scopes;
-
     public String getId() {
         return this.id;
     }
@@ -97,22 +91,6 @@ public class ResourceServerEntity {
         this.policyEnforcementMode = policyEnforcementMode;
     }
 
-    public List<ResourceEntity> getResources() {
-        return this.resources;
-    }
-
-    public void setResources(final List<ResourceEntity> resources) {
-        this.resources = resources;
-    }
-
-    public List<ScopeEntity> getScopes() {
-        return this.scopes;
-    }
-
-    public void setScopes(final List<ScopeEntity> scopes) {
-        this.scopes = scopes;
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
index 20404e5..8eb1037 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
@@ -19,9 +19,13 @@ package org.keycloak.authorization.jpa.store;
 
 import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.jpa.entities.PolicyEntity;
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
 import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
 import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
 import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
 import org.keycloak.authorization.store.ResourceServerStore;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
@@ -65,24 +69,45 @@ public class JPAResourceServerStore implements ResourceServerStore {
         //entityManager.createNamedQuery("deletePolicyByResourceServer")
         //        .setParameter("serverId", id).executeUpdate();
 
-        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
-        query.setParameter("serverId", id);
-        List<String> result = query.getResultList();
-        List<Policy> list = new LinkedList<>();
-        for (String policyId : result) {
-            entityManager.remove(entityManager.getReference(PolicyEntity.class, policyId));
+        {
+            TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
+            query.setParameter("serverId", id);
+            List<String> result = query.getResultList();
+            for (String policyId : result) {
+                entityManager.remove(entityManager.getReference(PolicyEntity.class, policyId));
+            }
         }
 
-        entityManager.flush();
-        entityManager.createNamedQuery("deleteResourceByResourceServer")
-                .setParameter("serverId", id).executeUpdate();
-        entityManager.flush();
-        entityManager.createNamedQuery("deleteScopeByResourceServer")
-                .setParameter("serverId", id).executeUpdate();
-        entityManager.flush();
+        //entityManager.createNamedQuery("deleteResourceByResourceServer")
+        //        .setParameter("serverId", id).executeUpdate();
+        {
+            TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByServerId", String.class);
+
+            query.setParameter("serverId", id);
+
+            List<String> result = query.getResultList();
+            List<Resource> list = new LinkedList<>();
+            for (String resourceId : result) {
+                entityManager.remove(entityManager.getReference(ResourceEntity.class, resourceId));
+            }
+        }
+
+        //entityManager.createNamedQuery("deleteScopeByResourceServer")
+        //        .setParameter("serverId", id).executeUpdate();
+        {
+            TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByResourceServer", String.class);
+
+            query.setParameter("serverId", id);
+
+            List<String> result = query.getResultList();
+            for (String scopeId : result) {
+                entityManager.remove(entityManager.getReference(ScopeEntity.class, scopeId));
+            }
+        }
 
         this.entityManager.remove(entity);
         entityManager.flush();
+        entityManager.detach(entity);
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
index 5c53d45..219b9a5 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
@@ -360,6 +360,24 @@ public class JpaRealmProvider implements RealmProvider {
             return false;
         }
 
+        GroupModel.GroupRemovedEvent event = new GroupModel.GroupRemovedEvent() {
+            @Override
+            public RealmModel getRealm() {
+                return realm;
+            }
+
+            @Override
+            public GroupModel getGroup() {
+                return group;
+            }
+
+            @Override
+            public KeycloakSession getKeycloakSession() {
+                return session;
+            }
+        };
+        session.getKeycloakSessionFactory().publish(event);
+
         session.users().preRemove(realm, group);
 
         realm.removeDefaultGroup(group);
diff --git a/server-spi/src/main/java/org/keycloak/models/GroupModel.java b/server-spi/src/main/java/org/keycloak/models/GroupModel.java
index 5a0e006..aac0ddb 100755
--- a/server-spi/src/main/java/org/keycloak/models/GroupModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/GroupModel.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.models;
 
+import org.keycloak.provider.ProviderEvent;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -26,6 +28,11 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 public interface GroupModel extends RoleMapperModel {
+    interface GroupRemovedEvent extends ProviderEvent {
+        RealmModel getRealm();
+        GroupModel getGroup();
+        KeycloakSession getKeycloakSession();
+    }
     String getId();
 
     String getName();
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResult.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResult.java
new file mode 100644
index 0000000..2189c32
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResult.java
@@ -0,0 +1,51 @@
+/*
+ * 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.authorization.policy.evaluation;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DecisionResult extends DecisionResultCollector {
+    protected List<Result> results;
+    protected Throwable error;
+
+    @Override
+    protected void onComplete(List<Result> results) {
+        this.results = results;
+
+    }
+
+    @Override
+    public void onError(Throwable cause) {
+        this.error = cause;
+    }
+
+    public boolean completed() {
+        return results != null && error == null;
+    }
+
+    public List<Result> getResults() {
+        return results;
+    }
+
+    public Throwable getError() {
+        return error;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/RealmSynchronizer.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/RealmSynchronizer.java
index ed24c53..971ae31 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/RealmSynchronizer.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/RealmSynchronizer.java
@@ -40,9 +40,9 @@ public class RealmSynchronizer implements Synchronizer<RealmRemovedEvent> {
 
             if (resourceServer != null) {
                 String id = resourceServer.getId();
-                storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
-                storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
-                storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
+                //storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
+                //storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
+                //storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
                 storeFactory.getResourceServerStore().delete(id);
             }
         });
diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java
index 85f2296..17cd0ac 100644
--- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java
+++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java
@@ -14,18 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.keycloak.migration.migrators;
 
-
+import org.keycloak.migration.ModelVersion;
+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.migration.ModelVersion;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
 
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
 public class MigrateTo3_2_0 implements Migration {
 
-    public static final ModelVersion VERSION = new ModelVersion("3.1.0");
+    public static final ModelVersion VERSION = new ModelVersion("3.2.0");
 
     @Override
     public void migrate(KeycloakSession session) {
@@ -34,6 +43,33 @@ public class MigrateTo3_2_0 implements Migration {
             if (!builder.contains(PasswordPolicy.HASH_ALGORITHM_ID) && "20000".equals(builder.get(PasswordPolicy.HASH_ITERATIONS_ID))) {
                 realm.setPasswordPolicy(builder.remove(PasswordPolicy.HASH_ITERATIONS_ID).build(session));
             }
+
+            ClientModel realmAccess = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+            if (realmAccess != null) {
+                addRoles(realmAccess);
+            }
+            ClientModel masterAdminClient = realm.getMasterAdminClient();
+            if (masterAdminClient != null) {
+                addRoles(masterAdminClient);
+
+            }
+
+        }
+    }
+
+    public void addRoles(ClientModel realmAccess) {
+        RoleModel queryClients = realmAccess.addRole(AdminRoles.QUERY_CLIENTS);
+        RoleModel queryUsers = realmAccess.addRole(AdminRoles.QUERY_USERS);
+        RoleModel queryGroups = realmAccess.addRole(AdminRoles.QUERY_GROUPS);
+
+        RoleModel viewClients = realmAccess.getRole(AdminRoles.VIEW_CLIENTS);
+        if (viewClients != null) {
+            viewClients.addCompositeRole(queryClients);
+        }
+        RoleModel viewUsers = realmAccess.getRole(AdminRoles.VIEW_USERS);
+        if (viewUsers != null) {
+            viewUsers.addCompositeRole(queryUsers);
+            viewUsers.addCompositeRole(queryGroups);
         }
     }
 
@@ -41,5 +77,4 @@ public class MigrateTo3_2_0 implements Migration {
     public ModelVersion getVersion() {
         return VERSION;
     }
-
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/models/AdminRoles.java b/server-spi-private/src/main/java/org/keycloak/models/AdminRoles.java
index 24455b8..c2304e8 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/AdminRoles.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/AdminRoles.java
@@ -17,6 +17,9 @@
 
 package org.keycloak.models;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
@@ -46,6 +49,21 @@ public class AdminRoles {
     public static String MANAGE_EVENTS = "manage-events";
     public static String MANAGE_AUTHORIZATION = "manage-authorization";
 
-    public static String[] ALL_REALM_ROLES = {CREATE_CLIENT, VIEW_REALM, VIEW_USERS, VIEW_CLIENTS, VIEW_EVENTS, VIEW_IDENTITY_PROVIDERS, VIEW_AUTHORIZATION, MANAGE_REALM, MANAGE_USERS, MANAGE_CLIENTS, MANAGE_EVENTS, MANAGE_IDENTITY_PROVIDERS, MANAGE_AUTHORIZATION};
+    public static String QUERY_USERS = "query-users";
+    public static String QUERY_CLIENTS = "query-clients";
+    public static String QUERY_REALMS = "query-realms";
+    public static String QUERY_GROUPS = "query-groups";
+
+    public static String[] ALL_REALM_ROLES = {CREATE_CLIENT, VIEW_REALM, VIEW_USERS, VIEW_CLIENTS, VIEW_EVENTS, VIEW_IDENTITY_PROVIDERS, VIEW_AUTHORIZATION, MANAGE_REALM, MANAGE_USERS, MANAGE_CLIENTS, MANAGE_EVENTS, MANAGE_IDENTITY_PROVIDERS, MANAGE_AUTHORIZATION, QUERY_USERS, QUERY_CLIENTS, QUERY_REALMS, QUERY_GROUPS};
 
+    public static Set<String> ALL_ROLES = new HashSet<>();
+    static {
+        for (String name : ALL_REALM_ROLES) {
+            ALL_ROLES.add(name);
+        }
+        ALL_ROLES.add(ImpersonationConstants.IMPERSONATION_ROLE);
+        ALL_ROLES.add(ADMIN);
+        ALL_ROLES.add(CREATE_REALM);
+        ALL_ROLES.add(CREATE_CLIENT);
+    }
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index bdde153..6a7aeaa 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -168,7 +168,6 @@ public class ModelToRepresentation {
         return rep;
     }
 
-
     public static UserRepresentation toRepresentation(KeycloakSession session, RealmModel realm, UserModel user) {
         UserRepresentation rep = new UserRepresentation();
         rep.setId(user.getId());
diff --git a/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
index bc9dd1f..535634b 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
@@ -23,8 +23,8 @@ import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 
 import javax.ws.rs.Path;
 
@@ -33,22 +33,20 @@ import javax.ws.rs.Path;
  */
 public class AuthorizationService {
 
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final ClientModel client;
+    private final KeycloakSession session;
     private final ResourceServer resourceServer;
     private final AuthorizationProvider authorization;
     private final AdminEventBuilder adminEvent;
 
-    public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public AuthorizationService(KeycloakSession session, ClientModel client, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
+        this.session = session;
         this.client = client;
         this.authorization = session.getProvider(AuthorizationProvider.class);
         this.adminEvent = adminEvent;
         this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().findByClient(this.client.getId());
         this.auth = auth;
-
-        if (auth != null) {
-            this.auth.init(RealmAuth.Resource.AUTHORIZATION);
-        }
     }
 
     @Path("/resource-server")
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java b/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java
index ea4677d..6973b4d 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PermissionService.java
@@ -22,15 +22,15 @@ import java.util.Map;
 import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 public class PermissionService extends PolicyService {
 
-    public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         super(resourceServer, authorization, auth, adminEvent);
     }
 
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
index 5d9114f..ecebaae 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
@@ -71,7 +71,7 @@ import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.resources.admin.RealmAuth;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.sessions.AuthenticationSessionModel;
 
 /**
@@ -80,13 +80,13 @@ import org.keycloak.sessions.AuthenticationSessionModel;
 public class PolicyEvaluationService {
 
     private final AuthorizationProvider authorization;
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     @Context
     private HttpRequest httpRequest;
 
     private final ResourceServer resourceServer;
 
-    PolicyEvaluationService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+    PolicyEvaluationService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth) {
         this.resourceServer = resourceServer;
         this.authorization = authorization;
         this.auth = auth;
@@ -118,7 +118,7 @@ public class PolicyEvaluationService {
     @Consumes("application/json")
     @Produces("application/json")
     public Response evaluate(PolicyEvaluationRequest evaluationRequest) throws Throwable {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         CloseableKeycloakIdentity identity = createIdentity(evaluationRequest);
         try {
             return Response.ok(PolicyEvaluationResponseBuilder.build(evaluate(evaluationRequest, createEvaluationContext(evaluationRequest, identity)), resourceServer, authorization, identity)).build();
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
index c0728bc..b32899f 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
@@ -46,8 +46,8 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
 import org.keycloak.representations.idm.authorization.PolicyRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 import org.keycloak.util.JsonSerialization;
 
 /**
@@ -58,10 +58,10 @@ public class PolicyResourceService {
     private final Policy policy;
     protected final ResourceServer resourceServer;
     protected final AuthorizationProvider authorization;
-    protected final RealmAuth auth;
+    protected final AdminPermissionEvaluator auth;
     private final AdminEventBuilder adminEvent;
 
-    public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.policy = policy;
         this.resourceServer = resourceServer;
         this.authorization = authorization;
@@ -73,8 +73,8 @@ public class PolicyResourceService {
     @Consumes("application/json")
     @Produces("application/json")
     @NoCache
-    public Response update(@Context UriInfo uriInfo,  String payload) {
-        this.auth.requireManage();
+    public Response update(@Context UriInfo uriInfo,String payload) {
+        this.auth.realm().requireManageAuthorization();
 
         AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
 
@@ -94,7 +94,7 @@ public class PolicyResourceService {
 
     @DELETE
     public Response delete(@Context UriInfo uriInfo) {
-        this.auth.requireManage();
+        this.auth.realm().requireManageAuthorization();
 
         if (policy == null) {
             return Response.status(Status.NOT_FOUND).build();
@@ -119,7 +119,7 @@ public class PolicyResourceService {
     @Produces("application/json")
     @NoCache
     public Response findById() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
 
         if (policy == null) {
             return Response.status(Status.NOT_FOUND).build();
@@ -137,7 +137,7 @@ public class PolicyResourceService {
     @Produces("application/json")
     @NoCache
     public Response getDependentPolicies() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
 
         if (policy == null) {
             return Response.status(Status.NOT_FOUND).build();
@@ -161,7 +161,7 @@ public class PolicyResourceService {
     @Produces("application/json")
     @NoCache
     public Response getScopes() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
 
         if (policy == null) {
             return Response.status(Status.NOT_FOUND).build();
@@ -182,7 +182,7 @@ public class PolicyResourceService {
     @Produces("application/json")
     @NoCache
     public Response getResources() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
 
         if (policy == null) {
             return Response.status(Status.NOT_FOUND).build();
@@ -203,7 +203,7 @@ public class PolicyResourceService {
     @Produces("application/json")
     @NoCache
     public Response getAssociatedPolicies() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
 
         if (policy == null) {
             return Response.status(Status.NOT_FOUND).build();
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
index e8d4aa8..33e6299 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
@@ -57,8 +57,8 @@ import org.keycloak.representations.idm.authorization.PolicyProviderRepresentati
 import org.keycloak.representations.idm.authorization.PolicyRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 import org.keycloak.util.JsonSerialization;
 
 /**
@@ -68,10 +68,10 @@ public class PolicyService {
 
     protected final ResourceServer resourceServer;
     protected final AuthorizationProvider authorization;
-    protected final RealmAuth auth;
+    protected final AdminPermissionEvaluator auth;
     protected final AdminEventBuilder adminEvent;
 
-    public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.resourceServer = resourceServer;
         this.authorization = authorization;
         this.auth = auth;
@@ -103,8 +103,8 @@ public class PolicyService {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
-    public Response create(@Context UriInfo uriInfo,  String payload) {
-        this.auth.requireManage();
+    public Response create(@Context UriInfo uriInfo, String payload) {
+        this.auth.realm().requireManageAuthorization();
 
         AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
         Policy policy = create(representation);
@@ -144,7 +144,7 @@ public class PolicyService {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public Response findByName(@QueryParam("name") String name) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         StoreFactory storeFactory = authorization.getStoreFactory();
 
         if (name == null) {
@@ -171,7 +171,7 @@ public class PolicyService {
                             @QueryParam("permission") Boolean permission,
                             @QueryParam("first") Integer firstResult,
                             @QueryParam("max") Integer maxResult) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
 
         Map<String, String[]> search = new HashMap<>();
 
@@ -250,7 +250,7 @@ public class PolicyService {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public Response findPolicyProviders() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         return Response.ok(
                 authorization.getProviderFactories().stream()
                         .map(provider -> {
@@ -268,7 +268,7 @@ public class PolicyService {
 
     @Path("evaluate")
     public PolicyEvaluationService getPolicyEvaluateResource() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         PolicyEvaluationService resource = new PolicyEvaluationService(this.resourceServer, this.authorization, this.auth);
 
         ResteasyProviderFactory.getInstance().injectProperties(resource);
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java
index 9044c0d..1297b6a 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java
@@ -24,8 +24,8 @@ import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 import org.keycloak.util.JsonSerialization;
 
 /**
@@ -33,7 +33,7 @@ import org.keycloak.util.JsonSerialization;
  */
 public class PolicyTypeResourceService extends PolicyResourceService {
 
-    public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         super(policy, resourceServer, authorization, auth, adminEvent);
     }
 
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java
index 6f37f6c..4b41e94 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeService.java
@@ -30,8 +30,8 @@ import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
 import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 import org.keycloak.util.JsonSerialization;
 
 /**
@@ -41,7 +41,7 @@ public class PolicyTypeService extends PolicyService {
 
     private final String type;
 
-    PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+    PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         super(resourceServer, authorization, auth, adminEvent);
         this.type = type;
     }
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
index 777d843..e52da9a 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
@@ -56,8 +56,8 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
 import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@@ -65,7 +65,7 @@ import org.keycloak.services.resources.admin.RealmAuth;
 public class ResourceServerService {
 
     private final AuthorizationProvider authorization;
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final AdminEventBuilder adminEvent;
     private final KeycloakSession session;
     private ResourceServer resourceServer;
@@ -74,7 +74,7 @@ public class ResourceServerService {
     @Context
     private UriInfo uriInfo;
 
-    public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.authorization = authorization;
         this.session = authorization.getKeycloakSession();
         this.client = client;
@@ -84,7 +84,7 @@ public class ResourceServerService {
     }
 
     public void create(boolean newClient) {
-        this.auth.requireManage();
+        this.auth.realm().requireManageAuthorization();
 
         UserModel serviceAccount = this.session.users().getServiceAccount(client);
 
@@ -101,8 +101,8 @@ public class ResourceServerService {
     @PUT
     @Consumes("application/json")
     @Produces("application/json")
-    public Response update(@Context UriInfo uriInfo, ResourceServerRepresentation server) {
-        this.auth.requireManage();
+    public Response update(ResourceServerRepresentation server) {
+        this.auth.realm().requireManageAuthorization();
         this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement());
         this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode());
         audit(OperationType.UPDATE, uriInfo, false);
@@ -110,7 +110,7 @@ public class ResourceServerService {
     }
 
     public void delete() {
-        this.auth.requireManage();
+        this.auth.realm().requireManageAuthorization();
         StoreFactory storeFactory = authorization.getStoreFactory();
         ResourceStore resourceStore = storeFactory.getResourceStore();
         String id = resourceServer.getId();
@@ -133,7 +133,7 @@ public class ResourceServerService {
     @GET
     @Produces("application/json")
     public Response findById() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         return Response.ok(toRepresentation(this.resourceServer, this.client)).build();
     }
 
@@ -141,7 +141,7 @@ public class ResourceServerService {
     @GET
     @Produces("application/json")
     public Response exportSettings() {
-        this.auth.requireManage();
+        this.auth.realm().requireManageAuthorization();
         return Response.ok(ExportUtils.exportAuthorizationSettings(session, client)).build();
     }
 
@@ -149,7 +149,7 @@ public class ResourceServerService {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response importSettings(@Context final UriInfo uriInfo, ResourceServerRepresentation rep) throws IOException {
-        this.auth.requireManage();
+        this.auth.realm().requireManageAuthorization();
 
         rep.setClientId(client.getId());
 
@@ -189,7 +189,7 @@ public class ResourceServerService {
 
     @Path("/permission")
     public Object getPermissionTypeResource() {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         PermissionService resource = new PermissionService(this.resourceServer, this.authorization, this.auth, adminEvent);
 
         ResteasyProviderFactory.getInstance().injectProperties(resource);
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
index 3c7f34f..7c95281 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
@@ -39,8 +39,8 @@ import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentatio
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -74,11 +74,11 @@ import static org.keycloak.models.utils.RepresentationToModel.toModel;
 public class ResourceSetService {
 
     private final AuthorizationProvider authorization;
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final AdminEventBuilder adminEvent;
     private ResourceServer resourceServer;
 
-    public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.resourceServer = resourceServer;
         this.authorization = authorization;
         this.auth = auth;
@@ -292,7 +292,7 @@ public class ResourceSetService {
     @NoCache
     @Produces("application/json")
     public Response find(@QueryParam("name") String name) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         StoreFactory storeFactory = authorization.getStoreFactory();
 
         if (name == null) {
@@ -387,13 +387,13 @@ public class ResourceSetService {
 
     private void requireView() {
         if (this.auth != null) {
-            this.auth.requireView();
+            this.auth.realm().requireViewAuthorization();
         }
     }
 
     private void requireManage() {
         if (this.auth != null) {
-            this.auth.requireManage();
+            this.auth.realm().requireManageAuthorization();
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java b/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
index a2a2320..1ab3546 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
@@ -32,8 +32,8 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.resources.admin.AdminEventBuilder;
-import org.keycloak.services.resources.admin.RealmAuth;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -65,11 +65,11 @@ import static org.keycloak.models.utils.RepresentationToModel.toModel;
 public class ScopeService {
 
     private final AuthorizationProvider authorization;
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final AdminEventBuilder adminEvent;
     private ResourceServer resourceServer;
 
-    public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.resourceServer = resourceServer;
         this.authorization = authorization;
         this.auth = auth;
@@ -81,7 +81,7 @@ public class ScopeService {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Response create(@Context UriInfo uriInfo,  ScopeRepresentation scope) {
-        this.auth.requireManage();
+            this.auth.realm().requireManageAuthorization();
         Scope model = toModel(scope, this.resourceServer, authorization);
 
         scope.setId(model.getId());
@@ -96,7 +96,7 @@ public class ScopeService {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, ScopeRepresentation scope) {
-        this.auth.requireManage();
+            this.auth.realm().requireManageAuthorization();
         scope.setId(id);
         StoreFactory storeFactory = authorization.getStoreFactory();
         Scope model = storeFactory.getScopeStore().findById(scope.getId(), resourceServer.getId());
@@ -115,7 +115,7 @@ public class ScopeService {
     @Path("{id}")
     @DELETE
     public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
-        this.auth.requireManage();
+        this.auth.realm().requireManageAuthorization();
         StoreFactory storeFactory = authorization.getStoreFactory();
         List<Resource> resources = storeFactory.getResourceStore().findByScope(Arrays.asList(id), resourceServer.getId());
 
@@ -154,7 +154,7 @@ public class ScopeService {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Response findById(@PathParam("id") String id) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         Scope model = this.authorization.getStoreFactory().getScopeStore().findById(id, resourceServer.getId());
 
         if (model == null) {
@@ -169,7 +169,7 @@ public class ScopeService {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Response getResources(@PathParam("id") String id) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         StoreFactory storeFactory = this.authorization.getStoreFactory();
         Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId());
 
@@ -192,7 +192,7 @@ public class ScopeService {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Response getPermissions(@PathParam("id") String id) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         StoreFactory storeFactory = this.authorization.getStoreFactory();
         Scope model = storeFactory.getScopeStore().findById(id, resourceServer.getId());
 
@@ -218,7 +218,7 @@ public class ScopeService {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public Response find(@QueryParam("name") String name) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
         StoreFactory storeFactory = authorization.getStoreFactory();
 
         if (name == null) {
@@ -241,7 +241,7 @@ public class ScopeService {
                             @QueryParam("name") String name,
                             @QueryParam("first") Integer firstResult,
                             @QueryParam("max") Integer maxResult) {
-        this.auth.requireView();
+        this.auth.realm().requireViewAuthorization();
 
         Map<String, String[]> search = new HashMap<>();
 
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
index fc929ec..da3cb0f 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
@@ -18,34 +18,28 @@
 
 package org.keycloak.authorization.common;
 
-import org.keycloak.authorization.attribute.Attributes;
 import org.keycloak.authorization.identity.Identity;
-import org.keycloak.authorization.policy.evaluation.EvaluationContext;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.representations.AccessToken;
 
-import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
-public class KeycloakEvaluationContext implements EvaluationContext {
+public class KeycloakEvaluationContext extends DefaultEvaluationContext {
 
     private final KeycloakIdentity identity;
-    private final KeycloakSession keycloakSession;
 
     public KeycloakEvaluationContext(KeycloakSession keycloakSession) {
         this(new KeycloakIdentity(keycloakSession), keycloakSession);
     }
 
     public KeycloakEvaluationContext(KeycloakIdentity identity, KeycloakSession keycloakSession) {
+        super(identity, keycloakSession);
         this.identity = identity;
-        this.keycloakSession = keycloakSession;
     }
 
     @Override
@@ -54,27 +48,13 @@ public class KeycloakEvaluationContext implements EvaluationContext {
     }
 
     @Override
-    public Attributes getAttributes() {
-        HashMap<String, Collection<String>> attributes = new HashMap<>();
-
-        attributes.put("kc.time.date_time", Arrays.asList(new SimpleDateFormat("MM/dd/yyyy hh:mm:ss").format(new Date())));
-        attributes.put("kc.client.network.ip_address", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteAddr()));
-        attributes.put("kc.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));
-
+    public Map<String, Collection<String>> getBaseAttributes() {
+        Map<String, Collection<String>> attributes = super.getBaseAttributes();
         AccessToken accessToken = this.identity.getAccessToken();
 
         if (accessToken != null) {
             attributes.put("kc.client.id", Arrays.asList(accessToken.getIssuedFor()));
         }
-
-        List<String> userAgents = this.keycloakSession.getContext().getRequestHeaders().getRequestHeader("User-Agent");
-
-        if (userAgents != null) {
-            attributes.put("kc.client.user_agent", userAgents);
-        }
-
-        attributes.put("kc.realm.name", Arrays.asList(this.keycloakSession.getContext().getRealm().getName()));
-
-        return Attributes.from(attributes);
+        return attributes;
     }
 }
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
index 9ea53e2..59963ba 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
@@ -53,6 +53,74 @@ public class KeycloakIdentity implements Identity {
         this(Tokens.getAccessToken(keycloakSession), keycloakSession);
     }
 
+    public KeycloakIdentity(KeycloakSession keycloakSession, AccessToken accessToken) {
+        this(accessToken, keycloakSession, keycloakSession.getContext().getRealm());
+    }
+
+    public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession, RealmModel realm) {
+        if (accessToken == null) {
+            throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
+        }
+        if (keycloakSession == null) {
+            throw new ErrorResponseException("no_keycloak_session", "No keycloak session", Status.FORBIDDEN);
+        }
+        if (realm == null) {
+            throw new ErrorResponseException("no_keycloak_session", "No realm set", Status.FORBIDDEN);
+        }
+        this.accessToken = accessToken;
+        this.keycloakSession = keycloakSession;
+        this.realm = realm;
+
+        Map<String, Collection<String>> attributes = new HashMap<>();
+
+        try {
+            ObjectNode objectNode = JsonSerialization.createObjectNode(this.accessToken);
+            Iterator<String> iterator = objectNode.fieldNames();
+
+            while (iterator.hasNext()) {
+                String fieldName = iterator.next();
+                JsonNode fieldValue = objectNode.get(fieldName);
+                List<String> values = new ArrayList<>();
+
+                if (fieldValue.isArray()) {
+                    Iterator<JsonNode> valueIterator = fieldValue.iterator();
+
+                    while (valueIterator.hasNext()) {
+                        values.add(valueIterator.next().asText());
+                    }
+                } else {
+                    String value = fieldValue.asText();
+
+                    if (StringUtil.isNullOrEmpty(value)) {
+                        continue;
+                    }
+
+                    values.add(value);
+                }
+
+                if (!values.isEmpty()) {
+                    attributes.put(fieldName, values);
+                }
+            }
+
+            AccessToken.Access realmAccess = accessToken.getRealmAccess();
+
+            if (realmAccess != null) {
+                attributes.put("kc.realm.roles", realmAccess.getRoles());
+            }
+
+            Map<String, AccessToken.Access> resourceAccess = accessToken.getResourceAccess();
+
+            if (resourceAccess != null) {
+                resourceAccess.forEach((clientId, access) -> attributes.put("kc.client." + clientId + ".roles", access.getRoles()));
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Error while reading attributes from security token.", e);
+        }
+
+        this.attributes = Attributes.from(attributes);
+    }
+
     public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession) {
         if (accessToken == null) {
             throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
diff --git a/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java b/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java
index 67e6bb4..c54e4c0 100644
--- a/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java
+++ b/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java
@@ -34,7 +34,8 @@ public class UserModelIdentity implements Identity {
     protected RealmModel realm;
     protected UserModel user;
 
-    public UserModelIdentity(UserModel user) {
+    public UserModelIdentity(RealmModel realm, UserModel user) {
+        this.realm = realm;
         this.user = user;
     }
 
diff --git a/services/src/main/java/org/keycloak/authorization/util/Permissions.java b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
index 325c056..b0e5daa 100644
--- a/services/src/main/java/org/keycloak/authorization/util/Permissions.java
+++ b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
@@ -19,6 +19,8 @@
 package org.keycloak.authorization.util;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -48,6 +50,10 @@ import org.keycloak.representations.idm.authorization.Permission;
  */
 public final class Permissions {
 
+    public static List<ResourcePermission> permission(ResourceServer server, Resource resource, Scope scope) {
+       return Arrays.asList(new ResourcePermission(resource, Arrays.asList(scope), server));
+    }
+
     /**
      * Returns a list of permissions for all resources and scopes that belong to the given <code>resourceServer</code> and
      * <code>identity</code>.
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
index 9b2b284..dfed5aa 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
@@ -31,12 +31,15 @@ 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.protocol.oidc.utils.AuthorizeClientUtil;
 import org.keycloak.representations.JsonWebToken;
 import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.clientregistration.policy.RegistrationAuth;
 import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyException;
 import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
+import org.keycloak.services.managers.RealmManager;
 import org.keycloak.util.TokenUtil;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -231,42 +234,70 @@ public class ClientRegistrationAuth {
         return initialAccessModel;
     }
 
-    private boolean hasRole(String... role) {
+    private boolean hasRole(String... roles) {
         try {
-            Map<String, Object> otherClaims = jwt.getOtherClaims();
-            if (otherClaims != null) {
-                Map<String, Map<String, List<String>>> resourceAccess = (Map<String, Map<String, List<String>>>) jwt.getOtherClaims().get("resource_access");
-                if (resourceAccess == null) {
-                    return false;
-                }
+            if (jwt.getIssuedFor().equals(Constants.ADMIN_CLI_CLIENT_ID)
+                    || jwt.getIssuedFor().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
+                return hasRoleInModel(roles);
 
-                List<String> roles = null;
+            } else {
+                return hasRoleInToken(roles);
+            }
+        } catch (Throwable t) {
+            return false;
+        }
+    }
 
-                Map<String, List<String>> map;
-                if (realm.getName().equals(Config.getAdminRealm())) {
-                    map = resourceAccess.get(realm.getMasterAdminClient().getClientId());
-                } else {
-                    map = resourceAccess.get(Constants.REALM_MANAGEMENT_CLIENT_ID);
-                }
+    private boolean hasRoleInModel(String[] roles) {
+        ClientModel roleNamespace;
+        UserModel user = session.users().getUserById(jwt.getSubject(), realm);
+        if (user == null) {
+            return false;
+        }
+        if (realm.getName().equals(Config.getAdminRealm())) {
+            roleNamespace = realm.getMasterAdminClient();
+        } else {
+            roleNamespace = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        }
+        for (String role : roles) {
+            RoleModel roleModel = roleNamespace.getRole(role);
+            if (user.hasRole(roleModel)) return true;
+        }
+        return false;
+    }
 
-                if (map != null) {
-                    roles = map.get("roles");
-                }
+    private boolean hasRoleInToken(String[] role) {
+        Map<String, Object> otherClaims = jwt.getOtherClaims();
+        if (otherClaims != null) {
+            Map<String, Map<String, List<String>>> resourceAccess = (Map<String, Map<String, List<String>>>) jwt.getOtherClaims().get("resource_access");
+            if (resourceAccess == null) {
+                return false;
+            }
 
-                if (roles == null) {
-                    return false;
-                }
+            List<String> roles = null;
+
+            Map<String, List<String>> map;
+            if (realm.getName().equals(Config.getAdminRealm())) {
+                map = resourceAccess.get(realm.getMasterAdminClient().getClientId());
+            } else {
+                map = resourceAccess.get(Constants.REALM_MANAGEMENT_CLIENT_ID);
+            }
 
-                for (String r : role) {
-                    if (roles.contains(r)) {
-                        return true;
-                    }
+            if (map != null) {
+                roles = map.get("roles");
+            }
+
+            if (roles == null) {
+                return false;
+            }
+
+            for (String r : role) {
+                if (roles.contains(r)) {
+                    return true;
                 }
             }
-            return false;
-        } catch (Throwable t) {
-            return false;
         }
+        return false;
     }
 
     private boolean authenticateClient(ClientModel client) {
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index 0134229..0869c5d 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -30,6 +30,7 @@ import org.keycloak.provider.ProviderManager;
 import org.keycloak.provider.ProviderManagerDeployer;
 import org.keycloak.provider.ProviderManagerRegistry;
 import org.keycloak.provider.Spi;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -93,6 +94,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
         }
         // make the session factory ready for hot deployment
         ProviderManagerRegistry.SINGLETON.setDeployer(this);
+        AdminPermissions.registerListener(this);
 
     }
     protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> getFactoriesCopy() {
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index a83d80d..bab0440 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -159,7 +159,6 @@ public class RealmManager {
             ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
             adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
         }
-        adminConsole.addScopeMapping(adminRole);
     }
 
     protected void setupAdminConsoleLocaleMapper(RealmModel realm) {
@@ -194,10 +193,21 @@ public class RealmManager {
                 ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
                 adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
             }
-            adminCli.addScopeMapping(adminRole);
         }
 
     }
+    public void addQueryCompositeRoles(ClientModel realmAccess) {
+        RoleModel queryClients = realmAccess.getRole(AdminRoles.QUERY_CLIENTS);
+        RoleModel queryUsers = realmAccess.getRole(AdminRoles.QUERY_USERS);
+        RoleModel queryGroups = realmAccess.getRole(AdminRoles.QUERY_GROUPS);
+
+        RoleModel viewClients = realmAccess.getRole(AdminRoles.VIEW_CLIENTS);
+        viewClients.addCompositeRole(queryClients);
+        RoleModel viewUsers = realmAccess.getRole(AdminRoles.VIEW_USERS);
+        viewUsers.addCompositeRole(queryUsers);
+        viewUsers.addCompositeRole(queryGroups);
+    }
+
 
     public String getRealmAdminClientId(RealmModel realm) {
         return Constants.REALM_MANAGEMENT_CLIENT_ID;
@@ -325,6 +335,7 @@ public class RealmManager {
             role.setScopeParamRequired(false);
             adminRole.addCompositeRole(role);
         }
+        addQueryCompositeRoles(realmAdminApp);
     }
 
     private void checkMasterAdminManagementRoles(RealmModel realm) {
@@ -338,6 +349,7 @@ public class RealmManager {
                 addAndSetAdminRole(r, masterAdminClient, adminRole);
             }
         }
+        addQueryCompositeRoles(masterAdminClient);
     }
 
 
@@ -360,6 +372,7 @@ public class RealmManager {
         for (String r : AdminRoles.ALL_REALM_ROLES) {
             addAndSetAdminRole(r, realmAdminClient, adminRole);
         }
+        addQueryCompositeRoles(realmAdminClient);
     }
 
     private void addAndSetAdminRole(String roleName, ClientModel parentClient, RoleModel parentRole) {
@@ -383,6 +396,7 @@ public class RealmManager {
                 addAndSetAdminRole(r, realmAdminClient, adminRole);
             }
         }
+        addQueryCompositeRoles(realmAdminClient);
     }
 
 
@@ -500,7 +514,8 @@ public class RealmManager {
         // I need to postpone impersonation because it needs "realm-management" client and its roles set
         if (postponeImpersonationSetup) {
             setupImpersonationService(realm);
-        }
+            String realmAdminClientId = getRealmAdminClientId(realm);
+         }
 
         if (postponeAdminCliSetup) {
             setupAdminCli(realm);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java
index 924b35e..98d4538 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java
@@ -98,4 +98,7 @@ public class AdminAuth {
         return false;
     }
 
+    public enum Resource {
+        CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION, AUTHORIZATION
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
index 5db1ea4..650ac75 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
@@ -38,6 +38,8 @@ import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.Cors;
 import org.keycloak.services.resources.admin.info.ServerInfoAdminResource;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
+import org.keycloak.services.resources.admin.permissions.RealmsPermissionEvaluator;
 import org.keycloak.theme.Theme;
 import org.keycloak.theme.ThemeProvider;
 
@@ -229,7 +231,7 @@ public class AdminRoot {
         handlePreflightRequest();
 
         AdminAuth auth = authenticateRealmAdminRequest(headers);
-        if (!isAdmin(auth)) {
+        if (!AdminPermissions.realms(session, auth).isAdmin()) {
             throw new ForbiddenException();
         }
 
@@ -244,26 +246,6 @@ public class AdminRoot {
         return adminResource;
     }
 
-    protected boolean isAdmin(AdminAuth auth) {
-
-        RealmManager realmManager = new RealmManager(session);
-        if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
-            if (auth.hasOneOfRealmRole(AdminRoles.ADMIN, AdminRoles.CREATE_REALM)) {
-                return true;
-            }
-            for (RealmModel realm : session.realms().getRealms()) {
-                ClientModel client = realm.getMasterAdminClient();
-                if (auth.hasOneOfAppRole(client, AdminRoles.ALL_REALM_ROLES)) {
-                    return true;
-                }
-            }
-            return false;
-        } else {
-            ClientModel client = auth.getRealm().getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm()));
-            return auth.hasOneOfAppRole(client, AdminRoles.ALL_REALM_ROLES);
-        }
-    }
-
     protected void handlePreflightRequest() {
         if (request.getHttpMethod().equalsIgnoreCase("OPTIONS")) {
             logger.debug("Cors admin pre-flight");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java
index 5ac7593..c6064bb 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java
@@ -18,6 +18,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.common.ClientConnection;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
@@ -26,6 +27,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.services.managers.BruteForceProtector;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -48,7 +50,7 @@ import java.util.Map;
  */
 public class AttackDetectionResource {
     protected static final Logger logger = Logger.getLogger(AttackDetectionResource.class);
-    protected RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
     protected RealmModel realm;
     private AdminEventBuilder adminEvent;
 
@@ -64,12 +66,10 @@ public class AttackDetectionResource {
     @Context
     protected HttpHeaders headers;
 
-    public AttackDetectionResource(RealmAuth auth, RealmModel realm, AdminEventBuilder adminEvent) {
+    public AttackDetectionResource(AdminPermissionEvaluator auth, RealmModel realm, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
         this.adminEvent = adminEvent.realm(realm).resource(ResourceType.USER_LOGIN_FAILURE);
-
-        auth.init(RealmAuth.Resource.USER);
     }
 
     /**
@@ -83,7 +83,12 @@ public class AttackDetectionResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId) {
-        auth.requireView();
+        UserModel user = session.users().getUserById(userId, realm);
+        if (user == null) {
+            auth.users().requireView();
+        } else {
+            auth.users().requireView(user);
+        }
 
         Map<String, Object> data = new HashMap<>();
         data.put("disabled", false);
@@ -92,7 +97,6 @@ public class AttackDetectionResource {
         data.put("lastIPFailure", "n/a");
         if (!realm.isBruteForceProtected()) return data;
 
-        UserModel user = session.users().getUserById(userId, realm);
 
         UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
         if (model == null) return data;
@@ -115,8 +119,12 @@ public class AttackDetectionResource {
     @Path("brute-force/users/{userId}")
     @DELETE
     public void clearBruteForceForUser(@PathParam("userId") String userId) {
-        auth.requireManage();
-
+        UserModel user = session.users().getUserById(userId, realm);
+        if (user == null) {
+            auth.users().requireManage();
+        } else {
+            auth.users().requireManage(user);
+        }
         UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
         if (model != null) {
             session.sessions().removeUserLoginFailure(realm, userId);
@@ -133,7 +141,7 @@ public class AttackDetectionResource {
     @Path("brute-force/users")
     @DELETE
     public void clearAllBruteForce() {
-        auth.requireManage();
+        auth.users().requireManage();
 
         session.sessions().removeAllUserLoginFailures(realm);
         adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
index 2f7362b..61f6254 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
@@ -50,6 +50,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
 import org.keycloak.representations.idm.ConfigPropertyRepresentation;
 import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.utils.CredentialHelper;
 
 import javax.ws.rs.Consumes;
@@ -80,18 +81,17 @@ public class AuthenticationManagementResource {
 
     private final RealmModel realm;
     private final KeycloakSession session;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     private AdminEventBuilder adminEvent;
     @Context
     private UriInfo uriInfo;
 
     protected static final Logger logger = Logger.getLogger(AuthenticationManagementResource.class);
 
-    public AuthenticationManagementResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public AuthenticationManagementResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.session = session;
         this.auth = auth;
-        this.auth.init(RealmAuth.Resource.REALM);
         this.adminEvent = adminEvent.resource(ResourceType.AUTH_FLOW);
     }
 
@@ -105,7 +105,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<Map<String, Object>> getFormProviders() {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAuthenticator.class);
         return buildProviderMetadata(factories);
@@ -121,7 +121,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<Map<String, Object>> getAuthenticatorProviders() {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(Authenticator.class);
         return buildProviderMetadata(factories);
@@ -137,7 +137,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<Map<String, Object>> getClientAuthenticatorProviders() {
-        auth.requireAny();
+        auth.requireAnyAdminRole();
 
         List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
         return buildProviderMetadata(factories);
@@ -167,7 +167,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<Map<String, Object>> getFormActionProviders() {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAction.class);
         return buildProviderMetadata(factories);
@@ -184,7 +184,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<AuthenticationFlowRepresentation> getFlows() {
-        auth.requireAny();
+        auth.realm().requireViewRealm();
 
         List<AuthenticationFlowRepresentation> flows = new LinkedList<>();
         for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
@@ -207,7 +207,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public Response createFlow(AuthenticationFlowRepresentation flow) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         if (flow.getAlias() == null || flow.getAlias().isEmpty()) {
             return ErrorResponse.exists("Failed to create flow with empty alias name");
@@ -235,7 +235,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public AuthenticationFlowRepresentation getFlow(@PathParam("id") String id) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id);
         if (flow == null) {
@@ -253,7 +253,7 @@ public class AuthenticationManagementResource {
     @DELETE
     @NoCache
     public void deleteFlow(@PathParam("id") String id) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
         
         deleteFlow(id, true);
     }
@@ -292,7 +292,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public Response copy(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         String newName = data.get("newName");
         if (realm.getFlowByAlias(newName) != null) {
@@ -351,7 +351,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public Response addExecutionFlow(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
         if (parentFlow == null) {
@@ -403,7 +403,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public void addExecution(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
         if (parentFlow == null) {
@@ -450,7 +450,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Response getExecutions(@PathParam("flowAlias") String flowAlias) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias);
         if (flow == null) {
@@ -535,7 +535,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public void updateExecutions(@PathParam("flowAlias") String flowAlias, AuthenticationExecutionInfoRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias);
         if (flow == null) {
@@ -566,7 +566,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public Response addExecution(AuthenticationExecutionRepresentation execution) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationExecutionModel model = RepresentationToModel.toModel(realm, execution);
         AuthenticationFlowModel parentFlow = getParentFlow(model);
@@ -601,7 +601,7 @@ public class AuthenticationManagementResource {
     @POST
     @NoCache
     public void raisePriority(@PathParam("executionId") String execution) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
@@ -647,7 +647,7 @@ public class AuthenticationManagementResource {
     @POST
     @NoCache
     public void lowerPriority(@PathParam("executionId") String execution) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
@@ -687,7 +687,7 @@ public class AuthenticationManagementResource {
     @DELETE
     @NoCache
     public void removeExecution(@PathParam("executionId") String execution) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
@@ -723,7 +723,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public Response newExecutionConfig(@PathParam("executionId") String execution, AuthenticatorConfigRepresentation json) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
@@ -753,7 +753,7 @@ public class AuthenticationManagementResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("executionId") String execution,@PathParam("id") String id) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
         if (config == null) {
@@ -773,7 +773,7 @@ public class AuthenticationManagementResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<Map<String, String>> getUnregisteredRequiredActions() {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class);
         List<Map<String, String>> unregisteredList = new LinkedList<>();
@@ -807,7 +807,7 @@ public class AuthenticationManagementResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @NoCache
     public void registerRequiredAction(Map<String, String> data) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         String providerId = data.get("providerId");
         String name = data.get("name");
@@ -834,7 +834,7 @@ public class AuthenticationManagementResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RequiredActionProviderRepresentation> getRequiredActions() {
-        auth.requireAny();
+        auth.requireAnyAdminRole();
 
         List<RequiredActionProviderRepresentation> list = new LinkedList<>();
         for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {
@@ -863,7 +863,7 @@ public class AuthenticationManagementResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public RequiredActionProviderRepresentation getRequiredAction(@PathParam("alias") String alias) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
         if (model == null) {
@@ -883,7 +883,7 @@ public class AuthenticationManagementResource {
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public void updateRequiredAction(@PathParam("alias") String alias, RequiredActionProviderRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
         if (model == null) {
@@ -909,7 +909,7 @@ public class AuthenticationManagementResource {
     @Path("required-actions/{alias}")
     @DELETE
     public void removeRequiredAction(@PathParam("alias") String alias) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
         if (model == null) {
@@ -928,7 +928,7 @@ public class AuthenticationManagementResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public AuthenticatorConfigInfoRepresentation getAuthenticatorConfigDescription(@PathParam("providerId") String providerId) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         ConfigurableAuthenticatorFactory factory = CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId);
         if (factory == null) {
@@ -959,7 +959,7 @@ public class AuthenticationManagementResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public Map<String, List<ConfigPropertyRepresentation>> getPerClientConfigDescription() {
-        auth.requireAny();
+        auth.requireAnyAdminRole();
 
         List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
 
@@ -991,7 +991,7 @@ public class AuthenticationManagementResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public Response createAuthenticatorConfig(AuthenticatorConfigRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticatorConfigModel config = realm.addAuthenticatorConfig(RepresentationToModel.toModel(rep));
         adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTHENTICATOR_CONFIG).resourcePath(uriInfo, config.getId()).representation(rep).success();
@@ -1007,7 +1007,7 @@ public class AuthenticationManagementResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("id") String id) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
         if (config == null) {
@@ -1025,7 +1025,7 @@ public class AuthenticationManagementResource {
     @DELETE
     @NoCache
     public void removeAuthenticatorConfig(@PathParam("id") String id) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id);
         if (config == null) {
@@ -1057,7 +1057,7 @@ public class AuthenticationManagementResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @NoCache
     public void updateAuthenticatorConfig(@PathParam("id") String id, AuthenticatorConfigRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         AuthenticatorConfigModel exists = realm.getAuthenticatorConfigById(id);
         if (exists == null) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
index 1f4277b..a798414 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
@@ -37,10 +37,12 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.KeyStoreConfig;
 import org.keycloak.representations.idm.CertificateRepresentation;
 import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.util.CertificateInfoHelper;
 import org.keycloak.util.JWKSUtils;
 import org.keycloak.util.JsonSerialization;
 
+import javax.ws.rs.BadRequestException;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -73,13 +75,13 @@ public class ClientAttributeCertificateResource {
     public static final String JSON_WEB_KEY_SET = "JSON Web Key Set";
 
     protected RealmModel realm;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     protected ClientModel client;
     protected KeycloakSession session;
     protected AdminEventBuilder adminEvent;
     protected String attributePrefix;
 
-    public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix, AdminEventBuilder adminEvent) {
+    public ClientAttributeCertificateResource(RealmModel realm, AdminPermissionEvaluator auth, ClientModel client, KeycloakSession session, String attributePrefix, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.auth = auth;
         this.client = client;
@@ -97,11 +99,7 @@ public class ClientAttributeCertificateResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public CertificateRepresentation getKeyInfo() {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         CertificateRepresentation info = CertificateInfoHelper.getCertificateFromClient(client, attributePrefix);
         return info;
@@ -117,11 +115,7 @@ public class ClientAttributeCertificateResource {
     @Path("generate")
     @Produces(MediaType.APPLICATION_JSON)
     public CertificateRepresentation generate() {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId());
 
@@ -145,11 +139,7 @@ public class ClientAttributeCertificateResource {
     @Consumes(MediaType.MULTIPART_FORM_DATA)
     @Produces(MediaType.APPLICATION_JSON)
     public CertificateRepresentation uploadJks(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         try {
             CertificateRepresentation info = getCertFromRequest(input);
@@ -175,11 +165,7 @@ public class ClientAttributeCertificateResource {
     @Consumes(MediaType.MULTIPART_FORM_DATA)
     @Produces(MediaType.APPLICATION_JSON)
     public CertificateRepresentation uploadJksCertificate(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         try {
             CertificateRepresentation info = getCertFromRequest(input);
@@ -194,10 +180,12 @@ public class ClientAttributeCertificateResource {
     }
 
     private CertificateRepresentation getCertFromRequest(MultipartFormDataInput input) throws IOException {
-        auth.requireManage();
+        auth.clients().requireManage(client);
         CertificateRepresentation info = new CertificateRepresentation();
         Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
-        String keystoreFormat = uploadForm.get("keystoreFormat").get(0).getBodyAsString();
+        List<InputPart> keystoreFormatPart = uploadForm.get("keystoreFormat");
+        if (keystoreFormatPart == null) throw new BadRequestException();
+        String keystoreFormat = keystoreFormatPart.get(0).getBodyAsString();
         List<InputPart> inputParts = uploadForm.get("file");
         if (keystoreFormat.equals(CERTIFICATE_PEM)) {
             String pem = StreamUtil.readString(inputParts.get(0).getBody(InputStream.class, null));
@@ -279,11 +267,7 @@ public class ClientAttributeCertificateResource {
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
     @Consumes(MediaType.APPLICATION_JSON)
     public byte[] getKeystore(final KeyStoreConfig config) {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) {
             throw new NotAcceptableException("Only support jks or pkcs12 format.");
@@ -322,11 +306,7 @@ public class ClientAttributeCertificateResource {
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
     @Consumes(MediaType.APPLICATION_JSON)
     public byte[] generateAndGetKeystore(final KeyStoreConfig config) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         if (config.getFormat() != null && !config.getFormat().equals("JKS") && !config.getFormat().equals("PKCS12")) {
             throw new NotAcceptableException("Only support jks or pkcs12 format.");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
index 0fe0090..609b9b0 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
@@ -25,6 +25,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
 import org.keycloak.representations.idm.ClientInitialAccessPresentation;
 import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.Consumes;
@@ -48,7 +49,7 @@ import java.util.List;
  */
 public class ClientInitialAccessResource {
 
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final RealmModel realm;
     private final AdminEventBuilder adminEvent;
 
@@ -58,12 +59,11 @@ public class ClientInitialAccessResource {
     @Context
     protected UriInfo uriInfo;
 
-    public ClientInitialAccessResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ClientInitialAccessResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
 
-        auth.init(RealmAuth.Resource.CLIENT);
     }
 
     /**
@@ -76,7 +76,7 @@ public class ClientInitialAccessResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public ClientInitialAccessPresentation create(ClientInitialAccessCreatePresentation config, @Context final HttpServletResponse response) {
-        auth.requireManage();
+        auth.clients().requireManage();
 
         int expiration = config.getExpiration() != null ? config.getExpiration() : 0;
         int count = config.getCount() != null ? config.getCount() : 1;
@@ -99,7 +99,7 @@ public class ClientInitialAccessResource {
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     public List<ClientInitialAccessPresentation> list() {
-        auth.requireView();
+        auth.clients().requireView();
 
         List<ClientInitialAccessModel> models = session.realms().listClientInitialAccess(realm);
         List<ClientInitialAccessPresentation> reps = new LinkedList<>();
@@ -113,7 +113,7 @@ public class ClientInitialAccessResource {
     @DELETE
     @Path("{id}")
     public void delete(final @PathParam("id") String id) {
-        auth.requireManage();
+        auth.clients().requireManage();
 
         session.realms().removeClientInitialAccessModel(realm, id);
         adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientRegistrationPolicyResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientRegistrationPolicyResource.java
index f8c57e2..9250326 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientRegistrationPolicyResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientRegistrationPolicyResource.java
@@ -37,6 +37,7 @@ import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.idm.ComponentTypeRepresentation;
 import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy;
 import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyFactory;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 /**
  * @resource Client Registration Policy
@@ -44,7 +45,7 @@ import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyF
  */
 public class ClientRegistrationPolicyResource {
 
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final RealmModel realm;
     private final AdminEventBuilder adminEvent;
 
@@ -54,12 +55,11 @@ public class ClientRegistrationPolicyResource {
     @Context
     protected UriInfo uriInfo;
 
-    public ClientRegistrationPolicyResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ClientRegistrationPolicyResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
 
-        auth.init(RealmAuth.Resource.CLIENT);
     }
 
 
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 43c897c..e7d611e 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
@@ -27,10 +27,12 @@ import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.AuthenticatedClientSessionModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
@@ -40,7 +42,9 @@ import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.protocol.ClientInstallationProvider;
 import org.keycloak.representations.adapters.action.GlobalRequestResult;
 import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.ManagementPermissionReference;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.representations.idm.UserSessionRepresentation;
 import org.keycloak.services.ErrorResponse;
@@ -51,6 +55,9 @@ import org.keycloak.services.managers.ClientManager;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.managers.ResourceAdminManager;
 import org.keycloak.services.resources.KeycloakApplication;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
 import org.keycloak.services.validation.ClientValidator;
 import org.keycloak.services.validation.PairwiseClientValidator;
 import org.keycloak.services.validation.ValidationMessages;
@@ -89,7 +96,7 @@ import static java.lang.Boolean.TRUE;
 public class ClientResource {
     protected static final Logger logger = Logger.getLogger(ClientResource.class);
     protected RealmModel realm;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     private AdminEventBuilder adminEvent;
     protected ClientModel client;
     protected KeycloakSession session;
@@ -104,19 +111,19 @@ public class ClientResource {
         return keycloak;
     }
 
-    public ClientResource(RealmModel realm, RealmAuth auth, ClientModel clientModel, KeycloakSession session, AdminEventBuilder adminEvent) {
+    public ClientResource(RealmModel realm, AdminPermissionEvaluator auth, ClientModel clientModel, KeycloakSession session, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.auth = auth;
         this.client = clientModel;
         this.session = session;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
-
-        auth.init(RealmAuth.Resource.CLIENT);
     }
 
     @Path("protocol-mappers")
     public ProtocolMappersResource getProtocolMappers() {
-        ProtocolMappersResource mappers = new ProtocolMappersResource(realm, client, auth, adminEvent);
+        AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(client);
+        AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(client);
+        ProtocolMappersResource mappers = new ProtocolMappersResource(realm, client, auth, adminEvent, manageCheck, viewCheck);
         ResteasyProviderFactory.getInstance().injectProperties(mappers);
         return mappers;
     }
@@ -129,15 +136,11 @@ public class ClientResource {
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public Response update(final ClientRepresentation rep) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         ValidationMessages validationMessages = new ValidationMessages();
         if (!ClientValidator.validate(rep, validationMessages) || !PairwiseClientValidator.validate(session, rep, validationMessages)) {
-            Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
+            Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
             throw new ErrorResponseException(
                     validationMessages.getStringMessages(),
                     validationMessages.getStringMessages(messages),
@@ -164,17 +167,14 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public ClientRepresentation getClient() {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         ClientRepresentation representation = ModelToRepresentation.toRepresentation(client);
 
         if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
             representation.setAuthorizationServicesEnabled(authorization().isEnabled());
         }
+        representation.setAccess(auth.clients().getAccess(client));
 
         return representation;
     }
@@ -194,11 +194,7 @@ public class ClientResource {
     @NoCache
     @Path("installation/providers/{providerId}")
     public Response getInstallationProvider(@PathParam("providerId") String providerId) {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         ClientInstallationProvider provider = session.getProvider(ClientInstallationProvider.class, providerId);
         if (provider == null) throw new NotFoundException("Unknown Provider");
@@ -212,7 +208,7 @@ public class ClientResource {
     @DELETE
     @NoCache
     public void deleteClient() {
-        auth.requireManage();
+        auth.clients().requireManage(client);
 
         if (client == null) {
             throw new NotFoundException("Could not find client");
@@ -233,11 +229,7 @@ public class ClientResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
     public CredentialRepresentation regenerateSecret() {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         logger.debug("regenerateSecret");
         UserCredentialModel cred = KeycloakModelUtils.generateSecret(client);
@@ -256,11 +248,7 @@ public class ClientResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
     public ClientRepresentation regenerateRegistrationAccessToken() {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireManage(client);
 
         String token = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, realm, uriInfo, client, RegistrationAuth.AUTHENTICATED);
 
@@ -281,11 +269,7 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public CredentialRepresentation getClientSecret() {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         logger.debug("getClientSecret");
         UserCredentialModel model = UserCredentialModel.secret(client.getSecret());
@@ -300,12 +284,14 @@ public class ClientResource {
      */
     @Path("scope-mappings")
     public ScopeMappedResource getScopeMappedResource() {
-        return new ScopeMappedResource(realm, auth, client, session, adminEvent);
+        AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(client);
+        AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(client);
+        return new ScopeMappedResource(realm, auth, client, session, adminEvent, manageCheck, viewCheck);
     }
 
     @Path("roles")
     public RoleContainerResource getRoleContainerResource() {
-        return new RoleContainerResource(uriInfo, realm, auth, client, adminEvent);
+        return new RoleContainerResource(session, uriInfo, realm, auth, client, adminEvent);
     }
 
     /**
@@ -318,11 +304,7 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public UserRepresentation getServiceAccountUser() {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         UserModel user = session.users().getServiceAccount(client);
         if (user == null) {
@@ -346,11 +328,7 @@ public class ClientResource {
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     public GlobalRequestResult pushRevocation() {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).resource(ResourceType.CLIENT).success();
         return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
@@ -373,11 +351,7 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Map<String, Long> getApplicationSessionCount() {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         Map<String, Long> map = new HashMap<>();
         map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client));
@@ -398,11 +372,7 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<UserSessionRepresentation> getUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         firstResult = firstResult != null ? firstResult : -1;
         maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
@@ -430,11 +400,7 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Map<String, Long> getOfflineSessionCount() {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         Map<String, Long> map = new HashMap<>();
         map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client));
@@ -455,11 +421,7 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<UserSessionRepresentation> getOfflineUserSessions(@QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
-        auth.requireView();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireView(client);
 
         firstResult = firstResult != null ? firstResult : -1;
         maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
@@ -496,11 +458,7 @@ public class ClientResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void registerNode(Map<String, String> formParams) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         String node = formParams.get("node");
         if (node == null) {
@@ -520,11 +478,7 @@ public class ClientResource {
     @DELETE
     @NoCache
     public void unregisterNode(final @PathParam("node") String node) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         if (logger.isDebugEnabled()) logger.debug("Unregister node: " + node);
 
@@ -548,11 +502,7 @@ public class ClientResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public GlobalRequestResult testNodesAvailable() {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.clients().requireConfigure(client);
 
         logger.debug("Test availability of cluster nodes");
         GlobalRequestResult result = new ResourceAdminManager(session).testNodesAvailability(uriInfo.getRequestUri(), realm, client);
@@ -571,6 +521,57 @@ public class ClientResource {
         return resource;
     }
 
+    /**
+     * Return object stating whether client Authorization permissions have been initialized or not and a reference
+     *
+     * @return
+     */
+    @Path("management/permissions")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference getManagementPermissions() {
+        auth.roles().requireView(client);
+
+        AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+        if (!permissions.clients().isPermissionsEnabled(client)) {
+            return new ManagementPermissionReference();
+        }
+        return toMgmtRef(client, permissions);
+    }
+
+    public static ManagementPermissionReference toMgmtRef(ClientModel client, AdminPermissionManagement permissions) {
+        ManagementPermissionReference ref = new ManagementPermissionReference();
+        ref.setEnabled(true);
+        ref.setResource(permissions.clients().resource(client).getId());
+        ref.setScopePermissions(permissions.clients().getPermissions(client));
+        return ref;
+    }
+
+
+    /**
+     * Return object stating whether client Authorization permissions have been initialized or not and a reference
+     *
+     *
+     * @return initialized manage permissions reference
+     */
+    @Path("management/permissions")
+    @PUT
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
+        auth.clients().requireManage(client);
+         if (ref.isEnabled()) {
+            AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+            permissions.clients().setPermissionsEnabled(client, ref.isEnabled());
+            return toMgmtRef(client, permissions);
+        } else {
+            return new ManagementPermissionReference();
+        }
+    }
+
+
     private void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
         if (TRUE.equals(rep.isServiceAccountsEnabled())) {
             UserModel serviceAccount = this.session.users().getServiceAccount(client);
@@ -584,6 +585,30 @@ public class ClientResource {
             new ClientManager(new RealmManager(session)).clientIdChanged(client, rep.getClientId());
         }
 
+        if (rep.isFullScopeAllowed() != null && rep.isFullScopeAllowed().booleanValue() != client.isFullScopeAllowed()) {
+            auth.clients().requireManage(client);
+        }
+
+        if (rep.getClientTemplate() != null) {
+            ClientTemplateModel currTemplate = client.getClientTemplate();
+            if (currTemplate == null) {
+                if (!rep.getClientTemplate().equals(ClientTemplateRepresentation.NONE)) {
+                    auth.clients().requireManage(client);
+                }
+            }  else if (!rep.getClientTemplate().equals(currTemplate.getName())){
+                auth.clients().requireManage(client);
+            }
+            if ((rep.isUseTemplateConfig() != null && rep.isUseTemplateConfig().booleanValue() != client.useTemplateConfig())
+                    || (rep.isUseTemplateScope() != null && rep.isUseTemplateScope().booleanValue() != client.useTemplateScope())
+                    || (rep.isUseTemplateMappers() != null && rep.isUseTemplateMappers().booleanValue() != client.useTemplateMappers())
+
+                    ) {
+                auth.clients().requireManage(client);
+            }
+        }
+
+
+
         RepresentationToModel.updateClient(rep, client);
     }
 
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..ae7d519 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.services.resources.admin.permissions.AdminPermissionEvaluator;
 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;
@@ -47,6 +49,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @resource Client Role Mappings
@@ -58,19 +61,26 @@ public class ClientRoleMappingsResource {
 
     protected KeycloakSession session;
     protected RealmModel realm;
-    protected RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
     protected RoleMapperModel user;
     protected ClientModel client;
     protected AdminEventBuilder adminEvent;
     private UriInfo uriInfo;
+    protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
+    protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
 
-    public ClientRoleMappingsResource(UriInfo uriInfo, KeycloakSession session, RealmModel realm, RealmAuth auth, RoleMapperModel user, ClientModel client, AdminEventBuilder adminEvent) {
+
+    public ClientRoleMappingsResource(UriInfo uriInfo, KeycloakSession session, RealmModel realm, AdminPermissionEvaluator auth,
+                                      RoleMapperModel user, ClientModel client, AdminEventBuilder adminEvent,
+                                      AdminPermissionEvaluator.RequirePermissionCheck manageCheck, AdminPermissionEvaluator.RequirePermissionCheck viewCheck ) {
         this.uriInfo = uriInfo;
         this.session = session;
         this.realm = realm;
         this.auth = auth;
         this.user = user;
         this.client = client;
+        this.managePermission = manageCheck;
+        this.viewPermission = viewCheck;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING);
     }
 
@@ -83,11 +93,7 @@ public class ClientRoleMappingsResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getClientRoleMappings() {
-        auth.requireView();
-
-        if (user == null || client == null) {
-            throw new NotFoundException("Not found");
-        }
+        viewPermission.require();
 
         Set<RoleModel> mappings = user.getClientRoleMappings(client);
         List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
@@ -109,11 +115,8 @@ public class ClientRoleMappingsResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getCompositeClientRoleMappings() {
-        auth.requireView();
+        viewPermission.require();
 
-        if (user == null || client == null) {
-            throw new NotFoundException("Not found");
-        }
 
         Set<RoleModel> roles = client.getRoles();
         List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
@@ -133,13 +136,12 @@ public class ClientRoleMappingsResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getAvailableClientRoleMappings() {
-        auth.requireView();
-
-        if (user == null || client == null) {
-            throw new NotFoundException("Not found");
-        }
+        viewPermission.require();
 
         Set<RoleModel> available = client.getRoles();
+        available = available.stream().filter(r ->
+                auth.roles().canMapRole(r)
+        ).collect(Collectors.toSet());
         return getAvailableRoles(user, available);
     }
 
@@ -165,17 +167,14 @@ public class ClientRoleMappingsResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addClientRoleMapping(List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        if (user == null || client == null) {
-            throw new NotFoundException("Not found");
-        }
+        managePermission.require();
 
         for (RoleRepresentation role : roles) {
             RoleModel roleModel = client.getRole(role.getName());
             if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                 throw new NotFoundException("Role not found");
             }
+            auth.roles().requireMapRole(roleModel);
             user.grantRole(roleModel);
         }
         adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
@@ -183,18 +182,14 @@ public class ClientRoleMappingsResource {
     }
 
     /**
-     * Delete client-level roles from user role mapping
-     *
-     * @param roles
-     */
+         * Delete client-level roles from user role mapping
+         *
+         * @param roles
+         */
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     public void deleteClientRoleMapping(List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        if (user == null || client == null) {
-            throw new NotFoundException("Not found");
-        }
+        managePermission.require();
 
         if (roles == null) {
             Set<RoleModel> roleModels = user.getClientRoleMappings(client);
@@ -205,6 +200,7 @@ public class ClientRoleMappingsResource {
                     ClientModel client = (ClientModel) roleModel.getContainer();
                     if (!client.getId().equals(this.client.getId())) continue;
                 }
+                auth.roles().requireMapRole(roleModel);
                 user.deleteRoleMapping(roleModel);
                 roles.add(ModelToRepresentation.toRepresentation(roleModel));
             }
@@ -216,10 +212,11 @@ public class ClientRoleMappingsResource {
                     throw new NotFoundException("Role not found");
                 }
 
+                auth.roles().requireMapRole(roleModel);
                 try {
                     user.deleteRoleMapping(roleModel);
                 } catch (ModelException me) {
-                    Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
+                    Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
                     throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
                             Response.Status.BAD_REQUEST);
                 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
index a488ba3..decb4da 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
@@ -26,6 +26,7 @@ import org.keycloak.common.Profile;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
@@ -34,14 +35,18 @@ import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.services.ErrorResponse;
 import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.ForbiddenException;
 import org.keycloak.services.managers.ClientManager;
 import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.services.validation.ClientValidator;
 import org.keycloak.services.validation.PairwiseClientValidator;
 import org.keycloak.services.validation.ValidationMessages;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -65,18 +70,17 @@ import java.util.Properties;
 public class ClientsResource {
     protected static final Logger logger = Logger.getLogger(ClientsResource.class);
     protected RealmModel realm;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     private AdminEventBuilder adminEvent;
 
     @Context
     protected KeycloakSession session;
 
-    public ClientsResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ClientsResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.auth = auth;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
 
-        auth.init(RealmAuth.Resource.CLIENT);
     }
 
     /**
@@ -85,21 +89,20 @@ public class ClientsResource {
      * Returns a list of clients belonging to the realm
      *
      * @param clientId filter by clientId
+     * @param viewableOnly filter clients that cannot be viewed in full by admin
      */
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
-    public List<ClientRepresentation> getClients(@QueryParam("clientId") String clientId) {
-        auth.requireAny();
-
+    public List<ClientRepresentation> getClients(@QueryParam("clientId") String clientId, @QueryParam("viewableOnly") @DefaultValue("false") boolean viewableOnly) {
         List<ClientRepresentation> rep = new ArrayList<>();
 
         if (clientId == null) {
             List<ClientModel> clientModels = realm.getClients();
-
-            boolean view = auth.hasView();
+            auth.clients().requireList();
+            boolean view = auth.clients().canView();
             for (ClientModel clientModel : clientModels) {
-                if (view) {
+                if (view || auth.clients().canView(clientModel)) {
                     ClientRepresentation representation = ModelToRepresentation.toRepresentation(clientModel);
 
                     if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) {
@@ -111,7 +114,8 @@ public class ClientsResource {
                     }
 
                     rep.add(representation);
-                } else {
+                    representation.setAccess(auth.clients().getAccess(clientModel));
+                } else if (!viewableOnly) {
                     ClientRepresentation client = new ClientRepresentation();
                     client.setId(clientModel.getId());
                     client.setClientId(clientModel.getClientId());
@@ -120,9 +124,22 @@ public class ClientsResource {
                 }
             }
         } else {
-            ClientModel client = realm.getClientByClientId(clientId);
-            if (client != null) {
-                rep.add(ModelToRepresentation.toRepresentation(client));
+            ClientModel clientModel = realm.getClientByClientId(clientId);
+            if (clientModel != null) {
+                if (auth.clients().canView(clientModel)) {
+                    ClientRepresentation representation = ModelToRepresentation.toRepresentation(clientModel);
+                    representation.setAccess(auth.clients().getAccess(clientModel));
+                    rep.add(representation);
+                } else if (!viewableOnly && auth.clients().canList()){
+                    ClientRepresentation client = new ClientRepresentation();
+                    client.setId(clientModel.getId());
+                    client.setClientId(clientModel.getClientId());
+                    client.setDescription(clientModel.getDescription());
+                    rep.add(client);
+
+                } else {
+                    throw new ForbiddenException();
+                }
             }
         }
         return rep;
@@ -144,11 +161,11 @@ public class ClientsResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response createClient(final @Context UriInfo uriInfo, final ClientRepresentation rep) {
-        auth.requireManage();
+        auth.clients().requireManage();
 
         ValidationMessages validationMessages = new ValidationMessages();
         if (!ClientValidator.validate(rep, validationMessages) || !PairwiseClientValidator.validate(session, rep, validationMessages)) {
-            Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
+            Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
             throw new ErrorResponseException(
                     validationMessages.getStringMessages(),
                     validationMessages.getStringMessages(messages),
@@ -189,7 +206,13 @@ public class ClientsResource {
      */
     @Path("{id}")
     public ClientResource getClient(final @PathParam("id") String id) {
+
         ClientModel clientModel = realm.getClientById(id);
+        if (clientModel == null) {
+            // we do this to make sure somebody can't phish ids
+            if (auth.clients().canList()) throw new NotFoundException("Could not find client");
+            else throw new ForbiddenException();
+        }
 
         session.getContext().setClient(clientModel);
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java
index f760a41..f076850 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java
@@ -31,6 +31,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.representations.idm.ClientTemplateRepresentation;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -54,7 +55,7 @@ import javax.ws.rs.core.UriInfo;
 public class ClientTemplateResource {
     protected static final Logger logger = Logger.getLogger(ClientTemplateResource.class);
     protected RealmModel realm;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     private AdminEventBuilder adminEvent;
     protected ClientTemplateModel template;
     protected KeycloakSession session;
@@ -62,19 +63,20 @@ public class ClientTemplateResource {
     @Context
     protected UriInfo uriInfo;
 
-    public ClientTemplateResource(RealmModel realm, RealmAuth auth, ClientTemplateModel template, KeycloakSession session, AdminEventBuilder adminEvent) {
+    public ClientTemplateResource(RealmModel realm, AdminPermissionEvaluator auth, ClientTemplateModel template, KeycloakSession session, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.auth = auth;
         this.template = template;
         this.session = session;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
 
-        auth.init(RealmAuth.Resource.CLIENT);
     }
 
     @Path("protocol-mappers")
     public ProtocolMappersResource getProtocolMappers() {
-        ProtocolMappersResource mappers = new ProtocolMappersResource(realm, template, auth, adminEvent);
+        AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(template);
+        AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(template);
+        ProtocolMappersResource mappers = new ProtocolMappersResource(realm, template, auth, adminEvent, manageCheck, viewCheck);
         ResteasyProviderFactory.getInstance().injectProperties(mappers);
         return mappers;
     }
@@ -86,7 +88,9 @@ public class ClientTemplateResource {
      */
     @Path("scope-mappings")
     public ScopeMappedResource getScopeMappedResource() {
-        return new ScopeMappedResource(realm, auth, template, session, adminEvent);
+        AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.clients().requireManage(template);
+        AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.clients().requireView(template);
+        return new ScopeMappedResource(realm, auth, template, session, adminEvent, manageCheck, viewCheck);
     }
 
     /**
@@ -97,11 +101,7 @@ public class ClientTemplateResource {
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public Response update(final ClientTemplateRepresentation rep) {
-        auth.requireManage();
-
-        if (template == null) {
-            throw new NotFoundException("Could not find client template");
-        }
+        auth.clients().requireManageTemplates();
 
         try {
             RepresentationToModel.updateClientTemplate(rep, template);
@@ -125,11 +125,8 @@ public class ClientTemplateResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public ClientTemplateRepresentation getClient() {
-        auth.requireView();
+        auth.clients().requireView(template);
 
-        if (template == null) {
-            throw new NotFoundException("Could not find client template");
-        }
 
         return ModelToRepresentation.toRepresentation(template);
     }
@@ -141,11 +138,7 @@ public class ClientTemplateResource {
     @DELETE
     @NoCache
     public Response deleteClientTemplate() {
-        auth.requireManage();
-
-        if (template == null) {
-            throw new NotFoundException("Could not find client template");
-        }
+        auth.clients().requireManage(template);
 
         try {
             realm.removeClientTemplate(template.getId());
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java
index 5e27712..1e8105d 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java
@@ -18,6 +18,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.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
@@ -29,6 +30,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.representations.idm.ClientTemplateRepresentation;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -53,18 +55,16 @@ import java.util.List;
 public class ClientTemplatesResource {
     protected static final Logger logger = Logger.getLogger(ClientTemplatesResource.class);
     protected RealmModel realm;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     private AdminEventBuilder adminEvent;
 
     @Context
     protected KeycloakSession session;
 
-    public ClientTemplatesResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ClientTemplatesResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.auth = auth;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
-
-        auth.init(RealmAuth.Resource.CLIENT);
     }
 
     /**
@@ -76,22 +76,19 @@ public class ClientTemplatesResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<ClientTemplateRepresentation> getClientTemplates() {
-        auth.requireView();
+        auth.clients().requireListTemplates();
 
         List<ClientTemplateRepresentation> rep = new ArrayList<>();
         List<ClientTemplateModel> clientModels = realm.getClientTemplates();
 
-        boolean view = auth.hasView();
+        boolean viewable = auth.clients().canViewTemplates();
         for (ClientTemplateModel clientModel : clientModels) {
-            if (view) {
-                rep.add(ModelToRepresentation.toRepresentation(clientModel));
-            } else {
-                ClientTemplateRepresentation client = new ClientTemplateRepresentation();
-                client.setId(clientModel.getId());
-                client.setName(clientModel.getName());
-                client.setDescription(clientModel.getDescription());
-                client.setProtocol(clientModel.getProtocol());
-                rep.add(client);
+            if (viewable) rep.add(ModelToRepresentation.toRepresentation(clientModel));
+            else {
+                ClientTemplateRepresentation tempRep = new ClientTemplateRepresentation();
+                tempRep.setName(clientModel.getName());
+                tempRep.setId(clientModel.getId());
+                tempRep.setProtocol(clientModel.getProtocol());
             }
         }
         return rep;
@@ -109,7 +106,7 @@ public class ClientTemplatesResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response createClientTemplate(final @Context UriInfo uriInfo, final ClientTemplateRepresentation rep) {
-        auth.requireManage();
+        auth.clients().requireManageTemplates();
 
         try {
             ClientTemplateModel clientModel = RepresentationToModel.createClientTemplate(session, realm, rep);
@@ -130,7 +127,11 @@ public class ClientTemplatesResource {
      */
     @Path("{id}")
     public ClientTemplateResource getClient(final @PathParam("id") String id) {
+        auth.clients().requireListTemplates();
         ClientTemplateModel clientModel = realm.getClientTemplateById(id);
+        if (clientModel == null) {
+            throw new NotFoundException("Could not find client template");
+        }
         ClientTemplateResource clientResource = new ClientTemplateResource(realm, auth, clientModel, session, adminEvent);
         ResteasyProviderFactory.getInstance().injectProperties(clientResource);
         return clientResource;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
index b39b773..c532245 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
@@ -38,7 +38,7 @@ import org.keycloak.representations.idm.ComponentRepresentation;
 import org.keycloak.representations.idm.ComponentTypeRepresentation;
 import org.keycloak.representations.idm.ConfigPropertyRepresentation;
 import org.keycloak.services.ErrorResponse;
-import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.Consumes;
@@ -63,7 +63,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.stream.Collectors;
 
 /**
  * @resource Component
@@ -75,7 +74,7 @@ public class ComponentResource {
 
     protected RealmModel realm;
 
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
 
     private AdminEventBuilder adminEvent;
 
@@ -91,12 +90,10 @@ public class ComponentResource {
     @Context
     protected HttpHeaders headers;
 
-    public ComponentResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ComponentResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
         this.adminEvent = adminEvent.resource(ResourceType.COMPONENT);
-
-        auth.init(RealmAuth.Resource.REALM);
     }
 
     @GET
@@ -105,7 +102,7 @@ public class ComponentResource {
     public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent,
                                                        @QueryParam("type") String type,
                                                        @QueryParam("name") String name) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
         List<ComponentModel> components = Collections.EMPTY_LIST;
         if (parent == null && type == null) {
             components = realm.getComponents();
@@ -135,7 +132,7 @@ public class ComponentResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response create(ComponentRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
         try {
             ComponentModel model = RepresentationToModel.toModel(session, rep);
             if (model.getParentId() == null) model.setParentId(realm.getId());
@@ -156,7 +153,7 @@ public class ComponentResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public ComponentRepresentation getComponent(@PathParam("id") String id) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
         ComponentModel model = realm.getComponent(id);
         if (model == null) {
             throw new NotFoundException("Could not find component");
@@ -169,7 +166,7 @@ public class ComponentResource {
     @Path("{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     public Response updateComponent(@PathParam("id") String id, ComponentRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
         try {
             ComponentModel model = realm.getComponent(id);
             if (model == null) {
@@ -188,7 +185,7 @@ public class ComponentResource {
     @DELETE
     @Path("{id}")
     public void removeComponent(@PathParam("id") String id) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
         ComponentModel model = realm.getComponent(id);
         if (model == null) {
             throw new NotFoundException("Could not find component");
@@ -199,7 +196,7 @@ public class ComponentResource {
     }
 
     private Response localizedErrorResponse(ComponentValidationException cve) {
-        Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale(), "admin-messages", "messages");
+        Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale(), "admin-messages", "messages");
 
         Object[] localizedParameters = cve.getParameters()==null ? null : Arrays.asList(cve.getParameters()).stream().map((Object parameter) -> {
 
@@ -228,7 +225,7 @@ public class ComponentResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<ComponentTypeRepresentation> getSubcomponentConfig(@PathParam("id") String parentId, @QueryParam("type") String subtype) {
-        auth.requireView();
+        auth.realm().requireViewRealm();
         ComponentModel parent = realm.getComponent(parentId);
         if (parent == null) {
             throw new NotFoundException("Could not find parent component");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java b/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
index c9fe194..3de46b0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
@@ -21,6 +21,7 @@ import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.GroupModel;
 import org.keycloak.models.KeycloakSession;
@@ -28,6 +29,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.ManagementPermissionReference;
 import org.keycloak.representations.idm.UserRepresentation;
 
 import javax.ws.rs.Consumes;
@@ -49,6 +51,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
 
 /**
  * @resource Groups
@@ -58,11 +63,11 @@ public class GroupResource {
 
     private final RealmModel realm;
     private final KeycloakSession session;
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final AdminEventBuilder adminEvent;
     private final GroupModel group;
 
-    public GroupResource(RealmModel realm, GroupModel group, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public GroupResource(RealmModel realm, GroupModel group, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.session = session;
         this.auth = auth;
@@ -72,7 +77,7 @@ public class GroupResource {
 
     @Context private UriInfo uriInfo;
 
-    /**
+     /**
      *
      *
      * @return
@@ -81,13 +86,13 @@ public class GroupResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public GroupRepresentation getGroup() {
-        this.auth.requireView();
+        this.auth.groups().requireView(group);
 
-        if (group == null) {
-            throw new NotFoundException("Could not find group by id");
-        }
+        GroupRepresentation rep = ModelToRepresentation.toGroupHierarchy(group, true);
+
+        rep.setAccess(auth.groups().getAccess(group));
 
-        return ModelToRepresentation.toGroupHierarchy(group, true);
+        return rep;
     }
 
     /**
@@ -98,11 +103,7 @@ public class GroupResource {
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public void updateGroup(GroupRepresentation rep) {
-        this.auth.requireManage();
-
-        if (group == null) {
-            throw new NotFoundException("Could not find group by id");
-        }
+        this.auth.groups().requireManage(group);
 
         updateGroup(rep, group);
         adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
@@ -112,11 +113,7 @@ public class GroupResource {
 
     @DELETE
     public void deleteGroup() {
-        this.auth.requireManage();
-
-        if (group == null) {
-            throw new NotFoundException("Could not find group by id");
-        }
+        this.auth.groups().requireManage(group);
 
         realm.removeGroup(group);
         adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
@@ -135,12 +132,8 @@ public class GroupResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
     public Response addChild(GroupRepresentation rep) {
-        this.auth.requireManage();
+        this.auth.groups().requireManage(group);
 
-        if (group == null) {
-            throw new NotFoundException("Could not find group by id");
-        }
-        
         for (GroupModel group : group.getSubGroups()) {
             if (group.getName().equals(rep.getName())) {
                 return ErrorResponse.exists("Parent already contains subgroup named '" + rep.getName() + "'");
@@ -191,9 +184,9 @@ public class GroupResource {
 
     @Path("role-mappings")
     public RoleMapperResource getRoleMappings() {
-        auth.init(RealmAuth.Resource.USER);
-
-        RoleMapperResource resource =  new RoleMapperResource(realm, auth, group, adminEvent);
+        AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.groups().requireManage(group);
+        AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.groups().requireView(group);
+        RoleMapperResource resource =  new RoleMapperResource(realm, auth, group, adminEvent, manageCheck, viewCheck);
         ResteasyProviderFactory.getInstance().injectProperties(resource);
         return resource;
 
@@ -214,11 +207,8 @@ public class GroupResource {
     @Produces(MediaType.APPLICATION_JSON)
     public List<UserRepresentation> getMembers(@QueryParam("first") Integer firstResult,
                                                @QueryParam("max") Integer maxResults) {
-        auth.requireView();
+        this.auth.groups().requireViewMembers(group);
 
-        if (group == null) {
-            throw new NotFoundException("Could not find group by id");
-        }
 
         firstResult = firstResult != null ? firstResult : 0;
         maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
@@ -232,4 +222,55 @@ public class GroupResource {
         return results;
     }
 
+    /**
+     * Return object stating whether client Authorization permissions have been initialized or not and a reference
+     *
+     * @return
+     */
+    @Path("management/permissions")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference getManagementPermissions() {
+        auth.groups().requireView(group);
+
+        AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+        if (!permissions.groups().isPermissionsEnabled(group)) {
+            return new ManagementPermissionReference();
+        }
+        return toMgmtRef(group, permissions);
+    }
+
+    public static ManagementPermissionReference toMgmtRef(GroupModel group, AdminPermissionManagement permissions) {
+        ManagementPermissionReference ref = new ManagementPermissionReference();
+        ref.setEnabled(true);
+        ref.setResource(permissions.groups().resource(group).getId());
+        ref.setScopePermissions(permissions.groups().getPermissions(group));
+        return ref;
+    }
+
+
+    /**
+     * Return object stating whether client Authorization permissions have been initialized or not and a reference
+     *
+     *
+     * @return initialized manage permissions reference
+     */
+    @Path("management/permissions")
+    @PUT
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    @NoCache
+    public ManagementPermissionReference setManagementPermissionsEnabled(ManagementPermissionReference ref) {
+        auth.groups().requireManage(group);
+        if (ref.isEnabled()) {
+            AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+            permissions.groups().setPermissionsEnabled(group, ref.isEnabled());
+            return toMgmtRef(group, permissions);
+        } else {
+            return new ManagementPermissionReference();
+        }
+    }
+
 }
+
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
index 5be1c0d..2a1909b 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
@@ -40,6 +40,7 @@ import javax.ws.rs.core.UriInfo;
 import java.net.URI;
 import java.util.List;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 /**
  * @resource Groups
@@ -49,15 +50,14 @@ public class GroupsResource {
 
     private final RealmModel realm;
     private final KeycloakSession session;
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final AdminEventBuilder adminEvent;
 
-    public GroupsResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public GroupsResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.session = session;
         this.auth = auth;
         this.adminEvent = adminEvent.resource(ResourceType.GROUP);
-        auth.init(RealmAuth.Resource.USER);
 
     }
 
@@ -72,7 +72,7 @@ public class GroupsResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<GroupRepresentation> getGroups() {
-        auth.requireView();
+        auth.groups().requireList();
 
         return ModelToRepresentation.toGroupHierarchy(realm, false);
     }
@@ -85,9 +85,10 @@ public class GroupsResource {
      */
     @Path("{id}")
     public GroupResource getGroupById(@PathParam("id") String id) {
-        auth.requireView();
-
         GroupModel group = realm.getGroupById(id);
+        if (group == null) {
+            throw new NotFoundException("Could not find group by id");
+        }
         GroupResource resource =  new GroupResource(realm, group, session, this.auth, adminEvent);
         ResteasyProviderFactory.getInstance().injectProperties(resource);
         return resource;
@@ -102,7 +103,7 @@ public class GroupsResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response addTopLevelGroup(GroupRepresentation rep) {
-        auth.requireManage();
+        auth.groups().requireManage();
 
         for (GroupModel group : realm.getGroups()) {
             if (group.getName().equals(rep.getName())) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index aa4a054..4c08c20 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -44,6 +44,7 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
 import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -72,7 +73,7 @@ public class IdentityProviderResource {
 
     protected static final Logger logger = Logger.getLogger(IdentityProviderResource.class);
 
-    private final RealmAuth auth;
+    private final AdminPermissionEvaluator auth;
     private final RealmModel realm;
     private final KeycloakSession session;
     private final IdentityProviderModel identityProviderModel;
@@ -80,7 +81,7 @@ public class IdentityProviderResource {
 
     @Context private UriInfo uriInfo;
 
-    public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel, AdminEventBuilder adminEvent) {
+    public IdentityProviderResource(AdminPermissionEvaluator auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.session = session;
         this.identityProviderModel = identityProviderModel;
@@ -97,7 +98,7 @@ public class IdentityProviderResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public IdentityProviderRepresentation getIdentityProvider() {
-        this.auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -115,7 +116,7 @@ public class IdentityProviderResource {
     @DELETE
     @NoCache
     public Response delete() {
-        this.auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -138,7 +139,7 @@ public class IdentityProviderResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @NoCache
     public Response update(IdentityProviderRepresentation providerRep) {
-        this.auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -229,7 +230,7 @@ public class IdentityProviderResource {
     @Path("export")
     @NoCache
     public Response export(@Context UriInfo uriInfo, @QueryParam("format") String format) {
-        this.auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -250,7 +251,7 @@ public class IdentityProviderResource {
     @Path("mapper-types")
     @NoCache
     public Map<String, IdentityProviderMapperTypeRepresentation> getMapperTypes() {
-        this.auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -289,7 +290,7 @@ public class IdentityProviderResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<IdentityProviderMapperRepresentation> getMappers() {
-        this.auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -312,7 +313,7 @@ public class IdentityProviderResource {
     @Path("mappers")
     @Consumes(MediaType.APPLICATION_JSON)
     public Response addMapper(IdentityProviderMapperRepresentation mapper) {
-        auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -343,7 +344,7 @@ public class IdentityProviderResource {
     @Path("mappers/{id}")
     @Produces(MediaType.APPLICATION_JSON)
     public IdentityProviderMapperRepresentation getMapperById(@PathParam("id") String id) {
-        auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -365,7 +366,7 @@ public class IdentityProviderResource {
     @Path("mappers/{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     public void update(@PathParam("id") String id, IdentityProviderMapperRepresentation rep) {
-        auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
@@ -388,7 +389,7 @@ public class IdentityProviderResource {
     @NoCache
     @Path("mappers/{id}")
     public void delete(@PathParam("id") String id) {
-        auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
 
         if (identityProviderModel == null) {
             throw new javax.ws.rs.NotFoundException();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
index c5250ac..646b463 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
@@ -37,6 +37,7 @@ import org.keycloak.models.utils.StripSecretsUtils;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.Consumes;
@@ -65,14 +66,13 @@ public class IdentityProvidersResource {
 
     private final RealmModel realm;
     private final KeycloakSession session;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     private AdminEventBuilder adminEvent;
 
-    public IdentityProvidersResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public IdentityProvidersResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.session = session;
         this.auth = auth;
-        this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
         this.adminEvent = adminEvent.resource(ResourceType.IDENTITY_PROVIDER);
     }
 
@@ -87,7 +87,7 @@ public class IdentityProvidersResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Response getIdentityProviders(@PathParam("provider_id") String providerId) {
-        this.auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
         IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
         if (providerFactory != null) {
             return Response.ok(providerFactory).build();
@@ -108,7 +108,7 @@ public class IdentityProvidersResource {
     @Consumes(MediaType.MULTIPART_FORM_DATA)
     @Produces(MediaType.APPLICATION_JSON)
     public Map<String, String> importFrom(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
-        this.auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
         Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
         if (!(formDataMap.containsKey("providerId") && formDataMap.containsKey("file"))) {
             throw new BadRequestException();
@@ -134,7 +134,7 @@ public class IdentityProvidersResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Map<String, String> importFrom(@Context UriInfo uriInfo, Map<String, Object> data) throws IOException {
-        this.auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
         if (!(data.containsKey("providerId") && data.containsKey("fromUrl"))) {
             throw new BadRequestException();
         }
@@ -164,7 +164,7 @@ public class IdentityProvidersResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<IdentityProviderRepresentation> getIdentityProviders() {
-        this.auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
 
         List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
 
@@ -185,7 +185,7 @@ public class IdentityProvidersResource {
     @Path("instances")
     @Consumes(MediaType.APPLICATION_JSON)
     public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) {
-        this.auth.requireManage();
+        this.auth.realm().requireManageIdentityProviders();
 
         try {
             IdentityProviderModel identityProvider = RepresentationToModel.toModel(realm, representation);
@@ -203,7 +203,7 @@ public class IdentityProvidersResource {
 
     @Path("instances/{alias}")
     public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) {
-        this.auth.requireView();
+        this.auth.realm().requireViewIdentityProviders();
         IdentityProviderModel identityProviderModel = null;
 
         for (IdentityProviderModel storedIdentityProvider : this.realm.getIdentityProviders()) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java b/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
index f2c9401..d990fd1 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
@@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeyManager;
 import org.keycloak.models.RealmModel;
 import org.keycloak.representations.idm.KeysMetadataRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Produces;
@@ -43,9 +44,9 @@ public class KeyResource {
 
     private RealmModel realm;
     private KeycloakSession session;
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
 
-    public KeyResource(RealmModel realm, KeycloakSession session, RealmAuth auth) {
+    public KeyResource(RealmModel realm, KeycloakSession session, AdminPermissionEvaluator auth) {
         this.realm = realm;
         this.session = session;
         this.auth = auth;
@@ -55,7 +56,7 @@ public class KeyResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public KeysMetadataRepresentation getKeyMetadata() {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         KeyManager keystore = session.keys();
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissionEvaluator.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissionEvaluator.java
new file mode 100644
index 0000000..19abaf4
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissionEvaluator.java
@@ -0,0 +1,57 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.services.resources.admin.AdminAuth;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface AdminPermissionEvaluator {
+    RealmPermissionEvaluator realm();
+
+    void requireAnyAdminRole();
+
+    AdminAuth adminAuth();
+
+    RolePermissionEvaluator roles();
+    UserPermissionEvaluator users();
+    ClientPermissionEvaluator clients();
+    GroupPermissionEvaluator groups();
+
+    /**
+     * Useful as a function pointer, i.e. 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.
+     *
+     */
+    interface PermissionCheck {
+        boolean evaluate();
+    }
+    /**
+     * Useful as a function pointer, i.e. 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.
+     *
+     * throws appropriate exception if permission is deny
+     *
+     */
+    interface RequirePermissionCheck {
+        void require();
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissionManagement.java
new file mode 100644
index 0000000..2a94132
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissionManagement.java
@@ -0,0 +1,38 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface AdminPermissionManagement {
+    public static final String MANAGE_SCOPE = "manage";
+    public static final String VIEW_SCOPE = "view";
+
+    AuthorizationProvider authz();
+
+    RolePermissionManagement roles();
+    UserPermissionManagement users();
+    GroupPermissionManagement groups();
+    ClientPermissionManagement clients();
+
+    ResourceServer realmResourceServer();
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissions.java
new file mode 100644
index 0000000..f809e1d
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/AdminPermissions.java
@@ -0,0 +1,80 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
+import org.keycloak.provider.ProviderEventManager;
+import org.keycloak.services.resources.admin.AdminAuth;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AdminPermissions {
+
+
+    public static AdminPermissionEvaluator evaluator(KeycloakSession session, RealmModel realm, AdminAuth auth) {
+        return new MgmtPermissions(session, realm, auth);
+    }
+    public static AdminPermissionEvaluator evaluator(KeycloakSession session, RealmModel realm, RealmModel adminsRealm, UserModel admin) {
+        return new MgmtPermissions(session, realm, adminsRealm, admin);
+    }
+
+    public static RealmsPermissionEvaluator realms(KeycloakSession session, AdminAuth auth) {
+        return new MgmtPermissions(session, auth);
+    }
+
+    public static AdminPermissionManagement management(KeycloakSession session, RealmModel realm) {
+        return new MgmtPermissions(session, realm);
+    }
+
+    public static void registerListener(ProviderEventManager manager) {
+        manager.register(new ProviderEventListener() {
+            @Override
+            public void onEvent(ProviderEvent event) {
+                if (event instanceof RoleContainerModel.RoleRemovedEvent) {
+                    RoleContainerModel.RoleRemovedEvent cast = (RoleContainerModel.RoleRemovedEvent)event;
+                    RoleModel role = cast.getRole();
+                    RealmModel realm;
+                    if (role.getContainer() instanceof ClientModel) {
+                        realm = ((ClientModel)role.getContainer()).getRealm();
+
+                    } else {
+                        realm = (RealmModel)role.getContainer();
+                    }
+                    management(cast.getKeycloakSession(), realm).roles().setPermissionsEnabled(role, false);
+                } else if (event instanceof RealmModel.ClientRemovedEvent) {
+                    RealmModel.ClientRemovedEvent cast = (RealmModel.ClientRemovedEvent)event;
+                    management(cast.getKeycloakSession(), cast.getClient().getRealm()).clients().setPermissionsEnabled(cast.getClient(), false);
+                } else if (event instanceof GroupModel.GroupRemovedEvent) {
+                    GroupModel.GroupRemovedEvent cast = (GroupModel.GroupRemovedEvent)event;
+                    management(cast.getKeycloakSession(), cast.getRealm()).groups().setPermissionsEnabled(cast.getGroup(), false);
+                }
+            }
+        });
+    }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionEvaluator.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionEvaluator.java
new file mode 100644
index 0000000..3b64a27
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionEvaluator.java
@@ -0,0 +1,84 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClientPermissionEvaluator {
+    boolean isPermissionsEnabled(ClientModel client);
+
+    void setPermissionsEnabled(ClientModel client, boolean enable);
+
+    void requireListTemplates();
+
+    boolean canManage();
+
+    void requireManage();
+
+    boolean canManageTemplates();
+
+    void requireManageTemplates();
+
+    boolean canView();
+
+    boolean canList();
+
+    boolean canViewTemplates();
+
+    void requireList();
+
+    boolean canListTemplates();
+
+    void requireView();
+
+    void requireViewTemplates();
+
+    boolean canManage(ClientModel client);
+
+    boolean canConfigure(ClientModel client);
+
+    void requireConfigure(ClientModel client);
+
+    void requireManage(ClientModel client);
+
+    boolean canView(ClientModel client);
+
+    void requireView(ClientModel client);
+
+    boolean canManage(ClientTemplateModel template);
+
+    void requireManage(ClientTemplateModel template);
+
+    boolean canView(ClientTemplateModel template);
+
+    void requireView(ClientTemplateModel template);
+
+    boolean canMapRoles(ClientModel client);
+
+    boolean canMapCompositeRoles(ClientModel client);
+
+    boolean canMapClientScopeRoles(ClientModel client);
+
+    Map<String, Boolean> getAccess(ClientModel client);
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java
new file mode 100644
index 0000000..8a6b76d
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissionManagement.java
@@ -0,0 +1,57 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.models.ClientModel;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClientPermissionManagement {
+    public static final String MAP_ROLES_SCOPE = "map-roles";
+    public static final String MAP_ROLES_CLIENT_SCOPE = "map-roles-client-scope";
+    public static final String MAP_ROLES_COMPOSITE_SCOPE = "map-roles-composite";
+    public static final String CONFIGURE_SCOPE = "configure";
+
+    boolean isPermissionsEnabled(ClientModel client);
+
+    void setPermissionsEnabled(ClientModel client, boolean enable);
+
+    Resource resource(ClientModel client);
+
+    Map<String, String> getPermissions(ClientModel client);
+
+    Policy mapRolesPermission(ClientModel client);
+
+    Policy mapRolesClientScopePermission(ClientModel client);
+
+    Policy mapRolesCompositePermission(ClientModel client);
+
+    Policy managePermission(ClientModel client);
+
+    Policy configurePermission(ClientModel client);
+
+    Policy viewPermission(ClientModel client);
+
+    ResourceServer resourceServer(ClientModel client);
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java
new file mode 100644
index 0000000..2b1e234
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/ClientPermissions.java
@@ -0,0 +1,568 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.services.ForbiddenException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manages default policies for all users.
+ *
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+class ClientPermissions implements ClientPermissionEvaluator, ClientPermissionManagement {
+    private static final Logger logger = Logger.getLogger(ClientPermissions.class);
+    protected final KeycloakSession session;
+    protected final RealmModel realm;
+    protected final AuthorizationProvider authz;
+    protected final MgmtPermissions root;
+
+    public ClientPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
+        this.session = session;
+        this.realm = realm;
+        this.authz = authz;
+        this.root = root;
+    }
+
+    private String getResourceName(ClientModel client) {
+        return "client.resource." + client.getId();
+    }
+
+    private String getManagePermissionName(ClientModel client) {
+        return "manage.permission.client." + client.getId();
+    }
+    private String getConfigurePermissionName(ClientModel client) {
+        return "configure.permission.client." + client.getId();
+    }
+    private String getViewPermissionName(ClientModel client) {
+        return "view.permission.client." + client.getId();
+    }
+    private String getMapRolesPermissionName(ClientModel client) {
+        return MAP_ROLES_SCOPE + ".permission.client." + client.getId();
+    }
+    private String getMapRolesClientScopePermissionName(ClientModel client) {
+        return MAP_ROLES_CLIENT_SCOPE + ".permission.client." + client.getId();
+    }
+    private String getMapRolesCompositePermissionName(ClientModel client) {
+        return MAP_ROLES_COMPOSITE_SCOPE + ".permission.client." + client.getId();
+    }
+
+    private void initialize(ClientModel client) {
+        ResourceServer server = root.findOrCreateResourceServer(client);
+        Scope manageScope = manageScope(server);
+        if (manageScope == null) {
+            manageScope = authz.getStoreFactory().getScopeStore().create(AdminPermissionManagement.MANAGE_SCOPE, server);
+        }
+        Scope viewScope = viewScope(server);
+        if (viewScope == null) {
+            viewScope = authz.getStoreFactory().getScopeStore().create(AdminPermissionManagement.VIEW_SCOPE, server);
+        }
+        Scope mapRoleScope = mapRolesScope(server);
+        if (mapRoleScope == null) {
+            mapRoleScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_SCOPE, server);
+        }
+        Scope mapRoleClientScope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_CLIENT_SCOPE, server.getId());
+        if (mapRoleClientScope == null) {
+            mapRoleClientScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_CLIENT_SCOPE, server);
+        }
+        Scope mapRoleCompositeScope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_COMPOSITE_SCOPE, server.getId());
+        if (mapRoleCompositeScope == null) {
+            mapRoleCompositeScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLES_COMPOSITE_SCOPE, server);
+        }
+        Scope configureScope = authz.getStoreFactory().getScopeStore().findByName(CONFIGURE_SCOPE, server.getId());
+        if (configureScope == null) {
+            configureScope = authz.getStoreFactory().getScopeStore().create(CONFIGURE_SCOPE, server);
+        }
+
+        String resourceName = getResourceName(client);
+        Resource resource = authz.getStoreFactory().getResourceStore().findByName(resourceName, server.getId());
+        if (resource == null) {
+            resource = authz.getStoreFactory().getResourceStore().create(resourceName, server, server.getClientId());
+            resource.setType("Client");
+            Set<Scope> scopeset = new HashSet<>();
+            scopeset.add(configureScope);
+            scopeset.add(manageScope);
+            scopeset.add(viewScope);
+            scopeset.add(mapRoleScope);
+            scopeset.add(mapRoleClientScope);
+            scopeset.add(mapRoleCompositeScope);
+            resource.updateScopes(scopeset);
+        }
+        String managePermissionName = getManagePermissionName(client);
+        Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
+        if (managePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, managePermissionName, resource, manageScope);
+        }
+        String configurePermissionName = getConfigurePermissionName(client);
+        Policy configurePermission = authz.getStoreFactory().getPolicyStore().findByName(configurePermissionName, server.getId());
+        if (configurePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, configurePermissionName, resource, configureScope);
+        }
+        String viewPermissionName = getViewPermissionName(client);
+        Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
+        if (viewPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, viewPermissionName, resource, viewScope);
+        }
+        String mapRolePermissionName = getMapRolesPermissionName(client);
+        Policy mapRolePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRolePermissionName, server.getId());
+        if (mapRolePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, mapRolePermissionName, resource, mapRoleScope);
+        }
+        String mapRoleClientScopePermissionName = getMapRolesClientScopePermissionName(client);
+        Policy mapRoleClientScopePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRoleClientScopePermissionName, server.getId());
+        if (mapRoleClientScopePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, mapRoleClientScopePermissionName, resource, mapRoleClientScope);
+        }
+        String mapRoleCompositePermissionName = getMapRolesCompositePermissionName(client);
+        Policy mapRoleCompositePermission = authz.getStoreFactory().getPolicyStore().findByName(mapRoleCompositePermissionName, server.getId());
+        if (mapRoleCompositePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, mapRoleCompositePermissionName, resource, mapRoleCompositeScope);
+        }
+    }
+
+    private void deletePolicy(String name, ResourceServer server) {
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(name, server.getId());
+        if (policy != null) {
+            authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+        }
+
+    }
+
+    private void deletePermissions(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return;
+        deletePolicy(getManagePermissionName(client), server);
+        deletePolicy(getViewPermissionName(client), server);
+        deletePolicy(getMapRolesPermissionName(client), server);
+        deletePolicy(getMapRolesClientScopePermissionName(client), server);
+        deletePolicy(getMapRolesCompositePermissionName(client), server);
+        deletePolicy(getConfigurePermissionName(client), server);
+        Resource resource = authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());;
+        if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
+    }
+
+    @Override
+    public boolean isPermissionsEnabled(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return false;
+
+        return authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId()) != null;
+    }
+
+    @Override
+    public void setPermissionsEnabled(ClientModel client, boolean enable) {
+        if (enable) {
+            initialize(client);
+        } else {
+            deletePermissions(client);
+        }
+    }
+
+
+
+    private Scope manageScope(ResourceServer server) {
+        return authz.getStoreFactory().getScopeStore().findByName(AdminPermissionManagement.MANAGE_SCOPE, server.getId());
+    }
+
+    private Scope configureScope(ResourceServer server) {
+        return authz.getStoreFactory().getScopeStore().findByName(CONFIGURE_SCOPE, server.getId());
+    }
+
+    private Scope viewScope(ResourceServer server) {
+        return authz.getStoreFactory().getScopeStore().findByName(AdminPermissionManagement.VIEW_SCOPE, server.getId());
+    }
+    private Scope mapRolesScope(ResourceServer server) {
+        return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_SCOPE, server.getId());
+    }
+
+    @Override
+    public boolean canList() {
+        return root.hasAnyAdminRole();
+    }
+
+    @Override
+    public void requireList() {
+        if (!canList()) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canListTemplates() {
+        return root.hasAnyAdminRole();
+    }
+
+    @Override
+    public void requireListTemplates() {
+        if (!canListTemplates()) {
+            throw new ForbiddenException();
+        }
+    }
+    public boolean canManageClientsDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_CLIENTS);
+    }
+    public boolean canViewClientDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_CLIENTS, AdminRoles.VIEW_CLIENTS);
+    }
+
+    @Override
+    public boolean canManage() {
+        return canManageClientsDefault();
+    }
+
+    @Override
+    public void requireManage() {
+        if (!canManage()) {
+            throw new ForbiddenException();
+        }
+    }
+    @Override
+    public boolean canView() {
+        return canManageClientsDefault() || canViewClientDefault();
+    }
+
+    @Override
+    public void requireView() {
+        if (!canView()) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public Resource resource(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return null;
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+        if (resource == null) return null;
+        return resource;
+    }
+
+    @Override
+    public Map<String, String> getPermissions(ClientModel client) {
+        Map<String, String> scopes = new HashMap<>();
+        scopes.put(MAP_ROLES_SCOPE,  mapRolesPermission(client).getId());
+        scopes.put(MAP_ROLES_CLIENT_SCOPE, mapRolesClientScopePermission(client).getId());
+        scopes.put(MAP_ROLES_COMPOSITE_SCOPE, mapRolesCompositePermission(client).getId());
+        scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission(client).getId());
+        scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission(client).getId());
+        scopes.put(CONFIGURE_SCOPE, configurePermission(client).getId());
+        return scopes;
+    }
+
+
+    @Override
+    public boolean canManage(ClientModel client) {
+        if (canManageClientsDefault()) return true;
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = resourceServer(client);
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = manageScope(server);
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public boolean canConfigure(ClientModel client) {
+        if (canManage(client)) return true;
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = resourceServer(client);
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getConfigurePermissionName(client), server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = configureScope(server);
+        return root.evaluatePermission(resource, scope, server);
+    }
+    @Override
+    public void requireConfigure(ClientModel client) {
+        if (!canConfigure(client)) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+    @Override
+    public void requireManage(ClientModel client) {
+        if (!canManage(client)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canView(ClientModel client) {
+        return hasView(client) || canConfigure(client);
+    }
+
+    private boolean hasView(ClientModel client) {
+        if (canView()) return true;
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = resourceServer(client);
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = viewScope(server);
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public void requireView(ClientModel client) {
+        if (!canView(client)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    // templates
+
+    @Override
+    public boolean canViewTemplates() {
+        return canView();
+    }
+
+    @Override
+    public boolean canManageTemplates() {
+        return canManageClientsDefault();
+    }
+
+    @Override
+    public void requireManageTemplates() {
+        if (!canManageTemplates()) {
+            throw new ForbiddenException();
+        }
+    }
+    @Override
+    public void requireViewTemplates() {
+        if (!canViewTemplates()) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canManage(ClientTemplateModel template) {
+        return canManageClientsDefault();
+    }
+
+    @Override
+    public void requireManage(ClientTemplateModel template) {
+        if (!canManage(template)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canView(ClientTemplateModel template) {
+        return canViewClientDefault();
+    }
+
+    @Override
+    public void requireView(ClientTemplateModel template) {
+        if (!canView(template)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canMapRoles(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesPermissionName(client), server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = mapRolesScope(server);
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public Policy mapRolesPermission(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return null;
+        return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesPermissionName(client), server.getId());
+    }
+
+    @Override
+    public Policy mapRolesClientScopePermission(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return null;
+        return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesClientScopePermissionName(client), server.getId());
+    }
+
+    @Override
+    public Policy mapRolesCompositePermission(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return null;
+        return authz.getStoreFactory().getPolicyStore().findByName(getMapRolesCompositePermissionName(client), server.getId());
+    }
+
+    @Override
+    public Policy managePermission(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return null;
+        return authz.getStoreFactory().getPolicyStore().findByName(getManagePermissionName(client), server.getId());
+    }
+
+    @Override
+    public Policy configurePermission(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return null;
+        return authz.getStoreFactory().getPolicyStore().findByName(getConfigurePermissionName(client), server.getId());
+    }
+
+    @Override
+    public Policy viewPermission(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return null;
+        return authz.getStoreFactory().getPolicyStore().findByName(getViewPermissionName(client), server.getId());
+    }
+
+    @Override
+    public ResourceServer resourceServer(ClientModel client) {
+        return root.resourceServer(client);
+    }
+
+    @Override
+    public boolean canMapCompositeRoles(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesCompositePermissionName(client), server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_COMPOSITE_SCOPE, server.getId());
+        return root.evaluatePermission(resource, scope, server);
+    }
+    @Override
+    public boolean canMapClientScopeRoles(ClientModel client) {
+        ResourceServer server = resourceServer(client);
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getResourceName(client), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolesClientScopePermissionName(client), server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLES_CLIENT_SCOPE, server.getId());
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public Map<String, Boolean> getAccess(ClientModel client) {
+        Map<String, Boolean> map = new HashMap<>();
+        map.put("view", canView(client));
+        map.put("manage", canManage(client));
+        map.put("configure", canConfigure(client));
+        return map;
+    }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionEvaluator.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionEvaluator.java
new file mode 100644
index 0000000..d3a5213
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionEvaluator.java
@@ -0,0 +1,61 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.models.GroupModel;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface GroupPermissionEvaluator {
+    boolean canList();
+
+    void requireList();
+
+    boolean canManage(GroupModel group);
+
+    void requireManage(GroupModel group);
+
+    boolean canView(GroupModel group);
+
+    void requireView(GroupModel group);
+
+    boolean canManage();
+
+    void requireManage();
+
+    boolean canView();
+
+    void requireView();
+
+    boolean canViewMembers(GroupModel group);
+
+    void requireViewMembers(GroupModel group);
+
+    boolean canManageMembers(GroupModel group);
+
+    void requireManageMembers(GroupModel group);
+
+    boolean canManageMembership(GroupModel group);
+
+    void requireManageMembership(GroupModel group);
+
+    Map<String, Boolean> getAccess(GroupModel group);
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java
new file mode 100644
index 0000000..2ec602c
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissionManagement.java
@@ -0,0 +1,46 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RoleModel;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface GroupPermissionManagement {
+    boolean isPermissionsEnabled(GroupModel group);
+    void setPermissionsEnabled(GroupModel group, boolean enable);
+
+    Policy viewMembersPermission(GroupModel group);
+    Policy manageMembersPermission(GroupModel group);
+
+    Policy manageMembershipPermission(GroupModel group);
+
+    Policy viewPermission(GroupModel group);
+    Policy managePermission(GroupModel group);
+
+    Resource resource(GroupModel group);
+
+    Map<String, String> getPermissions(GroupModel group);
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java
new file mode 100644
index 0000000..a7e9f37
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java
@@ -0,0 +1,483 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.services.ForbiddenException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManagement {
+    private static final Logger logger = Logger.getLogger(GroupPermissions.class);
+    public static final String MAP_ROLE_SCOPE = "map-role";
+    public static final String MANAGE_MEMBERSHIP_SCOPE = "manage-membership";
+    public static final String MANAGE_MEMBERS_SCOPE = "manage-members";
+    public static final String VIEW_MEMBERS_SCOPE = "view-members";
+    protected final KeycloakSession session;
+    protected final RealmModel realm;
+    protected final AuthorizationProvider authz;
+    protected final MgmtPermissions root;
+
+    public GroupPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
+        this.session = session;
+        this.realm = realm;
+        this.authz = authz;
+        this.root = root;
+    }
+
+    private static String getGroupResourceName(GroupModel group) {
+        return "group.resource." + group.getId();
+    }
+
+
+    public static String getManagePermissionGroup(GroupModel group) {
+        return "manage.permission.group." + group.getId();
+    }
+
+    public static String getManageMembersPermissionGroup(GroupModel group) {
+        return "manage.members.permission.group." + group.getId();
+    }
+
+    public static String getManageMembershipPermissionGroup(GroupModel group) {
+        return "manage.membership.permission.group." + group.getId();
+    }
+
+    public static String getViewPermissionGroup(GroupModel group) {
+        return "view.permission.group." + group.getId();
+    }
+
+    public static String getViewMembersPermissionGroup(GroupModel group) {
+        return "view.members.permission.group." + group.getId();
+    }
+
+    private void initialize(GroupModel group) {
+        root.initializeRealmResourceServer();
+        root.initializeRealmDefaultScopes();
+        ResourceServer server = root.realmResourceServer();
+        Scope manageScope = root.realmManageScope();
+        Scope viewScope = root.realmViewScope();
+        Scope manageMembersScope = root.initializeRealmScope(MANAGE_MEMBERS_SCOPE);
+        Scope viewMembersScope = root.initializeRealmScope(VIEW_MEMBERS_SCOPE);
+        Scope manageMembershipScope = root.initializeRealmScope(MANAGE_MEMBERSHIP_SCOPE);
+
+        String groupResourceName = getGroupResourceName(group);
+        Resource groupResource = authz.getStoreFactory().getResourceStore().findByName(groupResourceName, server.getId());
+        if (groupResource == null) {
+            groupResource = authz.getStoreFactory().getResourceStore().create(groupResourceName, server, server.getClientId());
+            Set<Scope> scopeset = new HashSet<>();
+            scopeset.add(manageScope);
+            scopeset.add(viewScope);
+            scopeset.add(manageMembershipScope);
+            scopeset.add(manageMembersScope);
+            groupResource.updateScopes(scopeset);
+        }
+        String managePermissionName = getManagePermissionGroup(group);
+        Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
+        if (managePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, managePermissionName, groupResource, manageScope);
+        }
+        String viewPermissionName = getViewPermissionGroup(group);
+        Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
+        if (viewPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, viewPermissionName, groupResource, viewScope);
+        }
+        String manageMembersPermissionName = getManageMembersPermissionGroup(group);
+        Policy manageMembersPermission = authz.getStoreFactory().getPolicyStore().findByName(manageMembersPermissionName, server.getId());
+        if (manageMembersPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, manageMembersPermissionName, groupResource, manageMembersScope);
+        }
+        String viewMembersPermissionName = getViewMembersPermissionGroup(group);
+        Policy viewMembersPermission = authz.getStoreFactory().getPolicyStore().findByName(viewMembersPermissionName, server.getId());
+        if (viewMembersPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, viewMembersPermissionName, groupResource, viewMembersScope);
+        }
+        String manageMembershipPermissionName = getManageMembershipPermissionGroup(group);
+        Policy manageMembershipPermission = authz.getStoreFactory().getPolicyStore().findByName(manageMembershipPermissionName, server.getId());
+        if (manageMembershipPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, manageMembershipPermissionName, groupResource, manageMembershipScope);
+        }
+
+    }
+
+    @Override
+    public boolean canList() {
+        return root.hasOneAdminRole(AdminRoles.VIEW_USERS, AdminRoles.MANAGE_USERS, AdminRoles.QUERY_GROUPS);
+    }
+
+    @Override
+    public void requireList() {
+        if (!canList()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+
+    @Override
+    public boolean isPermissionsEnabled(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        return authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId()) != null;
+    }
+
+    private Resource groupResource(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+        String groupResourceName = getGroupResourceName(group);
+        return authz.getStoreFactory().getResourceStore().findByName(groupResourceName, server.getId());
+    }
+
+    @Override
+    public void setPermissionsEnabled(GroupModel group, boolean enable) {
+       if (enable) {
+           initialize(group);
+       } else {
+           deletePermissions(group);
+       }
+    }
+
+    private void deletePermissions(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return;
+        Policy managePermission = managePermission(group);
+        if (managePermission != null) {
+            authz.getStoreFactory().getPolicyStore().delete(managePermission.getId());
+        }
+        Policy viewPermission = viewPermission(group);
+        if (viewPermission != null) {
+            authz.getStoreFactory().getPolicyStore().delete(viewPermission.getId());
+        }
+        Policy manageMembersPermission = manageMembersPermission(group);
+        if (manageMembersPermission != null) {
+            authz.getStoreFactory().getPolicyStore().delete(manageMembersPermission.getId());
+        }
+        Policy viewMembersPermission = viewMembersPermission(group);
+        if (manageMembersPermission == null) {
+            authz.getStoreFactory().getPolicyStore().delete(viewMembersPermission.getId());
+        }
+        Resource resource = groupResource(group);
+        if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
+    }
+
+    @Override
+    public Policy viewMembersPermission(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+        String viewMembersPermissionName = getViewMembersPermissionGroup(group);
+        return authz.getStoreFactory().getPolicyStore().findByName(viewMembersPermissionName, server.getId());
+    }
+
+    @Override
+    public Policy manageMembersPermission(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+        String manageMembersPermissionName = getManageMembersPermissionGroup(group);
+        return authz.getStoreFactory().getPolicyStore().findByName(manageMembersPermissionName, server.getId());
+    }
+
+    @Override
+    public Policy manageMembershipPermission(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+        String manageMembershipPermissionName = getManageMembershipPermissionGroup(group);
+        return authz.getStoreFactory().getPolicyStore().findByName(manageMembershipPermissionName, server.getId());
+    }
+
+    @Override
+    public Policy viewPermission(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+        String viewPermissionName = getViewPermissionGroup(group);
+        return authz.getStoreFactory().getPolicyStore().findByName(viewPermissionName, server.getId());
+    }
+
+    @Override
+    public Policy managePermission(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+        String managePermissionName = getManagePermissionGroup(group);
+        return authz.getStoreFactory().getPolicyStore().findByName(managePermissionName, server.getId());
+    }
+
+    @Override
+    public Resource resource(GroupModel group) {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
+        if (resource == null) return null;
+        return resource;
+    }
+
+    @Override
+    public Map<String, String> getPermissions(GroupModel group) {
+        Map<String, String> scopes = new HashMap<>();
+        scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission(group).getId());
+        scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission(group).getId());
+        scopes.put(MANAGE_MEMBERS_SCOPE, manageMembersPermission(group).getId());
+        scopes.put(VIEW_MEMBERS_SCOPE, viewMembersPermission(group).getId());
+        scopes.put(MANAGE_MEMBERSHIP_SCOPE, manageMembershipPermission(group).getId());
+        return scopes;
+    }
+
+
+
+
+    @Override
+    public boolean canManage(GroupModel group) {
+        if (canManage()) return true;
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = managePermission(group);
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = root.realmManageScope();
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public void requireManage(GroupModel group) {
+        if (!canManage(group)) {
+            throw new ForbiddenException();
+        }
+    }
+    @Override
+    public boolean canView(GroupModel group) {
+        return hasView(group) || canManage(group);
+    }
+
+    private boolean hasView(GroupModel group) {
+        if (canView()) return true;
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = viewPermission(group);
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then abort
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = root.realmViewScope();
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public void requireView(GroupModel group) {
+        if (!canView(group)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canManage() {
+        return root.users().canManageDefault();
+    }
+
+    @Override
+    public void requireManage() {
+        if (!canManage()) {
+            throw new ForbiddenException();
+        }
+    }
+    @Override
+    public boolean canView() {
+        return root.users().canViewDefault();
+    }
+
+    @Override
+    public void requireView() {
+        if (!canView()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+
+    @Override
+    public boolean canViewMembers(GroupModel group) {
+        return canViewMembersEvaluation(group) || canManageMembers(group);
+    }
+
+    private boolean canViewMembersEvaluation(GroupModel group) {
+        if (root.users().canView()) return true;
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = viewMembersPermission(group);
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = authz.getStoreFactory().getScopeStore().findByName(VIEW_MEMBERS_SCOPE, server.getId());
+
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+
+    @Override
+    public void requireViewMembers(GroupModel group) {
+        if (!canViewMembers(group)) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+    @Override
+    public boolean canManageMembers(GroupModel group) {
+        if (root.users().canManage()) return true;
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = manageMembersPermission(group);
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = authz.getStoreFactory().getScopeStore().findByName(MANAGE_MEMBERS_SCOPE, server.getId());
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public void requireManageMembers(GroupModel group) {
+        if (!canManageMembers(group)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canManageMembership(GroupModel group) {
+        if (canManage(group)) return true;
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getGroupResourceName(group), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = manageMembershipPermission(group);
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = authz.getStoreFactory().getScopeStore().findByName(MANAGE_MEMBERSHIP_SCOPE, server.getId());
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public void requireManageMembership(GroupModel group) {
+        if (!canManageMembership(group)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public Map<String, Boolean> getAccess(GroupModel group) {
+        Map<String, Boolean> map = new HashMap<>();
+        map.put("view", canView(group));
+        map.put("manage", canManage(group));
+        map.put("manageMembership", canManageMembership(group));
+        return map;
+    }
+
+
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/Helper.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/Helper.java
new file mode 100644
index 0000000..2e7942d
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/Helper.java
@@ -0,0 +1,95 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+class Helper {
+    public static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) {
+        ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
+
+        representation.setName(name);
+        representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+        representation.setLogic(Logic.POSITIVE);
+        representation.addResource(resource.getName());
+        representation.addScope(scope.getName());
+        representation.addPolicy(policy.getName());
+
+        return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
+    }
+
+    public static Policy addEmptyScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope) {
+        ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
+
+        representation.setName(name);
+        representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+        representation.setLogic(Logic.POSITIVE);
+        representation.addResource(resource.getName());
+        representation.addScope(scope.getName());
+
+        return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
+    }
+
+    public static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
+        String roleName = getRolePolicyName(role);
+        return createRolePolicy(authz, resourceServer, role, roleName);
+    }
+
+    public static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role, String policyName) {
+        PolicyRepresentation representation = new PolicyRepresentation();
+
+        representation.setName(policyName);
+        representation.setType("role");
+        representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+        representation.setLogic(Logic.POSITIVE);
+        String roleValues = "[{\"id\":\"" + role.getId() + "\",\"required\": true}]";
+        Map<String, String> config = new HashMap<>();
+        config.put("roles", roleValues);
+        representation.setConfig(config);
+
+        return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
+    }
+
+    public static String getRolePolicyName(RoleModel role) {
+        String roleName = "";
+        if (role.getContainer() instanceof ClientModel) {
+            ClientModel client = (ClientModel) role.getContainer();
+            roleName = client.getClientId() + "." + role.getName();
+        } else {
+            roleName = role.getName();
+        }
+        roleName = "role.policy." + roleName;
+        return roleName;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
new file mode 100644
index 0000000..2df4953
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
@@ -0,0 +1,364 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationProviderFactory;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.common.DefaultEvaluationContext;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.common.UserModelIdentity;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+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.ResourceServerStore;
+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.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.ForbiddenException;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.admin.AdminAuth;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManagement, RealmsPermissionEvaluator {
+    private static final Logger logger = Logger.getLogger(MgmtPermissions.class);
+
+    protected RealmModel realm;
+    protected KeycloakSession session;
+    protected AuthorizationProvider authz;
+    protected AdminAuth auth;
+    protected Identity identity;
+    protected UserModel admin;
+    protected RealmModel adminsRealm;
+    protected ResourceServer realmResourceServer;
+    protected UserPermissions users;
+    protected GroupPermissions groups;
+    protected RealmPermissions realmPermissions;
+    protected ClientPermissions clientPermissions;
+
+
+    MgmtPermissions(KeycloakSession session, RealmModel realm) {
+        this.session = session;
+        this.realm = realm;
+        KeycloakSessionFactory keycloakSessionFactory = session.getKeycloakSessionFactory();
+        AuthorizationProviderFactory factory = (AuthorizationProviderFactory) keycloakSessionFactory.getProviderFactory(AuthorizationProvider.class);
+        this.authz = factory.create(session, realm);
+    }
+
+    MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
+        this(session, realm);
+        this.auth = auth;
+        this.admin = auth.getUser();
+        this.adminsRealm = auth.getRealm();
+        if (!auth.getRealm().equals(realm)
+                && !auth.getRealm().equals(new RealmManager(session).getKeycloakAdminstrationRealm())) {
+            throw new ForbiddenException();
+        }
+        if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)
+                || auth.getClient().getClientId().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
+            this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser());
+
+        } else {
+            this.identity = new KeycloakIdentity(auth.getToken(), session);
+        }
+    }
+    MgmtPermissions(KeycloakSession session, AdminAuth auth) {
+        this.session = session;
+        this.auth = auth;
+        this.admin = auth.getUser();
+        this.adminsRealm = auth.getRealm();
+        if (auth.getClient().getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)
+                || auth.getClient().getClientId().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
+            this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser());
+
+        } else {
+            this.identity = new KeycloakIdentity(auth.getToken(), session);
+        }
+    }
+    MgmtPermissions(KeycloakSession session, RealmModel realm, RealmModel adminsRealm, UserModel admin) {
+        this(session, realm);
+        this.admin = admin;
+        this.adminsRealm = adminsRealm;
+        this.identity = new UserModelIdentity(realm, admin);
+    }
+
+    public ClientModel getRealmManagementClient() {
+        ClientModel client = null;
+        if (realm.getName().equals(Config.getAdminRealm())) {
+            client = realm.getClientByClientId(Config.getAdminRealm() + "-realm");
+        } else {
+            client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+
+        }
+        return client;
+    }
+
+    @Override
+    public AuthorizationProvider authz() {
+        return authz;
+    }
+
+
+
+    @Override
+    public void requireAnyAdminRole() {
+        if (!hasAnyAdminRole()) {
+            throw new ForbiddenException();
+        }
+    }
+
+    public boolean hasAnyAdminRole() {
+        return hasOneAdminRole(AdminRoles.ALL_REALM_ROLES);
+    }
+
+    public boolean hasAnyAdminRole(RealmModel realm) {
+        return hasOneAdminRole(realm, AdminRoles.ALL_REALM_ROLES);
+    }
+
+    public boolean hasOneAdminRole(String... adminRoles) {
+        String clientId;
+        RealmModel realm = this.realm;
+        return hasOneAdminRole(realm, adminRoles);
+    }
+
+    public boolean hasOneAdminRole(RealmModel realm, String... adminRoles) {
+        String clientId;
+        RealmManager realmManager = new RealmManager(session);
+        if (adminsRealm.equals(realmManager.getKeycloakAdminstrationRealm())) {
+            clientId = realm.getMasterAdminClient().getClientId();
+        } else if (adminsRealm.equals(realm)) {
+            clientId = realm.getClientByClientId(realmManager.getRealmAdminClientId(realm)).getClientId();
+        } else {
+            return false;
+        }
+        for (String adminRole : adminRoles) {
+            if (identity.hasClientRole(clientId, adminRole)) return true;
+        }
+        return false;
+    }
+
+
+    public boolean isAdminSameRealm() {
+        return auth == null || realm.getId().equals(auth.getRealm().getId());
+    }
+
+    @Override
+    public AdminAuth adminAuth() {
+        return auth;
+    }
+
+    public Identity identity() {
+        return identity;
+    }
+
+    public UserModel admin() {
+        return admin;
+    }
+
+
+    @Override
+    public RolePermissions roles() {
+        return new RolePermissions(session, realm, authz, this);
+    }
+
+    @Override
+    public UserPermissions users() {
+        if (users != null) return users;
+        users = new UserPermissions(session, realm, authz, this);
+        return users;
+    }
+
+    @Override
+    public RealmPermissions realm() {
+        if (realmPermissions != null) return realmPermissions;
+        realmPermissions = new RealmPermissions(session, realm, authz, this);
+        return realmPermissions;
+    }
+
+    @Override
+    public ClientPermissions clients() {
+        if (clientPermissions != null) return clientPermissions;
+        clientPermissions = new ClientPermissions(session, realm, authz, this);
+        return clientPermissions;
+    }
+
+    @Override
+    public GroupPermissions groups() {
+        if (groups != null) return groups;
+        groups = new GroupPermissions(session, realm, authz, this);
+        return groups;
+    }
+
+    public ResourceServer findOrCreateResourceServer(ClientModel client) {
+         return initializeRealmResourceServer();
+    }
+
+    public ResourceServer resourceServer(ClientModel client) {
+        return realmResourceServer();
+    }
+
+    @Override
+    public ResourceServer realmResourceServer() {
+        if (realmResourceServer != null) return realmResourceServer;
+        ResourceServerStore resourceServerStore = authz.getStoreFactory().getResourceServerStore();
+        ClientModel client = getRealmManagementClient();
+        if (client == null) return null;
+        realmResourceServer = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+        return realmResourceServer;
+
+    }
+
+    public ResourceServer initializeRealmResourceServer() {
+        if (realmResourceServer != null) return realmResourceServer;
+        ClientModel client = getRealmManagementClient();
+        realmResourceServer = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+        if (realmResourceServer == null) {
+            realmResourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
+        }
+        return realmResourceServer;
+    }
+
+    protected Scope manageScope;
+    protected Scope viewScope;
+
+    public void initializeRealmDefaultScopes() {
+        ResourceServer server = initializeRealmResourceServer();
+        manageScope = initializeRealmScope(MgmtPermissions.MANAGE_SCOPE);
+        viewScope = initializeRealmScope(MgmtPermissions.VIEW_SCOPE);
+    }
+
+    public Scope initializeRealmScope(String name) {
+        ResourceServer server = initializeRealmResourceServer();
+        Scope scope  = authz.getStoreFactory().getScopeStore().findByName(name, server.getId());
+        if (scope == null) {
+            scope = authz.getStoreFactory().getScopeStore().create(name, server);
+        }
+        return scope;
+    }
+
+
+
+    public Scope realmManageScope() {
+        if (manageScope != null) return manageScope;
+        manageScope = realmScope(MgmtPermissions.MANAGE_SCOPE);
+        return manageScope;
+    }
+
+
+    public Scope realmViewScope() {
+        if (viewScope != null) return viewScope;
+        viewScope = realmScope(MgmtPermissions.VIEW_SCOPE);
+        return viewScope;
+    }
+
+    public Scope realmScope(String scope) {
+        ResourceServer server = realmResourceServer();
+        if (server == null) return null;
+        return authz.getStoreFactory().getScopeStore().findByName(scope, server.getId());
+    }
+
+    public boolean evaluatePermission(Resource resource, Scope scope, ResourceServer resourceServer) {
+        Identity identity = identity();
+        if (identity == null) {
+            throw new RuntimeException("Identity of admin is not set for permission query");
+        }
+        return evaluatePermission(resource, scope, resourceServer, identity);
+    }
+
+    public boolean evaluatePermission(Resource resource, Scope scope, ResourceServer resourceServer, Identity identity) {
+        RealmModel oldRealm = session.getContext().getRealm();
+        try {
+            session.getContext().setRealm(realm);
+            EvaluationContext context = new DefaultEvaluationContext(identity, session);
+            DecisionResult decisionCollector = new DecisionResult();
+            List<ResourcePermission> permissions = Permissions.permission(resourceServer, resource, scope);
+            PermissionEvaluator from = authz.evaluators().from(permissions, context);
+            from.evaluate(decisionCollector);
+            if (!decisionCollector.completed()) {
+                logger.error("Failed to run permission check", decisionCollector.getError());
+                return false;
+            }
+            return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
+        } finally {
+            session.getContext().setRealm(oldRealm);
+        }
+    }
+
+    @Override
+    public boolean canView(RealmModel realm) {
+        return hasOneAdminRole(realm, AdminRoles.VIEW_REALM, AdminRoles.MANAGE_REALM);
+    }
+
+    @Override
+    public boolean isAdmin(RealmModel realm) {
+        return hasAnyAdminRole(realm);
+    }
+
+    @Override
+    public boolean isAdmin() {
+        RealmManager realmManager = new RealmManager(session);
+        if (adminsRealm.equals(realmManager.getKeycloakAdminstrationRealm())) {
+            if (identity.hasRealmRole(AdminRoles.ADMIN) || identity.hasRealmRole(AdminRoles.CREATE_REALM)) {
+                return true;
+            }
+            for (RealmModel realm : session.realms().getRealms()) {
+                if (isAdmin(realm)) return true;
+            }
+            return false;
+        } else {
+            return isAdmin(adminsRealm);
+        }
+    }
+
+    @Override
+    public boolean canCreateRealm() {
+        RealmManager realmManager = new RealmManager(session);
+        if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
+           return false;
+        }
+        return identity.hasRealmRole(AdminRoles.CREATE_REALM);
+    }
+
+    @Override
+    public void requireCreateRealm() {
+        if (!canCreateRealm()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmPermissionEvaluator.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmPermissionEvaluator.java
new file mode 100644
index 0000000..7020667
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmPermissionEvaluator.java
@@ -0,0 +1,61 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface RealmPermissionEvaluator {
+    boolean canListRealms();
+
+    void requireViewRealmNameList();
+
+    boolean canManageRealm();
+
+    void requireManageRealm();
+
+    boolean canViewRealm();
+
+    void requireViewRealm();
+
+    boolean canManageIdentityProviders();
+
+    boolean canViewIdentityProviders();
+
+    void requireViewIdentityProviders();
+
+    void requireManageIdentityProviders();
+
+    boolean canManageAuthorization();
+
+    boolean canViewAuthorization();
+
+    void requireManageAuthorization();
+
+    void requireViewAuthorization();
+
+    boolean canManageEvents();
+
+    void requireManageEvents();
+
+    boolean canViewEvents();
+
+    void requireViewEvents();
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmPermissions.java
new file mode 100644
index 0000000..3fc752f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmPermissions.java
@@ -0,0 +1,189 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.ForbiddenException;
+
+/**
+ * Manages default policies for all users.
+ *
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+class RealmPermissions implements RealmPermissionEvaluator {
+    private static final Logger logger = Logger.getLogger(RealmPermissions.class);
+    protected final KeycloakSession session;
+    protected final RealmModel realm;
+    protected final AuthorizationProvider authz;
+    protected final MgmtPermissions root;
+
+    public RealmPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
+        this.session = session;
+        this.realm = realm;
+        this.authz = authz;
+        this.root = root;
+    }
+
+
+    public boolean canManageRealmDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_REALM);
+
+    }
+    public boolean canViewRealmDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_REALM, AdminRoles.VIEW_REALM);
+    }
+
+    public boolean canManageIdentityProvidersDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_IDENTITY_PROVIDERS);
+
+    }
+    public boolean canViewIdentityProvidersDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_IDENTITY_PROVIDERS, AdminRoles.VIEW_IDENTITY_PROVIDERS);
+    }
+
+    public boolean canManageAuthorizationDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_AUTHORIZATION);
+
+    }
+    public boolean canViewAuthorizationDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_AUTHORIZATION, AdminRoles.VIEW_AUTHORIZATION);
+    }
+    public boolean canManageEventsDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_EVENTS);
+    }
+    public boolean canViewEventsDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_EVENTS, AdminRoles.VIEW_EVENTS);
+    }
+
+    @Override
+    public boolean canListRealms() {
+        return root.hasAnyAdminRole();
+    }
+
+    @Override
+    public void requireViewRealmNameList() {
+        if (!canListRealms()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+    @Override
+    public boolean canManageRealm() {
+        return canManageRealmDefault();
+    }
+
+    @Override
+    public void requireManageRealm() {
+        if (!canManageRealm()) {
+            throw new ForbiddenException();
+        }
+    }
+    @Override
+    public boolean canViewRealm() {
+        return canViewRealmDefault();
+    }
+
+    @Override
+    public void requireViewRealm() {
+        if (!canViewRealm()) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canManageIdentityProviders() {
+        return canManageIdentityProvidersDefault();
+    }
+
+    @Override
+    public boolean canViewIdentityProviders() {
+        return canViewIdentityProvidersDefault();
+    }
+
+    @Override
+    public void requireViewIdentityProviders() {
+        if (!canViewIdentityProviders()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+    @Override
+    public void requireManageIdentityProviders() {
+        if (!canManageIdentityProviders()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+    @Override
+    public boolean canManageAuthorization() {
+        return canManageAuthorizationDefault();
+    }
+
+    @Override
+    public boolean canViewAuthorization() {
+        return canViewAuthorizationDefault();
+    }
+
+    @Override
+    public void requireManageAuthorization() {
+        if (!canManageAuthorization()) {
+            throw new ForbiddenException();
+        }
+    }
+    @Override
+    public void requireViewAuthorization() {
+        if (!canViewAuthorization()) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canManageEvents() {
+        return canManageEventsDefault();
+    }
+
+    @Override
+    public void requireManageEvents() {
+        if (!canManageEvents()) {
+            throw new ForbiddenException();
+        }
+    }
+    @Override
+    public boolean canViewEvents() {
+        return canViewEventsDefault();
+    }
+
+    @Override
+    public void requireViewEvents() {
+        if (!canViewEvents()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmsPermissionEvaluator.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmsPermissionEvaluator.java
new file mode 100644
index 0000000..5286d10
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RealmsPermissionEvaluator.java
@@ -0,0 +1,35 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface RealmsPermissionEvaluator {
+    boolean canView(RealmModel realm);
+
+    boolean isAdmin(RealmModel realm);
+
+    boolean isAdmin();
+
+    boolean canCreateRealm();
+
+    void requireCreateRealm();
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissionEvaluator.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissionEvaluator.java
new file mode 100644
index 0000000..a4a8b71
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissionEvaluator.java
@@ -0,0 +1,56 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface RolePermissionEvaluator {
+    boolean canList(RoleContainerModel container);
+
+    void requireList(RoleContainerModel container);
+
+    boolean canMapRole(RoleModel role);
+    void requireMapRole(RoleModel role);
+
+    boolean canManage(RoleModel role);
+
+    void requireManage(RoleModel role);
+
+    boolean canView(RoleModel role);
+
+    void requireView(RoleModel role);
+
+    boolean canMapClientScope(RoleModel role);
+    void requireMapClientScope(RoleModel role);
+
+    boolean canMapComposite(RoleModel role);
+    void requireMapComposite(RoleModel role);
+
+    boolean canManage(RoleContainerModel container);
+
+    void requireManage(RoleContainerModel container);
+
+    boolean canView(RoleContainerModel container);
+
+    void requireView(RoleContainerModel container);
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissionManagement.java
new file mode 100644
index 0000000..977e109
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissionManagement.java
@@ -0,0 +1,56 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface RolePermissionManagement {
+    public static final String MAP_ROLE_SCOPE = "map-role";
+    public static final String MAP_ROLE_CLIENT_SCOPE_SCOPE = "map-role-client-scope";
+    public static final String MAP_ROLE_COMPOSITE_SCOPE = "map-role-composite";
+
+    boolean isPermissionsEnabled(RoleModel role);
+    void setPermissionsEnabled(RoleModel role, boolean enable);
+
+    Map<String, String> getPermissions(RoleModel role);
+
+    Policy mapRolePermission(RoleModel role);
+
+    Policy mapCompositePermission(RoleModel role);
+
+    Policy mapClientScopePermission(RoleModel role);
+
+    Resource resource(RoleModel role);
+
+    ResourceServer resourceServer(RoleModel role);
+
+    Policy manageUsersPolicy(ResourceServer server);
+
+    Policy viewUsersPolicy(ResourceServer server);
+
+    Policy rolePolicy(ResourceServer server, RoleModel role);
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java
new file mode 100644
index 0000000..091d7a5
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/RolePermissions.java
@@ -0,0 +1,585 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ImpersonationConstants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.services.ForbiddenException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+class RolePermissions implements RolePermissionEvaluator, RolePermissionManagement {
+    private static final Logger logger = Logger.getLogger(RolePermissions.class);
+    protected final KeycloakSession session;
+    protected final RealmModel realm;
+    protected final AuthorizationProvider authz;
+    protected final MgmtPermissions root;
+
+    public RolePermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
+        this.session = session;
+        this.realm = realm;
+        this.authz = authz;
+        this.root = root;
+    }
+
+    @Override
+    public boolean isPermissionsEnabled(RoleModel role) {
+        return mapRolePermission(role) != null;
+    }
+
+    @Override
+    public void setPermissionsEnabled(RoleModel role, boolean enable) {
+       if (enable) {
+           initialize(role);
+       } else {
+           disablePermissions(role);
+       }
+    }
+
+    private void disablePermissions(RoleModel role) {
+        ResourceServer server = resourceServer(role);
+        if (server == null) return;
+        Policy policy = mapRolePermission(role);
+        if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+        policy = mapClientScopePermission(role);
+        if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+        policy = mapCompositePermission(role);
+        if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+        Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
+        if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
+    }
+
+    @Override
+    public Map<String, String> getPermissions(RoleModel role) {
+        Map<String, String> scopes = new HashMap<>();
+        scopes.put(RolePermissionManagement.MAP_ROLE_SCOPE, mapRolePermission(role).getId());
+        scopes.put(RolePermissionManagement.MAP_ROLE_CLIENT_SCOPE_SCOPE, mapClientScopePermission(role).getId());
+        scopes.put(RolePermissionManagement.MAP_ROLE_COMPOSITE_SCOPE, mapCompositePermission(role).getId());
+        return scopes;
+    }
+
+    @Override
+    public Policy mapRolePermission(RoleModel role) {
+        ResourceServer server = resourceServer(role);
+        if (server == null) return null;
+        return  authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), server.getId());
+    }
+
+    @Override
+    public Policy mapCompositePermission(RoleModel role) {
+        ResourceServer server = resourceServer(role);
+        if (server == null) return null;
+
+        return  authz.getStoreFactory().getPolicyStore().findByName(getMapCompositePermissionName(role), server.getId());
+    }
+
+    @Override
+    public Policy mapClientScopePermission(RoleModel role) {
+        ResourceServer server = resourceServer(role);
+        if (server == null) return null;
+
+        return  authz.getStoreFactory().getPolicyStore().findByName(getMapClientScopePermissionName(role), server.getId());
+    }
+
+    @Override
+    public Resource resource(RoleModel role) {
+        ResourceStore resourceStore = authz.getStoreFactory().getResourceStore();
+        ResourceServer server = resourceServer(role);
+        if (server == null) return null;
+        return  resourceStore.findByName(getRoleResourceName(role), server.getId());
+    }
+
+    @Override
+    public ResourceServer resourceServer(RoleModel role) {
+        ClientModel client = getRoleClient(role);
+        return root.resourceServer(client);
+    }
+
+    private boolean checkAdminRoles(RoleModel role) {
+        if (AdminRoles.ALL_ROLES.contains(role.getName())) {
+            if (root.admin().hasRole(role)) return true;
+
+            ClientModel adminClient = root.getRealmManagementClient();
+            if (adminClient.equals(role.getContainer())) {
+                // if this is realm admin role, then check to see if admin has similar permissions
+                // we do this so that the authz service is invoked
+                if (role.getName().equals(AdminRoles.MANAGE_CLIENTS)) {
+                    if (!root.clients().canManage()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.VIEW_CLIENTS)) {
+                    if (!root.clients().canView()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.QUERY_CLIENTS)) {
+                    return true;
+                } else if (role.getName().equals(AdminRoles.QUERY_USERS)) {
+                    return true;
+                } else if (role.getName().equals(AdminRoles.QUERY_GROUPS)) {
+                    return true;
+                } else if (role.getName().equals(AdminRoles.MANAGE_AUTHORIZATION)) {
+                    if (!root.realm().canManageAuthorization()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.VIEW_AUTHORIZATION)) {
+                    if (!root.realm().canViewAuthorization()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.MANAGE_EVENTS)) {
+                    if (!root.realm().canManageEvents()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.VIEW_EVENTS)) {
+                    if (!root.realm().canViewEvents()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.MANAGE_USERS)) {
+                    if (!root.users().canManage()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.VIEW_USERS)) {
+                    if (!root.users().canView()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.MANAGE_IDENTITY_PROVIDERS)) {
+                    if (!root.realm().canManageIdentityProviders()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.VIEW_IDENTITY_PROVIDERS)) {
+                    if (!root.realm().canViewIdentityProviders()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.MANAGE_REALM)) {
+                    if (!root.realm().canManageRealm()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(AdminRoles.VIEW_REALM)) {
+                    if (!root.realm().canViewRealm()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else if (role.getName().equals(ImpersonationConstants.IMPERSONATION_ROLE)) {
+                    if (!root.users().canImpersonate()) {
+                        return adminConflictMessage(role);
+                    } else {
+                        return true;
+                    }
+                } else {
+                    return adminConflictMessage(role);
+                }
+
+            } else {
+                // now we need to check to see if this is a master admin role
+                if (role.getContainer() instanceof RealmModel) {
+                    RealmModel realm = (RealmModel)role.getContainer();
+                    // If realm role is master admin role then abort
+                    if (realm.getName().equals(Config.getAdminRealm())) {
+                        return adminConflictMessage(role);
+                    }
+                } else {
+                    ClientModel container = (ClientModel)role.getContainer();
+                    // abort if this is an role in master realm and role is an admin role of any realm
+                    if (container.getRealm().getName().equals(Config.getAdminRealm())
+                            && container.getClientId().endsWith("-realm")) {
+                        return adminConflictMessage(role);
+                    }
+                }
+                return true;
+            }
+
+        }
+        return true;
+
+    }
+
+    private boolean adminConflictMessage(RoleModel role) {
+        logger.debug("Trying to assign admin privileges of role: " + role.getName() + " but admin doesn't have same privilege");
+        return false;
+    }
+
+    /**
+     * Is admin allowed to map this role?
+     *
+     * @param role
+     * @return
+     */
+    @Override
+    public boolean canMapRole(RoleModel role) {
+        if (root.users().canManageDefault()) return checkAdminRoles(role);
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        if (role.getContainer() instanceof ClientModel) {
+            if (root.clients().canMapRoles((ClientModel)role.getContainer())) return true;
+        }
+        if (!isPermissionsEnabled(role)){
+            return false;
+        }
+
+        ResourceServer resourceServer = resourceServer(role);
+        if (resourceServer == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRolePermissionName(role), resourceServer.getId());
+        if (policy == null || policy.getAssociatedPolicies().isEmpty()) {
+            return false;
+        }
+
+        Resource roleResource = resource(role);
+        Scope mapRoleScope = mapRoleScope(resourceServer);
+        if (root.evaluatePermission(roleResource, mapRoleScope, resourceServer)) {
+            return checkAdminRoles(role);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public void requireMapRole(RoleModel role) {
+        if (!canMapRole(role)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+    @Override
+    public boolean canList(RoleContainerModel container) {
+        return root.hasAnyAdminRole();
+    }
+
+    @Override
+    public void requireList(RoleContainerModel container) {
+        if (!canList(container)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+    @Override
+    public boolean canManage(RoleContainerModel container) {
+        if (container instanceof RealmModel) {
+            return root.realm().canManageRealm();
+        } else {
+            return root.clients().canConfigure((ClientModel)container);
+        }
+    }
+
+    @Override
+    public void requireManage(RoleContainerModel container) {
+        if (!canManage(container)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canView(RoleContainerModel container) {
+        if (container instanceof RealmModel) {
+            return root.realm().canViewRealm();
+        } else {
+            return root.clients().canView((ClientModel)container);
+        }
+    }
+
+    @Override
+    public void requireView(RoleContainerModel container) {
+        if (!canView(container)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canMapComposite(RoleModel role) {
+        if (canManageDefault(role)) return checkAdminRoles(role);
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+        if (role.getContainer() instanceof ClientModel) {
+            if (root.clients().canMapCompositeRoles((ClientModel)role.getContainer())) return true;
+        }
+        if (!isPermissionsEnabled(role)){
+            return false;
+        }
+
+        ResourceServer resourceServer = resourceServer(role);
+        if (resourceServer == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapCompositePermissionName(role), resourceServer.getId());
+        if (policy == null || policy.getAssociatedPolicies().isEmpty()) {
+            return false;
+        }
+
+        Resource roleResource = resource(role);
+        Scope scope = mapCompositeScope(resourceServer);
+        if (root.evaluatePermission(roleResource, scope, resourceServer)) {
+            return checkAdminRoles(role);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public void requireMapComposite(RoleModel role) {
+        if (!canMapComposite(role)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+
+    @Override
+    public boolean canMapClientScope(RoleModel role) {
+        if (root.clients().canManageClientsDefault()) return true;
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+        if (role.getContainer() instanceof ClientModel) {
+            if (root.clients().canMapClientScopeRoles((ClientModel)role.getContainer())) return true;
+        }
+        if (!isPermissionsEnabled(role)){
+            return false;
+        }
+
+        ResourceServer resourceServer = resourceServer(role);
+        if (resourceServer == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapClientScopePermissionName(role), resourceServer.getId());
+        if (policy == null || policy.getAssociatedPolicies().isEmpty()) {
+            return false;
+        }
+
+        Resource roleResource = resource(role);
+        Scope scope = mapClientScope(resourceServer);
+        return root.evaluatePermission(roleResource, scope, resourceServer);
+    }
+
+    @Override
+    public void requireMapClientScope(RoleModel role) {
+        if (!canMapClientScope(role)) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+    @Override
+    public boolean canManage(RoleModel role) {
+        if (role.getContainer() instanceof RealmModel) {
+            return root.realm().canManageRealm();
+        } else if (role.getContainer() instanceof ClientModel) {
+            ClientModel client = (ClientModel)role.getContainer();
+            return root.clients().canManage(client);
+        }
+        return false;
+    }
+
+    public boolean canManageDefault(RoleModel role) {
+        if (role.getContainer() instanceof RealmModel) {
+            return root.realm().canManageRealmDefault();
+        } else if (role.getContainer() instanceof ClientModel) {
+            ClientModel client = (ClientModel)role.getContainer();
+            return root.clients().canManageClientsDefault();
+        }
+        return false;
+    }
+
+    @Override
+    public void requireManage(RoleModel role) {
+        if (!canManage(role)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+    @Override
+    public boolean canView(RoleModel role) {
+        if (role.getContainer() instanceof RealmModel) {
+            return root.realm().canViewRealm();
+        } else if (role.getContainer() instanceof ClientModel) {
+            ClientModel client = (ClientModel)role.getContainer();
+            return root.clients().canView(client);
+        }
+        return false;
+    }
+
+    @Override
+    public void requireView(RoleModel role) {
+        if (!canView(role)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+    private ClientModel getRoleClient(RoleModel role) {
+        ClientModel client = null;
+        if (role.getContainer() instanceof ClientModel) {
+            client = (ClientModel)role.getContainer();
+        } else {
+            client = root.getRealmManagementClient();
+        }
+        return client;
+    }
+
+    @Override
+    public Policy manageUsersPolicy(ResourceServer server) {
+        RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.MANAGE_USERS);
+        return rolePolicy(server, role);
+    }
+
+    @Override
+    public Policy viewUsersPolicy(ResourceServer server) {
+        RoleModel role = root.getRealmManagementClient().getRole(AdminRoles.VIEW_USERS);
+        return rolePolicy(server, role);
+    }
+
+    @Override
+    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;
+        return Helper.createRolePolicy(authz, server, role, policyName);
+    }
+
+    private Scope mapRoleScope(ResourceServer server) {
+        return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_SCOPE, server.getId());
+    }
+
+    private Scope mapClientScope(ResourceServer server) {
+        return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_CLIENT_SCOPE_SCOPE, server.getId());
+    }
+
+    private Scope mapCompositeScope(ResourceServer server) {
+        return authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_COMPOSITE_SCOPE, server.getId());
+    }
+
+
+    private void initialize(RoleModel role) {
+        ResourceServer server = resourceServer(role);
+        if (server == null) {
+            ClientModel client = getRoleClient(role);
+            server = root.findOrCreateResourceServer(client);
+        }
+        Scope mapRoleScope = mapRoleScope(server);
+        if (mapRoleScope == null) {
+            mapRoleScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_SCOPE, server);
+        }
+        Scope mapClientScope = mapClientScope(server);
+        if (mapClientScope == null) {
+            mapClientScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_CLIENT_SCOPE_SCOPE, server);
+        }
+        Scope mapCompositeScope = mapCompositeScope(server);
+        if (mapCompositeScope == null) {
+            mapCompositeScope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_COMPOSITE_SCOPE, server);
+        }
+
+        String roleResourceName = getRoleResourceName(role);
+        Resource resource = authz.getStoreFactory().getResourceStore().findByName(roleResourceName, server.getId());
+        if (resource == null) {
+            resource = authz.getStoreFactory().getResourceStore().create(roleResourceName, server, server.getClientId());
+            Set<Scope> scopeset = new HashSet<>();
+            scopeset.add(mapClientScope);
+            scopeset.add(mapCompositeScope);
+            scopeset.add(mapRoleScope);
+            resource.updateScopes(scopeset);
+            resource.setType("Role");
+        }
+        Policy mapRolePermission = mapRolePermission(role);
+        if (mapRolePermission == null) {
+            mapRolePermission = Helper.addEmptyScopePermission(authz, server, getMapRolePermissionName(role), resource, mapRoleScope);
+            mapRolePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        }
+
+        Policy mapClientScopePermission = mapClientScopePermission(role);
+        if (mapClientScopePermission == null) {
+            mapClientScopePermission = Helper.addEmptyScopePermission(authz, server, getMapClientScopePermissionName(role), resource, mapClientScope);
+            mapClientScopePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        }
+
+        Policy mapCompositePermission = mapCompositePermission(role);
+        if (mapCompositePermission == null) {
+            mapCompositePermission = Helper.addEmptyScopePermission(authz, server, getMapCompositePermissionName(role), resource, mapCompositeScope);
+            mapCompositePermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        }
+    }
+
+    private String getMapRolePermissionName(RoleModel role) {
+        return MAP_ROLE_SCOPE + ".permission." + role.getId();
+    }
+
+    private String getMapClientScopePermissionName(RoleModel role) {
+        return MAP_ROLE_CLIENT_SCOPE_SCOPE + ".permission." + role.getId();
+    }
+
+    private String getMapCompositePermissionName(RoleModel role) {
+        return MAP_ROLE_COMPOSITE_SCOPE + ".permission." + role.getId();
+    }
+
+    private ResourceServer sdfgetResourceServer(RoleModel role) {
+        ClientModel client = getRoleClient(role);
+        return root.findOrCreateResourceServer(client);
+    }
+
+    private static String getRoleResourceName(RoleModel role) {
+        return "role.resource." + role.getId();
+    }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionEvaluator.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionEvaluator.java
new file mode 100644
index 0000000..40b1f8f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionEvaluator.java
@@ -0,0 +1,65 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.models.UserModel;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserPermissionEvaluator {
+     boolean canManage();
+
+    void requireManage();
+
+    boolean canManage(UserModel user);
+    void requireManage(UserModel user);
+
+    boolean canQuery();
+
+    void requireQuery();
+
+    boolean canQuery(UserModel user);
+
+    void requireQuery(UserModel user);
+
+    boolean canView();
+    boolean canView(UserModel user);
+    void requireView(UserModel user);
+
+    void requireView();
+
+    boolean canImpersonate(UserModel user);
+
+    boolean canImpersonate();
+
+    void requireImpersonate(UserModel user);
+
+    Map<String, Boolean> getAccess(UserModel user);
+
+    boolean canMapRoles(UserModel user);
+
+    void requireMapRoles(UserModel user);
+
+    boolean canManageGroupMembership(UserModel user);
+
+    void requireManageGroupMembership(UserModel user);
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionManagement.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionManagement.java
new file mode 100644
index 0000000..d465378
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissionManagement.java
@@ -0,0 +1,49 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.models.RoleModel;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserPermissionManagement {
+    boolean isPermissionsEnabled();
+
+    void setPermissionsEnabled(boolean enable);
+
+    Map<String, String> getPermissions();
+
+    Resource resource();
+
+    Policy managePermission();
+
+    Policy viewPermission();
+
+    Policy manageGroupMembershipPermission();
+
+    Policy mapRolesPermission();
+
+    Policy adminImpersonatingPermission();
+
+    Policy userImpersonatedPermission();
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissions.java
new file mode 100644
index 0000000..149e526
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/UserPermissions.java
@@ -0,0 +1,635 @@
+/*
+ * 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.services.resources.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.common.UserModelIdentity;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.ImpersonationConstants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.ForbiddenException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manages default policies for all users.
+ *
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+class UserPermissions implements UserPermissionEvaluator, UserPermissionManagement {
+    private static final Logger logger = Logger.getLogger(UserPermissions.class);
+    public static final String MAP_ROLES_SCOPE="map-roles";
+    public static final String IMPERSONATE_SCOPE="impersonate";
+    public static final String USER_IMPERSONATED_SCOPE="user-impersonated";
+    public static final String MANAGE_GROUP_MEMBERSHIP_SCOPE="manage-group-membership";
+    public static final String MAP_ROLES_PERMISSION_USERS = "map-roles.permission.users";
+    public static final String ADMIN_IMPERSONATING_PERMISSION = "admin-impersonating.permission.users";
+    public static final String USER_IMPERSONATED_PERMISSION = "user-impersonated.permission.users";
+    public static final String MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS = "manage-group-membership.permission.users";
+    public static final String MANAGE_PERMISSION_USERS = "manage.permission.users";
+    public static final String VIEW_PERMISSION_USERS = "view.permission.users";
+    public static final String USERS_RESOURCE = "Users";
+    protected final KeycloakSession session;
+    protected final RealmModel realm;
+    protected final AuthorizationProvider authz;
+    protected final MgmtPermissions root;
+
+    public UserPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
+        this.session = session;
+        this.realm = realm;
+        this.authz = authz;
+        this.root = root;
+    }
+
+
+    private void initialize() {
+        root.initializeRealmResourceServer();
+        root.initializeRealmDefaultScopes();
+        ResourceServer server = root.realmResourceServer();
+        Scope manageScope = root.realmManageScope();
+        Scope viewScope = root.realmViewScope();
+        Scope mapRolesScope = root.initializeRealmScope(MAP_ROLES_SCOPE);
+        Scope impersonateScope = root.initializeRealmScope(IMPERSONATE_SCOPE);
+        Scope userImpersonatedScope = root.initializeRealmScope(USER_IMPERSONATED_SCOPE);
+        Scope manageGroupMembershipScope = root.initializeRealmScope(MANAGE_GROUP_MEMBERSHIP_SCOPE);
+
+        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (usersResource == null) {
+            usersResource = authz.getStoreFactory().getResourceStore().create(USERS_RESOURCE, server, server.getClientId());
+            Set<Scope> scopeset = new HashSet<>();
+            scopeset.add(manageScope);
+            scopeset.add(viewScope);
+            scopeset.add(mapRolesScope);
+            scopeset.add(impersonateScope);
+            scopeset.add(manageGroupMembershipScope);
+            scopeset.add(userImpersonatedScope);
+            usersResource.updateScopes(scopeset);
+        }
+        Policy managePermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
+        if (managePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, MANAGE_PERMISSION_USERS, usersResource, manageScope);
+        }
+        Policy viewPermission = authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
+        if (viewPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, VIEW_PERMISSION_USERS, usersResource, viewScope);
+        }
+        Policy mapRolesPermission = authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
+        if (mapRolesPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, MAP_ROLES_PERMISSION_USERS, usersResource, mapRolesScope);
+        }
+        Policy membershipPermission = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
+        if (membershipPermission == null) {
+            Helper.addEmptyScopePermission(authz, server, MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, usersResource, manageGroupMembershipScope);
+        }
+        Policy impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
+        if (impersonatePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, ADMIN_IMPERSONATING_PERMISSION, usersResource, impersonateScope);
+        }
+        impersonatePermission = authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
+        if (impersonatePermission == null) {
+            Helper.addEmptyScopePermission(authz, server, USER_IMPERSONATED_PERMISSION, usersResource, userImpersonatedScope);
+        }
+    }
+
+    @Override
+    public Map<String, String> getPermissions() {
+        Map<String, String> scopes = new HashMap<>();
+        scopes.put(AdminPermissionManagement.MANAGE_SCOPE, managePermission().getId());
+        scopes.put(AdminPermissionManagement.VIEW_SCOPE, viewPermission().getId());
+        scopes.put(MAP_ROLES_SCOPE, mapRolesPermission().getId());
+        scopes.put(MANAGE_GROUP_MEMBERSHIP_SCOPE, manageGroupMembershipPermission().getId());
+        scopes.put(IMPERSONATE_SCOPE, adminImpersonatingPermission().getId());
+        scopes.put(USER_IMPERSONATED_SCOPE, userImpersonatedPermission().getId());
+        return scopes;
+    }
+
+    @Override
+    public boolean isPermissionsEnabled() {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return false;
+
+        Policy policy = managePermission();
+
+        return policy != null;
+    }
+
+    @Override
+    public void setPermissionsEnabled(boolean enable) {
+        if (enable) {
+            initialize();
+        } else {
+            deletePermissionSetup();
+        }
+    }
+
+    private void deletePermissionSetup() {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return;
+        Policy policy = managePermission();
+        if (policy == null) {
+            authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+        }
+        policy = viewPermission();
+        if (policy == null) {
+            authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+        }
+        policy = mapRolesPermission();
+        if (policy == null) {
+            authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+        }
+        policy = manageGroupMembershipPermission();
+        if (policy == null) {
+            authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+        }
+        policy = adminImpersonatingPermission();
+        if (policy == null) {
+            authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+        }
+        policy = userImpersonatedPermission();
+        if (policy == null) {
+            authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+        }
+        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (usersResource == null) {
+            authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
+        }
+    }
+
+    public boolean canManageDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_USERS);
+    }
+
+    @Override
+    public Resource resource() {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return null;
+
+        return  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+    }
+
+    @Override
+    public Policy managePermission() {
+        ResourceServer server = root.realmResourceServer();
+        return authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
+    }
+
+    @Override
+    public Policy viewPermission() {
+        ResourceServer server = root.realmResourceServer();
+        return authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
+    }
+
+    @Override
+    public Policy manageGroupMembershipPermission() {
+        ResourceServer server = root.realmResourceServer();
+        return authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
+    }
+
+    @Override
+    public Policy mapRolesPermission() {
+        ResourceServer server = root.realmResourceServer();
+        return authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
+    }
+
+
+    @Override
+    public Policy adminImpersonatingPermission() {
+        ResourceServer server = root.realmResourceServer();
+        return authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
+    }
+
+    @Override
+    public Policy userImpersonatedPermission() {
+        ResourceServer server = root.realmResourceServer();
+        return authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
+    }
+
+
+
+    /**
+     * Is admin allowed to manage all users?  In Authz terms, does the admin have the "manage" scope for the Users 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.
+     *
+     * @return
+     */
+    @Override
+    public boolean canManage() {
+        if (canManageDefault()) return true;
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_PERMISSION_USERS, server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = root.realmManageScope();
+        return root.evaluatePermission(resource, scope, server);
+
+    }
+
+    @Override
+    public void requireManage() {
+        if (!canManage()) {
+            throw new ForbiddenException();
+        }
+    }
+
+
+    /**
+     * Does current admin have manage permissions for this particular user?
+     *
+     * @param user
+     * @return
+     */
+    @Override
+    public boolean canManage(UserModel user) {
+        return canManage() || canManageByGroup(user);
+    }
+
+    @Override
+    public void requireManage(UserModel user) {
+        if (!canManage(user)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    private interface EvaluateGroup {
+        boolean evaluate(GroupModel group);
+    }
+
+    private boolean evaluateGroups(UserModel user, EvaluateGroup eval) {
+        for (GroupModel group : user.getGroups()) {
+            if (eval.evaluate(group)) return true;
+        }
+        return false;
+    }
+
+    private boolean evaluateHierarchy(UserModel user, EvaluateGroup eval) {
+        Set<GroupModel> visited = new HashSet<>();
+        for (GroupModel group : user.getGroups()) {
+            if (evaluateHierarchy(eval, group, visited)) return true;
+        }
+        return false;
+    }
+
+    private boolean evaluateHierarchy(EvaluateGroup eval, GroupModel group, Set<GroupModel> visited) {
+        if (visited.contains(group)) return false;
+        if (eval.evaluate(group)) {
+            return true;
+        }
+        visited.add(group);
+        if (group.getParent() == null) return false;
+        return evaluateHierarchy(eval, group.getParent(), visited);
+    }
+
+    private boolean canManageByGroup(UserModel user) {
+        /* no inheritance
+        return evaluateGroups(user,
+                (group) -> root.groups().canViewMembers(group)
+        );
+        */
+
+        /* inheritance
+        */
+        return evaluateHierarchy(user, (group) -> root.groups().canManageMembers(group));
+
+    }
+    private boolean canViewByGroup(UserModel user) {
+        /* no inheritance
+        return evaluateGroups(user,
+                (group) -> root.groups().canViewMembers(group)
+        );
+        */
+
+        /* inheritance
+        */
+        return evaluateHierarchy(user, (group) -> root.groups().canViewMembers(group));
+    }
+
+    public boolean canViewDefault() {
+        return root.hasOneAdminRole(AdminRoles.MANAGE_USERS, AdminRoles.VIEW_USERS);
+    }
+
+    @Override
+    public boolean canQuery() {
+        return canView() || root.hasOneAdminRole(AdminRoles.QUERY_USERS);
+    }
+
+    @Override
+    public void requireQuery() {
+        if (!canQuery()) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canQuery(UserModel user) {
+        return canView(user);
+    }
+
+    @Override
+    public void requireQuery(UserModel user) {
+        if (!canQuery(user)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+
+
+    /**
+     * Is admin allowed to view all users?  In Authz terms, does the admin have the "view" scope for the Users Authz resource?
+     *
+     * This method will follow the old default behavior (does the admin have the view-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 "view" permission for the Users resource has an empty associatedPolicy list.
+     *
+     * Otherwise, it will use the Authz policy engine to resolve this answer.
+     *
+     * @return
+     */
+    @Override
+    public boolean canView() {
+        if (canViewDefault()) return true;
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        return hasViewPermission() || canManage();
+    }
+
+    private boolean hasViewPermission() {
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return canViewDefault();
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return canViewDefault();
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(VIEW_PERMISSION_USERS, server.getId());
+        if (policy == null) {
+            return canViewDefault();
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return canViewDefault();
+        }
+
+        Scope scope = root.realmViewScope();
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    /**
+     * Does current admin have view permissions for this particular user?
+     *
+     * Evaluates in this order. If any true, return true:
+     * - canViewUsers
+     * - canManageUsers
+     *
+     *
+     * @param user
+     * @return
+     */
+    @Override
+    public boolean canView(UserModel user) {
+        return canView() || canViewByGroup(user);
+    }
+
+    @Override
+    public void requireView(UserModel user) {
+        if (!canView(user)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public void requireView() {
+        if (!(canView())) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public boolean canImpersonate(UserModel user) {
+        if (!canImpersonate()) {
+            return false;
+        }
+
+        Identity userIdentity = new UserModelIdentity(root.realm, user);
+        if (!root.isAdminSameRealm()) {
+            return true;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return true;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return true;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(USER_IMPERSONATED_PERMISSION, server.getId());
+        if (policy == null) {
+            return true;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return true;
+        }
+
+        Scope scope = root.realmScope(USER_IMPERSONATED_SCOPE);
+        return root.evaluatePermission(resource, scope, server, userIdentity);
+
+    }
+
+    @Override
+    public boolean canImpersonate() {
+        if (root.hasOneAdminRole(ImpersonationConstants.IMPERSONATION_ROLE)) return true;
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(ADMIN_IMPERSONATING_PERMISSION, server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = root.realmScope(IMPERSONATE_SCOPE);
+        return root.evaluatePermission(resource, scope, server);
+    }
+
+    @Override
+    public void requireImpersonate(UserModel user) {
+        if (!canImpersonate(user)) {
+            throw new ForbiddenException();
+        }
+    }
+
+    @Override
+    public Map<String, Boolean> getAccess(UserModel user) {
+        Map<String, Boolean> map = new HashMap<>();
+        map.put("view", canView(user));
+        map.put("manage", canManage(user));
+        map.put("mapRoles", canMapRoles(user));
+        map.put("manageGroupMembership", canManageGroupMembership(user));
+        map.put("impersonate", canImpersonate(user));
+        return map;
+    }
+
+    @Override
+    public boolean canMapRoles(UserModel user) {
+        if (canManage(user)) return true;
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MAP_ROLES_PERMISSION_USERS, server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = root.realmScope(MAP_ROLES_SCOPE);
+        return root.evaluatePermission(resource, scope, server);
+
+    }
+
+    @Override
+    public void requireMapRoles(UserModel user) {
+        if (!canMapRoles(user)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+
+    @Override
+    public boolean canManageGroupMembership(UserModel user) {
+        if (canManage(user)) return true;
+
+        if (!root.isAdminSameRealm()) {
+            return false;
+        }
+
+        ResourceServer server = root.realmResourceServer();
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(USERS_RESOURCE, server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(MANAGE_GROUP_MEMBERSHIP_PERMISSION_USERS, server.getId());
+        if (policy == null) {
+            return false;
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return false;
+        }
+
+        Scope scope = root.realmScope(MANAGE_GROUP_MEMBERSHIP_SCOPE);
+        return root.evaluatePermission(resource, scope, server);
+
+    }
+
+    @Override
+    public void requireManageGroupMembership(UserModel user) {
+        if (!canManageGroupMembership(user)) {
+            throw new ForbiddenException();
+        }
+
+    }
+
+
+
+
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
index ad473b9..709197d 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
@@ -33,7 +33,7 @@ import org.keycloak.protocol.ProtocolMapperConfigException;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.services.ErrorResponse;
 import org.keycloak.services.ErrorResponseException;
-import org.keycloak.services.resources.admin.RealmAuth.Resource;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -66,7 +66,9 @@ public class ProtocolMappersResource {
 
     protected ProtocolMapperContainerModel client;
 
-    protected RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
+    protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
+    protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
 
     protected AdminEventBuilder adminEvent;
 
@@ -76,13 +78,17 @@ public class ProtocolMappersResource {
     @Context
     protected KeycloakSession session;
 
-    public ProtocolMappersResource(RealmModel realm, ProtocolMapperContainerModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public ProtocolMappersResource(RealmModel realm, ProtocolMapperContainerModel client, AdminPermissionEvaluator auth,
+                                   AdminEventBuilder adminEvent,
+                                   AdminPermissionEvaluator.RequirePermissionCheck managePermission,
+                                   AdminPermissionEvaluator.RequirePermissionCheck viewPermission) {
         this.realm = realm;
         this.auth = auth;
         this.client = client;
         this.adminEvent = adminEvent.resource(ResourceType.PROTOCOL_MAPPER);
+        this.managePermission = managePermission;
+        this.viewPermission = viewPermission;
 
-        auth.init(Resource.CLIENT);
     }
 
     /**
@@ -96,11 +102,7 @@ public class ProtocolMappersResource {
     @Path("protocol/{protocol}")
     @Produces(MediaType.APPLICATION_JSON)
     public List<ProtocolMapperRepresentation> getMappersPerProtocol(@PathParam("protocol") String protocol) {
-        auth.requireAny();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        viewPermission.require();
 
         List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
         for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
@@ -119,11 +121,7 @@ public class ProtocolMappersResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public Response createMapper(ProtocolMapperRepresentation rep) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        managePermission.require();
 
         ProtocolMapperModel model = null;
         try {
@@ -147,11 +145,7 @@ public class ProtocolMappersResource {
     @NoCache
     @Consumes(MediaType.APPLICATION_JSON)
     public void createMapper(List<ProtocolMapperRepresentation> reps) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        managePermission.require();
 
         ProtocolMapperModel model = null;
         for (ProtocolMapperRepresentation rep : reps) {
@@ -172,11 +166,7 @@ public class ProtocolMappersResource {
     @Path("models")
     @Produces(MediaType.APPLICATION_JSON)
     public List<ProtocolMapperRepresentation> getMappers() {
-        auth.requireAny();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        viewPermission.require();
 
         List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
         for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
@@ -196,11 +186,7 @@ public class ProtocolMappersResource {
     @Path("models/{id}")
     @Produces(MediaType.APPLICATION_JSON)
     public ProtocolMapperRepresentation getMapperById(@PathParam("id") String id) {
-        auth.requireAny();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        viewPermission.require();
 
         ProtocolMapperModel model = client.getProtocolMapperById(id);
         if (model == null) throw new NotFoundException("Model not found");
@@ -218,11 +204,7 @@ public class ProtocolMappersResource {
     @Path("models/{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     public void update(@PathParam("id") String id, ProtocolMapperRepresentation rep) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        managePermission.require();
 
         ProtocolMapperModel model = client.getProtocolMapperById(id);
         if (model == null) throw new NotFoundException("Model not found");
@@ -243,11 +225,7 @@ public class ProtocolMappersResource {
     @NoCache
     @Path("models/{id}")
     public void delete(@PathParam("id") String id) {
-        auth.requireManage();
-
-        if (client == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        managePermission.require();
 
         ProtocolMapperModel model = client.getProtocolMapperById(id);
         if (model == null) throw new NotFoundException("Model not found");
@@ -261,10 +239,12 @@ public class ProtocolMappersResource {
             ProtocolMapper mapper = (ProtocolMapper)session.getKeycloakSessionFactory().getProviderFactory(ProtocolMapper.class, model.getProtocolMapper());
             if (mapper != null) {
                 mapper.validateConfig(session, realm, client, model);
+            } else {
+                throw new NotFoundException("ProtocolMapper provider not found");
             }
         } catch (ProtocolMapperConfigException ex) {
             logger.error(ex.getMessage());
-            Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
+            Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
             throw new ErrorResponseException(ex.getMessage(), MessageFormat.format(messages.getProperty(ex.getMessageKey(), ex.getMessage()), ex.getParameters()),
                     Response.Status.BAD_REQUEST);
         }
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 f1469d0..28392f7 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.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.common.VerificationException;
 import org.keycloak.common.util.PemUtils;
@@ -63,6 +66,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ComponentRepresentation;
 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;
@@ -72,7 +76,6 @@ import org.keycloak.services.managers.LDAPConnectionTestManager;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.managers.ResourceAdminManager;
 import org.keycloak.services.managers.UserStorageSyncManager;
-import org.keycloak.services.resources.admin.RealmAuth.Resource;
 import org.keycloak.storage.UserStorageProviderModel;
 
 import javax.ws.rs.Consumes;
@@ -112,7 +115,7 @@ import static org.keycloak.models.utils.StripSecretsUtils.stripForExport;
  */
 public class RealmAdminResource {
     protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
-    protected RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
     protected RealmModel realm;
     private TokenManager tokenManager;
     private AdminEventBuilder adminEvent;
@@ -129,14 +132,11 @@ public class RealmAdminResource {
     @Context
     protected HttpHeaders headers;
 
-    public RealmAdminResource(RealmAuth auth, RealmModel realm, TokenManager tokenManager, AdminEventBuilder adminEvent) {
+    public RealmAdminResource(AdminPermissionEvaluator auth, RealmModel realm, TokenManager tokenManager, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
         this.tokenManager = tokenManager;
         this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM);
-
-        auth.init(RealmAuth.Resource.REALM);
-        auth.requireAny();
     }
 
     /**
@@ -149,7 +149,7 @@ public class RealmAdminResource {
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     public ClientRepresentation convertClientDescription(String description) {
-        auth.init(Resource.CLIENT).requireManage();
+        auth.clients().requireManage();
 
         if (realm == null) {
             throw new NotFoundException("Realm not found.");
@@ -238,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);
     }
 
     /**
@@ -252,15 +252,15 @@ public class RealmAdminResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public RealmRepresentation getRealm() {
-        if (auth.hasView()) {
+        if (auth.realm().canViewRealm()) {
             return ModelToRepresentation.toRepresentation(realm, false);
         } else {
-            auth.requireAny();
+            auth.realm().requireViewRealmNameList();
 
             RealmRepresentation rep = new RealmRepresentation();
             rep.setRealm(realm.getName());
 
-            if (auth.init(Resource.IDENTITY_PROVIDER).hasView()) {
+            if (auth.realm().canViewIdentityProviders()) {
                 RealmRepresentation r = ModelToRepresentation.toRepresentation(realm, false);
                 rep.setIdentityProviders(r.getIdentityProviders());
                 rep.setIdentityProviderMappers(r.getIdentityProviderMappers());
@@ -282,7 +282,7 @@ public class RealmAdminResource {
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public Response updateRealm(final RealmRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         logger.debug("updating realm: " + realm.getName());
 
@@ -344,7 +344,7 @@ public class RealmAdminResource {
      */
     @DELETE
     public void deleteRealm() {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         if (!new RealmManager(session).removeRealm(realm)) {
             throw new NotFoundException("Realm doesn't exist");
@@ -364,6 +364,50 @@ public class RealmAdminResource {
         return users;
     }
 
+    @NoCache
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("users-management-permissions")
+    public ManagementPermissionReference getUserMgmtPermissions() {
+        auth.realm().requireViewRealm();
+
+        AdminPermissionManagement permissions = AdminPermissions.management(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.realm().requireManageRealm();
+
+        AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+        permissions.users().setPermissionsEnabled(ref.isEnabled());
+        if (ref.isEnabled()) {
+            return toUsersMgmtRef(permissions);
+        } else {
+            return new ManagementPermissionReference();
+        }
+    }
+
+
+    public static ManagementPermissionReference toUsersMgmtRef(AdminPermissionManagement permissions) {
+        ManagementPermissionReference ref = new ManagementPermissionReference();
+        ref.setEnabled(true);
+        ref.setResource(permissions.users().resource().getId());
+        Map<String, String> scopes = permissions.users().getPermissions();
+        ref.setScopePermissions(scopes);
+        return ref;
+    }
+
+
     @Path("user-storage")
     public UserStorageProviderResource userStorage() {
         UserStorageProviderResource fed = new UserStorageProviderResource(realm, auth, adminEvent);
@@ -388,7 +432,7 @@ public class RealmAdminResource {
      */
     @Path("roles-by-id")
     public RoleByIdResource rolesById() {
-        RoleByIdResource resource = new RoleByIdResource(realm, auth, adminEvent);
+         RoleByIdResource resource = new RoleByIdResource(realm, auth, adminEvent);
         ResteasyProviderFactory.getInstance().injectProperties(resource);
         //resourceContext.initResource(resource);
         return resource;
@@ -401,7 +445,7 @@ public class RealmAdminResource {
     @Path("push-revocation")
     @POST
     public GlobalRequestResult pushRevocation() {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         GlobalRequestResult result = new ResourceAdminManager(session).pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm);
         adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).representation(result).success();
@@ -416,7 +460,7 @@ public class RealmAdminResource {
     @Path("logout-all")
     @POST
     public GlobalRequestResult logoutAll() {
-        auth.init(RealmAuth.Resource.USER).requireManage();
+        auth.users().requireManage();
 
         session.sessions().removeUserSessions(realm);
         GlobalRequestResult result = new ResourceAdminManager(session).logoutAll(uriInfo.getRequestUri(), realm);
@@ -433,7 +477,7 @@ public class RealmAdminResource {
     @Path("sessions/{session}")
     @DELETE
     public void deleteSession(@PathParam("session") String sessionId) {
-        auth.init(RealmAuth.Resource.USER).requireManage();
+        auth.users().requireManage();
 
         UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
         if (userSession == null) throw new NotFoundException("Sesssion not found");
@@ -455,7 +499,7 @@ public class RealmAdminResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<Map<String, String>> getClientSessionStats() {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         List<Map<String, String>> data = new LinkedList<Map<String, String>>();
         for (ClientModel client : realm.getClients()) {
@@ -482,7 +526,7 @@ public class RealmAdminResource {
     @Path("events/config")
     @Produces(MediaType.APPLICATION_JSON)
     public RealmEventsConfigRepresentation getRealmEventsConfig() {
-        auth.init(RealmAuth.Resource.EVENTS).requireView();
+        auth.realm().requireViewEvents();
 
         RealmEventsConfigRepresentation config = ModelToRepresentation.toEventsConfigReprensetation(realm);
         if (config.getEnabledEventTypes() == null || config.getEnabledEventTypes().isEmpty()) {
@@ -507,7 +551,7 @@ public class RealmAdminResource {
     @Path("events/config")
     @Consumes(MediaType.APPLICATION_JSON)
     public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
-        auth.init(RealmAuth.Resource.EVENTS).requireManage();
+        auth.realm().requireManageEvents();
 
         logger.debug("updating realm events config: " + realm.getName());
         new RealmManager(session).updateRealmEventsConfig(rep, realm);
@@ -536,7 +580,7 @@ public class RealmAdminResource {
                                                @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
                                                @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
                                                @QueryParam("max") Integer maxResults) {
-        auth.init(RealmAuth.Resource.EVENTS).requireView();
+        auth.realm().requireViewEvents();
 
         EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
 
@@ -629,7 +673,7 @@ public class RealmAdminResource {
                                                     @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
                                                     @QueryParam("max") Integer maxResults,
                                                     @QueryParam("resourceTypes") List<String> resourceTypes) {
-        auth.init(RealmAuth.Resource.EVENTS).requireView();
+        auth.realm().requireViewEvents();
 
         EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
         AdminEventQuery query = eventStore.createAdminQuery().realm(realm.getId());;
@@ -722,7 +766,7 @@ public class RealmAdminResource {
     @Path("events")
     @DELETE
     public void clearEvents() {
-        auth.init(RealmAuth.Resource.EVENTS).requireManage();
+        auth.realm().requireManageEvents();
 
         EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
         eventStore.clear(realm.getId());
@@ -735,7 +779,7 @@ public class RealmAdminResource {
     @Path("admin-events")
     @DELETE
     public void clearAdminEvents() {
-        auth.init(RealmAuth.Resource.EVENTS).requireManage();
+        auth.realm().requireManageEvents();
 
         EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
         eventStore.clearAdmin(realm.getId());
@@ -757,7 +801,7 @@ public class RealmAdminResource {
                                        @QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential,
                                        @QueryParam("useTruststoreSpi") String useTruststoreSpi, @QueryParam("connectionTimeout") String connectionTimeout,
                                        @QueryParam("componentId") String componentId) {
-        auth.init(RealmAuth.Resource.REALM).requireManage();
+        auth.realm().requireManageRealm();
 
         if (componentId != null && bindCredential.equals(ComponentRepresentation.SECRET_VALUE)) {
             bindCredential = realm.getComponent(componentId).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL);
@@ -782,7 +826,7 @@ public class RealmAdminResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Path("default-groups")
     public List<GroupRepresentation> getDefaultGroups() {
-        auth.requireView();
+        auth.realm().requireViewRealm();
 
         List<GroupRepresentation> defaults = new LinkedList<>();
         for (GroupModel group : realm.getDefaultGroups()) {
@@ -794,7 +838,7 @@ public class RealmAdminResource {
     @NoCache
     @Path("default-groups/{groupId}")
     public void addDefaultGroup(@PathParam("groupId") String groupId) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         GroupModel group = realm.getGroupById(groupId);
         if (group == null) {
@@ -809,7 +853,7 @@ public class RealmAdminResource {
     @NoCache
     @Path("default-groups/{groupId}")
     public void removeDefaultGroup(@PathParam("groupId") String groupId) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         GroupModel group = realm.getGroupById(groupId);
         if (group == null) {
@@ -834,13 +878,12 @@ public class RealmAdminResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public GroupRepresentation getGroupByPath(@PathParam("path") String path) {
-        auth.requireView();
-
         GroupModel found = KeycloakModelUtils.findGroupByPath(realm, path);
         if (found == null) {
             throw new NotFoundException("Group path does not exist");
 
         }
+        auth.groups().requireView(found);
         return ModelToRepresentation.toGroupHierarchy(found, true);
     }
 
@@ -854,7 +897,7 @@ public class RealmAdminResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response partialImport(PartialImportRepresentation rep) {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         PartialImportManager partialImport = new PartialImportManager(rep, session, realm, adminEvent);
         return partialImport.saveResources();
@@ -888,7 +931,7 @@ public class RealmAdminResource {
     @Path("clear-realm-cache")
     @POST
     public void clearRealmCache() {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         CacheRealmProvider cache = session.getProvider(CacheRealmProvider.class);
         if (cache != null) {
@@ -905,7 +948,7 @@ public class RealmAdminResource {
     @Path("clear-user-cache")
     @POST
     public void clearUserCache() {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         UserCache cache = session.getProvider(UserCache.class);
         if (cache != null) {
@@ -922,7 +965,7 @@ public class RealmAdminResource {
     @Path("clear-keys-cache")
     @POST
     public void clearKeysCache() {
-        auth.requireManage();
+        auth.realm().requireManageRealm();
 
         PublicKeyStorageProvider cache = session.getProvider(PublicKeyStorageProvider.class);
         if (cache != null) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index 7a948d9..b00f2e4 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -34,6 +34,8 @@ import org.keycloak.services.ErrorResponse;
 import org.keycloak.services.ForbiddenException;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.KeycloakApplication;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -94,18 +96,11 @@ public class RealmsAdminResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<RealmRepresentation> getRealms() {
-        RealmManager realmManager = new RealmManager(session);
         List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
-        if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
-            List<RealmModel> realms = session.realms().getRealms();
-            for (RealmModel realm : realms) {
-                addRealmRep(reps, realm, realm.getMasterAdminClient());
-            }
-        } else {
-            ClientModel adminApp = auth.getRealm().getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm()));
-            addRealmRep(reps, auth.getRealm(), adminApp);
+        List<RealmModel> realms = session.realms().getRealms();
+        for (RealmModel realm : realms) {
+            addRealmRep(reps, realm);
         }
-
         if (reps.isEmpty()) {
             throw new ForbiddenException();
         }
@@ -114,10 +109,10 @@ public class RealmsAdminResource {
         return reps;
     }
 
-    protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm, ClientModel realmManagementClient) {
-        if (auth.hasAppRole(realmManagementClient, AdminRoles.VIEW_REALM)) {
+    protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm) {
+        if (AdminPermissions.realms(session, auth).canView(realm)) {
             reps.add(ModelToRepresentation.toRepresentation(realm, false));
-        } else if (auth.hasOneOfAppRole(realmManagementClient, AdminRoles.ALL_REALM_ROLES)) {
+        } else if (AdminPermissions.realms(session, auth).isAdmin(realm)) {
             RealmRepresentation rep = new RealmRepresentation();
             rep.setRealm(realm.getName());
             reps.add(rep);
@@ -138,12 +133,7 @@ public class RealmsAdminResource {
     public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
         RealmManager realmManager = new RealmManager(session);
         realmManager.setContextPath(keycloak.getContextPath());
-        if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
-            throw new ForbiddenException();
-        }
-        if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
-            throw new ForbiddenException();
-        }
+        AdminPermissions.realms(session, auth).requireCreateRealm();
 
         logger.debugv("importRealm: {0}", rep.getRealm());
 
@@ -191,13 +181,7 @@ public class RealmsAdminResource {
                 && !auth.getRealm().equals(realm)) {
             throw new ForbiddenException();
         }
-        RealmAuth realmAuth;
-
-        if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
-            realmAuth = new RealmAuth(auth, realm.getMasterAdminClient());
-        } else {
-            realmAuth = new RealmAuth(auth, realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())));
-        }
+        AdminPermissionEvaluator realmAuth = AdminPermissions.evaluator(session, realm, auth);
 
         AdminEventBuilder adminEvent = new AdminEventBuilder(realm, auth, session, clientConnection);
         session.getContext().setRealm(realm);
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..b2ae6ad 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,10 @@ 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.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
+import org.keycloak.services.resources.admin.permissions.RolePermissionManagement;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
@@ -26,6 +30,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 +44,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;
 
 /**
@@ -52,7 +59,7 @@ import java.util.Set;
 public class RoleByIdResource extends RoleResource {
     protected static final Logger logger = Logger.getLogger(RoleByIdResource.class);
     private final RealmModel realm;
-    private final RealmAuth auth;
+    private AdminPermissionEvaluator auth;
     private AdminEventBuilder adminEvent;
 
     @Context
@@ -61,7 +68,7 @@ public class RoleByIdResource extends RoleResource {
     @Context
     private UriInfo uriInfo;
 
-    public RoleByIdResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public RoleByIdResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         super(realm);
 
         this.realm = realm;
@@ -80,9 +87,9 @@ public class RoleByIdResource extends RoleResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public RoleRepresentation getRole(final @PathParam("role-id") String id) {
-        auth.requireAny();
 
         RoleModel roleModel = getRoleModel(id);
+        auth.roles().requireView(roleModel);
         return getRole(roleModel);
     }
 
@@ -91,17 +98,7 @@ public class RoleByIdResource extends RoleResource {
         if (roleModel == null) {
             throw new NotFoundException("Could not find role with id");
         }
-
-        RealmAuth.Resource r = null;
-        if (roleModel.getContainer() instanceof RealmModel) {
-            r = RealmAuth.Resource.REALM;
-        } else if (roleModel.getContainer() instanceof ClientModel) {
-            r = RealmAuth.Resource.CLIENT;
-        } else if (roleModel.getContainer() instanceof UserModel) {
-            r = RealmAuth.Resource.USER;
-        }
-        auth.init(r);
-        return roleModel;
+       return roleModel;
     }
 
     /**
@@ -113,9 +110,8 @@ public class RoleByIdResource extends RoleResource {
     @DELETE
     @NoCache
     public void deleteRole(final @PathParam("role-id") String id) {
-        auth.requireManage();
-
         RoleModel role = getRoleModel(id);
+        auth.roles().requireManage(role);
         deleteRole(role);
 
         if (role.isClientRole()) {
@@ -137,9 +133,8 @@ public class RoleByIdResource extends RoleResource {
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public void updateRole(final @PathParam("role-id") String id, final RoleRepresentation rep) {
-        auth.requireManage();
-
         RoleModel role = getRoleModel(id);
+        auth.roles().requireManage(role);
         updateRole(rep, role);
 
         if (role.isClientRole()) {
@@ -161,10 +156,9 @@ public class RoleByIdResource extends RoleResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
-        auth.requireManage();
-
         RoleModel role = getRoleModel(id);
-        addComposites(adminEvent, uriInfo, roles, role);
+        auth.roles().requireManage(role);
+        addComposites(auth, adminEvent, uriInfo, roles, role);
     }
 
     /**
@@ -180,11 +174,10 @@ public class RoleByIdResource extends RoleResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-id") String id) {
-        auth.requireAny();
 
         if (logger.isDebugEnabled()) logger.debug("*** getRoleComposites: '" + id + "'");
         RoleModel role = getRoleModel(id);
-        auth.requireView();
+        auth.roles().requireView(role);
         return getRoleComposites(role);
     }
 
@@ -199,9 +192,9 @@ public class RoleByIdResource extends RoleResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-id") String id) {
-        auth.requireAny();
-
         RoleModel role = getRoleModel(id);
+        auth.roles().requireView(role);
+        auth.roles().requireView(role);
         return getRealmRoleComposites(role);
     }
 
@@ -218,9 +211,9 @@ public class RoleByIdResource extends RoleResource {
     @Produces(MediaType.APPLICATION_JSON)
     public Set<RoleRepresentation> getClientRoleComposites(final @PathParam("role-id") String id,
                                                                 final @PathParam("client") String client) {
-        auth.requireAny();
 
         RoleModel role = getRoleModel(id);
+        auth.roles().requireView(role);
         ClientModel clientModel = realm.getClientById(client);
         if (clientModel == null) {
             throw new NotFoundException("Could not find client");
@@ -238,10 +231,64 @@ public class RoleByIdResource extends RoleResource {
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     public void deleteComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
-        auth.requireManage();
-
         RoleModel role = getRoleModel(id);
+        auth.roles().requireManage(role);
         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) {
+        RoleModel role = getRoleModel(id);
+        auth.roles().requireView(role);
+
+        AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+        if (!permissions.roles().isPermissionsEnabled(role)) {
+            return new ManagementPermissionReference();
+        }
+        return toMgmtRef(role, permissions);
+    }
+
+    public static ManagementPermissionReference toMgmtRef(RoleModel role, AdminPermissionManagement permissions) {
+        ManagementPermissionReference ref = new ManagementPermissionReference();
+        ref.setEnabled(true);
+        ref.setResource(permissions.roles().resource(role).getId());
+        ref.setScopePermissions(permissions.roles().getPermissions(role));
+        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) {
+        RoleModel role = getRoleModel(id);
+        auth.roles().requireManage(role);
+
+        AdminPermissionManagement permissions = AdminPermissions.management(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..79bb6c8 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,26 +19,33 @@ package org.keycloak.services.resources.admin;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
 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;
 
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -54,18 +61,22 @@ import java.util.Set;
  */
 public class RoleContainerResource extends RoleResource {
     private final RealmModel realm;
-    private final RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
+
     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,
+                                 AdminPermissionEvaluator 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;
     }
 
     /**
@@ -77,11 +88,7 @@ public class RoleContainerResource extends RoleResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<RoleRepresentation> getRoles() {
-        auth.requireAny();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.roles().requireList(roleContainer);
 
         Set<RoleModel> roleModels = roleContainer.getRoles();
         List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
@@ -100,11 +107,7 @@ public class RoleContainerResource extends RoleResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response createRole(final RoleRepresentation rep) {
-        auth.requireManage();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.roles().requireManage(roleContainer);
 
         if (rep.getName() == null) {
             throw new BadRequestException();
@@ -143,11 +146,7 @@ public class RoleContainerResource extends RoleResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public RoleRepresentation getRole(final @PathParam("role-name") String roleName) {
-        auth.requireView();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        auth.roles().requireView(roleContainer);
 
         RoleModel roleModel = roleContainer.getRole(roleName);
         if (roleModel == null) {
@@ -166,12 +165,7 @@ public class RoleContainerResource extends RoleResource {
     @DELETE
     @NoCache
     public void deleteRole(final @PathParam("role-name") String roleName) {
-        auth.requireManage();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
-
+        auth.roles().requireManage(roleContainer);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
@@ -199,12 +193,7 @@ public class RoleContainerResource extends RoleResource {
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public Response updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
-        auth.requireManage();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
-
+        auth.roles().requireManage(roleContainer);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
@@ -236,17 +225,12 @@ public class RoleContainerResource extends RoleResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
-
+        auth.roles().requireManage(roleContainer);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
         }
-        addComposites(adminEvent, uriInfo, roles, role);
+        addComposites(auth, adminEvent, uriInfo, roles, role);
     }
 
     /**
@@ -260,12 +244,7 @@ public class RoleContainerResource extends RoleResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-name") String roleName) {
-        auth.requireView();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
-
+        auth.roles().requireView(roleContainer);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
@@ -284,12 +263,7 @@ public class RoleContainerResource extends RoleResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) {
-        auth.requireView();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
-
+        auth.roles().requireView(roleContainer);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
@@ -311,12 +285,7 @@ public class RoleContainerResource extends RoleResource {
     public Set<RoleRepresentation> getClientRoleComposites(@Context final UriInfo uriInfo,
                                                                 final @PathParam("role-name") String roleName,
                                                                 final @PathParam("client") String client) {
-        auth.requireView();
-
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
-
+        auth.roles().requireView(roleContainer);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
@@ -342,17 +311,66 @@ public class RoleContainerResource extends RoleResource {
     public void deleteComposites(
                                    final @PathParam("role-name") String roleName,
                                    List<RoleRepresentation> roles) {
-        auth.requireManage();
 
-        if (roleContainer == null) {
-            throw new NotFoundException("Could not find client");
+        auth.roles().requireManage(roleContainer);
+        RoleModel role = roleContainer.getRole(roleName);
+        if (role == null) {
+            throw new NotFoundException("Could not find role");
         }
+        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.roles().requireView(roleContainer);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
         }
-        deleteComposites(adminEvent, uriInfo, roles, role);
+
+        AdminPermissionManagement permissions = AdminPermissions.management(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.roles().requireManage(roleContainer);
+        RoleModel role = roleContainer.getRole(roleName);
+        if (role == null) {
+            throw new NotFoundException("Could not find role");
+        }
+
+        if (ref.isEnabled()) {
+            AdminPermissionManagement permissions = AdminPermissions.management(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..b785b1a 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.services.resources.admin.permissions.AdminPermissionEvaluator;
 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;
@@ -55,6 +57,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Base resource for managing users
@@ -64,16 +67,19 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 public class RoleMapperResource {
+
     protected static final Logger logger = Logger.getLogger(RoleMapperResource.class);
 
     protected RealmModel realm;
 
-    private RealmAuth auth;
-
     private RoleMapperModel roleMapper;
 
     private AdminEventBuilder adminEvent;
 
+    protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
+    protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
+    private AdminPermissionEvaluator auth;
+
     @Context
     protected ClientConnection clientConnection;
 
@@ -86,15 +92,21 @@ public class RoleMapperResource {
     @Context
     protected HttpHeaders headers;
 
-    public RoleMapperResource(RealmModel realm, RealmAuth auth,  RoleMapperModel roleMapper, AdminEventBuilder adminEvent) {
+    public RoleMapperResource(RealmModel realm,
+                              AdminPermissionEvaluator auth,
+                              RoleMapperModel roleMapper,
+                              AdminEventBuilder adminEvent,
+                              AdminPermissionEvaluator.RequirePermissionCheck manageCheck,
+                              AdminPermissionEvaluator.RequirePermissionCheck viewCheck) {
         this.auth = auth;
         this.realm = realm;
         this.adminEvent = adminEvent.resource(ResourceType.REALM_ROLE_MAPPING);
         this.roleMapper = roleMapper;
+        this.managePermission = manageCheck;
+        this.viewPermission = viewCheck;
 
     }
 
-
     /**
      * Get role mappings
      *
@@ -104,11 +116,7 @@ public class RoleMapperResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public MappingsRepresentation getRoleMappings() {
-        auth.requireView();
-
-        if (roleMapper == null) {
-            throw new NotFoundException("User not found");
-        }
+        viewPermission.require();
 
         MappingsRepresentation all = new MappingsRepresentation();
         Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
@@ -153,11 +161,7 @@ public class RoleMapperResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getRealmRoleMappings() {
-        auth.requireView();
-
-        if (roleMapper == null) {
-            throw new NotFoundException("User not found");
-        }
+        viewPermission.require();
 
         Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
         List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
@@ -179,11 +183,7 @@ public class RoleMapperResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getCompositeRealmRoleMappings() {
-        auth.requireView();
-
-        if (roleMapper == null) {
-            throw new NotFoundException("User not found");
-        }
+        viewPermission.require();
 
         Set<RoleModel> roles = realm.getRoles();
         List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
@@ -205,14 +205,13 @@ public class RoleMapperResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getAvailableRealmRoleMappings() {
-        auth.requireView();
-
-        if (roleMapper == null) {
-            throw new NotFoundException("User not found");
-        }
+        viewPermission.require();
 
         Set<RoleModel> available = realm.getRoles();
-        return ClientRoleMappingsResource.getAvailableRoles(roleMapper, available);
+        Set<RoleModel> set = available.stream().filter(r ->
+            canMapRole(r)
+        ).collect(Collectors.toSet());
+        return ClientRoleMappingsResource.getAvailableRoles(roleMapper, set);
     }
 
     /**
@@ -224,11 +223,7 @@ public class RoleMapperResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addRealmRoleMappings(List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        if (roleMapper == null) {
-            throw new NotFoundException("User not found");
-        }
+        managePermission.require();
 
         logger.debugv("** addRealmRoleMappings: {0}", roles);
 
@@ -237,6 +232,7 @@ public class RoleMapperResource {
             if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                 throw new NotFoundException("Role not found");
             }
+            auth.roles().requireMapRole(roleModel);
             roleMapper.grantRole(roleModel);
         }
 
@@ -252,11 +248,7 @@ public class RoleMapperResource {
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     public void deleteRealmRoleMappings(List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        if (roleMapper == null) {
-            throw new NotFoundException("User not found");
-        }
+        managePermission.require();
 
         logger.debug("deleteRealmRoleMappings");
         if (roles == null) {
@@ -264,6 +256,7 @@ public class RoleMapperResource {
             roles = new LinkedList<>();
 
             for (RoleModel roleModel : roleModels) {
+                auth.roles().requireMapRole(roleModel);
                 roleMapper.deleteRoleMapping(roleModel);
                 roles.add(ModelToRepresentation.toRepresentation(roleModel));
             }
@@ -274,11 +267,11 @@ public class RoleMapperResource {
                 if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                     throw new NotFoundException("Role not found");
                 }
-
+                auth.roles().requireMapRole(roleModel);
                 try {
                     roleMapper.deleteRoleMapping(roleModel);
                 } catch (ModelException me) {
-                    Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
+                    Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
                     throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
                             Response.Status.BAD_REQUEST);
                 }
@@ -290,10 +283,20 @@ public class RoleMapperResource {
 
     }
 
+    private boolean canMapRole(RoleModel roleModel) {
+        return auth.roles().canMapRole(roleModel);
+    }
+
     @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);
+        if (clientModel == null) {
+            throw new NotFoundException("Client not found");
+        }
+        ClientRoleMappingsResource resource = new ClientRoleMappingsResource(uriInfo, session, realm, auth, roleMapper,
+                clientModel, adminEvent,
+                managePermission, viewPermission);
+        return resource;
 
     }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
index 5fb1d34..0161ee6 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
@@ -25,6 +25,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.core.UriInfo;
 import java.util.Collections;
@@ -60,12 +61,13 @@ public abstract class RoleResource {
         if (rep.isScopeParamRequired() != null) role.setScopeParamRequired(rep.isScopeParamRequired());
     }
 
-    protected void addComposites(AdminEventBuilder adminEvent, UriInfo uriInfo, List<RoleRepresentation> roles, RoleModel role) {
+    protected void addComposites(AdminPermissionEvaluator auth, AdminEventBuilder adminEvent, UriInfo uriInfo, List<RoleRepresentation> roles, RoleModel role) {
         for (RoleRepresentation rep : roles) {
             RoleModel composite = realm.getRoleById(rep.getId());
             if (composite == null) {
                 throw new NotFoundException("Could not find composite role");
             }
+            auth.roles().requireMapComposite(composite);
             role.addCompositeRole(composite);
         }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
index 431e97c..4f7b5dc 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
@@ -29,6 +29,7 @@ import org.keycloak.models.ScopeContainerModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -49,19 +50,25 @@ import java.util.Set;
  */
 public class ScopeMappedClientResource {
     protected RealmModel realm;
-    private RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
+    protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
+    protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
     protected ScopeContainerModel scopeContainer;
     protected KeycloakSession session;
     protected ClientModel scopedClient;
     protected AdminEventBuilder adminEvent;
     
-    public ScopeMappedClientResource(RealmModel realm, RealmAuth auth, ScopeContainerModel scopeContainer, KeycloakSession session, ClientModel scopedClient, AdminEventBuilder adminEvent) {
+    public ScopeMappedClientResource(RealmModel realm, AdminPermissionEvaluator auth, ScopeContainerModel scopeContainer, KeycloakSession session, ClientModel scopedClient, AdminEventBuilder adminEvent,
+                                     AdminPermissionEvaluator.RequirePermissionCheck managePermission,
+                                     AdminPermissionEvaluator.RequirePermissionCheck viewPermission) {
         this.realm = realm;
         this.auth = auth;
         this.scopeContainer = scopeContainer;
         this.session = session;
         this.scopedClient = scopedClient;
         this.adminEvent = adminEvent.resource(ResourceType.CLIENT_SCOPE_MAPPING);
+        this.managePermission = managePermission;
+        this.viewPermission = viewPermission;
     }
 
     /**
@@ -75,11 +82,7 @@ public class ScopeMappedClientResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getClientScopeMappings() {
-        auth.requireView();
-
-        if (scopeContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        viewPermission.require();
 
         Set<RoleModel> mappings = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer); //scopedClient.getClientScopeMappings(client);
         List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
@@ -101,14 +104,10 @@ public class ScopeMappedClientResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getAvailableClientScopeMappings() {
-        auth.requireView();
-
-        if (scopeContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        viewPermission.require();
 
         Set<RoleModel> roles = scopedClient.getRoles();
-        return ScopeMappedResource.getAvailable(scopeContainer, roles);
+        return ScopeMappedResource.getAvailable(auth, scopeContainer, roles);
     }
 
     /**
@@ -123,11 +122,7 @@ public class ScopeMappedClientResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getCompositeClientScopeMappings() {
-        auth.requireView();
-
-        if (scopeContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        viewPermission.require();
 
         Set<RoleModel> roles = scopedClient.getRoles();
         return ScopeMappedResource.getComposite(scopeContainer, roles);
@@ -141,11 +136,7 @@ public class ScopeMappedClientResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addClientScopeMapping(List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        if (scopeContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        managePermission.require();
 
         for (RoleRepresentation role : roles) {
             RoleModel roleModel = scopedClient.getRole(role.getName());
@@ -166,11 +157,7 @@ public class ScopeMappedClientResource {
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     public void deleteClientScopeMapping(List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        if (scopeContainer == null) {
-            throw new NotFoundException("Could not find client");
-        }
+        managePermission.require();
 
         if (roles == null) {
             Set<RoleModel> roleModels = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer);//scopedClient.getClientScopeMappings(client);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
index 19a32f9..286e22b 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
@@ -31,6 +31,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.ClientMappingsRepresentation;
 import org.keycloak.representations.idm.MappingsRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -56,17 +57,25 @@ import java.util.Set;
  */
 public class ScopeMappedResource {
     protected RealmModel realm;
-    private RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
+    protected AdminPermissionEvaluator.RequirePermissionCheck managePermission;
+    protected AdminPermissionEvaluator.RequirePermissionCheck viewPermission;
+
     protected ScopeContainerModel scopeContainer;
     protected KeycloakSession session;
     protected AdminEventBuilder adminEvent;
 
-    public ScopeMappedResource(RealmModel realm, RealmAuth auth, ScopeContainerModel scopeContainer, KeycloakSession session, AdminEventBuilder adminEvent) {
+    public ScopeMappedResource(RealmModel realm, AdminPermissionEvaluator auth, ScopeContainerModel scopeContainer,
+                               KeycloakSession session, AdminEventBuilder adminEvent,
+                               AdminPermissionEvaluator.RequirePermissionCheck managePermission,
+                               AdminPermissionEvaluator.RequirePermissionCheck viewPermission) {
         this.realm = realm;
         this.auth = auth;
         this.scopeContainer = scopeContainer;
         this.session = session;
         this.adminEvent = adminEvent.resource(ResourceType.REALM_SCOPE_MAPPING);
+        this.managePermission = managePermission;
+        this.viewPermission = viewPermission;
     }
 
     /**
@@ -78,7 +87,7 @@ public class ScopeMappedResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public MappingsRepresentation getScopeMappings() {
-        auth.requireView();
+        viewPermission.require();
 
         if (scopeContainer == null) {
             throw new NotFoundException("Could not find client");
@@ -126,7 +135,7 @@ public class ScopeMappedResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getRealmScopeMappings() {
-        auth.requireView();
+        viewPermission.require();
 
         if (scopeContainer == null) {
             throw new NotFoundException("Could not find client");
@@ -150,20 +159,21 @@ public class ScopeMappedResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getAvailableRealmScopeMappings() {
-        auth.requireView();
+        viewPermission.require();
 
         if (scopeContainer == null) {
             throw new NotFoundException("Could not find client");
         }
 
         Set<RoleModel> roles = realm.getRoles();
-        return getAvailable(scopeContainer, roles);
+        return getAvailable(auth, scopeContainer, roles);
     }
 
-    public static List<RoleRepresentation> getAvailable(ScopeContainerModel client, Set<RoleModel> roles) {
+    public static List<RoleRepresentation> getAvailable(AdminPermissionEvaluator auth, ScopeContainerModel client, Set<RoleModel> roles) {
         List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roles) {
             if (client.hasScope(roleModel)) continue;
+            if (!auth.roles().canMapClientScope(roleModel)) continue;
             available.add(ModelToRepresentation.toRepresentation(roleModel));
         }
         return available;
@@ -183,7 +193,7 @@ public class ScopeMappedResource {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public List<RoleRepresentation> getCompositeRealmScopeMappings() {
-        auth.requireView();
+        viewPermission.require();
 
         if (scopeContainer == null) {
             throw new NotFoundException("Could not find client");
@@ -210,7 +220,7 @@ public class ScopeMappedResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public void addRealmScopeMappings(List<RoleRepresentation> roles) {
-        auth.requireManage();
+        managePermission.require();
 
         if (scopeContainer == null) {
             throw new NotFoundException("Could not find client");
@@ -236,7 +246,7 @@ public class ScopeMappedResource {
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     public void deleteRealmScopeMappings(List<RoleRepresentation> roles) {
-        auth.requireManage();
+        managePermission.require();
 
         if (scopeContainer == null) {
             throw new NotFoundException("Could not find client");
@@ -268,6 +278,9 @@ public class ScopeMappedResource {
     @Path("clients/{client}")
     public ScopeMappedClientResource getClientByIdScopeMappings(@PathParam("client") String client) {
         ClientModel clientModel = realm.getClientById(client);
-        return new ScopeMappedClientResource(realm, auth, this.scopeContainer, session, clientModel, adminEvent);
+        if (clientModel == null) {
+            throw new NotFoundException("Could not find client");
+        }
+        return new ScopeMappedClientResource(realm, auth, this.scopeContainer, session, clientModel, adminEvent, managePermission, viewPermission);
     }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
new file mode 100755
index 0000000..bf3b236
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
@@ -0,0 +1,795 @@
+/*
+ * 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.services.resources.admin;
+
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.annotations.cache.NoCache;
+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.authentication.actiontoken.execactions.ExecuteActionsActionToken;
+import org.keycloak.common.ClientConnection;
+import org.keycloak.common.Profile;
+import org.keycloak.common.util.Time;
+import org.keycloak.credential.CredentialModel;
+import org.keycloak.email.EmailException;
+import org.keycloak.email.EmailTemplateProvider;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.events.EventType;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.AuthenticatedClientSessionModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserLoginFailureModel;
+import org.keycloak.models.UserManager;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.utils.RedirectUtils;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
+import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.UserConsentRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.ForbiddenException;
+import org.keycloak.services.ServicesLogger;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.BruteForceProtector;
+import org.keycloak.services.managers.UserSessionManager;
+import org.keycloak.services.resources.AccountService;
+import org.keycloak.services.resources.LoginActionsService;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.validation.Validation;
+import org.keycloak.storage.ReadOnlyException;
+import org.keycloak.utils.ProfileHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base resource for managing users
+ *
+ * @resource Users
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserResource {
+    private static final Logger logger = Logger.getLogger(UserResource.class);
+
+    protected RealmModel realm;
+
+    private AdminPermissionEvaluator auth;
+
+    private AdminEventBuilder adminEvent;
+    private UserModel user;
+
+    @Context
+    protected ClientConnection clientConnection;
+
+    @Context
+    protected UriInfo uriInfo;
+
+    @Context
+    protected KeycloakSession session;
+
+    @Context
+    protected HttpHeaders headers;
+
+    public UserResource(RealmModel realm, UserModel user, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
+        this.auth = auth;
+        this.realm = realm;
+        this.user = user;
+        this.adminEvent = adminEvent.resource(ResourceType.USER);
+    }
+
+    /**
+     * Update the user
+     *
+     * @param rep
+     * @return
+     */
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateUser(final UserRepresentation rep) {
+
+        auth.users().requireManage(user);
+        try {
+            Set<String> attrsToRemove;
+            if (rep.getAttributes() != null) {
+                attrsToRemove = new HashSet<>(user.getAttributes().keySet());
+                attrsToRemove.removeAll(rep.getAttributes().keySet());
+            } else {
+                attrsToRemove = Collections.emptySet();
+            }
+
+            if (rep.isEnabled() != null && rep.isEnabled()) {
+                UserLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, user.getId());
+                if (failureModel != null) {
+                    failureModel.clearFailures();
+                }
+            }
+
+            updateUserFromRep(user, rep, attrsToRemove, realm, session, true);
+            adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
+
+            if (session.getTransactionManager().isActive()) {
+                session.getTransactionManager().commit();
+            }
+            return Response.noContent().build();
+        } catch (ModelDuplicateException e) {
+            return ErrorResponse.exists("User exists with same username or email");
+        } catch (ReadOnlyException re) {
+            return ErrorResponse.exists("User is read only!");
+        } catch (ModelException me) {
+            logger.warn("Could not update user!", me);
+            return ErrorResponse.exists("Could not update user!");
+        } catch (ForbiddenException fe) {
+            throw fe;
+        } catch (Exception me) { // JPA
+            logger.warn("Could not update user!", me);// may be committed by JTA which can't
+            return ErrorResponse.exists("Could not update user!");
+        }
+    }
+
+    public static void updateUserFromRep(UserModel user, UserRepresentation rep, Set<String> attrsToRemove, RealmModel realm, KeycloakSession session, boolean removeMissingRequiredActions) {
+        if (rep.getUsername() != null && realm.isEditUsernameAllowed()) {
+            user.setUsername(rep.getUsername());
+        }
+        if (rep.getEmail() != null) user.setEmail(rep.getEmail());
+        if (rep.getFirstName() != null) user.setFirstName(rep.getFirstName());
+        if (rep.getLastName() != null) user.setLastName(rep.getLastName());
+
+        if (rep.isEnabled() != null) user.setEnabled(rep.isEnabled());
+        if (rep.isEmailVerified() != null) user.setEmailVerified(rep.isEmailVerified());
+
+        List<String> reqActions = rep.getRequiredActions();
+
+        if (reqActions != null) {
+            Set<String> allActions = new HashSet<>();
+            for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
+                allActions.add(factory.getId());
+            }
+            for (String action : allActions) {
+                if (reqActions.contains(action)) {
+                    user.addRequiredAction(action);
+                } else if (removeMissingRequiredActions) {
+                    user.removeRequiredAction(action);
+                }
+            }
+        }
+
+        if (rep.getAttributes() != null) {
+            for (Map.Entry<String, List<String>> attr : rep.getAttributes().entrySet()) {
+                user.setAttribute(attr.getKey(), attr.getValue());
+            }
+
+            for (String attr : attrsToRemove) {
+                user.removeAttribute(attr);
+            }
+        }
+    }
+
+    /**
+     * Get representation of the user
+     *
+     * @return
+     */
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUser() {
+        auth.users().requireView(user);
+
+        UserRepresentation rep = ModelToRepresentation.toRepresentation(session, realm, user);
+
+        if (realm.isIdentityFederationEnabled()) {
+            List<FederatedIdentityRepresentation> reps = getFederatedIdentities(user);
+            rep.setFederatedIdentities(reps);
+        }
+
+        if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
+            rep.setEnabled(false);
+        }
+        rep.setAccess(auth.users().getAccess(user));
+
+        return rep;
+    }
+
+    /**
+     * Impersonate the user
+     *
+     * @return
+     */
+    @Path("impersonation")
+    @POST
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public Map<String, Object> impersonate() {
+        ProfileHelper.requireFeature(Profile.Feature.IMPERSONATION);
+
+        auth.users().requireImpersonate(user);
+        RealmModel authenticatedRealm = auth.adminAuth().getRealm();
+        // if same realm logout before impersonation
+        boolean sameRealm = false;
+        if (authenticatedRealm.getId().equals(realm.getId())) {
+            sameRealm = true;
+            UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, auth.adminAuth().getToken().getSessionState());
+            AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
+            AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection);
+            AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true);
+        }
+        EventBuilder event = new EventBuilder(realm, session, clientConnection);
+
+        String sessionId = KeycloakModelUtils.generateId();
+        UserSessionModel userSession = session.sessions().createUserSession(sessionId, realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
+        AuthenticationManager.createLoginCookie(session, realm, userSession.getUser(), userSession, uriInfo, clientConnection);
+        URI redirect = AccountService.accountServiceApplicationPage(uriInfo).build(realm.getName());
+        Map<String, Object> result = new HashMap<>();
+        result.put("sameRealm", sameRealm);
+        result.put("redirect", redirect.toString());
+        event.event(EventType.IMPERSONATE)
+             .session(userSession)
+             .user(user)
+             .detail(Details.IMPERSONATOR_REALM,authenticatedRealm.getName())
+             .detail(Details.IMPERSONATOR, auth.adminAuth().getUser().getUsername()).success();
+
+        return result;
+    }
+
+
+    /**
+     * Get sessions associated with the user
+     *
+     * @return
+     */
+    @Path("sessions")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<UserSessionRepresentation> getSessions() {
+        auth.users().requireView(user);
+        List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
+        List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
+        for (UserSessionModel session : sessions) {
+            UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
+            reps.add(rep);
+        }
+        return reps;
+    }
+
+    /**
+     * Get offline sessions associated with the user and client
+     *
+     * @return
+     */
+    @Path("offline-sessions/{clientId}")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<UserSessionRepresentation> getOfflineSessions(final @PathParam("clientId") String clientId) {
+        auth.users().requireView(user);
+        ClientModel client = realm.getClientById(clientId);
+        if (client == null) {
+            throw new NotFoundException("Client not found");
+        }
+        List<UserSessionModel> sessions = new UserSessionManager(session).findOfflineSessions(realm, user);
+        List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
+        for (UserSessionModel session : sessions) {
+            UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
+
+            // Update lastSessionRefresh with the timestamp from clientSession
+            AuthenticatedClientSessionModel clientSession = session.getAuthenticatedClientSessions().get(clientId);
+
+            // Skip if userSession is not for this client
+            if (clientSession == null) {
+                continue;
+            }
+
+            rep.setLastAccess(clientSession.getTimestamp());
+
+            reps.add(rep);
+        }
+        return reps;
+    }
+
+    /**
+     * Get social logins associated with the user
+     *
+     * @return
+     */
+    @Path("federated-identity")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<FederatedIdentityRepresentation> getFederatedIdentity() {
+        auth.users().requireView(user);
+
+        return getFederatedIdentities(user);
+    }
+
+    private List<FederatedIdentityRepresentation> getFederatedIdentities(UserModel user) {
+        Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
+        List<FederatedIdentityRepresentation> result = new ArrayList<FederatedIdentityRepresentation>();
+
+        for (FederatedIdentityModel identity : identities) {
+            for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
+                if (identityProviderModel.getAlias().equals(identity.getIdentityProvider())) {
+                    FederatedIdentityRepresentation rep = ModelToRepresentation.toRepresentation(identity);
+                    result.add(rep);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Add a social login provider to the user
+     *
+     * @param provider Social login provider id
+     * @param rep
+     * @return
+     */
+    @Path("federated-identity/{provider}")
+    @POST
+    @NoCache
+    public Response addFederatedIdentity(final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) {
+        auth.users().requireManage(user);
+        if (session.users().getFederatedIdentity(user, provider, realm) != null) {
+            return ErrorResponse.exists("User is already linked with provider");
+        }
+
+        FederatedIdentityModel socialLink = new FederatedIdentityModel(provider, rep.getUserId(), rep.getUserName());
+        session.users().addFederatedIdentity(realm, user, socialLink);
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(rep).success();
+        return Response.noContent().build();
+    }
+
+    /**
+     * Remove a social login provider from user
+     *
+     * @param provider Social login provider id
+     */
+    @Path("federated-identity/{provider}")
+    @DELETE
+    @NoCache
+    public void removeFederatedIdentity(final @PathParam("provider") String provider) {
+        auth.users().requireManage(user);
+        if (!session.users().removeFederatedIdentity(realm, user, provider)) {
+            throw new NotFoundException("Link not found");
+        }
+        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+    }
+
+    /**
+     * Get consents granted by the user
+     *
+     * @return
+     */
+    @Path("consents")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<Map<String, Object>> getConsents() {
+        auth.users().requireView(user);
+        List<Map<String, Object>> result = new LinkedList<>();
+
+        Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
+
+        for (ClientModel client : realm.getClients()) {
+            UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
+            boolean hasOfflineToken = offlineClients.contains(client);
+
+            if (consent == null && !hasOfflineToken) {
+                continue;
+            }
+
+            UserConsentRepresentation rep = (consent == null) ? null : ModelToRepresentation.toRepresentation(consent);
+
+            Map<String, Object> currentRep = new HashMap<>();
+            currentRep.put("clientId", client.getClientId());
+            currentRep.put("grantedProtocolMappers", (rep==null ? Collections.emptyMap() : rep.getGrantedProtocolMappers()));
+            currentRep.put("grantedRealmRoles", (rep==null ? Collections.emptyList() : rep.getGrantedRealmRoles()));
+            currentRep.put("grantedClientRoles", (rep==null ? Collections.emptyMap() : rep.getGrantedClientRoles()));
+            currentRep.put("createdDate", (rep==null ? null : rep.getCreatedDate()));
+            currentRep.put("lastUpdatedDate", (rep==null ? null : rep.getLastUpdatedDate()));
+
+            List<Map<String, String>> additionalGrants = new LinkedList<>();
+            if (hasOfflineToken) {
+                Map<String, String> offlineTokens = new HashMap<>();
+                offlineTokens.put("client", client.getId());
+                // TODO: translate
+                offlineTokens.put("key", "Offline Token");
+                additionalGrants.add(offlineTokens);
+            }
+            currentRep.put("additionalGrants", additionalGrants);
+
+            result.add(currentRep);
+        }
+
+        return result;
+    }
+
+    /**
+     * Revoke consent and offline tokens for particular client from user
+     *
+     * @param clientId Client id
+     */
+    @Path("consents/{client}")
+    @DELETE
+    @NoCache
+    public void revokeConsent(final @PathParam("client") String clientId) {
+        auth.users().requireManage(user);
+
+        ClientModel client = realm.getClientByClientId(clientId);
+        if (client == null) {
+            throw new NotFoundException("Client not found");
+        }
+        boolean revokedConsent = session.users().revokeConsentForClient(realm, user.getId(), client.getId());
+        boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
+
+        if (revokedConsent) {
+            // Logout clientSessions for this user and client
+            AuthenticationManager.backchannelUserFromClient(session, realm, user, client, uriInfo, headers);
+        }
+
+        if (!revokedConsent && !revokedOfflineToken) {
+            throw new NotFoundException("Consent nor offline token not found");
+        }
+        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
+    }
+
+    /**
+     * Remove all user sessions associated with the user
+     *
+     * Also send notification to all clients that have an admin URL to invalidate the sessions for the particular user.
+     *
+     */
+    @Path("logout")
+    @POST
+    public void logout() {
+        auth.users().requireManage(user);
+
+        List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
+        for (UserSessionModel userSession : userSessions) {
+            AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
+        }
+        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
+    }
+
+    /**
+     * Delete the user
+     */
+    @DELETE
+    @NoCache
+    public Response deleteUser() {
+        auth.users().requireManage(user);
+
+        boolean removed = new UserManager(session).removeUser(realm, user);
+        if (removed) {
+            adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+            return Response.noContent().build();
+        } else {
+            return ErrorResponse.error("User couldn't be deleted", Status.BAD_REQUEST);
+        }
+    }
+
+    @Path("role-mappings")
+    public RoleMapperResource getRoleMappings() {
+        AdminPermissionEvaluator.RequirePermissionCheck manageCheck = () -> auth.users().requireMapRoles(user);
+        AdminPermissionEvaluator.RequirePermissionCheck viewCheck = () -> auth.users().requireView(user);
+        RoleMapperResource resource =  new RoleMapperResource(realm, auth, user, adminEvent, manageCheck, viewCheck);
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+        return resource;
+
+    }
+
+    /**
+     * Disable all credentials for a user of a specific type
+     *
+     * @param credentialTypes
+     */
+    @Path("disable-credential-types")
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void disableCredentialType(List<String> credentialTypes) {
+        auth.users().requireManage(user);
+        if (credentialTypes == null) return;
+        for (String type : credentialTypes) {
+            session.userCredentialManager().disableCredentialType(realm, user, type);
+
+        }
+
+
+    }
+
+    /**
+     * Set up a temporary password for the user
+     *
+     * User will have to reset the temporary password next time they log in.
+     *
+     * @param pass A Temporary password
+     */
+    @Path("reset-password")
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void resetPassword(CredentialRepresentation pass) {
+        auth.users().requireManage(user);
+        if (pass == null || pass.getValue() == null || !CredentialRepresentation.PASSWORD.equals(pass.getType())) {
+            throw new BadRequestException("No password provided");
+        }
+        if (Validation.isBlank(pass.getValue())) {
+            throw new BadRequestException("Empty password not allowed");
+        }
+
+        UserCredentialModel cred = UserCredentialModel.password(pass.getValue(), true);
+        try {
+            session.userCredentialManager().updateCredential(realm, user, cred);
+        } catch (IllegalStateException ise) {
+            throw new BadRequestException("Resetting to N old passwords is not allowed.");
+        } catch (ReadOnlyException mre) {
+            throw new BadRequestException("Can't reset password as account is read only");
+        } catch (ModelException e) {
+            Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
+            throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()),
+                    Status.BAD_REQUEST);
+        }
+        if (pass.isTemporary() != null && pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+
+        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
+    }
+
+    /**
+     * Remove TOTP from the user
+     *
+     */
+    @Path("remove-totp")
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void removeTotp() {
+        auth.users().requireManage(user);
+
+        session.userCredentialManager().disableCredentialType(realm, user, CredentialModel.OTP);
+        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
+    }
+
+    /**
+     * Send an email to the user with a link they can click to reset their password.
+     * The redirectUri and clientId parameters are optional. The default for the
+     * redirect is the account client.
+     *
+     * This endpoint has been deprecated.  Please use the execute-actions-email passing a list with
+     * UPDATE_PASSWORD within it.
+     *
+     * @param redirectUri redirect uri
+     * @param clientId client id
+     * @return
+     */
+    @Deprecated
+    @Path("reset-password-email")
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response resetPasswordEmail(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
+                                       @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
+        List<String> actions = new LinkedList<>();
+        actions.add(UserModel.RequiredAction.UPDATE_PASSWORD.name());
+        return executeActionsEmail(redirectUri, clientId, null, actions);
+    }
+
+
+    /**
+     * Send a update account email to the user
+     *
+     * An email contains a link the user can click to perform a set of required actions.
+     * The redirectUri and clientId parameters are optional. If no redirect is given, then there will
+     * be no link back to click after actions have completed.  Redirect uri must be a valid uri for the
+     * particular clientId.
+     *
+     * @param redirectUri Redirect uri
+     * @param clientId Client id
+     * @param lifespan Number of seconds after which the generated token expires
+     * @param actions required actions the user needs to complete
+     * @return
+     */
+    @Path("execute-actions-email")
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response executeActionsEmail(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
+                                        @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId,
+                                        @QueryParam("lifespan") Integer lifespan,
+                                        List<String> actions) {
+        auth.users().requireManage(user);
+
+        if (user.getEmail() == null) {
+            return ErrorResponse.error("User email missing", Status.BAD_REQUEST);
+        }
+
+        if (!user.isEnabled()) {
+            throw new WebApplicationException(
+                ErrorResponse.error("User is disabled", Status.BAD_REQUEST));
+        }
+
+        if (redirectUri != null && clientId == null) {
+            throw new WebApplicationException(
+                ErrorResponse.error("Client id missing", Status.BAD_REQUEST));
+        }
+
+        if (clientId == null) {
+            clientId = Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
+        }
+
+        ClientModel client = realm.getClientByClientId(clientId);
+        if (client == null || !client.isEnabled()) {
+            throw new WebApplicationException(
+                ErrorResponse.error(clientId + " not enabled", Status.BAD_REQUEST));
+        }
+
+        String redirect;
+        if (redirectUri != null) {
+            redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
+            if (redirect == null) {
+                throw new WebApplicationException(
+                    ErrorResponse.error("Invalid redirect uri.", Status.BAD_REQUEST));
+            }
+        }
+
+        if (lifespan == null) {
+            lifespan = realm.getActionTokenGeneratedByAdminLifespan();
+        }
+        int expiration = Time.currentTime() + lifespan;
+        ExecuteActionsActionToken token = new ExecuteActionsActionToken(user.getId(), expiration, actions, redirectUri, clientId);
+
+        try {
+            UriBuilder builder = LoginActionsService.actionTokenProcessor(uriInfo);
+            builder.queryParam("key", token.serialize(session, realm, uriInfo));
+
+            String link = builder.build(realm.getName()).toString();
+
+            this.session.getProvider(EmailTemplateProvider.class)
+              .setRealm(realm)
+              .setUser(user)
+              .sendExecuteActions(link, TimeUnit.SECONDS.toMinutes(lifespan));
+
+            //audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
+
+            adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
+
+            return Response.ok().build();
+        } catch (EmailException e) {
+            ServicesLogger.LOGGER.failedToSendActionsEmail(e);
+            return ErrorResponse.error("Failed to send execute actions email", Status.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    /**
+     * Send an email-verification email to the user
+     *
+     * An email contains a link the user can click to verify their email address.
+     * The redirectUri and clientId parameters are optional. The default for the
+     * redirect is the account client.
+     *
+     * @param redirectUri Redirect uri
+     * @param clientId Client id
+     * @return
+     */
+    @Path("send-verify-email")
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response sendVerifyEmail(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri, @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
+        List<String> actions = new LinkedList<>();
+        actions.add(UserModel.RequiredAction.VERIFY_EMAIL.name());
+        return executeActionsEmail(redirectUri, clientId, null, actions);
+    }
+
+    @GET
+    @Path("groups")
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<GroupRepresentation> groupMembership() {
+        auth.users().requireView(user);
+        List<GroupRepresentation> memberships = new LinkedList<>();
+        for (GroupModel group : user.getGroups()) {
+            memberships.add(ModelToRepresentation.toRepresentation(group, false));
+        }
+        return memberships;
+    }
+
+    @DELETE
+    @Path("groups/{groupId}")
+    @NoCache
+    public void removeMembership(@PathParam("groupId") String groupId) {
+        auth.users().requireManageGroupMembership(user);
+
+        GroupModel group = session.realms().getGroupById(groupId, realm);
+        if (group == null) {
+            throw new NotFoundException("Group not found");
+        }
+        auth.groups().requireManageMembership(group);
+
+        try {
+            if (user.isMemberOf(group)){
+                user.leaveGroup(group);
+                adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
+            }
+        } catch (ModelException me) {
+            Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
+            throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
+                    Status.BAD_REQUEST);
+        }
+    }
+
+    @PUT
+    @Path("groups/{groupId}")
+    @NoCache
+    public void joinGroup(@PathParam("groupId") String groupId) {
+        auth.users().requireManageGroupMembership(user);
+        GroupModel group = session.realms().getGroupById(groupId, realm);
+        if (group == null) {
+            throw new NotFoundException("Group not found");
+        }
+        auth.groups().requireManageMembership(group);
+        if (!user.isMemberOf(group)){
+            user.joinGroup(group);
+            adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
+        }
+    }
+
+}
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 815ee89..6ed677f 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
@@ -23,6 +23,7 @@ import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.authentication.RequiredActionProvider;
 import org.keycloak.authentication.actiontoken.execactions.ExecuteActionsActionToken;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.common.Profile;
 import org.keycloak.common.util.Time;
@@ -34,6 +35,20 @@ import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserLoginFailureModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.*;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.ModelToRepresentation;
@@ -67,18 +82,26 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import java.net.URI;
 import java.text.MessageFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import javax.ws.rs.*;
-import javax.ws.rs.core.*;
 
 /**
  * Base resource for managing users
@@ -92,7 +115,7 @@ public class UsersResource {
 
     protected RealmModel realm;
 
-    private RealmAuth auth;
+    private AdminPermissionEvaluator auth;
 
     private AdminEventBuilder adminEvent;
 
@@ -108,66 +131,10 @@ public class UsersResource {
     @Context
     protected HttpHeaders headers;
 
-    public UsersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public UsersResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
         this.adminEvent = adminEvent.resource(ResourceType.USER);
-
-        auth.init(RealmAuth.Resource.USER);
-    }
-
-    /**
-     * Update the user
-     *
-     * @param id User id
-     * @param rep
-     * @return
-     */
-    @Path("{id}")
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response updateUser(final @PathParam("id") String id, final UserRepresentation rep) {
-        auth.requireManage();
-
-        try {
-            UserModel user = session.users().getUserById(id, realm);
-            if (user == null) {
-                return Response.status(Status.NOT_FOUND).build();
-            }
-
-            Set<String> attrsToRemove;
-            if (rep.getAttributes() != null) {
-                attrsToRemove = new HashSet<>(user.getAttributes().keySet());
-                attrsToRemove.removeAll(rep.getAttributes().keySet());
-            } else {
-                attrsToRemove = Collections.emptySet();
-            }
-
-            if (rep.isEnabled() != null && rep.isEnabled()) {
-                UserLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, id);
-                if (failureModel != null) {
-                    failureModel.clearFailures();
-                }
-            }
-
-            updateUserFromRep(user, rep, attrsToRemove, realm, session, true);
-            adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
-
-            if (session.getTransactionManager().isActive()) {
-                session.getTransactionManager().commit();
-            }
-            return Response.noContent().build();
-        } catch (ModelDuplicateException e) {
-            return ErrorResponse.exists("User exists with same username or email");
-        } catch (ReadOnlyException re) {
-            return ErrorResponse.exists("User is read only!");
-        } catch (ModelException me) {
-            logger.warn("Could not update user!", me);
-            return ErrorResponse.exists("Could not update user!");
-        } catch (Exception me) { // JPA
-            logger.warn("Could not update user!", me);// may be committed by JTA which can't
-            return ErrorResponse.exists("Could not update user!");
-        }
     }
 
     /**
@@ -182,7 +149,7 @@ public class UsersResource {
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     public Response createUser(final @Context UriInfo uriInfo, final UserRepresentation rep) {
-        auth.requireManage();
+        auth.users().requireManage();
 
         // Double-check duplicated username and email here due to federation
         if (session.users().getUserByUsername(rep.getUsername(), realm) != null) {
@@ -195,7 +162,7 @@ public class UsersResource {
         try {
             UserModel user = session.users().addUser(realm, rep.getUsername());
             Set<String> emptySet = Collections.emptySet();
-            updateUserFromRep(user, rep, emptySet, realm, session, false);
+            UserResource.updateUserFromRep(user, rep, emptySet, realm, session, false);
 
             adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, user.getId()).representation(rep).success();
 
@@ -217,45 +184,6 @@ public class UsersResource {
             return ErrorResponse.exists("Could not create user");
         }
     }
-
-    public static void updateUserFromRep(UserModel user, UserRepresentation rep, Set<String> attrsToRemove, RealmModel realm, KeycloakSession session, boolean removeMissingRequiredActions) {
-        if (rep.getUsername() != null && realm.isEditUsernameAllowed()) {
-            user.setUsername(rep.getUsername());
-        }
-        if (rep.getEmail() != null) user.setEmail(rep.getEmail());
-        if (rep.getFirstName() != null) user.setFirstName(rep.getFirstName());
-        if (rep.getLastName() != null) user.setLastName(rep.getLastName());
-
-        if (rep.isEnabled() != null) user.setEnabled(rep.isEnabled());
-        if (rep.isEmailVerified() != null) user.setEmailVerified(rep.isEmailVerified());
-
-        List<String> reqActions = rep.getRequiredActions();
-
-        if (reqActions != null) {
-            Set<String> allActions = new HashSet<>();
-            for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
-                allActions.add(factory.getId());
-            }
-            for (String action : allActions) {
-                if (reqActions.contains(action)) {
-                    user.addRequiredAction(action);
-                } else if (removeMissingRequiredActions) {
-                    user.removeRequiredAction(action);
-                }
-            }
-        }
-
-        if (rep.getAttributes() != null) {
-            for (Map.Entry<String, List<String>> attr : rep.getAttributes().entrySet()) {
-                user.setAttribute(attr.getKey(), attr.getValue());
-            }
-
-            for (String attr : attrsToRemove) {
-                user.removeAttribute(attr);
-            }
-        }
-    }
-
     /**
      * Get representation of the user
      *
@@ -263,368 +191,17 @@ public class UsersResource {
      * @return
      */
     @Path("{id}")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public UserRepresentation getUser(final @PathParam("id") String id) {
-        auth.requireView();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        UserRepresentation rep = ModelToRepresentation.toRepresentation(session, realm, user);
-
-        if (realm.isIdentityFederationEnabled()) {
-            List<FederatedIdentityRepresentation> reps = getFederatedIdentities(user);
-            rep.setFederatedIdentities(reps);
-        }
-
-        if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
-            rep.setEnabled(false);
-        }
-
-        return rep;
-    }
-
-    /**
-     * Impersonate the user
-     *
-     * @param id User id
-     * @return
-     */
-    @Path("{id}/impersonation")
-    @POST
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public Map<String, Object> impersonate(final @PathParam("id") String id) {
-        ProfileHelper.requireFeature(Profile.Feature.IMPERSONATION);
-
-        auth.init(RealmAuth.Resource.IMPERSONATION);
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        RealmModel authenticatedRealm = auth.getAuth().getRealm();
-        // if same realm logout before impersonation
-        boolean sameRealm = false;
-        if (authenticatedRealm.getId().equals(realm.getId())) {
-            sameRealm = true;
-            UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, auth.getAuth().getToken().getSessionState());
-            AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
-            AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection);
-            AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true);
-        }
-        EventBuilder event = new EventBuilder(realm, session, clientConnection);
-
-        String sessionId = KeycloakModelUtils.generateId();
-        UserSessionModel userSession = session.sessions().createUserSession(sessionId, realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
-        AuthenticationManager.createLoginCookie(session, realm, userSession.getUser(), userSession, uriInfo, clientConnection);
-        URI redirect = AccountService.accountServiceApplicationPage(uriInfo).build(realm.getName());
-        Map<String, Object> result = new HashMap<>();
-        result.put("sameRealm", sameRealm);
-        result.put("redirect", redirect.toString());
-        event.event(EventType.IMPERSONATE)
-             .session(userSession)
-             .user(user)
-             .detail(Details.IMPERSONATOR_REALM,authenticatedRealm.getName())
-             .detail(Details.IMPERSONATOR, auth.getAuth().getUser().getUsername()).success();
-
-        return result;
-    }
-
-
-    /**
-     * Get sessions associated with the user
-     *
-     * @param id User id
-     * @return
-     */
-    @Path("{id}/sessions")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public List<UserSessionRepresentation> getSessions(final @PathParam("id") String id) {
-        auth.requireView();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
-        List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
-        for (UserSessionModel session : sessions) {
-            UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
-            reps.add(rep);
-        }
-        return reps;
-    }
-
-    /**
-     * Get offline sessions associated with the user and client
-     *
-     * @param id User id
-     * @return
-     */
-    @Path("{id}/offline-sessions/{clientId}")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public List<UserSessionRepresentation> getOfflineSessions(final @PathParam("id") String id, final @PathParam("clientId") String clientId) {
-        auth.requireView();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        ClientModel client = realm.getClientById(clientId);
-        if (client == null) {
-            throw new NotFoundException("Client not found");
-        }
-        List<UserSessionModel> sessions = new UserSessionManager(session).findOfflineSessions(realm, user);
-        List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>();
-        for (UserSessionModel session : sessions) {
-            UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
-
-            // Update lastSessionRefresh with the timestamp from clientSession
-            AuthenticatedClientSessionModel clientSession = session.getAuthenticatedClientSessions().get(clientId);
-
-            // Skip if userSession is not for this client
-            if (clientSession == null) {
-                continue;
-            }
-
-            rep.setLastAccess(clientSession.getTimestamp());
-
-            reps.add(rep);
-        }
-        return reps;
-    }
-
-    /**
-     * Get social logins associated with the user
-     *
-     * @param id User id
-     * @return
-     */
-    @Path("{id}/federated-identity")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public List<FederatedIdentityRepresentation> getFederatedIdentity(final @PathParam("id") String id) {
-        auth.requireView();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        return getFederatedIdentities(user);
-    }
-
-    private List<FederatedIdentityRepresentation> getFederatedIdentities(UserModel user) {
-        Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
-        List<FederatedIdentityRepresentation> result = new ArrayList<FederatedIdentityRepresentation>();
-
-        for (FederatedIdentityModel identity : identities) {
-            for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
-                if (identityProviderModel.getAlias().equals(identity.getIdentityProvider())) {
-                    FederatedIdentityRepresentation rep = ModelToRepresentation.toRepresentation(identity);
-                    result.add(rep);
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Add a social login provider to the user
-     *
-     * @param id User id
-     * @param provider Social login provider id
-     * @param rep
-     * @return
-     */
-    @Path("{id}/federated-identity/{provider}")
-    @POST
-    @NoCache
-    public Response addFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        if (session.users().getFederatedIdentity(user, provider, realm) != null) {
-            return ErrorResponse.exists("User is already linked with provider");
-        }
-
-        FederatedIdentityModel socialLink = new FederatedIdentityModel(provider, rep.getUserId(), rep.getUserName());
-        session.users().addFederatedIdentity(realm, user, socialLink);
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(rep).success();
-        return Response.noContent().build();
-    }
-
-    /**
-     * Remove a social login provider from user
-     *
-     * @param id User id
-     * @param provider Social login provider id
-     */
-    @Path("{id}/federated-identity/{provider}")
-    @DELETE
-    @NoCache
-    public void removeFederatedIdentity(final @PathParam("id") String id, final @PathParam("provider") String provider) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        if (!session.users().removeFederatedIdentity(realm, user, provider)) {
-            throw new NotFoundException("Link not found");
-        }
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
-    }
-
-    /**
-     * Get consents granted by the user
-     *
-     * @param id User id
-     * @return
-     */
-    @Path("{id}/consents")
-    @GET
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public List<Map<String, Object>> getConsents(final @PathParam("id") String id) {
-        auth.requireView();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        List<Map<String, Object>> result = new LinkedList<>();
-
-        Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
-
-        for (ClientModel client : realm.getClients()) {
-            UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
-            boolean hasOfflineToken = offlineClients.contains(client);
-
-            if (consent == null && !hasOfflineToken) {
-                continue;
-            }
-
-            UserConsentRepresentation rep = (consent == null) ? null : ModelToRepresentation.toRepresentation(consent);
-
-            Map<String, Object> currentRep = new HashMap<>();
-            currentRep.put("clientId", client.getClientId());
-            currentRep.put("grantedProtocolMappers", (rep==null ? Collections.emptyMap() : rep.getGrantedProtocolMappers()));
-            currentRep.put("grantedRealmRoles", (rep==null ? Collections.emptyList() : rep.getGrantedRealmRoles()));
-            currentRep.put("grantedClientRoles", (rep==null ? Collections.emptyMap() : rep.getGrantedClientRoles()));
-            currentRep.put("createdDate", (rep==null ? null : rep.getCreatedDate()));
-            currentRep.put("lastUpdatedDate", (rep==null ? null : rep.getLastUpdatedDate()));
-
-            List<Map<String, String>> additionalGrants = new LinkedList<>();
-            if (hasOfflineToken) {
-                Map<String, String> offlineTokens = new HashMap<>();
-                offlineTokens.put("client", client.getId());
-                // TODO: translate
-                offlineTokens.put("key", "Offline Token");
-                additionalGrants.add(offlineTokens);
-            }
-            currentRep.put("additionalGrants", additionalGrants);
-
-            result.add(currentRep);
-        }
-
-        return result;
-    }
-
-    /**
-     * Revoke consent and offline tokens for particular client from user
-     *
-     * @param id User id
-     * @param clientId Client id
-     */
-    @Path("{id}/consents/{client}")
-    @DELETE
-    @NoCache
-    public void revokeConsent(final @PathParam("id") String id, final @PathParam("client") String clientId) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        ClientModel client = realm.getClientByClientId(clientId);
-        boolean revokedConsent = session.users().revokeConsentForClient(realm, user.getId(), client.getId());
-        boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
-
-        if (revokedConsent) {
-            // Logout clientSessions for this user and client
-            AuthenticationManager.backchannelUserFromClient(session, realm, user, client, uriInfo, headers);
-        }
-
-        if (!revokedConsent && !revokedOfflineToken) {
-            throw new NotFoundException("Consent nor offline token not found");
-        }
-        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
-    }
-
-    /**
-     * Remove all user sessions associated with the user
-     *
-     * Also send notification to all clients that have an admin URL to invalidate the sessions for the particular user.
-     *
-     * @param id User id
-     */
-    @Path("{id}/logout")
-    @POST
-    public void logout(final @PathParam("id") String id) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
-        for (UserSessionModel userSession : userSessions) {
-            AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
-        }
-        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
-    }
-
-    /**
-     * Delete the user
-     *
-     * @param id User id
-     */
-    @Path("{id}")
-    @DELETE
-    @NoCache
-    public Response deleteUser(final @PathParam("id") String id) {
-        auth.requireManage();
-
+    public UserResource user(final @PathParam("id") String id) {
         UserModel user = session.users().getUserById(id, realm);
         if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        boolean removed = new UserManager(session).removeUser(realm, user);
-        if (removed) {
-            adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
-            return Response.noContent().build();
-        } else {
-            return ErrorResponse.error("User couldn't be deleted", Response.Status.BAD_REQUEST);
+            // we do this to make sure somebody can't phish ids
+            if (auth.users().canQuery()) throw new NotFoundException("User not found");
+            else throw new ForbiddenException();
         }
+        UserResource resource = new UserResource(realm, user, auth, adminEvent);
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+        //resourceContext.initResource(users);
+        return resource;
     }
 
     /**
@@ -651,7 +228,7 @@ public class UsersResource {
                                              @QueryParam("username") String username,
                                              @QueryParam("first") Integer firstResult,
                                              @QueryParam("max") Integer maxResults) {
-        auth.requireView();
+        auth.users().requireQuery();
 
         firstResult = firstResult != null ? firstResult : -1;
         maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS;
@@ -679,8 +256,12 @@ public class UsersResource {
             userModels = session.users().getUsers(realm, firstResult, maxResults, false);
         }
 
+        boolean canViewGlobal = auth.users().canView();
         for (UserModel user : userModels) {
-            results.add(ModelToRepresentation.toRepresentation(session, realm, user));
+            if (!canViewGlobal  && !auth.users().canView(user)) continue;
+            UserRepresentation userRep = ModelToRepresentation.toRepresentation(session, realm, user);
+            userRep.setAccess(auth.users().getAccess(user));
+            results.add(userRep);
         }
         return results;
     }
@@ -690,311 +271,8 @@ public class UsersResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public Integer getUsersCount() {
-        auth.requireView();
+        auth.users().requireView();
 
         return session.users().getUsersCount(realm);
     }
-
-    @Path("{id}/role-mappings")
-    public RoleMapperResource getRoleMappings(@PathParam("id") String id) {
-        auth.init(RealmAuth.Resource.USER);
-
-        UserModel user = session.users().getUserById(id, realm);
-
-        RoleMapperResource resource =  new RoleMapperResource(realm, auth, user, adminEvent);
-        ResteasyProviderFactory.getInstance().injectProperties(resource);
-        return resource;
-
-    }
-
-    /**
-     * Disable all credentials for a user of a specific type
-     *
-     * @param id
-     * @param credentialTypes
-     */
-    @Path("{id}/disable-credential-types")
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    public void disableCredentialType(@PathParam("id") String id, List<String> credentialTypes) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        if (credentialTypes == null) return;
-        for (String type : credentialTypes) {
-            session.userCredentialManager().disableCredentialType(realm, user, type);
-
-        }
-
-
-    }
-
-    /**
-     * Set up a temporary password for the user
-     *
-     * User will have to reset the temporary password next time they log in.
-     *
-     * @param id User id
-     * @param pass A Temporary password
-     */
-    @Path("{id}/reset-password")
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    public void resetPassword(@PathParam("id") String id, CredentialRepresentation pass) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        if (pass == null || pass.getValue() == null || !CredentialRepresentation.PASSWORD.equals(pass.getType())) {
-            throw new BadRequestException("No password provided");
-        }
-        if (Validation.isBlank(pass.getValue())) {
-            throw new BadRequestException("Empty password not allowed");
-        }
-
-        UserCredentialModel cred = UserCredentialModel.password(pass.getValue(), true);
-        try {
-            session.userCredentialManager().updateCredential(realm, user, cred);
-        } catch (IllegalStateException ise) {
-            throw new BadRequestException("Resetting to N old passwords is not allowed.");
-        } catch (ReadOnlyException mre) {
-            throw new BadRequestException("Can't reset password as account is read only");
-        } catch (ModelException e) {
-            Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
-            throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()),
-                    Status.BAD_REQUEST);
-        }
-        if (pass.isTemporary() != null && pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
-
-        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
-    }
-
-    /**
-     * Remove TOTP from the user
-     *
-     * @param id User id
-     */
-    @Path("{id}/remove-totp")
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    public void removeTotp(@PathParam("id") String id) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        session.userCredentialManager().disableCredentialType(realm, user, CredentialModel.OTP);
-        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
-    }
-
-    /**
-     * Send an email to the user with a link they can click to reset their password.
-     * The redirectUri and clientId parameters are optional. The default for the
-     * redirect is the account client.
-     *
-     * This endpoint has been deprecated.  Please use the execute-actions-email passing a list with
-     * UPDATE_PASSWORD within it.
-     *
-     * @param id
-     * @param redirectUri redirect uri
-     * @param clientId client id
-     * @return
-     */
-    @Deprecated
-    @Path("{id}/reset-password-email")
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response resetPasswordEmail(@PathParam("id") String id,
-                                        @QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
-                                        @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
-        List<String> actions = new LinkedList<>();
-        actions.add(UserModel.RequiredAction.UPDATE_PASSWORD.name());
-        return executeActionsEmail(id, redirectUri, clientId, null, actions);
-    }
-
-
-    /**
-     * Send a update account email to the user
-     *
-     * An email contains a link the user can click to perform a set of required actions.
-     * The redirectUri and clientId parameters are optional. If no redirect is given, then there will
-     * be no link back to click after actions have completed.  Redirect uri must be a valid uri for the
-     * particular clientId.
-     *
-     * @param id User is
-     * @param redirectUri Redirect uri
-     * @param clientId Client id
-     * @param lifespan Number of seconds after which the generated token expires
-     * @param actions required actions the user needs to complete
-     * @return
-     */
-    @Path("{id}/execute-actions-email")
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response executeActionsEmail(@PathParam("id") String id,
-                                        @QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri,
-                                        @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId,
-                                        @QueryParam("lifespan") Integer lifespan,
-                                        List<String> actions) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            return ErrorResponse.error("User not found", Response.Status.NOT_FOUND);
-        }
-
-        if (user.getEmail() == null) {
-            return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST);
-        }
-
-        if (!user.isEnabled()) {
-            throw new WebApplicationException(
-                ErrorResponse.error("User is disabled", Response.Status.BAD_REQUEST));
-        }
-
-        if (redirectUri != null && clientId == null) {
-            throw new WebApplicationException(
-                ErrorResponse.error("Client id missing", Response.Status.BAD_REQUEST));
-        }
-
-        if (clientId == null) {
-            clientId = Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
-        }
-
-        ClientModel client = realm.getClientByClientId(clientId);
-        if (client == null || !client.isEnabled()) {
-            throw new WebApplicationException(
-                ErrorResponse.error(clientId + " not enabled", Response.Status.BAD_REQUEST));
-        }
-
-        String redirect;
-        if (redirectUri != null) {
-            redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
-            if (redirect == null) {
-                throw new WebApplicationException(
-                    ErrorResponse.error("Invalid redirect uri.", Response.Status.BAD_REQUEST));
-            }
-        }
-
-        if (lifespan == null) {
-            lifespan = realm.getActionTokenGeneratedByAdminLifespan();
-        }
-        int expiration = Time.currentTime() + lifespan;
-        ExecuteActionsActionToken token = new ExecuteActionsActionToken(id, expiration, actions, redirectUri, clientId);
-
-        try {
-            UriBuilder builder = LoginActionsService.actionTokenProcessor(uriInfo);
-            builder.queryParam("key", token.serialize(session, realm, uriInfo));
-
-            String link = builder.build(realm.getName()).toString();
-
-            this.session.getProvider(EmailTemplateProvider.class)
-              .setRealm(realm)
-              .setUser(user)
-              .sendExecuteActions(link, TimeUnit.SECONDS.toMinutes(lifespan));
-
-            //audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
-
-            adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
-
-            return Response.ok().build();
-        } catch (EmailException e) {
-            ServicesLogger.LOGGER.failedToSendActionsEmail(e);
-            return ErrorResponse.error("Failed to send execute actions email", Response.Status.INTERNAL_SERVER_ERROR);
-        }
-    }
-
-    /**
-     * Send an email-verification email to the user
-     *
-     * An email contains a link the user can click to verify their email address.
-     * The redirectUri and clientId parameters are optional. The default for the
-     * redirect is the account client.
-     *
-     * @param id User id
-     * @param redirectUri Redirect uri
-     * @param clientId Client id
-     * @return
-     */
-    @Path("{id}/send-verify-email")
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response sendVerifyEmail(@PathParam("id") String id, @QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri, @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
-        List<String> actions = new LinkedList<>();
-        actions.add(UserModel.RequiredAction.VERIFY_EMAIL.name());
-        return executeActionsEmail(id, redirectUri, clientId, null, actions);
-    }
-
-    @GET
-    @Path("{id}/groups")
-    @NoCache
-    @Produces(MediaType.APPLICATION_JSON)
-    public List<GroupRepresentation> groupMembership(@PathParam("id") String id) {
-        auth.requireView();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        List<GroupRepresentation> memberships = new LinkedList<>();
-        for (GroupModel group : user.getGroups()) {
-            memberships.add(ModelToRepresentation.toRepresentation(group, false));
-        }
-        return memberships;
-    }
-
-    @DELETE
-    @Path("{id}/groups/{groupId}")
-    @NoCache
-    public void removeMembership(@PathParam("id") String id, @PathParam("groupId") String groupId) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        GroupModel group = session.realms().getGroupById(groupId, realm);
-        if (group == null) {
-            throw new NotFoundException("Group not found");
-        }
-
-        try {
-            if (user.isMemberOf(group)){
-                user.leaveGroup(group);
-                adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
-            }
-        } catch (ModelException me) {
-            Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
-            throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),
-                    Response.Status.BAD_REQUEST);
-        }
-    }
-
-    @PUT
-    @Path("{id}/groups/{groupId}")
-    @NoCache
-    public void joinGroup(@PathParam("id") String id, @PathParam("groupId") String groupId) {
-        auth.requireManage();
-
-        UserModel user = session.users().getUserById(id, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-        GroupModel group = session.realms().getGroupById(groupId, realm);
-        if (group == null) {
-            throw new NotFoundException("Group not found");
-        }
-        if (!user.isMemberOf(group)){
-            user.joinGroup(group);
-            adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
-        }
-    }
-
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserStorageProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserStorageProviderResource.java
index 4ffcf86..638f57b 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserStorageProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserStorageProviderResource.java
@@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.ServicesLogger;
 import org.keycloak.services.managers.UserStorageSyncManager;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
 import org.keycloak.storage.UserStorageProvider;
 import org.keycloak.storage.UserStorageProviderModel;
 import org.keycloak.storage.ldap.LDAPStorageProvider;
@@ -55,7 +56,7 @@ public class UserStorageProviderResource {
 
     protected RealmModel realm;
 
-    protected RealmAuth auth;
+    protected AdminPermissionEvaluator auth;
 
     protected AdminEventBuilder adminEvent;
 
@@ -71,12 +72,10 @@ public class UserStorageProviderResource {
     @Context
     protected HttpHeaders headers;
 
-    public UserStorageProviderResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+    public UserStorageProviderResource(RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
         this.adminEvent = adminEvent;
-
-        auth.init(RealmAuth.Resource.USER);
     }
 
     /**
@@ -94,7 +93,7 @@ public class UserStorageProviderResource {
     @Produces(MediaType.APPLICATION_JSON)
     public SynchronizationResult syncUsers(@PathParam("id") String id,
                                            @QueryParam("action") String action) {
-        auth.requireManage();
+        auth.users().requireManage();
 
         ComponentModel model = realm.getComponent(id);
         if (model == null) {
@@ -139,7 +138,7 @@ public class UserStorageProviderResource {
     @Path("{id}/remove-imported-users")
     @NoCache
     public void removeImportedUsers(@PathParam("id") String id) {
-        auth.requireManage();
+        auth.users().requireManage();
 
         ComponentModel model = realm.getComponent(id);
         if (model == null) {
@@ -162,7 +161,7 @@ public class UserStorageProviderResource {
     @Path("{id}/unlink-users")
     @NoCache
     public void unlinkUsers(@PathParam("id") String id) {
-        auth.requireManage();
+        auth.users().requireManage();
 
         ComponentModel model = realm.getComponent(id);
         if (model == null) {
@@ -187,7 +186,7 @@ public class UserStorageProviderResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public SynchronizationResult syncMapperData(@PathParam("parentId") String parentId, @PathParam("id") String mapperId, @QueryParam("direction") String direction) {
-        auth.requireManage();
+        auth.users().requireManage();
 
         ComponentModel parentModel = realm.getComponent(parentId);
         if (parentModel == null) throw new NotFoundException("Parent model not found");
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 a6f42c8..7dc4d6e 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
@@ -43,6 +43,14 @@ import static org.keycloak.testsuite.util.IOUtil.PROJECT_BUILD_DIRECTORY;
 public class AdminClientUtil {
 
     public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String authServerContextRoot) throws Exception {
+        return createAdminClient(ignoreUnknownProperties, authServerContextRoot, MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID, null);
+
+    }
+    public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String realmName, String username, String password, String clientId, String clientSecret) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
+        return createAdminClient(ignoreUnknownProperties, AuthServerTestEnricher.getAuthServerContextRoot(), realmName, username, password, clientId, clientSecret);
+    }
+
+    public static Keycloak createAdminClient(boolean ignoreUnknownProperties, String authServerContextRoot, 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");
@@ -63,13 +71,17 @@ public class AdminClientUtil {
         }
 
         return Keycloak.getInstance(authServerContextRoot + "/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 {
         return createAdminClient(false, AuthServerTestEnricher.getAuthServerContextRoot());
     }
 
+    public static Keycloak createAdminClient(boolean ignoreUnknownProperties) throws Exception {
+        return createAdminClient(ignoreUnknownProperties, AuthServerTestEnricher.getAuthServerContextRoot());
+    }
+
     private static SSLContext getSSLContextWithTrustore(File file, String password) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {
         if (!file.isFile()) {
             throw new RuntimeException("Truststore file not found: " + file.getAbsolutePath());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
index 1739370..262d0b2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -167,6 +167,7 @@ public abstract class AbstractKeycloakTest {
                 removeRealm(testRealm.getRealm());
             }
         } else {
+            log.info("calling all TestCleanup");
             // Logout all users after the test
             List<RealmRepresentation> realms = testContext.getTestRealmReps();
             for (RealmRepresentation realm : realms) {
@@ -175,7 +176,12 @@ public abstract class AbstractKeycloakTest {
 
             // Cleanup objects
             for (TestCleanup cleanup : testContext.getCleanups().values()) {
-                cleanup.executeCleanup();
+                try {
+                    if (cleanup != null) cleanup.executeCleanup();
+                } catch (Exception e) {
+                    log.error("failed cleanup!", e);
+                    throw new RuntimeException(e);
+                }
             }
             testContext.getCleanups().clear();
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index 257eb7d..9b001ac 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -479,8 +479,8 @@ public class ClientTest extends AbstractAdminTest {
         // Create foo mapper
         ProtocolMapperRepresentation fooMapper = new ProtocolMapperRepresentation();
         fooMapper.setName("foo");
-        fooMapper.setProtocol("fooProtocol");
-        fooMapper.setProtocolMapper("fooMapper");
+        fooMapper.setProtocol("openid-connect");
+        fooMapper.setProtocolMapper("oidc-hardcoded-claim-mapper");
         fooMapper.setConsentRequired(true);
         Response response = mappersResource.createMapper(fooMapper);
         String location = response.getLocation().toString();
@@ -493,13 +493,13 @@ public class ClientTest extends AbstractAdminTest {
         assertEquals(fooMapper.getName(), "foo");
 
         // Update foo mapper
-        fooMapper.setProtocolMapper("foo-mapper-updated");
+        fooMapper.setConsentRequired(false);
         mappersResource.update(fooMapperId, fooMapper);
 
         assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper, ResourceType.PROTOCOL_MAPPER);
 
         fooMapper = mappersResource.getMapperById(fooMapperId);
-        assertEquals(fooMapper.getProtocolMapper(), "foo-mapper-updated");
+        assertFalse(fooMapper.isConsentRequired());
 
         // Remove foo mapper
         mappersResource.delete(fooMapperId);
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..8386aa6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java
@@ -0,0 +1,705 @@
+/*
+ * 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.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationProviderFactory;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.models.ClientTemplateModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
+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.DecisionStrategy;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.util.AdminClientUtil;
+
+import javax.ws.rs.ClientErrorException;
+import java.util.LinkedList;
+import java.util.List;
+
+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 {
+
+    public static final String CLIENT_NAME = "application";
+
+    @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 setupDemo(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        ClientModel client = realm.addClient("sales-pipeline-application");
+        RoleModel clientAdmin = client.addRole("admin");
+        client.addRole("leader-creator");
+        client.addRole("viewLeads");
+        ClientModel client2 = realm.addClient("market-analysis-application");
+        RoleModel client2Admin = client2.addRole("admin");
+        client2.addRole("market-manager");
+        client2.addRole("viewMarkets");
+        GroupModel sales = realm.createGroup("sales");
+        RoleModel salesAppsAdminRole = realm.addRole("sales-apps-admin");
+        salesAppsAdminRole.addCompositeRole(clientAdmin);
+        salesAppsAdminRole.addCompositeRole(client2Admin);
+        ClientModel realmManagementClient = realm.getClientByClientId("realm-management");
+        RoleModel queryClient = realmManagementClient.getRole(AdminRoles.QUERY_CLIENTS);
+
+
+        UserModel admin = session.users().addUser(realm, "salesManager");
+        admin.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
+        admin = session.users().addUser(realm, "sales-group-admin");
+        admin.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
+        admin = session.users().addUser(realm, "sales-it");
+        admin.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
+        admin = session.users().addUser(realm, "sales-pipeline-admin");
+        admin.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
+        admin = session.users().addUser(realm, "client-admin");
+        admin.setEnabled(true);
+        admin.grantRole(queryClient);
+        session.userCredentialManager().updateCredential(realm, admin, UserCredentialModel.password("password"));
+
+        UserModel user = session.users().addUser(realm, "salesman");
+        user.setEnabled(true);
+        user.joinGroup(sales);
+
+        user = session.users().addUser(realm, "saleswoman");
+        user.setEnabled(true);
+
+    }
+
+    public static void setupPolices(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+        RoleModel realmRole = realm.addRole("realm-role");
+        RoleModel realmRole2 = realm.addRole("realm-role2");
+        ClientModel client1 = realm.addClient(CLIENT_NAME);
+        ClientTemplateModel template = realm.addClientTemplate("template");
+        client1.setFullScopeAllowed(false);
+        RoleModel client1Role = client1.addRole("client-role");
+        GroupModel group = realm.createGroup("top");
+
+        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 application.client-role will have a role policy associated with their map-role permission
+        {
+            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);
+        }
+
+        {
+            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);
+        }
+
+        // realmRole2 will have an empty map-role policy
+        {
+            permissions.roles().setPermissionsEnabled(realmRole2, true);
+        }
+
+        // setup Users manage policies
+        {
+            permissions.users().setPermissionsEnabled(true);
+            ResourceServer server = permissions.realmResourceServer();
+            Policy managerPolicy = permissions.roles().rolePolicy(server, managerRole);
+            Policy permission = permissions.users().managePermission();
+            permission.addAssociatedPolicy(managerPolicy);
+            permission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        }
+        {
+            permissions.groups().setPermissionsEnabled(group, true);
+        }
+        {
+            permissions.clients().setPermissionsEnabled(client1, true);
+        }
+        // setup Users impersonate policy
+        {
+            ClientModel realmManagementClient = realm.getClientByClientId("realm-management");
+            RoleModel adminRole = realmManagementClient.getRole(AdminRoles.REALM_ADMIN);
+            permissions.users().setPermissionsEnabled(true);
+            ResourceServer server = permissions.realmResourceServer();
+            Policy adminPolicy = permissions.roles().rolePolicy(server, adminRole);
+            adminPolicy.setLogic(Logic.NEGATIVE);
+            Policy permission = permissions.users().userImpersonatedPermission();
+            permission.addAssociatedPolicy(adminPolicy);
+            permission.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+        }
+
+
+    }
+
+    public static void setupUsers(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        ClientModel client = realm.getClientByClientId(CLIENT_NAME);
+        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");
+        ClientModel realmManagementClient = realm.getClientByClientId("realm-management");
+        RoleModel adminRole = realmManagementClient.getRole(AdminRoles.REALM_ADMIN);
+        RoleModel queryGroupsRole = realmManagementClient.getRole(AdminRoles.QUERY_GROUPS);
+        RoleModel queryUsersRole = realmManagementClient.getRole(AdminRoles.QUERY_USERS);
+        RoleModel queryClientsRole = realmManagementClient.getRole(AdminRoles.QUERY_CLIENTS);
+
+        UserModel nomapAdmin = session.users().addUser(realm, "nomap-admin");
+        nomapAdmin.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, nomapAdmin, UserCredentialModel.password("password"));
+        nomapAdmin.grantRole(adminRole);
+
+        UserModel anotherAdmin = session.users().addUser(realm, "anotherAdmin");
+        anotherAdmin.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, anotherAdmin, UserCredentialModel.password("password"));
+        anotherAdmin.grantRole(adminRole);
+
+        UserModel authorizedUser = session.users().addUser(realm, "authorized");
+        authorizedUser.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, authorizedUser, UserCredentialModel.password("password"));
+        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);
+
+        // group management
+        AdminPermissionManagement permissions = AdminPermissions.management(session, realm);
+
+        GroupModel group =  KeycloakModelUtils.findGroupByPath(realm, "top");
+        UserModel groupMember = session.users().addUser(realm, "groupMember");
+        groupMember.joinGroup(group);
+        groupMember.setEnabled(true);
+        UserModel groupManager = session.users().addUser(realm, "groupManager");
+        groupManager.grantRole(queryGroupsRole);
+        groupManager.grantRole(queryUsersRole);
+        groupManager.setEnabled(true);
+        groupManager.grantRole(mapperRole);
+        session.userCredentialManager().updateCredential(realm, groupManager, UserCredentialModel.password("password"));
+
+        UserModel groupManagerNoMapper = session.users().addUser(realm, "noMapperGroupManager");
+        groupManagerNoMapper.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, groupManagerNoMapper, UserCredentialModel.password("password"));
+        groupManagerNoMapper.grantRole(queryGroupsRole);
+        groupManagerNoMapper.grantRole(queryUsersRole);
+
+        UserPolicyRepresentation groupManagerRep = new UserPolicyRepresentation();
+        groupManagerRep.setName("groupManagers");
+        groupManagerRep.addUser("groupManager");
+        groupManagerRep.addUser("noMapperGroupManager");
+        ResourceServer server = permissions.realmResourceServer();
+        Policy groupManagerPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(groupManagerRep, server);
+        Policy groupManagerPermission = permissions.groups().manageMembersPermission(group);
+        groupManagerPermission.addAssociatedPolicy(groupManagerPolicy);
+        permissions.groups().viewPermission(group).addAssociatedPolicy(groupManagerPolicy);
+
+        UserModel clientMapper = session.users().addUser(realm, "clientMapper");
+        clientMapper.setEnabled(true);
+        clientMapper.grantRole(managerRole);
+        clientMapper.grantRole(queryUsersRole);
+        session.userCredentialManager().updateCredential(realm, clientMapper, UserCredentialModel.password("password"));
+        Policy clientMapperPolicy = permissions.clients().mapRolesPermission(client);
+        UserPolicyRepresentation userRep = new UserPolicyRepresentation();
+        userRep.setName("userClientMapper");
+        userRep.addUser("clientMapper");
+        Policy userPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(userRep, permissions.clients().resourceServer(client));
+        clientMapperPolicy.addAssociatedPolicy(userPolicy);
+
+        UserModel clientManager = session.users().addUser(realm, "clientManager");
+        clientManager.setEnabled(true);
+        clientManager.grantRole(queryClientsRole);
+        session.userCredentialManager().updateCredential(realm, clientManager, UserCredentialModel.password("password"));
+
+        Policy clientManagerPolicy = permissions.clients().managePermission(client);
+        userRep = new UserPolicyRepresentation();
+        userRep.setName("clientManager");
+        userRep.addUser("clientManager");
+        userPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(userRep, permissions.clients().resourceServer(client));
+        clientManagerPolicy.addAssociatedPolicy(userPolicy);
+
+
+        UserModel clientConfigurer = session.users().addUser(realm, "clientConfigurer");
+        clientConfigurer.setEnabled(true);
+        clientConfigurer.grantRole(queryClientsRole);
+        session.userCredentialManager().updateCredential(realm, clientConfigurer, UserCredentialModel.password("password"));
+
+        Policy clientConfigurePolicy = permissions.clients().configurePermission(client);
+        userRep = new UserPolicyRepresentation();
+        userRep.setName("clientConfigure");
+        userRep.addUser("clientConfigurer");
+        userPolicy = permissions.authz().getStoreFactory().getPolicyStore().create(userRep, permissions.clients().resourceServer(client));
+        clientConfigurePolicy.addAssociatedPolicy(userPolicy);
+
+
+
+
+
+
+    }
+
+    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(CLIENT_NAME);
+        RoleModel clientRole = client.getRole("client-role");
+
+        // test authorized
+        {
+            UserModel user = session.users().getUserByUsername("authorized", realm);
+            AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
+            Assert.assertTrue(permissionsForAdmin.users().canManage());
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
+        }
+        // test composite role
+        {
+            UserModel user = session.users().getUserByUsername("authorizedComposite", realm);
+            AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
+            Assert.assertTrue(permissionsForAdmin.users().canManage());
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
+        }
+
+        // test unauthorized
+        {
+            UserModel user = session.users().getUserByUsername("unauthorized", realm);
+            AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
+            Assert.assertFalse(permissionsForAdmin.users().canManage());
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(clientRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
+        }
+        // test unauthorized mapper
+        {
+            UserModel user = session.users().getUserByUsername("unauthorizedMapper", realm);
+            AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
+            Assert.assertTrue(permissionsForAdmin.users().canManage());
+            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.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
+        }
+        // test group management
+        {
+            UserModel admin = session.users().getUserByUsername("groupManager", realm);
+            AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin);
+            UserModel user = session.users().getUserByUsername("authorized", realm);
+            Assert.assertFalse(permissionsForAdmin.users().canManage(user));
+            Assert.assertFalse(permissionsForAdmin.users().canView(user));
+            UserModel member = session.users().getUserByUsername("groupMember", realm);
+            Assert.assertTrue(permissionsForAdmin.users().canManage(member));
+            Assert.assertTrue(permissionsForAdmin.users().canView(member));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
+
+        }
+        // test client.mapRoles
+        {
+            UserModel admin = session.users().getUserByUsername("clientMapper", realm);
+            AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin);
+            UserModel user = session.users().getUserByUsername("authorized", realm);
+            Assert.assertTrue(permissionsForAdmin.users().canManage(user));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
+            Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));
+            Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole2));
+
+        }
+
+    }
+
+
+    protected boolean isImportAfterEachMethod() {
+        return true;
+    }
+    //@Test
+    public void testDemo() throws Exception {
+        testingClient.server().run(FineGrainAdminUnitTest::setupDemo);
+        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 anotherAdmin = adminClient.realm(TEST).users().search("anotherAdmin").get(0);
+        UserRepresentation groupMember = adminClient.realm(TEST).users().search("groupMember").get(0);
+        RoleRepresentation realmRole = adminClient.realm(TEST).roles().get("realm-role").toRepresentation();
+        List<RoleRepresentation> realmRoleSet = new LinkedList<>();
+        realmRoleSet.add(realmRole);
+        RoleRepresentation realmRole2 = adminClient.realm(TEST).roles().get("realm-role2").toRepresentation();
+        List<RoleRepresentation> realmRole2Set = new LinkedList<>();
+        realmRole2Set.add(realmRole2);
+        ClientRepresentation client = adminClient.realm(TEST).clients().findByClientId(CLIENT_NAME).get(0);
+        ClientTemplateRepresentation template = adminClient.realm(TEST).clientTemplates().findAll().get(0);
+        RoleRepresentation clientRole = adminClient.realm(TEST).clients().get(client.getId()).roles().get("client-role").toRepresentation();
+        List<RoleRepresentation> clientRoleSet = new LinkedList<>();
+        clientRoleSet.add(clientRole);
+
+        // test configure client
+        {
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "clientConfigurer", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            client.setAdminUrl("http://nowhere");
+            realmClient.realm(TEST).clients().get(client.getId()).update(client);
+            client.setFullScopeAllowed(true);
+            try {
+                realmClient.realm(TEST).clients().get(client.getId()).update(client);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+            client.setFullScopeAllowed(false);
+            realmClient.realm(TEST).clients().get(client.getId()).update(client);
+
+            client.setClientTemplate(template.getName());
+            try {
+                realmClient.realm(TEST).clients().get(client.getId()).update(client);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+            client.setClientTemplate(null);
+            realmClient.realm(TEST).clients().get(client.getId()).update(client);
+
+            try {
+                realmClient.realm(TEST).clients().get(client.getId()).getScopeMappings().realmLevel().add(realmRoleSet);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+        }
+
+        // test illegal impersonation
+        {
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "nomap-admin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            realmClient.realm(TEST).users().get(user1.getId()).impersonate();
+            realmClient.close(); // just in case of cookie settings
+            realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "nomap-admin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            try {
+                realmClient.realm(TEST).users().get(anotherAdmin.getId()).impersonate();
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+        }
+
+
+        {
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    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);
+
+            }
+        }
+
+        {
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "groupManager", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            List<RoleRepresentation> roles = null;
+            realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
+            roles = realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).listAll();
+            Assert.assertTrue(roles.stream().anyMatch((r) -> {
+                return r.getName().equals("client-role");
+            }));
+            realmClient.realm(TEST).users().get(groupMember.getId()).roles().clientLevel(client.getId()).remove(clientRoleSet);
+
+            roles = realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().listAvailable();
+            Assert.assertEquals(roles.size(), 1);
+            realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().add(realmRoleSet);
+            realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().remove(realmRoleSet);
+            try {
+                realmClient.realm(TEST).users().get(groupMember.getId()).roles().realmLevel().add(realmRole2Set);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+            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);
+
+            }
+
+        }
+
+
+        // test client.mapRoles
+        {
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "clientMapper", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            List<RoleRepresentation> roles = null;
+            roles = realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+            Assert.assertTrue(roles.isEmpty());
+            realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).add(clientRoleSet);
+            roles = realmClient.realm(TEST).users().get(user1.getId()).roles().clientLevel(client.getId()).listAll();
+            Assert.assertTrue(roles.stream().anyMatch((r) -> {
+                return r.getName().equals("client-role");
+            }));
+            roles = realmClient.realm(TEST).users().get(user1.getId()).roles().realmLevel().listAvailable();
+            Assert.assertTrue(roles.isEmpty());
+            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);
+
+            }
+        }
+
+
+    }
+
+    @Test
+    public void testMasterRealm() throws Exception {
+        // test that master realm can still perform operations when policies are in place
+        //
+        testingClient.server().run(FineGrainAdminUnitTest::setupPolices);
+        testingClient.server().run(FineGrainAdminUnitTest::setupUsers);
+
+        UserRepresentation user1 = adminClient.realm(TEST).users().search("user1").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(CLIENT_NAME).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());
+            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();
+        }
+
+    }
+    // testRestEvaluationMasterRealm
+    // testRestEvaluationMasterAdminTestRealm
+
+    // test role deletion that it cleans up authz objects
+    public static void setupDeleteTest(KeycloakSession session )  {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        RoleModel removedRole = realm.addRole("removedRole");
+        ClientModel client = realm.addClient("removedClient");
+        RoleModel removedClientRole = client.addRole("removedClientRole");
+        GroupModel removedGroup = realm.createGroup("removedGroup");
+        AdminPermissionManagement management = AdminPermissions.management(session, realm);
+        management.roles().setPermissionsEnabled(removedRole, true);
+        management.roles().setPermissionsEnabled(removedClientRole, true);
+        management.groups().setPermissionsEnabled(removedGroup, true);
+        management.clients().setPermissionsEnabled(client, true);
+    }
+
+    public static void invokeDelete(KeycloakSession session)  {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        AdminPermissionManagement management = AdminPermissions.management(session, realm);
+        List<Resource> byResourceServer = management.authz().getStoreFactory().getResourceStore().findByResourceServer(management.realmResourceServer().getId());
+        Assert.assertEquals(4, byResourceServer.size());
+        RoleModel removedRole = realm.getRole("removedRole");
+        realm.removeRole(removedRole);
+        ClientModel client = realm.getClientByClientId("removedClient");
+        RoleModel removedClientRole = client.getRole("removedClientRole");
+        client.removeRole(removedClientRole);
+        GroupModel group = KeycloakModelUtils.findGroupByPath(realm, "removedGroup");
+        realm.removeGroup(group);
+        byResourceServer = management.authz().getStoreFactory().getResourceStore().findByResourceServer(management.realmResourceServer().getId());
+        Assert.assertEquals(1, byResourceServer.size());
+        realm.removeClient(client.getId());
+        byResourceServer = management.authz().getStoreFactory().getResourceStore().findByResourceServer(management.realmResourceServer().getId());
+        Assert.assertEquals(0, byResourceServer.size());
+    }
+
+    @Test
+    public void testRemoveCleanup() throws Exception {
+        testingClient.server().run(FineGrainAdminUnitTest::setupDeleteTest);
+        testingClient.server().run(FineGrainAdminUnitTest::invokeDelete);
+    }
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IllegalAdminUpgradeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IllegalAdminUpgradeTest.java
new file mode 100644
index 0000000..7c6ced5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IllegalAdminUpgradeTest.java
@@ -0,0 +1,648 @@
+/*
+ * 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.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.GroupModel;
+import org.keycloak.models.ImpersonationConstants;
+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.models.utils.KeycloakModelUtils;
+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.UserPolicyRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
+import org.keycloak.services.resources.admin.permissions.AdminPermissions;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.util.AdminClientUtil;
+
+import javax.ws.rs.ClientErrorException;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class IllegalAdminUpgradeTest extends AbstractKeycloakTest {
+
+    public static final String CLIENT_NAME = "application";
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation testRealmRep = new RealmRepresentation();
+        testRealmRep.setId(TEST);
+        testRealmRep.setRealm(TEST);
+        testRealmRep.setEnabled(true);
+        testRealms.add(testRealmRep);
+    }
+
+    protected boolean isImportAfterEachMethod() {
+        return true;
+    }
+
+
+    public static void setupUsers(KeycloakSession session) {
+        RealmModel realm = session.realms().getRealmByName(TEST);
+        RealmModel master = session.realms().getRealmByName("master");
+        ClientModel realmAdminClient = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        ClientModel realmMasterAdminClient = realm.getMasterAdminClient();
+        RoleModel realmManageUsers = realmAdminClient.getRole(AdminRoles.MANAGE_USERS);
+        RoleModel masterManageUsers = realmMasterAdminClient.getRole(AdminRoles.MANAGE_USERS);
+        RoleModel masterMasterManageUSers = master.getMasterAdminClient().getRole(AdminRoles.MANAGE_USERS);
+
+        UserModel realmUser = session.users().addUser(realm, "userAdmin");
+        realmUser.grantRole(realmManageUsers);
+        realmUser.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, realmUser, UserCredentialModel.password("password"));
+
+        UserModel masterUser = session.users().addUser(master, "userAdmin");
+        masterUser.grantRole(masterManageUsers);
+        masterUser.setEnabled(true);
+        session.userCredentialManager().updateCredential(master, masterUser, UserCredentialModel.password("password"));
+
+        UserModel masterAdmin = session.users().addUser(master, "masterAdmin");
+        masterAdmin.grantRole(masterMasterManageUSers);
+        masterAdmin.setEnabled(true);
+        session.userCredentialManager().updateCredential(master, masterAdmin, UserCredentialModel.password("password"));
+
+        UserModel user = session.users().addUser(master, "user");
+        user.grantRole(masterManageUsers);
+        user.setEnabled(true);
+        session.userCredentialManager().updateCredential(master, user, UserCredentialModel.password("password"));
+
+        user = session.users().addUser(realm, "user");
+        user.grantRole(realmManageUsers);
+        user.setEnabled(true);
+        session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password"));
+    }
+
+    @Test
+    public void testRestEvaluation() throws Exception {
+        testingClient.server().run(IllegalAdminUpgradeTest::setupUsers);
+
+        UserRepresentation realmUserAdmin = adminClient.realm(TEST).users().search("userAdmin").get(0);
+        UserRepresentation masterUserAdmin = adminClient.realm("master").users().search("userAdmin").get(0);
+        UserRepresentation realmUser = adminClient.realm(TEST).users().search("user").get(0);
+        UserRepresentation masterUser = adminClient.realm("master").users().search("user").get(0);
+
+        ClientRepresentation realmAdminClient = adminClient.realm(TEST).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
+        RoleRepresentation realmManageAuthorization = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_AUTHORIZATION).toRepresentation();
+        RoleRepresentation realmViewAuthorization = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_AUTHORIZATION).toRepresentation();
+        RoleRepresentation realmManageClients = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_CLIENTS).toRepresentation();
+        RoleRepresentation realmViewClients = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_CLIENTS).toRepresentation();
+        RoleRepresentation realmManageEvents = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_EVENTS).toRepresentation();
+        RoleRepresentation realmViewEvents = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_EVENTS).toRepresentation();
+        RoleRepresentation realmManageIdentityProviders = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_IDENTITY_PROVIDERS).toRepresentation();
+        RoleRepresentation realmViewIdentityProviders = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_IDENTITY_PROVIDERS).toRepresentation();
+        RoleRepresentation realmManageRealm = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_REALM).toRepresentation();
+        RoleRepresentation realmViewRealm = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_REALM).toRepresentation();
+        RoleRepresentation realmImpersonate = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(ImpersonationConstants.IMPERSONATION_ROLE).toRepresentation();
+        RoleRepresentation realmManageUsers = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.MANAGE_USERS).toRepresentation();
+        RoleRepresentation realmViewUsers = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.VIEW_USERS).toRepresentation();
+        RoleRepresentation realmQueryUsers = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.QUERY_USERS).toRepresentation();
+        RoleRepresentation realmQueryClients = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.QUERY_CLIENTS).toRepresentation();
+        RoleRepresentation realmQueryGroups = adminClient.realm(TEST).clients().get(realmAdminClient.getId()).roles().get(AdminRoles.QUERY_GROUPS).toRepresentation();
+
+        ClientRepresentation masterClient = adminClient.realm("master").clients().findByClientId(TEST + "-realm").get(0);
+        RoleRepresentation masterManageAuthorization = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_AUTHORIZATION).toRepresentation();
+        RoleRepresentation masterViewAuthorization = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_AUTHORIZATION).toRepresentation();
+        RoleRepresentation masterManageClients = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_CLIENTS).toRepresentation();
+        RoleRepresentation masterViewClients = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_CLIENTS).toRepresentation();
+        RoleRepresentation masterManageEvents = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_EVENTS).toRepresentation();
+        RoleRepresentation masterViewEvents = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_EVENTS).toRepresentation();
+        RoleRepresentation masterManageIdentityProviders = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_IDENTITY_PROVIDERS).toRepresentation();
+        RoleRepresentation masterViewIdentityProviders = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_IDENTITY_PROVIDERS).toRepresentation();
+        RoleRepresentation masterManageRealm = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_REALM).toRepresentation();
+        RoleRepresentation masterViewRealm = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_REALM).toRepresentation();
+        RoleRepresentation masterImpersonate = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(ImpersonationConstants.IMPERSONATION_ROLE).toRepresentation();
+        RoleRepresentation masterManageUsers = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.MANAGE_USERS).toRepresentation();
+        RoleRepresentation masterViewUsers = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.VIEW_USERS).toRepresentation();
+        RoleRepresentation masterQueryUsers = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.QUERY_USERS).toRepresentation();
+        RoleRepresentation masterQueryClients = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.QUERY_CLIENTS).toRepresentation();
+        RoleRepresentation masterQueryGroups = adminClient.realm("master").clients().get(masterClient.getId()).roles().get(AdminRoles.QUERY_GROUPS).toRepresentation();
+
+        List<RoleRepresentation> roles = new LinkedList<>();
+
+        {
+            ClientRepresentation client = realmAdminClient;
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    TEST, "userAdmin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            roles.clear();
+            roles.add(realmManageAuthorization);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmViewAuthorization);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmManageClients);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmViewClients);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmManageEvents);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmViewEvents);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmManageIdentityProviders);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmViewIdentityProviders);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmManageRealm);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmViewRealm);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmImpersonate);
+            try {
+                realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(realmManageUsers);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmViewUsers);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmQueryUsers);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmQueryGroups);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmQueryClients);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            realmClient.close();
+        }
+        // test master manageUsers only admin can do with master realm admin roles
+        {
+            ClientRepresentation client = masterClient;
+            Keycloak realmClient = AdminClientUtil.createAdminClient(suiteContext.isAdapterCompatTesting(),
+                    "master", "masterAdmin", "password", Constants.ADMIN_CLI_CLIENT_ID, null);
+            roles.clear();
+            roles.add(masterManageAuthorization);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterViewAuthorization);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterManageClients);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterViewClients);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterManageEvents);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterViewEvents);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterManageIdentityProviders);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterViewIdentityProviders);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterManageRealm);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterViewRealm);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterImpersonate);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterManageUsers);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterViewUsers);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterQueryUsers);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterQueryGroups);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            roles.clear();
+            roles.add(masterQueryClients);
+            try {
+                realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+                Assert.fail("should fail with forbidden exception");
+            } catch (ClientErrorException e) {
+                Assert.assertEquals(e.getResponse().getStatus(), 403);
+
+            }
+
+            realmClient.close();
+        }
+        // test master admin can add all admin roles in realm
+        {
+            ClientRepresentation client = realmAdminClient;
+            Keycloak realmClient = AdminClientUtil.createAdminClient();
+            roles.clear();
+            roles.add(realmManageAuthorization);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmViewAuthorization);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmManageClients);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmViewClients);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmManageEvents);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmViewEvents);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmManageIdentityProviders);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmViewIdentityProviders);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmManageRealm);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmViewRealm);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmImpersonate);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmManageUsers);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+
+            roles.clear();
+            roles.add(realmViewUsers);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+
+            roles.clear();
+            roles.add(realmQueryUsers);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+
+            roles.clear();
+            roles.add(realmQueryGroups);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(realmQueryClients);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm(TEST).users().get(realmUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            realmClient.close();
+        }
+        // test that "admin" in master realm can assign all roles of master realm realm client admin roles
+        {
+            ClientRepresentation client = masterClient;
+            Keycloak realmClient = AdminClientUtil.createAdminClient();
+            roles.clear();
+            roles.add(masterManageAuthorization);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterViewAuthorization);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterManageClients);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterViewClients);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterManageEvents);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterViewEvents);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterManageIdentityProviders);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterViewIdentityProviders);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterManageRealm);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterViewRealm);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterImpersonate);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterManageUsers);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+
+            roles.clear();
+            roles.add(masterViewUsers);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+
+            roles.clear();
+            roles.add(masterQueryUsers);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+
+            roles.clear();
+            roles.add(masterQueryGroups);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            roles.clear();
+            roles.add(masterQueryClients);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).add(roles);
+            realmClient.realm("master").users().get(masterUser.getId()).roles().clientLevel(client.getId()).remove(roles);
+
+            realmClient.close();
+        }
+    }
+
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java
index 531157d..16b0804 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java
@@ -51,7 +51,7 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceRepresentation;
 import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
-import org.keycloak.services.resources.admin.RealmAuth.Resource;
+import org.keycloak.services.resources.admin.AdminAuth.Resource;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
@@ -77,8 +77,8 @@ import java.util.concurrent.atomic.AtomicReference;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
-import static org.keycloak.services.resources.admin.RealmAuth.Resource.AUTHORIZATION;
-import static org.keycloak.services.resources.admin.RealmAuth.Resource.CLIENT;
+import static org.keycloak.services.resources.admin.AdminAuth.Resource.AUTHORIZATION;
+import static org.keycloak.services.resources.admin.AdminAuth.Resource.CLIENT;
 import org.keycloak.testsuite.ProfileAssume;
 
 /**
@@ -313,11 +313,18 @@ public class PermissionsTest extends AbstractKeycloakTest {
                 realm.removeDefaultGroup("nosuch");
             }
         }, Resource.REALM, true);
+        GroupRepresentation newGroup = new GroupRepresentation();
+        newGroup.setName("sample");
+        adminClient.realm(REALM_NAME).groups().add(newGroup);
+        GroupRepresentation group = adminClient.realms().realm(REALM_NAME).getGroupByPath("sample");
+
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.getGroupByPath("nosuch");
+                realm.getGroupByPath("sample");
             }
-        }, Resource.REALM, false);
+        }, Resource.USER, false);
+
+        adminClient.realms().realm(REALM_NAME).groups().group(group.getId()).remove();
 
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
@@ -425,14 +432,19 @@ public class PermissionsTest extends AbstractKeycloakTest {
 
     @Test
     public void attackDetection() {
+        UserRepresentation newUser = new UserRepresentation();
+        newUser.setUsername("attacked");
+        newUser.setEnabled(true);
+        adminClient.realms().realm(REALM_NAME).users().create(newUser);
+        UserRepresentation user = adminClient.realms().realm(REALM_NAME).users().search("attacked").get(0);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.attackDetection().bruteForceUserStatus("nosuch");
+                realm.attackDetection().bruteForceUserStatus(user.getId());
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.attackDetection().clearBruteForceForUser("nosuch");
+                realm.attackDetection().clearBruteForceForUser(user.getId());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
@@ -440,6 +452,7 @@ public class PermissionsTest extends AbstractKeycloakTest {
                 realm.attackDetection().clearAllBruteForce();
             }
         }, Resource.USER, true);
+        adminClient.realms().realm(REALM_NAME).users().get(user.getId()).remove();
     }
 
     @Test
@@ -462,183 +475,187 @@ public class PermissionsTest extends AbstractKeycloakTest {
                 response.set(realm.clients().create(ClientBuilder.create().clientId("foo").build()));
             }
         }, Resource.CLIENT, true);
+        ClientRepresentation foo = adminClient.realms().realm(REALM_NAME).clients().findByClientId("foo").get(0);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").toRepresentation();
+                realm.clients().get(foo.getId()).toRepresentation();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getInstallationProvider("nosuch");
+                realm.clients().get(foo.getId()).getInstallationProvider("nosuch");
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").update(new ClientRepresentation());
+                realm.clients().get(foo.getId()).update(foo);
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").remove();
+                realm.clients().get(foo.getId()).remove();
+                realm.clients().create(foo);
+                ClientRepresentation temp = realm.clients().findByClientId("foo").get(0);
+                foo.setId(temp.getId());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").generateNewSecret();
+                realm.clients().get(foo.getId()).generateNewSecret();
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").regenerateRegistrationAccessToken();
+                realm.clients().get(foo.getId()).regenerateRegistrationAccessToken();
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getSecret();
+                realm.clients().get(foo.getId()).getSecret();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getServiceAccountUser();
+                realm.clients().get(foo.getId()).getServiceAccountUser();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").pushRevocation();
+                realm.clients().get(foo.getId()).pushRevocation();
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getApplicationSessionCount();
+                realm.clients().get(foo.getId()).getApplicationSessionCount();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getUserSessions(0, 100);
+                realm.clients().get(foo.getId()).getUserSessions(0, 100);
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getOfflineSessionCount();
+                realm.clients().get(foo.getId()).getOfflineSessionCount();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getOfflineUserSessions(0, 100);
+                realm.clients().get(foo.getId()).getOfflineUserSessions(0, 100);
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").registerNode(Collections.<String, String>emptyMap());
+                realm.clients().get(foo.getId()).registerNode(Collections.<String, String>emptyMap());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").unregisterNode("nosuch");
+                realm.clients().get(foo.getId()).unregisterNode("nosuch");
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").testNodesAvailable();
+                realm.clients().get(foo.getId()).testNodesAvailable();
             }
         }, Resource.CLIENT, true);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getCertficateResource("nosuch").generate();
+                realm.clients().get(foo.getId()).getCertficateResource("nosuch").generate();
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getCertficateResource("nosuch").generateAndGetKeystore(new KeyStoreConfig());
+                realm.clients().get(foo.getId()).getCertficateResource("nosuch").generateAndGetKeystore(new KeyStoreConfig());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getCertficateResource("nosuch").getKeyInfo();
+                realm.clients().get(foo.getId()).getCertficateResource("nosuch").getKeyInfo();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getCertficateResource("nosuch").getKeystore(new KeyStoreConfig());
+                realm.clients().get(foo.getId()).getCertficateResource("nosuch").getKeystore(new KeyStoreConfig());
             }
         }, Resource.CLIENT, false);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getCertficateResource("nosuch").uploadJks(new MultipartFormDataOutput());
+                realm.clients().get(foo.getId()).getCertficateResource("nosuch").uploadJks(new MultipartFormDataOutput());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getCertficateResource("nosuch").uploadJksCertificate(new MultipartFormDataOutput());
+                realm.clients().get(foo.getId()).getCertficateResource("nosuch").uploadJksCertificate(new MultipartFormDataOutput());
             }
         }, Resource.CLIENT, true);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getProtocolMappers().createMapper(Collections.EMPTY_LIST);
+                realm.clients().get(foo.getId()).getProtocolMappers().createMapper(Collections.EMPTY_LIST);
             }
         }, Resource.CLIENT, true);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                response.set(realm.clients().get("nosuch").getProtocolMappers().createMapper(new ProtocolMapperRepresentation()));
+                response.set(realm.clients().get(foo.getId()).getProtocolMappers().createMapper(new ProtocolMapperRepresentation()));
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getProtocolMappers().getMapperById("nosuch");
+                realm.clients().get(foo.getId()).getProtocolMappers().getMapperById("nosuch");
             }
         }, Resource.CLIENT, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getProtocolMappers().getMappers();
+                realm.clients().get(foo.getId()).getProtocolMappers().getMappers();
             }
         }, Resource.CLIENT, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getProtocolMappers().getMappersPerProtocol("nosuch");
+                realm.clients().get(foo.getId()).getProtocolMappers().getMappersPerProtocol("nosuch");
             }
         }, Resource.CLIENT, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getProtocolMappers().update("nosuch", new ProtocolMapperRepresentation());
+                realm.clients().get(foo.getId()).getProtocolMappers().update("nosuch", new ProtocolMapperRepresentation());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getProtocolMappers().delete("nosuch");
+                realm.clients().get(foo.getId()).getProtocolMappers().delete("nosuch");
             }
         }, Resource.CLIENT, true);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getScopeMappings().getAll();
+                realm.clients().get(foo.getId()).getScopeMappings().getAll();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getScopeMappings().realmLevel().listAll();
+                realm.clients().get(foo.getId()).getScopeMappings().realmLevel().listAll();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getScopeMappings().realmLevel().listEffective();
+                realm.clients().get(foo.getId()).getScopeMappings().realmLevel().listEffective();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getScopeMappings().realmLevel().listAvailable();
+                realm.clients().get(foo.getId()).getScopeMappings().realmLevel().listAvailable();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getScopeMappings().realmLevel().add(Collections.<RoleRepresentation>emptyList());
+                realm.clients().get(foo.getId()).getScopeMappings().realmLevel().add(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").getScopeMappings().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
+                realm.clients().get(foo.getId()).getScopeMappings().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
 
@@ -649,47 +666,47 @@ public class PermissionsTest extends AbstractKeycloakTest {
         }, Resource.CLIENT, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().create(new RoleRepresentation());
+                realm.clients().get(foo.getId()).roles().create(new RoleRepresentation());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().get("nosuch").toRepresentation();
+                realm.clients().get(foo.getId()).roles().get("nosuch").toRepresentation();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().deleteRole("nosuch");
+                realm.clients().get(foo.getId()).roles().deleteRole("nosuch");
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().get("nosuch").update(new RoleRepresentation());
+                realm.clients().get(foo.getId()).roles().get("nosuch").update(new RoleRepresentation());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().get("nosuch").addComposites(Collections.<RoleRepresentation>emptyList());
+                realm.clients().get(foo.getId()).roles().get("nosuch").addComposites(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().get("nosuch").deleteComposites(Collections.<RoleRepresentation>emptyList());
+                realm.clients().get(foo.getId()).roles().get("nosuch").deleteComposites(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().get("nosuch").getRoleComposites();
+                realm.clients().get(foo.getId()).roles().get("nosuch").getRoleComposites();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().get("nosuch").getRealmRoleComposites();
+                realm.clients().get(foo.getId()).roles().get("nosuch").getRealmRoleComposites();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clients().get("nosuch").roles().get("nosuch").getClientRoleComposites("nosuch");
+                realm.clients().get(foo.getId()).roles().get("nosuch").getClientRoleComposites("nosuch");
             }
         }, Resource.CLIENT, false);
     }
@@ -700,117 +717,123 @@ public class PermissionsTest extends AbstractKeycloakTest {
             public void invoke(RealmResource realm) {
                 realm.clientTemplates().findAll();
             }
-        }, Resource.CLIENT, false);
+        }, Resource.CLIENT, false, true);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                response.set(realm.clientTemplates().create(new ClientTemplateRepresentation()));
+                ClientTemplateRepresentation template = new ClientTemplateRepresentation();
+                template.setName("template");
+                response.set(realm.clientTemplates().create(template));
             }
         }, Resource.CLIENT, true);
+
+        ClientTemplateRepresentation template = adminClient.realms().realm(REALM_NAME).clientTemplates().findAll().get(0);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").toRepresentation();
+                realm.clientTemplates().get(template.getId()).toRepresentation();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").update(new ClientTemplateRepresentation());
+                realm.clientTemplates().get(template.getId()).update(template);
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").remove();
+                realm.clientTemplates().get(template.getId()).remove();
+                realm.clientTemplates().create(template);
             }
         }, Resource.CLIENT, true);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getProtocolMappers().getMappers();
+                realm.clientTemplates().get(template.getId()).getProtocolMappers().getMappers();
             }
         }, Resource.CLIENT, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getProtocolMappers().getMappersPerProtocol("nosuch");
+                realm.clientTemplates().get(template.getId()).getProtocolMappers().getMappersPerProtocol("nosuch");
             }
         }, Resource.CLIENT, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getProtocolMappers().getMapperById("nosuch");
+                realm.clientTemplates().get(template.getId()).getProtocolMappers().getMapperById("nosuch");
             }
         }, Resource.CLIENT, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getProtocolMappers().update("nosuch", new ProtocolMapperRepresentation());
+                realm.clientTemplates().get(template.getId()).getProtocolMappers().update("nosuch", new ProtocolMapperRepresentation());
             }
         }, Resource.CLIENT, true);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                response.set(realm.clientTemplates().get("nosuch").getProtocolMappers().createMapper(new ProtocolMapperRepresentation()));
+                response.set(realm.clientTemplates().get(template.getId()).getProtocolMappers().createMapper(new ProtocolMapperRepresentation()));
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getProtocolMappers().createMapper(Collections.<ProtocolMapperRepresentation>emptyList());
+                realm.clientTemplates().get(template.getId()).getProtocolMappers().createMapper(Collections.<ProtocolMapperRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getProtocolMappers().delete("nosuch");
+                realm.clientTemplates().get(template.getId()).getProtocolMappers().delete("nosuch");
             }
         }, Resource.CLIENT, true);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().getAll();
+                realm.clientTemplates().get(template.getId()).getScopeMappings().getAll();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().realmLevel().listAll();
+                realm.clientTemplates().get(template.getId()).getScopeMappings().realmLevel().listAll();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().realmLevel().listAvailable();
+                realm.clientTemplates().get(template.getId()).getScopeMappings().realmLevel().listAvailable();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().realmLevel().listEffective();
+                realm.clientTemplates().get(template.getId()).getScopeMappings().realmLevel().listEffective();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().realmLevel().add(Collections.<RoleRepresentation>emptyList());
+                realm.clientTemplates().get(template.getId()).getScopeMappings().realmLevel().add(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
+                realm.clientTemplates().get(template.getId()).getScopeMappings().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
+        ClientRepresentation realmAccessClient = adminClient.realms().realm(REALM_NAME).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().clientLevel("nosuch").listAll();
+                realm.clientTemplates().get(template.getId()).getScopeMappings().clientLevel(realmAccessClient.getId()).listAll();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().clientLevel("nosuch").listAvailable();
+                realm.clientTemplates().get(template.getId()).getScopeMappings().clientLevel(realmAccessClient.getId()).listAvailable();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().clientLevel("nosuch").listEffective();
+                realm.clientTemplates().get(template.getId()).getScopeMappings().clientLevel(realmAccessClient.getId()).listEffective();
             }
         }, Resource.CLIENT, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().clientLevel("nosuch").add(Collections.<RoleRepresentation>emptyList());
+                realm.clientTemplates().get(template.getId()).getScopeMappings().clientLevel(realmAccessClient.getId()).add(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.clientTemplates().get("nosuch").getScopeMappings().clientLevel("nosuch").remove(Collections.<RoleRepresentation>emptyList());
+                realm.clientTemplates().get(template.getId()).getScopeMappings().clientLevel(realmAccessClient.getId()).remove(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.CLIENT, true);
     }
@@ -837,10 +860,13 @@ public class PermissionsTest extends AbstractKeycloakTest {
     @Test
     public void clientAuthorization() {
         ProfileAssume.assumePreview();
+
+        ClientRepresentation newClient = new ClientRepresentation();
+        newClient.setClientId("foo-authz");
+        adminClient.realms().realm(REALM_NAME).clients().create(newClient);
+        ClientRepresentation foo = adminClient.realms().realm(REALM_NAME).clients().findByClientId("foo-authz").get(0);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                realm.clients().create(ClientBuilder.create().clientId("foo-authz").build());
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 foo.setServiceAccountsEnabled(true);
                 foo.setAuthorizationServicesEnabled(true);
                 realm.clients().get(foo.getId()).update(foo);
@@ -848,13 +874,11 @@ public class PermissionsTest extends AbstractKeycloakTest {
         }, CLIENT, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 realm.clients().get(foo.getId()).authorization().getSettings();
             }
         }, AUTHORIZATION, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 ResourceServerRepresentation settings = authorization.getSettings();
                 authorization.update(settings);
@@ -862,42 +886,36 @@ public class PermissionsTest extends AbstractKeycloakTest {
         }, AUTHORIZATION, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.resources().resources();
             }
         }, AUTHORIZATION, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.scopes().scopes();
             }
         }, AUTHORIZATION, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.policies().policies();
             }
         }, AUTHORIZATION, false);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 response.set(authorization.resources().create(new ResourceRepresentation("Test", Collections.emptySet())));
             }
         }, AUTHORIZATION, true);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 response.set(authorization.scopes().create(new ScopeRepresentation("Test")));
             }
         }, AUTHORIZATION, true);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 PolicyRepresentation representation = new PolicyRepresentation();
                 representation.setName("Test PermissionsTest");
@@ -910,42 +928,36 @@ public class PermissionsTest extends AbstractKeycloakTest {
         }, AUTHORIZATION, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.resources().resource("nosuch").update(new ResourceRepresentation());
             }
         }, AUTHORIZATION, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.scopes().scope("nosuch").update(new ScopeRepresentation());
             }
         }, AUTHORIZATION, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.policies().policy("nosuch").update(new PolicyRepresentation());
             }
         }, AUTHORIZATION, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.resources().resource("nosuch").remove();
             }
         }, AUTHORIZATION, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.scopes().scope("nosuch").remove();
             }
         }, AUTHORIZATION, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                org.keycloak.representations.idm.ClientRepresentation foo = realm.clients().findByClientId("foo-authz").get(0);
                 AuthorizationResource authorization = realm.clients().get(foo.getId()).authorization();
                 authorization.policies().policy("nosuch").remove();
             }
@@ -954,6 +966,10 @@ public class PermissionsTest extends AbstractKeycloakTest {
 
     @Test
     public void roles() {
+        RoleRepresentation newRole = new RoleRepresentation();
+        newRole.setName("sample-role");
+        adminClient.realm(REALM_NAME).roles().create(newRole);
+
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
                 realm.roles().list();
@@ -961,12 +977,12 @@ public class PermissionsTest extends AbstractKeycloakTest {
         }, Resource.REALM, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").toRepresentation();
+                realm.roles().get("sample-role").toRepresentation();
             }
         }, Resource.REALM, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").update(new RoleRepresentation());
+                realm.roles().get("sample-role").update(newRole);
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
@@ -976,39 +992,42 @@ public class PermissionsTest extends AbstractKeycloakTest {
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().deleteRole("nosuch");
+                realm.roles().deleteRole("sample-role");
+                // need to recreate for other tests
+                realm.roles().create(newRole);
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").getRoleComposites();
+                realm.roles().get("sample-role").getRoleComposites();
             }
         }, Resource.REALM, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").addComposites(Collections.<RoleRepresentation>emptyList());
+                realm.roles().get("sample-role").addComposites(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").deleteComposites(Collections.<RoleRepresentation>emptyList());
+                realm.roles().get("sample-role").deleteComposites(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").getRoleComposites();
+                realm.roles().get("sample-role").getRoleComposites();
             }
         }, Resource.REALM, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").getRealmRoleComposites();
+                realm.roles().get("sample-role").getRealmRoleComposites();
             }
         }, Resource.REALM, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.roles().get("nosuch").getClientRoleComposites("nosuch");
+                realm.roles().get("sample-role").getClientRoleComposites("nosuch");
             }
         }, Resource.REALM, false);
+        adminClient.realms().realm(REALM_NAME).roles().deleteRole("sample-role");
     }
 
     @Test
@@ -1175,51 +1194,61 @@ public class PermissionsTest extends AbstractKeycloakTest {
 
     @Test
     public void rolesById() {
+        RoleRepresentation newRole = new RoleRepresentation();
+        newRole.setName("role-by-id");
+        adminClient.realm(REALM_NAME).roles().create(newRole);
+        RoleRepresentation role = adminClient.realm(REALM_NAME).roles().get("role-by-id").toRepresentation();
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().getRole("nosuch");
+                realm.rolesById().getRole(role.getId());
             }
         }, Resource.REALM, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().updateRole("nosuch", new RoleRepresentation());
+                realm.rolesById().updateRole(role.getId(), role);
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().deleteRole("nosuch");
+                realm.rolesById().deleteRole(role.getId());
+                // need to recreate for other tests
+                realm.roles().create(newRole);
+                RoleRepresentation temp = realm.roles().get("role-by-id").toRepresentation();
+                role.setId(temp.getId());
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().getRoleComposites("nosuch");
+                realm.rolesById().getRoleComposites(role.getId());
             }
         }, Resource.REALM, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().addComposites("nosuch", Collections.<RoleRepresentation>emptyList());
+                realm.rolesById().addComposites(role.getId(), Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().deleteComposites("nosuch", Collections.<RoleRepresentation>emptyList());
+                realm.rolesById().deleteComposites(role.getId(), Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.REALM, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().getRoleComposites("nosuch");
+                realm.rolesById().getRoleComposites(role.getId());
             }
         }, Resource.REALM, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().getRealmRoleComposites("nosuch");
+                realm.rolesById().getRealmRoleComposites(role.getId());
             }
         }, Resource.REALM, false, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.rolesById().getClientRoleComposites("nosuch", "nosuch");
+                realm.rolesById().getClientRoleComposites(role.getId(), "nosuch");
             }
         }, Resource.REALM, false, true);
+
+        adminClient.realm(REALM_NAME).roles().deleteRole("role-by-id");
     }
 
     @Test
@@ -1237,85 +1266,95 @@ public class PermissionsTest extends AbstractKeycloakTest {
             }
         }, Resource.USER, true);
 
+        GroupRepresentation group = adminClient.realms().realm(REALM_NAME).getGroupByPath("mygroup");
+        ClientRepresentation realmAccessClient = adminClient.realms().realm(REALM_NAME).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
+
+
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").toRepresentation();
+                realm.groups().group(group.getId()).toRepresentation();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").update(new GroupRepresentation());
-            }
-        }, Resource.USER, true);
-        invoke(new Invocation() {
-            public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").remove();
+                realm.groups().group(group.getId()).update(group);
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").members(0, 100);
+                realm.groups().group(group.getId()).members(0, 100);
             }
         }, Resource.USER, false);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
-                response.set(realm.groups().group("nosuch").subGroup(new GroupRepresentation()));
+                GroupRepresentation subgroup = new GroupRepresentation();
+                subgroup.setName("sub");
+                response.set(realm.groups().group(group.getId()).subGroup(subgroup));
             }
         }, Resource.USER, true);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().getAll();
+                realm.groups().group(group.getId()).roles().getAll();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().realmLevel().listAll();
+                realm.groups().group(group.getId()).roles().realmLevel().listAll();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().realmLevel().listEffective();
+                realm.groups().group(group.getId()).roles().realmLevel().listEffective();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().realmLevel().listAvailable();
+                realm.groups().group(group.getId()).roles().realmLevel().listAvailable();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().realmLevel().add(Collections.<RoleRepresentation>emptyList());
+                realm.groups().group(group.getId()).roles().realmLevel().add(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
+                realm.groups().group(group.getId()).roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().clientLevel("nosuch").listAll();
+                realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).listAll();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().clientLevel("nosuch").listEffective();
+                realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).listEffective();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().clientLevel("nosuch").listAvailable();
+                realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).listAvailable();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().clientLevel("nosuch").add(Collections.<RoleRepresentation>emptyList());
+                realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).add(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.groups().group("nosuch").roles().clientLevel("nosuch").remove(Collections.<RoleRepresentation>emptyList());
+                realm.groups().group(group.getId()).roles().clientLevel(realmAccessClient.getId()).remove(Collections.<RoleRepresentation>emptyList());
+            }
+        }, Resource.USER, true);
+        invoke(new Invocation() {
+            public void invoke(RealmResource realm) {
+                realm.groups().group(group.getId()).remove();
+                group.setId(null);
+                realm.groups().add(group);
+                GroupRepresentation temp = realm.getGroupByPath("mygroup");
+                group.setId(temp.getId());
             }
         }, Resource.USER, true);
     }
@@ -1323,176 +1362,181 @@ public class PermissionsTest extends AbstractKeycloakTest {
     // Permissions for impersonation tested in ImpersonationTest
     @Test
     public void users() {
-        invoke(new Invocation() {
-            public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").toRepresentation();
-            }
-        }, Resource.USER, false);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
                 response.set(realm.users().create(UserBuilder.create().username("testuser").build()));
             }
         }, Resource.USER, true);
+        UserRepresentation user = adminClient.realms().realm(REALM_NAME).users().search("testuser").get(0);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").update(UserBuilder.create().enabled(true).build());
+                realm.users().get(user.getId()).remove();
+                realm.users().create(user);
+                UserRepresentation temp = realm.users().search("testuser").get(0);
+                user.setId(temp.getId());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().search("foo", 0, 1);
+                realm.users().get(user.getId()).toRepresentation();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
+                realm.users().get(user.getId()).update(user);
+            }
+        }, Resource.USER, true);
+        invoke(new Invocation() {
+            public void invoke(RealmResource realm) {
                 realm.users().count();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").getUserSessions();
+                realm.users().get(user.getId()).getUserSessions();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").getOfflineSessions("nosuch");
+                realm.users().get(user.getId()).getOfflineSessions("nosuch");
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").getFederatedIdentity();
+                realm.users().get(user.getId()).getFederatedIdentity();
             }
         }, Resource.USER, false);
         invoke(new InvocationWithResponse() {
             public void invoke(RealmResource realm, AtomicReference<Response> response) {
                 response.set(realm.users()
-                        .get("nosuch")
+                        .get(user.getId())
                         .addFederatedIdentity("nosuch",
                                 FederatedIdentityBuilder.create().identityProvider("nosuch").userId("nosuch").userName("nosuch").build()));
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").removeFederatedIdentity("nosuch");
+                realm.users().get(user.getId()).removeFederatedIdentity("nosuch");
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").getConsents();
+                realm.users().get(user.getId()).getConsents();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").revokeConsent("testclient");
+                realm.users().get(user.getId()).revokeConsent("testclient");
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").logout();
+                realm.users().get(user.getId()).logout();
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").remove();
+                realm.users().get(user.getId()).resetPassword(CredentialBuilder.create().password("password").build());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").resetPassword(CredentialBuilder.create().password("password").build());
+                realm.users().get(user.getId()).removeTotp();
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").removeTotp();
+                realm.users().get(user.getId()).resetPasswordEmail();
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").resetPasswordEmail();
+                realm.users().get(user.getId()).executeActionsEmail(Collections.<String>emptyList());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").executeActionsEmail(Collections.<String>emptyList());
+                realm.users().get(user.getId()).sendVerifyEmail();
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").sendVerifyEmail();
-            }
-        }, Resource.USER, true);
-        invoke(new Invocation() {
-            public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").groups();
+                realm.users().get(user.getId()).groups();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").leaveGroup("nosuch");
+                realm.users().get(user.getId()).leaveGroup("nosuch");
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").joinGroup("nosuch");
+                realm.users().get(user.getId()).joinGroup("nosuch");
             }
         }, Resource.USER, true);
 
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().getAll();
+                realm.users().get(user.getId()).roles().getAll();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().realmLevel().listAll();
+                realm.users().get(user.getId()).roles().realmLevel().listAll();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().realmLevel().listAvailable();
+                realm.users().get(user.getId()).roles().realmLevel().listAvailable();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().realmLevel().listEffective();
+                realm.users().get(user.getId()).roles().realmLevel().listEffective();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().realmLevel().add(Collections.<RoleRepresentation>emptyList());
+                realm.users().get(user.getId()).roles().realmLevel().add(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
+                realm.users().get(user.getId()).roles().realmLevel().remove(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.USER, true);
 
+        ClientRepresentation realmAccessClient = adminClient.realms().realm(REALM_NAME).clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().clientLevel("nosuch").listAll();
+                realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).listAll();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().clientLevel("nosuch").listAvailable();
+                realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).listAvailable();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().clientLevel("nosuch").listEffective();
+                realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).listEffective();
             }
         }, Resource.USER, false);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().clientLevel("nosuch").add(Collections.<RoleRepresentation>emptyList());
+                realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).add(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.USER, true);
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
-                realm.users().get("nosuch").roles().clientLevel("nosuch").remove(Collections.<RoleRepresentation>emptyList());
+                realm.users().get(user.getId()).roles().clientLevel(realmAccessClient.getId()).remove(Collections.<RoleRepresentation>emptyList());
             }
         }, Resource.USER, true);
+        invoke(new Invocation() {
+            public void invoke(RealmResource realm) {
+                realm.users().search("foo", 0, 1);
+            }
+        }, Resource.USER, false);
     }
 
     @Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationCompositeRoleTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationCompositeRoleTest.java
index 80de8b0..e5f84e2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationCompositeRoleTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationCompositeRoleTest.java
@@ -22,6 +22,7 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationProviderFactory;
 import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.model.Resource;
 import org.keycloak.authorization.model.ResourceServer;
@@ -77,7 +78,8 @@ public class PolicyEvaluationCompositeRoleTest extends AbstractKeycloakTest {
         RoleModel role1 = client.addRole("client-role1");
 
 
-        AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
+        AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
+        AuthorizationProvider authz = factory.create(session, realm);
         ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
         Policy policy = createRolePolicy(authz, resourceServer, role1);
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties b/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties
index 1c42519..167c611 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties
@@ -70,4 +70,4 @@ log4j.logger.org.apache.directory.server.core=warn
 # log4j.logger.org.keycloak.keys.infinispan=trace
 log4j.logger.org.keycloak.services.clientregistration.policy=debug
 
-#log4j.logger.org.keycloak.authentication=debug
+#log4j.logger.org.keycloak.authentication=debug
\ No newline at end of file
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 1a0de6e..28a985c 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
@@ -1312,9 +1312,35 @@ credential-reset-actions-timeout=Expires In
 credential-reset-actions-timeout.tooltip=Maximum time before the action permit expires.
 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-authz-users-scope-description=Policies that decide if an admin can manage all users in the realm
+view-authz-users-scope-description=Policies that decide if an admin can view all users in realm
+permissions-enabled-role=Permissions Enabled
+permissions-enabled-role.tooltip=Whether or not to enable fine grain permissions for managing 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.
+permissions-enabled-users=Permissions Enabled
+permissions-enabled-users.tooltip=Whether or not to enable fine grain permissions for managing users.  Disabling will delete all current permissions that have been set up.
+manage-permissions-client.tooltip=Fine grain permssions for admins that want to manage this client or apply roles defined by this client.
+manage-permissions-group.tooltip=Fine grain permssions for admins that want to manage this group or the members of this group.
+manage-authz-group-scope-description=Policies that decide if an admin can manage this group
+view-authz-group-scope-description=Policies that decide if an admin can view this group
+view-members-authz-group-scope-description=Policies that decide if an admin can manage the members of this group
+manage-authz-client-scope-description=Policies that decide if an admin can manage this client
+configure-authz-client-scope-description=Reduced management permissions for admin.  Cannot set scope, template, or protocol mappers.
+view-authz-client-scope-description=Policies that decide if an admin can view this client
+map-roles-authz-client-scope-description=Policies that decide if an admin can map roles defined by this client
+map-roles-client-scope-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client to the client scope of another client
+map-roles-composite-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client as a composite to another role
+map-role-authz-role-scope-description=Policies that decide if an admin can map role this role to a user or group
+map-role-client-scope-authz-role-scope-description=Policies that decide if an admin can apply this role to the client scope of a client
+map-role-composite-authz-role-scope-description=Policies that decide if an admin can apply this role as a composite to another role
+manage-group-membership-authz-users-scope-description=Policies that decide if an admin can manage group membership for all users in the realm.  This is used in conjunction with specific group policy
+impersonate-authz-users-scope-description=Policies that decide if admin can impersonate other users
+map-roles-authz-users-scope-description=Policies that decide if admin can map roles for all users
+user-impersonated-authz-users-scope-description=Policies that decide which users can be impersonated.  These policies are applied to the user being impersonated.
+manage-membership-authz-group-scope-description=Policies that decide if admin can add or remove users from this group
+manage-members-authz-group-scope-description=Policies that decide if an admin can manage the members of this group
 
 
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 4451535..c4e870f 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
@@ -1398,9 +1398,6 @@ module.config([ '$routeProvider', function($routeProvider) {
                 realm : function(RealmLoader) {
                     return RealmLoader();
                 },
-                clients : function(ClientListLoader) {
-                    return ClientListLoader();
-                },
                 serverInfo : function(ServerInfoLoader) {
                     return ServerInfoLoader();
                 }
@@ -2358,6 +2355,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,
@@ -2367,6 +2382,15 @@ module.directive('kcTabsUser', function () {
     }
 });
 
+module.directive('kcTabsUsers', function () {
+    return {
+        scope: true,
+        restrict: 'E',
+        replace: true,
+        templateUrl: resourceUrl + '/templates/kc-tabs-users.html'
+    }
+});
+
 module.directive('kcTabsGroup', 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 2b92bc5..a59ebf3 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
@@ -412,7 +412,65 @@ 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'
+    })
+        .when('/realms/:realm/clients/:client/permissions', {
+            templateUrl : resourceUrl + '/partials/authz/mgmt/client-permissions.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                client : function(ClientLoader) {
+                    return ClientLoader();
+                }
+            },
+            controller : 'ClientPermissionsCtrl'
+        })
+        .when('/realms/:realm/groups/:group/permissions', {
+            templateUrl : resourceUrl + '/partials/authz/mgmt/group-permissions.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                group : function(GroupLoader) {
+                    return GroupLoader();
+                }
+            },
+            controller : 'GroupPermissionsCtrl'
+        })
+    ;
 }]);
 
 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 89d0a48..034d595 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
@@ -79,72 +79,7 @@ module.controller('ResourceServerDetailCtrl', function($scope, $http, $route, $l
     });
 });
 
-var Resources = {
-    delete: function(ResourceServerResource, realm, client, $scope, AuthzDialog, $location, Notifications, $route) {
-        ResourceServerResource.permissions({
-            realm : realm,
-            client : client.id,
-            rsrid : $scope.resource._id
-        }, function (permissions) {
-            var msg = "";
-
-            if (permissions.length > 0 && !$scope.deleteConsent) {
-                msg = "<p>This resource is referenced in some permissions:</p>";
-                msg += "<ul>";
-                for (i = 0; i < permissions.length; i++) {
-                    msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
-                }
-                msg += "</ul>";
-                msg += "<p>If you remove this resource, the permissions above will be affected and will not be associated with this resource anymore.</p>";
-            }
-
-            AuthzDialog.confirmDeleteWithMsg($scope.resource.name, "Resource", msg, function() {
-                ResourceServerResource.delete({realm : realm, client : $scope.client.id, rsrid : $scope.resource._id}, null, function() {
-                    $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource");
-                    $route.reload();
-                    Notifications.success("The resource has been deleted.");
-                });
-            });
-        });
-    }
-}
-
-var Policies = {
-    delete: function(service, realm, client, $scope, AuthzDialog, $location, Notifications, $route, isPermission) {
-        var msg = "";
-
-        service.dependentPolicies({
-            realm : realm,
-            client : client.id,
-            id : $scope.policy.id
-        }, function (dependentPolicies) {
-            if (dependentPolicies.length > 0 && !$scope.deleteConsent) {
-                msg = "<p>This policy is being used by other policies:</p>";
-                msg += "<ul>";
-                for (i = 0; i < dependentPolicies.length; i++) {
-                    msg+= "<li><strong>" + dependentPolicies[i].name + "</strong></li>";
-                }
-                msg += "</ul>";
-                msg += "<p>If you remove this policy, the policies above will be affected and will not be associated with this policy anymore.</p>";
-            }
-
-            AuthzDialog.confirmDeleteWithMsg($scope.policy.name, isPermission ? "Permission" : "Policy", msg, function() {
-                service.delete({realm : realm, client : $scope.client.id, id : $scope.policy.id}, null, function() {
-                    if (isPermission) {
-                        $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/permission");
-                        Notifications.success("The permission has been deleted.");
-                    } else {
-                        $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/policy");
-                        Notifications.success("The policy has been deleted.");
-                    }
-                    $route.reload();
-                });
-            });
-        });
-    }
-}
-
-module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client, AuthzDialog, Notifications) {
+module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client) {
     $scope.realm = realm;
     $scope.client = client;
 
@@ -236,11 +171,6 @@ module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, 
             }
         }
     };
-
-    $scope.delete = function(resource) {
-        $scope.resource = resource;
-        Resources.delete(ResourceServerResource, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
-    };
 });
 
 module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerResource, ResourceServerScope, AuthzDialog, Notifications) {
@@ -352,7 +282,30 @@ module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $r
                 }
 
                 $scope.remove = function() {
-                    Resources.delete(ResourceServerResource, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
+                    ResourceServerResource.permissions({
+                        realm : $route.current.params.realm,
+                        client : client.id,
+                        rsrid : $scope.resource._id
+                    }, function (permissions) {
+                        var msg = "";
+
+                        if (permissions.length > 0 && !$scope.deleteConsent) {
+                            msg = "<p>This resource is referenced in some policies:</p>";
+                            msg += "<ul>";
+                            for (i = 0; i < permissions.length; i++) {
+                                msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
+                            }
+                            msg += "</ul>";
+                            msg += "<p>If you remove this resource, the policies above will be affected and will not be associated with this resource anymore.</p>";
+                        }
+
+                        AuthzDialog.confirmDeleteWithMsg($scope.resource.name, "Resource", msg, function() {
+                            ResourceServerResource.delete({realm : realm.realm, client : $scope.client.id, rsrid : $scope.resource._id}, null, function() {
+                                $location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource");
+                                Notifications.success("The resource has been deleted.");
+                            });
+                        });
+                    });
                 }
 
                 $scope.reset = function() {
@@ -385,37 +338,7 @@ module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $r
     }
 });
 
-var Scopes = {
-    delete: function(ResourceServerScope, realm, client, $scope, AuthzDialog, $location, Notifications, $route) {
-        ResourceServerScope.permissions({
-            realm : realm,
-            client : client.id,
-            id : $scope.scope.id
-        }, function (permissions) {
-            var msg = "";
-
-            if (permissions.length > 0 && !$scope.deleteConsent) {
-                msg = "<p>This scope is referenced in some permissions:</p>";
-                msg += "<ul>";
-                for (i = 0; i < permissions.length; i++) {
-                    msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
-                }
-                msg += "</ul>";
-                msg += "<p>If you remove this scope, the permissions above will be affected and will not be associated with this scope anymore.</p>";
-            }
-
-            AuthzDialog.confirmDeleteWithMsg($scope.scope.name, "Scope", msg, function() {
-                ResourceServerScope.delete({realm : realm, client : $scope.client.id, id : $scope.scope.id}, null, function() {
-                    $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/scope");
-                    $route.reload();
-                    Notifications.success("The scope has been deleted.");
-                });
-            });
-        });
-    }
-}
-
-module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope,client, AuthzDialog, Notifications) {
+module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope, client) {
     $scope.realm = realm;
     $scope.client = client;
 
@@ -507,11 +430,6 @@ module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $lo
             }
         }
     };
-
-    $scope.delete = function(scope) {
-        $scope.scope = scope;
-        Scopes.delete(ResourceServerScope, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
-    };
 });
 
 module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerScope, AuthzDialog, Notifications) {
@@ -581,7 +499,30 @@ module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $rout
                 }
 
                 $scope.remove = function() {
-                    Scopes.delete(ResourceServerScope, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route);
+                    ResourceServerScope.permissions({
+                        realm : $route.current.params.realm,
+                        client : client.id,
+                        id : $scope.scope.id
+                    }, function (permissions) {
+                        var msg = "";
+
+                        if (permissions.length > 0 && !$scope.deleteConsent) {
+                            msg = "<p>This scope is referenced in some policies:</p>";
+                            msg += "<ul>";
+                            for (i = 0; i < permissions.length; i++) {
+                                msg+= "<li><strong>" + permissions[i].name + "</strong></li>";
+                            }
+                            msg += "</ul>";
+                            msg += "<p>If you remove this scope, the policies above will be affected and will not be associated with this scope anymore.</p>";
+                        }
+
+                        AuthzDialog.confirmDeleteWithMsg($scope.scope.name, "Scope", msg, function() {
+                            ResourceServerScope.delete({realm : realm.realm, client : $scope.client.id, id : $scope.scope.id}, null, function() {
+                                $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/scope");
+                                Notifications.success("The scope has been deleted.");
+                            });
+                        });
+                    });
                 }
 
                 $scope.reset = function() {
@@ -613,7 +554,7 @@ module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $rout
     }
 });
 
-module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPolicy, PolicyProvider, client, AuthzDialog, Notifications) {
+module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPolicy, PolicyProvider, client) {
     $scope.realm = realm;
     $scope.client = client;
     $scope.policyProviders = [];
@@ -709,14 +650,9 @@ module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $l
             }
         }
     };
-
-    $scope.delete = function(policy) {
-        $scope.policy = policy;
-        Policies.delete(ResourceServerPolicy, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, false);
-    };
 });
 
-module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPermission, PolicyProvider, client, AuthzDialog, Notifications) {
+module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPermission, PolicyProvider, client) {
     $scope.realm = realm;
     $scope.client = client;
     $scope.policyProviders = [];
@@ -811,11 +747,6 @@ module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route
             }
         }
     };
-
-    $scope.delete = function(policy) {
-        $scope.policy = policy;
-        Policies.delete(ResourceServerPermission, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, true);
-    };
 });
 
 module.controller('ResourceServerPolicyDroolsDetailCtrl', function($scope, $http, $route, realm, client, PolicyController) {
@@ -1260,19 +1191,17 @@ module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route
                 client : client.id,
                 id : policy.id
             }, function(policies) {
-                if (policies.length > 0) {
-                    $scope.selectedPolicies = [];
-                    for (i = 0; i < policies.length; i++) {
-                        policies[i].text = policies[i].name;
-                        $scope.selectedPolicies.push(policies[i]);
-                    }
-                    var copy = angular.copy($scope.selectedPolicies);
-                    $scope.$watch('selectedPolicies', function() {
-                        if (!angular.equals($scope.selectedPolicies, copy)) {
-                            $scope.changed = true;
-                        }
-                    }, true);
+                $scope.selectedPolicies = [];
+                for (i = 0; i < policies.length; i++) {
+                    policies[i].text = policies[i].name;
+                    $scope.selectedPolicies.push(policies[i]);
                 }
+                var copy = angular.copy($scope.selectedPolicies);
+                $scope.$watch('selectedPolicies', function() {
+                    if (!angular.equals($scope.selectedPolicies, copy)) {
+                        $scope.changed = true;
+                    }
+                }, true);
             });
         },
 
@@ -2169,7 +2098,35 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
                 });
 
                 $scope.remove = function() {
-                    Policies.delete(ResourceServerPolicy, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, delegate.isPermission());
+                    var msg = "";
+
+                    service.dependentPolicies({
+                        realm : $route.current.params.realm,
+                        client : client.id,
+                        id : $scope.policy.id
+                    }, function (dependentPolicies) {
+                        if (dependentPolicies.length > 0 && !$scope.deleteConsent) {
+                            msg = "<p>This policy is being used by other policies:</p>";
+                            msg += "<ul>";
+                            for (i = 0; i < dependentPolicies.length; i++) {
+                                msg+= "<li><strong>" + dependentPolicies[i].name + "</strong></li>";
+                            }
+                            msg += "</ul>";
+                            msg += "<p>If you remove this policy, the policies above will be affected and will not be associated with this policy anymore.</p>";
+                        }
+
+                        AuthzDialog.confirmDeleteWithMsg($scope.policy.name, "Policy", msg, function() {
+                            service.delete({realm : $scope.realm.realm, client : $scope.client.id, id : $scope.policy.id}, null, function() {
+                                if (delegate.isPermission()) {
+                                    $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission");
+                                    Notifications.success("The permission has been deleted.");
+                                } else {
+                                    $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy");
+                                    Notifications.success("The policy has been deleted.");
+                                }
+                            });
+                        });
+                    });
                 }
             }
         });
@@ -2204,21 +2161,13 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
     $scope.client = client;
     $scope.clients = clients;
     $scope.roles = roles;
-    authzRequest = {};
-    authzRequest.resources = [];
-    authzRequest.context = {};
-    authzRequest.context.attributes = {};
-    authzRequest.roleIds = [];
+    $scope.authzRequest = {};
+    $scope.authzRequest.resources = [];
+    $scope.authzRequest.context = {};
+    $scope.authzRequest.context.attributes = {};
+    $scope.authzRequest.roleIds = [];
     $scope.resultUrl = resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate-result.html';
 
-    $scope.authzRequest = angular.copy(authzRequest);
-
-    $scope.$watch('authzRequest', function() {
-        if (!angular.equals($scope.authzRequest, authzRequest)) {
-            $scope.changed = true;
-        }
-    }, true);
-
     $scope.addContextAttribute = function() {
         if (!$scope.newContextAttribute.value || $scope.newContextAttribute.value == '') {
             Notifications.error("You must provide a value to a context attribute.");
@@ -2531,4 +2480,103 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
         $scope.authzRequest = angular.copy(authzRequest);
         $scope.changed = false;
     }
-});
\ No newline at end of file
+});
+
+getManageClientId = function(realm) {
+    if (realm.realm == masterRealm) {
+        return 'master-realm';
+    } else {
+        return 'realm-management';
+    }
+}
+
+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: getManageClientId(realm)}, function(data) {
+        $scope.realmManagementClientId = data[0].id;
+    });
+    $scope.setEnabled = function() {
+        var param = { enabled: $scope.permissions.enabled};
+        $scope.permissions= RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param);
+    };
+
+
+});
+module.controller('ClientRolePermissionsCtrl', function($scope, $http, $route, $location, realm, client, role, Client, 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;
+    });
+    Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
+        $scope.realmManagementClientId = data[0].id;
+    });
+    $scope.setEnabled = function() {
+        console.log('perssions enabled: ' + $scope.permissions.enabled);
+        var param = { enabled: $scope.permissions.enabled};
+        $scope.permissions = RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param);
+    };
+
+
+});
+
+module.controller('UsersPermissionsCtrl', function($scope, $http, $route, $location, realm, UsersManagementPermissions, Client, Notifications) {
+    console.log('UsersPermissionsCtrl');
+    $scope.realm = realm;
+    UsersManagementPermissions.get({realm: realm.realm}, function(data) {
+        $scope.permissions = data;
+    });
+    Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
+        $scope.realmManagementClientId = data[0].id;
+    });
+    $scope.changeIt = function() {
+        console.log('before permissions.enabled=' + $scope.permissions.enabled);
+        var param = { enabled: $scope.permissions.enabled};
+        $scope.permissions = UsersManagementPermissions.update({realm: realm.realm}, param);
+    };
+
+
+});
+
+module.controller('ClientPermissionsCtrl', function($scope, $http, $route, $location, realm, client, Client, ClientManagementPermissions, Notifications) {
+    $scope.client = client;
+    $scope.realm = realm;
+    ClientManagementPermissions.get({realm: realm.realm, client: client.id}, function(data) {
+        $scope.permissions = data;
+    });
+    Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
+        $scope.realmManagementClientId = data[0].id;
+    });
+    $scope.setEnabled = function() {
+        var param = { enabled: $scope.permissions.enabled};
+        $scope.permissions = ClientManagementPermissions.update({realm: realm.realm, client: client.id}, param);
+    };
+
+
+});
+
+module.controller('GroupPermissionsCtrl', function($scope, $http, $route, $location, realm, group, GroupManagementPermissions, Client, Notifications) {
+    $scope.group = group;
+    $scope.realm = realm;
+    Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) {
+        $scope.realmManagementClientId = data[0].id;
+    });
+    GroupManagementPermissions.get({realm: realm.realm, group: group.id}, function(data) {
+        $scope.permissions = data;
+    });
+    $scope.setEnabled = function() {
+        var param = { enabled: $scope.permissions.enabled};
+        $scope.permissions = GroupManagementPermissions.update({realm: realm.realm, group: group.id}, param);
+    };
+
+
+});
+
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
index 92219bb..f56ca8f 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
@@ -144,4 +144,50 @@ module.service('AuthzDialog', function($modal) {
     }
 
     return dialog;
-});
\ No newline at end of file
+});
+
+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('ClientManagementPermissions', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/clients/:client/management/permissions', {
+        realm : '@realm',
+        client : '@client'
+    }, {
+        update: {
+            method: 'PUT'
+        }
+    });
+});
+
+module.factory('GroupManagementPermissions', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/groups/:group/management/permissions', {
+        realm : '@realm',
+        group : '@group'
+    }, {
+        update: {
+            method: 'PUT'
+        }
+    });
+});
+
+
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index 315b8a5..515eb99 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -728,9 +728,9 @@ module.controller('ClientImportCtrl', function($scope, $location, $upload, realm
 });
 
 
-module.controller('ClientListCtrl', function($scope, realm, clients, Client, serverInfo, $route, Dialog, Notifications, filterFilter) {
+module.controller('ClientListCtrl', function($scope, realm, Client, serverInfo, $route, Dialog, Notifications, filterFilter) {
     $scope.realm = realm;
-    $scope.clients = clients;
+    $scope.clients = Client.query({realm: realm.realm, viewableOnly: true});
     $scope.currentPage = 1;
     $scope.currentPageInput = 1;
     $scope.pageSize = 20;
@@ -1387,6 +1387,7 @@ module.controller('ClientScopeMappingCtrl', function($scope, $http, realm, clien
     }
 
     $scope.changeFlag = function() {
+        console.log('changeFlag');
         Client.update({
             realm : realm.realm,
             client : client.id
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 23f4ad8..ab4e72a 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
@@ -1,81 +1,95 @@
-module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location, Notifications, ServerInfo) {
-    $scope.authUrl = authUrl;
-    $scope.resourceUrl = resourceUrl;
-    $scope.auth = Auth;
-    $scope.serverInfo = ServerInfo.get();
-
-    function getAccess(role) {
-        if (!Current.realm) {
-            return false;
-        }
-
-        var realmAccess = Auth.user && Auth.user['realm_access'];
+function getAccess(Auth, Current, role) {
+    if (!Current.realm)return false;
+    var realmAccess = Auth.user && Auth.user['realm_access'];
+    if (realmAccess) {
+        realmAccess = realmAccess[Current.realm.realm];
         if (realmAccess) {
-            realmAccess = realmAccess[Current.realm.realm];
-            if (realmAccess) {
-                return realmAccess.indexOf(role) >= 0;
-            }
+            return realmAccess.indexOf(role) >= 0;
         }
-        return false;
     }
+    return false;
+}
 
-    $scope.access = {
+function getAccessObject(Auth, Current) {
+    return {
         get createRealm() {
             return Auth.user && Auth.user.createRealm;
         },
 
+        get queryUsers() {
+            return getAccess(Auth, Current, 'query-users') || this.viewUsers;
+        },
+
+        get queryGroups() {
+            return getAccess(Auth, Current, 'query-groups') || this.viewUsers;
+        },
+
+        get queryClients() {
+            return getAccess(Auth, Current, 'query-clients') || this.viewClients;
+        },
+
         get viewRealm() {
-            return getAccess('view-realm') || getAccess('manage-realm') || this.manageRealm;
+            return getAccess(Auth, Current, 'view-realm') || getAccess(Auth, Current, 'manage-realm') || this.manageRealm;
         },
 
         get viewClients() {
-            return getAccess('view-clients') || getAccess('manage-clients') || this.manageClients;
+            return getAccess(Auth, Current, 'view-clients') || getAccess(Auth, Current, 'manage-clients') || this.manageClients;
         },
 
         get viewUsers() {
-            return getAccess('view-users') || getAccess('manage-users') || this.manageClients;
+            return getAccess(Auth, Current, 'view-users') || getAccess(Auth, Current, 'manage-users') || this.manageClients;
         },
 
         get viewEvents() {
-            return getAccess('view-events') || getAccess('manage-events') || this.manageClients;
+            return getAccess(Auth, Current, 'view-events') || getAccess(Auth, Current, 'manage-events') || this.manageClients;
         },
 
         get viewIdentityProviders() {
-            return getAccess('view-identity-providers') || getAccess('manage-identity-providers') || this.manageIdentityProviders;
+            return getAccess(Auth, Current, 'view-identity-providers') || getAccess(Auth, Current, 'manage-identity-providers') || this.manageIdentityProviders;
         },
 
         get viewAuthorization() {
-            return getAccess('view-authorization') || this.manageAuthorization;
+            return getAccess(Auth, Current, 'view-authorization') || this.manageAuthorization;
         },
 
         get manageRealm() {
-            return getAccess('manage-realm');
+            return getAccess(Auth, Current, 'manage-realm');
         },
 
         get manageClients() {
-            return getAccess('manage-clients');
+            return getAccess(Auth, Current, 'manage-clients');
         },
 
         get manageUsers() {
-            return getAccess('manage-users');
+            return getAccess(Auth, Current, 'manage-users');
         },
 
         get manageEvents() {
-            return getAccess('manage-events');
+            return getAccess(Auth, Current, 'manage-events');
         },
 
         get manageIdentityProviders() {
-            return getAccess('manage-identity-providers');
+            return getAccess(Auth, Current, 'manage-identity-providers');
         },
 
         get manageAuthorization() {
-            return getAccess('manage-authorization');
+            return getAccess(Auth, Current, 'manage-authorization');
         },
 
         get impersonation() {
-            return getAccess('impersonation');
+            return getAccess(Auth, Current, 'impersonation');
         }
     };
+}
+
+
+module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location, Notifications, ServerInfo) {
+    $scope.authUrl = authUrl;
+    $scope.resourceUrl = resourceUrl;
+    $scope.auth = Auth;
+    $scope.serverInfo = ServerInfo.get();
+
+    $scope.access = getAccessObject(Auth, Current);
 
     $scope.$watch(function() {
         return $location.path();
@@ -85,20 +99,36 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
     });
 });
 
-module.controller('HomeCtrl', function(Realm, Auth, $location) {
+module.controller('HomeCtrl', function(Realm, Auth, Current, $location) {
+
     Realm.query(null, function(realms) {
         var realm;
         if (realms.length == 1) {
-            realm = realms[0].realm;
+            realm = realms[0];
         } else if (realms.length == 2) {
             if (realms[0].realm == Auth.user.realm) {
-                realm = realms[1].realm;
+                realm = realms[1];
             } else if (realms[1].realm == Auth.user.realm) {
-                realm = realms[0].realm;
+                realm = realms[0];
             }
         }
         if (realm) {
-            $location.url('/realms/' + realm);
+            Current.realms = realms;
+            Current.realm = realm;
+            var access = getAccessObject(Auth, Current);
+            if (access.viewRealm || access.manageRealm) {
+                $location.url('/realms/' + realm.realm );
+            } else if (access.queryClients) {
+                $location.url('/realms/' + realm.realm + "/clients");
+            } else if (access.viewIdentityProviders) {
+                $location.url('/realms/' + realm.realm + "/identity-provider-settings");
+            } else if (access.queryUsers) {
+                $location.url('/realms/' + realm.realm + "/users");
+            } else if (access.queryGroups) {
+                $location.url('/realms/' + realm.realm + "/groups");
+            } else if (access.viewEvents) {
+                $location.url('/realms/' + realm.realm + "/events");
+            }
         } else {
             $location.url('/realms');
         }
@@ -1322,6 +1352,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/partials/authz/mgmt/client-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-permissions.html
new file mode 100644
index 0000000..abc21a4
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-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}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li>{{client.clientId}}</li>
+    </ol>
+
+    <kc-tabs-client></kc-tabs-client>
+
+    <form class=form-horizontal" name="enableForm" novalidate kc-read-only="!client.access.manage || !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/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+            <td translate="{{scopeName}}-authz-client-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/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..c5f37ea
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/client-role-permissions.html
@@ -0,0 +1,40 @@
+<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>{{role.name}}</li>
+    </ol>
+
+    <kc-tabs-client-role></kc-tabs-client-role>
+
+    <form class=form-horizontal" name="enableForm" novalidate kc-read-only="!client.access.manage || !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/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+            <td translate="{{scopeName}}-authz-role-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/group-permissions.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/group-permissions.html
new file mode 100644
index 0000000..897a0ed
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/mgmt/group-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}}/groups">{{:: 'groups' | translate}}</a></li>
+        <li>{{group.name}}</li>
+    </ol>
+
+    <kc-tabs-group></kc-tabs-group>
+
+    <form class=form-horizontal" name="enableForm" novalidate kc-read-only="!group.access.manage || !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/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+            <td translate="{{scopeName}}-authz-group-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/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..9c03333
--- /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-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/{{realmManagementClientId}}/authz/resource-server/permission/scope/{{scopeId}}">{{scopeName}}</a></td>
+            <td translate="{{scopeName}}-authz-role-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..4a5661f
--- /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-users' | translate}}</label>
+            <div class="col-md-6">
+                <input ng-model="permissions.enabled" ng-click="changeIt()" name="permissionsEnabled" id="permissionsEnabled" ng-disabled="!access.manageAuthorization" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+            </div>
+            <kc-tooltip>{{:: 'permissions-enabled-users.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}}-authz-users-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-clustering.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-clustering.html
index 4a6312b..72ff437 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-clustering.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-clustering.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-client></kc-tabs-client>
 
-    <form class="form-horizontal" name="clusteringForm" novalidate kc-read-only="!access.manageClients">
+    <form class="form-horizontal" name="clusteringForm" novalidate kc-read-only="!client.access.configure">
         <legend><span class="text">{{:: 'basic-configuration' | translate}}</span></legend>
         <fieldset >
             <div class="form-group clearfix">
@@ -31,7 +31,7 @@
             </div>
 
             <div class="form-group">
-                <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+                <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                     <button data-kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                     <button data-kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
                 </div>
@@ -43,7 +43,7 @@
             <table class="table table-striped table-bordered">
                 <thead>
                     <tr>
-                        <th class="kc-table-actions" colspan="5" data-ng-show="access.manageClients">
+                        <th class="kc-table-actions" colspan="5" data-ng-show="client.access.configure">
                             <div class="pull-right">
                                 <a class="btn btn-default" tooltip="Manually register cluster node. This is usually not needed as cluster node should be registered automatically by adapter"
                                    tooltip-trigger="mouseover mouseout" tooltip-placement="bottom" href="#/register-node/realms/{{realm.realm}}/clients/{{client.id}}/clustering">{{:: 'register-node-manually' | translate}}</a>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-clustering-node.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-clustering-node.html
index 440994f..7df3a42 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-clustering-node.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-clustering-node.html
@@ -10,10 +10,10 @@
     <h1 data-ng-show="create">{{:: 'add-node' | translate}}</h1>
     <h1 data-ng-hide="create">
         {{node.host|capitalize}}
-        <i id="removeClient" class="pficon pficon-delete clickable" data-ng-show="access.manageClients" data-ng-click="unregisterNode()"></i>
+        <i id="removeClient" class="pficon pficon-delete clickable" data-ng-show="client.access.configure" data-ng-click="unregisterNode()"></i>
     </h1>
 
-    <form class="form-horizontal" name="clusteringForm" novalidate kc-read-only="!access.manageClients" data-ng-show="create || registered">
+    <form class="form-horizontal" name="clusteringForm" novalidate kc-read-only="!client.access.configure" data-ng-show="create || registered">
         <div class="form-group">
             <label class="col-md-2 control-label" for="host">{{:: 'host' | translate}}</label>
             <div class="col-sm-6">
@@ -27,7 +27,7 @@
             </div>
         </div>
         <div class="form-group">
-            <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                 <button data-kc-save data-ng-show="create">{{:: 'save' | translate}}</button>
             </div>
         </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html
index b1b1062..e6865a3 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-client></kc-tabs-client>
 
-    <form class="form-horizontal" name="clientForm" novalidate kc-read-only="!access.manageClients">
+    <form class="form-horizontal" name="clientForm" novalidate kc-read-only="!client.access.configure">
         <fieldset class="border-top">
             <div class="form-group clearfix">
                 <label class="col-md-2 control-label" for="clientAuthenticatorType"> {{:: 'client-authenticator' | translate}}</label>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-generic.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-generic.html
index 1d59078..39e9ebc 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-generic.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-generic.html
@@ -1,11 +1,11 @@
 <div>
-    <form class="form-horizontal no-margin-top" name="credentialForm" novalidate kc-read-only="!access.manageClients" data-ng-show="currentAuthenticatorConfigProperties.length > 0" data-ng-controller="ClientGenericCredentialsCtrl">
+    <form class="form-horizontal no-margin-top" name="credentialForm" novalidate kc-read-only="!client.access.configure" data-ng-show="currentAuthenticatorConfigProperties.length > 0" data-ng-controller="ClientGenericCredentialsCtrl">
         <fieldset>
             <kc-provider-config realm="realm" config="client.attributes" properties="currentAuthenticatorConfigProperties"></kc-provider-config>
         </fieldset>
 
         <div class="form-group">
-            <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageClients">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                 <button kc-save  data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                 <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
             </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
index 29f6524..b2a5bf4 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
@@ -1,4 +1,4 @@
- <div class="form-horizontal no-margin-top" name="keyForm" novalidate kc-read-only="!access.manageClients" data-ng-controller="ClientSignedJWTCtrl">
+ <div class="form-horizontal no-margin-top" name="keyForm" novalidate kc-read-only="!client.access.configure" data-ng-controller="ClientSignedJWTCtrl">
 
      <div class="form-group">
          <label class="col-md-2 control-label" for="useJwksUrl">{{:: 'use-jwks-url' | translate}}</label>
@@ -63,7 +63,7 @@
      </div>
 
      <div class="form-group">
-         <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageClients">
+         <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
              <button class="btn btn-default" type="submit" data-ng-click="generateSigningKey()">{{:: 'gen-new-keys-and-cert' | translate}}</button>
              <button data-ng-disabled="useJwksUrl" class="btn btn-default" type="submit" data-ng-click="importCertificate()">{{:: 'import-certificate' | translate}}</button>
              <button kc-save  data-ng-disabled="!changed" data-ng-click="save()">{{:: 'save' | translate}}</button>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-export.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-export.html
index 382f612..82e50b7 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-export.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-export.html
@@ -9,7 +9,7 @@
 
     <h1>{{:: 'generate-private-key' | translate}}</h1>
 
-    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
+    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
         <input type="text" readonly value="this is not a login form" style="display: none;">
         <input type="password" readonly value="this is not a login form" style="display: none;">
 
@@ -48,7 +48,7 @@
                 <kc-tooltip>{{:: 'store-password.tooltip' | translate}}</kc-tooltip>
             </div>
             <div class="form-group">
-                <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+                <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                     <button class="btn btn-primary" type="submit" data-ng-click="download()">{{:: 'generate-and-download' | translate}}</button>
                     <button class="btn btn-default" type="submit" data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
                 </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
index 9968a31..ec88cd6 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
@@ -9,7 +9,7 @@
 
     <h1>{{:: 'import-client-certificate' | translate}}</h1>
 
-    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
+    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
         <input type="text" readonly value="this is not a login form" style="display: none;">
         <input type="password" readonly value="this is not a login form" style="display: none;">
 
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-secret.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-secret.html
index 744ea80..7cf5bf1 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-secret.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-secret.html
@@ -1,5 +1,5 @@
 <div>
-    <form class="form-horizontal no-margin-top" name="credentialForm" novalidate kc-read-only="!access.manageClients" data-ng-controller="ClientSecretCtrl">
+    <form class="form-horizontal no-margin-top" name="credentialForm" novalidate kc-read-only="!client.access.configure" data-ng-controller="ClientSecretCtrl">
         <div class="form-group">
             <label class="col-md-2 control-label" for="secret">{{:: 'secret' | translate}}</label>
             <div class="col-sm-6">
@@ -7,7 +7,7 @@
                     <div class="col-sm-6">
                         <input readonly kc-select-action="click" class="form-control" type="text" id="secret" name="secret" data-ng-model="secret">
                     </div>
-                    <div class="col-sm-6" data-ng-show="access.manageClients">
+                    <div class="col-sm-6" data-ng-show="client.access.configure">
                         <button type="submit" data-ng-click="changePassword()" class="btn btn-default">{{:: 'regenerate-secret' | translate}}</button>
                     </div>
                 </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index 3eb084f..cd6e271 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-client></kc-tabs-client>
 
-    <form class="form-horizontal" name="clientForm" novalidate kc-read-only="!access.manageClients">
+    <form class="form-horizontal" name="clientForm" novalidate kc-read-only="!client.access.configure">
         <fieldset class="border-top">
             <div class="form-group">
                 <label class="col-md-2 control-label" for="clientId">{{:: 'client-id' | translate}}</label>
@@ -57,7 +57,7 @@
                 </div>
                 <kc-tooltip>{{:: 'client-protocol.tooltip' | translate}}</kc-tooltip>
             </div>
-            <div class="form-group">
+            <div class="form-group"  kc-read-only="!client.access.manage">
                 <label class="col-md-2 control-label" for="protocol">{{:: 'client-template' | translate}}</label>
                 <div class="col-sm-6">
                     <div>
@@ -391,7 +391,7 @@
         </fieldset>
 
         <div class="form-group">
-            <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageClients">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                 <button kc-save  data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                 <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
             </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-keys.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-keys.html
index e2bc22e..c74f54f 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-keys.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-keys.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-client></kc-tabs-client>
 
-    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
+    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
         <input type="text" readonly value="this is not a login form" style="display: none;">
         <input type="password" readonly value="this is not a login form" style="display: none;">
 
@@ -137,7 +137,7 @@
                               kc-select-action="click" readonly>{{keyInfo.certificate}}</textarea>
                 </div>
             </div>
-            <div class="form-group" data-ng-show="access.manageRealm">
+            <div class="form-group" data-ng-show="client.access.configure">
                 <div class="pull-right">
                     <button class="btn btn-primary" type="submit" data-ng-click="generate()">Generate new keys</button>
                 </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-list.html
index 51aaa20..03ebf5c 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-list.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-list.html
@@ -42,7 +42,7 @@
                 </td>
                 <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{client.id}}">{{:: 'edit' | translate}}</td>
                 <td class="kc-action-cell" data-ng-click="exportClient(client)">{{:: 'export' | translate}}</td>
-                <td class="kc-action-cell" data-ng-show="access.manageClients" data-ng-click="removeClient(client)">{{:: 'delete' | translate}}</td>
+                <td class="kc-action-cell" data-ng-show="client.access.manage" data-ng-click="removeClient(client)">{{:: 'delete' | translate}}</td>
             </tr>
             <tr data-ng-show="(clients | filter:search).length == 0">
                 <td class="text-muted" colspan="4" data-ng-show="search.clientId">{{:: 'no-results' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers.html
index ba9b9bf..5648c19 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-client></kc-tabs-client>
 
-    <form class="form-horizontal" name="allowScope" novalidate kc-read-only="!access.manageClients">
+    <form class="form-horizontal" name="allowScope" novalidate kc-read-only="!client.access.manage">
         <fieldset class="border-top">
             <div class="form-group" ng-show="client.clientTemplate">
                 <label class="col-md-2 control-label" for="useTemplateScope">Inherit Template Mappers</label>
@@ -35,7 +35,7 @@
                         </div>
                     </div>
 
-                    <div class="pull-right" data-ng-show="access.manageClients">
+                    <div class="pull-right" data-ng-show="client.access.manage">
                         <a class="btn btn-default" href="#/create/client/{{realm.realm}}/{{client.id}}/mappers">{{:: 'create' | translate}}</a>
                         <a class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/add-mappers">{{:: 'add-builtin' | translate}}</a>
                     </div>
@@ -55,7 +55,7 @@
             <td>{{mapperTypes[mapper.protocolMapper].category}}</td>
             <td>{{mapperTypes[mapper.protocolMapper].name}}</td>
             <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{client.id}}/mappers/{{mapper.id}}">{{:: 'edit' | translate}}</td>
-            <td class="kc-action-cell" data-ng-show="access.manageClients" data-ng-click="removeMapper(mapper)">{{:: 'delete' | translate}}</td>
+            <td class="kc-action-cell" data-ng-show="client.access.manage" data-ng-click="removeMapper(mapper)">{{:: 'delete' | translate}}</td>
         </tr>
         <tr data-ng-show="mappers.length == 0">
             <td>{{:: 'no-mappers-available' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers-add.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers-add.html
index 04c2339..6537779 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers-add.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-mappers-add.html
@@ -45,7 +45,7 @@
         </tbody>
     </table>
 
-    <div data-ng-show="access.manageRealm">
+    <div data-ng-show="client.access.manage">
         <button class="btn btn-primary" data-ng-click="add()">{{:: 'add-selected' | translate}}</button>
     </div>
 </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-registration-access-token.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-registration-access-token.html
index 55a3546..327b70d 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-registration-access-token.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-registration-access-token.html
@@ -1,5 +1,5 @@
 <div>
-    <form class="form-horizontal" name="registrationAccessTokenForm" novalidate kc-read-only="!access.manageClients">
+    <form class="form-horizontal" name="registrationAccessTokenForm" novalidate kc-read-only="!client.access.configure">
         <div class="form-group">
             <label class="col-md-2 control-label" for="registrationAccessToken">{{:: 'registrationAccessToken' | translate}}</label>
             <div class="col-sm-6">
@@ -7,7 +7,7 @@
                     <div class="col-sm-6">
                         <input readonly kc-select-action="click" class="form-control" type="text" id="registrationAccessToken" name="registrationAccessToken" data-ng-model="client.registrationAccessToken">
                     </div>
-                    <div class="col-sm-6" data-ng-show="access.manageClients">
+                    <div class="col-sm-6" data-ng-show="client.access.configure">
                         <button type="submit" data-ng-click="regenerateRegistrationAccessToken()" class="btn btn-default">{{:: 'registrationAccessToken.regenerate' | translate}}</button>
                     </div>
                 </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-revocation.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-revocation.html
index 38560e8..95db767 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-revocation.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-revocation.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-client></kc-tabs-client>
 
-    <form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageClients">
+    <form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!client.access.configure">
         <fieldset class="border-top">
             <div class="form-group">
                 <label class="col-md-2 control-label" for="notBefore">{{:: 'not-before' | translate}}</label>
@@ -18,7 +18,7 @@
             </div>
         </fieldset>
         <div class="form-group">
-            <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageClients">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                 <button type="submit" data-ng-click="clear()" class="btn btn-default">{{:: 'clear' | translate}}</button>
                 <button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-default">{{:: 'set-to-now' | translate}}</button>
                 <button type="submit" data-ng-click="pushRevocation()" class="btn btn-primary" tooltip-trigger="mouseover mouseout" tooltip="{{:: 'client-revoke.push.tooltip' | translate}}" tooltip-placement="bottom">{{:: 'push' | translate}}</button>
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..67c96fc 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,11 +8,9 @@
         <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">
+    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!client.access.configure">
 
         <fieldset class="border-top">
             <div class="form-group">
@@ -49,13 +47,13 @@
         </fieldset>
 
         <div class="form-group">
-            <div class="col-md-10 col-md-offset-2" data-ng-show="create && access.manageClients">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="create && client.access.configure">
                 <button kc-save>{{:: 'save' | translate}}</button>
                 <button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
             </div>
         </div>
         <div class="form-group">
-            <div class="col-md-10 col-md-offset-2" data-ng-show="!create && access.manageClients">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="!create && client.access.configure">
                 <button kc-save  data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                 <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
             </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-role-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-role-list.html
index da4d49d..9906074 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-role-list.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-role-list.html
@@ -10,7 +10,7 @@
     <table class="table table-striped table-bordered">
         <thead>
         <tr>
-            <th class="kc-table-actions" colspan="5" data-ng-show="access.manageClients">
+            <th class="kc-table-actions" colspan="5" data-ng-show="client.access.configure">
                 <div class="pull-right">
                     <a class="btn btn-default" href="#/create/role/{{realm.realm}}/clients/{{client.id}}">{{:: 'add-role' | translate}}</a>
                 </div>
@@ -29,7 +29,7 @@
             <td translate="{{role.composite}}"></td>
             <td>{{role.description}}</td>
             <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}">{{:: 'edit' | translate}}</td>
-            <td class="kc-action-cell" data-ng-show="access.manageClients" data-ng-click="removeRole(role)">{{:: 'delete' | translate}}</td>
+            <td class="kc-action-cell" data-ng-show="client.access.configure" data-ng-click="removeRole(role)">{{:: 'delete' | translate}}</td>
         </tr>
         <tr data-ng-show="!roles || roles.length == 0">
             <td>{{:: 'no-client-roles-available' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-export.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-export.html
index 2165165..ec51e96 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-export.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-export.html
@@ -9,7 +9,7 @@
 
     <h1>{{:: 'export-saml-key' | translate}} {{client.clientId|capitalize}}</h1>
 
-    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
+    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
         <input type="text" readonly value="this is not a login form" style="display: none;">
         <input type="password" readonly value="this is not a login form" style="display: none;">
 
@@ -55,7 +55,7 @@
                 <kc-tooltip>{{:: 'store-password.tooltip' | translate}}</kc-tooltip>
            </div>
             <div class="form-group">
-                <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+                <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                     <button class="btn btn-primary" type="submit" data-ng-click="download()">{{:: 'download' | translate}}</button>
                 </div>
             </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-import.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-import.html
index dec13a8..a580a61 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-import.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-key-import.html
@@ -9,7 +9,7 @@
 
     <h1>{{:: 'import-saml-key' | translate}} {{client.clientId|capitalize}}</h1>
 
-    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
+    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
         <input type="text" readonly value="this is not a login form" style="display: none;">
         <input type="password" readonly value="this is not a login form" style="display: none;">
 
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html
index 52e5468..776349d 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-client></kc-tabs-client>
 
-    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
+    <form class="form-horizontal" name="keyForm" novalidate kc-read-only="!client.access.configure">
         <fieldset class="form-group col-sm-10" data-ng-show="client.attributes['saml.client.signature'] == 'true'">
             <legend uncollapsed><span class="text">{{:: 'signing-key' | translate}}</span>  <kc-tooltip>{{:: 'saml-signing-key' | translate}}</kc-tooltip></legend>
             <div class="form-group" data-ng-hide="!signingKeyInfo.privateKey">
@@ -27,7 +27,7 @@
                 </div>
             </div>
             <div class="form-group">
-                <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+                <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                     <button class="btn btn-default" type="submit" data-ng-click="generateSigningKey()">{{:: 'generate-new-keys' | translate}}</button>
                     <button class="btn btn-default" type="submit" data-ng-click="importSigningKey()">{{:: 'import' | translate}}</button>
                     <button class="btn btn-default" type="submit" data-ng-hide="!signingKeyInfo.certificate" data-ng-click="exportSigningKey()">{{:: 'export' | translate}}</button>
@@ -53,7 +53,7 @@
                 </div>
             </div>
             <div class="form-group">
-                <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+                <div class="col-md-10 col-md-offset-2" data-ng-show="client.access.configure">
                     <button class="btn btn-default" type="submit" data-ng-click="generateEncryptionKey()">{{:: 'generate-new-keys' | translate}}</button>
                     <button class="btn btn-default" type="submit" data-ng-click="importEncryptionKey()">{{:: 'import' | translate}}</button>
                     <button class="btn btn-default" type="submit" data-ng-hide="!encryptionKeyInfo.certificate" data-ng-click="exportEncryptionKey()">{{:: 'export' | translate}}</button>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-scope-mappings.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-scope-mappings.html
index fc10e6b..6cb01f4 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-scope-mappings.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-scope-mappings.html
@@ -9,7 +9,7 @@
 
         <h2><span>{{client.clientId}}</span> {{:: 'scope-mappings' | translate}} </h2>
         <p class="subtitle"></p>
-        <form class="form-horizontal" name="allowScope" novalidate kc-read-only="!access.manageClients">
+        <form class="form-horizontal" name="allowScope" novalidate kc-read-only="!client.access.manage">
             <fieldset class="border-top">
                 <div class="form-group" ng-show="client.clientTemplate">
                     <label class="col-md-2 control-label" for="useTemplateScope">Inherit Template Scope</label>
@@ -25,14 +25,14 @@
                     <label class="col-md-2 control-label" for="fullScopeAllowed">{{:: 'full-scope-allowed' | translate}}</label>
                     <kc-tooltip>{{:: 'full-scope-allowed.tooltip' | translate}}</kc-tooltip>
                     <div class="col-md-6">
-                        <input ng-model="client.fullScopeAllowed" ng-click="changeFlag()" name="fullScopeAllowed" id="fullScopeAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
+                        <input kc-read-only="!client.access.manage" ng-model="client.fullScopeAllowed" ng-click="changeFlag()" name="fullScopeAllowed" id="fullScopeAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
                     </div>
                 </div>
                 <div class="form-group" ng-show="client.useTemplateScope && template && template.fullScopeAllowed">
                     <label class="col-md-2 control-label" for="fullScopeAllowed">{{:: 'full-scope-allowed' | translate}}</label>
                     <kc-tooltip>Client template has full scope allowed, which means this client will have the full scope of all roles.</kc-tooltip>
                     <div class="col-md-1">
-                        <input ng-model="template.fullScopeAllowed" name="fullScopeAllowed" id="fullScopeAllowed" ng-disabled="true" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+                        <input kc-read-only="!client.access.manage" ng-model="template.fullScopeAllowed" name="fullScopeAllowed" id="fullScopeAllowed" ng-disabled="true" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
                     </div>
                     <div class="col-md-1">
                         <i>inherited</i>
@@ -41,7 +41,7 @@
             </fieldset>
         </form>
 
-        <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients" data-ng-hide="hideRoleSelector()">
+        <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!client.access.manage" data-ng-hide="hideRoleSelector()">
             <div class="form-group">
                 <label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
                 <div class="col-md-10">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-service-account-roles.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-service-account-roles.html
index 27f967d..d57873f 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-service-account-roles.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-service-account-roles.html
@@ -10,7 +10,7 @@
     <h2><span>{{client.clientId}}</span> {{:: 'service-accounts' | translate}} </h2>
     <p class="subtitle"></p>
 
-    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients" data-ng-show="client.serviceAccountsEnabled">
+    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!client.access.configure" data-ng-show="client.serviceAccountsEnabled">
         <div class="form-group">
             <label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
             <div class="col-md-10">
@@ -102,7 +102,7 @@
         </div>
     </form>
 
-    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients" data-ng-show="!client.serviceAccountsEnabled">
+    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!client.access.configure" data-ng-show="!client.serviceAccountsEnabled">
         <legend><span class="text" translate="service-account-is-not-enabled-for" translate-values="{client: client.clientId}"></span></legend>
     </form>
 
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/group-attributes.html b/themes/src/main/resources/theme/base/admin/resources/partials/group-attributes.html
index c3962c5..e12c553 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/group-attributes.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/group-attributes.html
@@ -6,7 +6,7 @@
 
     <kc-tabs-group></kc-tabs-group>
 
-    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageUsers">
+    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!group.access.manage">
         <table class="table table-striped table-bordered">
             <thead>
             <tr>
@@ -29,7 +29,7 @@
             </tbody>
         </table>
 
-        <div class="form-group" data-ng-show="access.manageUsers">
+        <div class="form-group" data-ng-show="group.access.manage">
             <div class="col-md-12">
                 <button kc-save  data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                 <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/group-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/group-detail.html
index 677ea32..8fd6461 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/group-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/group-detail.html
@@ -16,7 +16,7 @@
             </div>
         </fieldset>
 
-        <div class="form-group" data-ng-show="access.manageUsers">
+        <div class="form-group" data-ng-show="group.access.manage">
             <div class="col-md-10 col-md-offset-2">
                 <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                 <button kc-reset data-ng-disabled="!changed" data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/group-role-mappings.html b/themes/src/main/resources/theme/base/admin/resources/partials/group-role-mappings.html
index 9a1c5b8..62aa7d4 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/group-role-mappings.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/group-role-mappings.html
@@ -7,7 +7,7 @@
     <kc-tabs-group></kc-tabs-group>
 
     <form class="form-horizontal" name="realmForm" novalidate>
-        <div class="form-group" kc-read-only="!access.manageUsers">
+        <div class="form-group" kc-read-only="!group.access.manage">
             <label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
 
             <div class="col-md-10">
@@ -54,7 +54,7 @@
                     <span>{{:: 'client-roles' | translate}}</span>
                     <select class="form-control" id="clients" name="clients" ng-change="changeClient()" ng-model="targetClient" ng-options="a.clientId for a in clients | orderBy:'clientId'" ng-disabled="false"></select>
                 </label>
-                <div class="col-md-10" kc-read-only="!access.manageUsers">
+                <div class="col-md-10" kc-read-only="!group.access.manage">
                     <div class="row" data-ng-hide="targetClient">
                         <div class="col-md-4"><span class="text-muted">{{:: 'select-client-to-view-roles' | translate}}</span></div>
                     </div>
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/role-mappings.html b/themes/src/main/resources/theme/base/admin/resources/partials/role-mappings.html
index b57b1d2..013dae7 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/role-mappings.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/role-mappings.html
@@ -7,7 +7,7 @@
     <kc-tabs-user></kc-tabs-user>
 
     <form class="form-horizontal" name="realmForm" novalidate>
-        <div class="form-group" kc-read-only="!access.manageUsers">
+        <div class="form-group" kc-read-only="!user.access.mapRoles">
             <label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
 
             <div class="col-md-10">
@@ -54,7 +54,7 @@
                     <span>{{:: 'client-roles' | translate}}</span>
                     <select class="form-control" id="clients" name="clients" ng-change="changeClient()" ng-model="targetClient" ng-options="a.clientId for a in clients | orderBy:'clientId'" ng-disabled="false"></select>
                 </label>
-                <div class="col-md-10" kc-read-only="!access.manageUsers">
+                <div class="col-md-10" kc-read-only="!user.access.mapRoles">
                     <div class="row" data-ng-hide="targetClient">
                         <div class="col-md-4"><span class="text-muted">{{:: 'select-client-to-view-roles' | translate}}</span></div>
                     </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-attributes.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-attributes.html
index 26d30e1..10e3d8f 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-attributes.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-attributes.html
@@ -6,7 +6,7 @@
 
     <kc-tabs-user></kc-tabs-user>
 
-    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageUsers">
+    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!user.access.manage">
         <table class="table table-striped table-bordered">
             <thead>
             <tr>
@@ -29,7 +29,7 @@
             </tbody>
         </table>
 
-        <div class="form-group" data-ng-show="access.manageUsers">
+        <div class="form-group" data-ng-show="user.access.manage">
             <div class="col-md-12">
                 <button kc-save  data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                 <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
index f1998f8..88e66e7 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
@@ -7,7 +7,7 @@
 
     <kc-tabs-user></kc-tabs-user>
 
-    <form class="form-horizontal" name="userForm" novalidate kc-read-only="!access.manageUsers">
+    <form class="form-horizontal" name="userForm" novalidate kc-read-only="!create && !user.access.manage">
 
         <fieldset class="border-top">
             <div class="form-group">
@@ -62,7 +62,7 @@
             <div class="form-group clearfix block">
                 <label class="col-md-2 control-label" for="userEnabled">{{:: 'user-enabled' | translate}}</label>
                 <div class="col-md-6">
-                    <input ng-model="user.enabled" name="userEnabled" id="userEnabled" ng-disabled="!access.manageUsers" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+                    <input ng-model="user.enabled" name="userEnabled" id="userEnabled" ng-disabled="!create && !user.access.manage" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
                 </div>
                 <kc-tooltip>{{:: 'user-enabled.tooltip' | translate}}</kc-tooltip>
             </div>
@@ -93,7 +93,7 @@
             <div class="form-group clearfix block">
                 <label class="col-md-2 control-label" for="emailVerified">{{:: 'email-verified' | translate}}</label>
                 <div class="col-md-6">
-                    <input ng-model="user.emailVerified" name="emailVerified" id="emailVerified" ng-disabled="!access.manageUsers" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+                    <input ng-model="user.emailVerified" name="emailVerified" id="emailVerified" ng-disabled="!create && !user.access.manage" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
                 </div>
                 <kc-tooltip>{{:: 'email-verified.tooltip' | translate}}</kc-tooltip>
             </div>
@@ -138,7 +138,7 @@
                 <button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
             </div>
 
-            <div class="col-md-10 col-md-offset-2" data-ng-show="!create && access.manageUsers">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="!create && user.access.manage">
                 <button kc-save  data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
                 <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
             </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-group-membership.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-group-membership.html
index a9c0e6d..f7bf04e 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-group-membership.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-group-membership.html
@@ -7,7 +7,7 @@
      <kc-tabs-user></kc-tabs-user>
 
      <form class="form-horizontal" name="realmForm" novalidate>
-         <div class="form-group" kc-read-only="!access.manageUsers">
+         <div class="form-group" kc-read-only="!user.access.manageGroupMembership">
              <label class="col-md-1 control-label" class="control-label"></label>
 
              <div class="col-md-8" >
@@ -21,7 +21,7 @@
                                          <label class="control-label">{{:: 'group-membership' | translate}}</label>
                                          <kc-tooltip>{{:: 'group-membership.tooltip' | translate}}</kc-tooltip>
 
-                                         <div class="pull-right" data-ng-show="access.manageUsers">
+                                         <div class="pull-right" data-ng-show="user.access.manageGroupMembership">
                                              <button id="leaveGroups" class="btn btn-default" ng-click="leaveGroup()">{{:: 'leave' | translate}}</button>
                                          </div>
                                      </div>
@@ -53,7 +53,7 @@
                                          <label class="control-label">{{:: 'available-groups' | translate}}</label>
                                          <kc-tooltip>{{:: 'membership.available-groups.tooltip' | translate}}</kc-tooltip>
 
-                                         <div class="pull-right" data-ng-show="access.manageUsers">
+                                         <div class="pull-right" data-ng-show="user.access.manageGroupMembership">
                                              <button id="joinGroup" class="btn btn-default" ng-click="joinGroup()">{{:: 'join' | translate}}</button>
                                          </div>
                                      </div>
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..569e1fc 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>
@@ -54,7 +55,7 @@
             <td class="clip">{{user.firstName}}</td>
             <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/users/{{user.id}}">{{:: 'edit' | translate}}</td>
             <td data-ng-show="serverInfo.profileInfo.disabledFeatures.indexOf('IMPERSONATION') == -1 && access.impersonation" class="kc-action-cell" data-ng-click="impersonate(user.id)">{{:: 'impersonate' | translate}}</td>
-            <td data-ng-show="access.manageUsers" class="kc-action-cell" data-ng-click="removeUser(user)">{{:: 'delete' | translate}}</td>
+            <td data-ng-show="user.access.manage" class="kc-action-cell" data-ng-click="removeUser(user)">{{:: 'delete' | translate}}</td>
         </tr>
         <tr data-ng-show="!users || users.length == 0">
             <td class="text-muted" data-ng-show="!users">{{:: 'users.instruction' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-sessions.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-sessions.html
index 1fe11e9..02c1959 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-sessions.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-sessions.html
@@ -8,9 +8,9 @@
 
     <table class="table table-striped table-bordered">
         <thead>
-        <tr data-ng-show="access.manageUsers">
+        <tr data-ng-show="user.access.manage">
             <th class="kc-table-actions" colspan="6">
-                <div class="pull-right" data-ng-show="access.manageUsers">
+                <div class="pull-right" data-ng-show="user.access.manage">
                     <a id="logoutAllSessions" class="btn btn-default" ng-click="logoutAll()">{{:: 'logout-all-sessions' | translate}}</a>
                 </div>
             </th>
@@ -20,7 +20,7 @@
             <th>{{:: 'started' | translate}}</th>
             <th>{{:: 'last-access' | translate}}</th>
             <th>{{:: 'clients' | translate}}</th>
-            <th data-ng-show="access.manageUsers">{{:: 'action' | translate}}</th>
+            <th data-ng-show="user.access.manage">{{:: 'action' | translate}}</th>
         </tr>
         </thead>
         <tbody>
@@ -34,7 +34,7 @@
                 </div>
             </ul>
             </td>
-            <td class="kc-action-cell" data-ng-show="access.manageUsers" ng-click="logoutSession(session.id)">{{:: 'logout' | translate}}</td>
+            <td class="kc-action-cell" data-ng-show="user.access.manage" ng-click="logoutSession(session.id)">{{:: 'logout' | translate}}</td>
         </tr>
         </tbody>
     </table>
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
index 25d22d7..53b0a3d 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
@@ -16,7 +16,7 @@
       </div>
     </div>
 
-    <div class="nav-category" data-ng-show="current.realm">
+    <div class="nav-category" data-ng-show="current.realm && (access.viewRealm || access.queryClients || access.viewIdentityProviders)">
         <h2>{{:: 'configure' | translate}}</h2>
         <ul class="nav nav-pills nav-stacked">
             <li data-ng-show="access.viewRealm" data-ng-class="((!path[2]
@@ -32,7 +32,7 @@
     || path[2] == 'keys-settings' || path[2] == 'smtp-settings' || path[2] == 'ldap-settings' || path[2] == 'auth-settings') && path[3] != 'clients') && 'active'">
                 <a href="#/realms/{{realm.realm}}"><span class="pficon pficon-settings"></span> {{:: 'realm-settings' | translate}}</a>
             </li>
-            <li data-ng-show="access.viewClients" data-ng-class="(path[2] == 'clients' || path[3] == 'clients') && 'active'"><a href="#/realms/{{realm.realm}}/clients"><i class="fa fa-cube"></i> {{:: 'clients' | translate}}</a></li>
+            <li data-ng-show="access.queryClients" data-ng-class="(path[2] == 'clients' || path[3] == 'clients') && 'active'"><a href="#/realms/{{realm.realm}}/clients"><i class="fa fa-cube"></i> {{:: 'clients' | translate}}</a></li>
             <li data-ng-show="access.viewClients" data-ng-class="(path[2] == 'client-templates' || path[3] == 'client-templates') && 'active'"><a href="#/realms/{{realm.realm}}/client-templates"><i class="fa fa-cubes"></i> {{:: 'client-templates' | translate}}</a></li>
             <li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'roles' || path[2] == 'default-roles') && 'active'"><a href="#/realms/{{realm.realm}}/roles"><i class="fa fa-tasks"></i> {{:: 'roles' | translate}}</a></li>
             <li data-ng-show="access.viewIdentityProviders" data-ng-class="(path[2] == 'identity-provider-settings' || path[2] == 'identity-provider-mappers') && 'active'"><a href="#/realms/{{realm.realm}}/identity-provider-settings"><i class="fa fa-exchange"></i> {{:: 'identity-providers' | translate}}</a></li>
@@ -45,12 +45,12 @@
         </ul>
     </div>
 
-    <div class="nav-category" data-ng-show="current.realm">
+    <div class="nav-category" data-ng-show="current.realm && (access.viewRealm || access.queryGroups || access.queryUsers || access.viewEvents)">
         <h2>{{:: 'manage' | translate}}</h2>
         <ul class="nav nav-pills nav-stacked">
-            <li data-ng-show="access.viewUsers" data-ng-class="(path[2] == 'groups' 
+            <li data-ng-show="access.queryGroups" data-ng-class="(path[2] == 'groups'
                         || path[2] == 'default-groups') && 'active'"><a href="#/realms/{{realm.realm}}/groups"><span class="pficon pficon-users"></span> {{:: 'groups' | translate}}</a></li>
-            <li data-ng-show="access.viewUsers" data-ng-class="(path[2] == 'users') && 'active'"><a href="#/realms/{{realm.realm}}/users"><span class="pficon pficon-user"></span> {{:: 'users' | translate}}</a></li>
+            <li data-ng-show="access.queryUsers" data-ng-class="(path[2] == 'users') && 'active'"><a href="#/realms/{{realm.realm}}/users"><span class="pficon pficon-user"></span> {{:: 'users' | translate}}</a></li>
             <li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'sessions') && 'active'"><a href="#/realms/{{realm.realm}}/sessions/realm"><i class="fa fa-clock-o"></i> {{:: 'sessions' | translate}}</a></li>
             <li data-ng-show="access.viewEvents" data-ng-class="(path[2] == 'events' 
                         || path[2] == 'events-settings'
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
index 2a3be32..e5b7c21 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
@@ -3,7 +3,7 @@
     <h1 data-ng-show="create">{{:: 'add-client' | translate}}</h1>
     <h1 data-ng-hide="create">
         {{client.clientId|capitalize}}
-        <i id="removeClient" class="pficon pficon-delete clickable" data-ng-show="access.manageClients" data-ng-click="removeClient()"></i>
+        <i id="removeClient" class="pficon pficon-delete clickable" data-ng-show="client.access.manage" data-ng-click="removeClient()"></i>
     </h1>
 
     <ul class="nav nav-tabs"  data-ng-hide="create && !path[4]">
@@ -43,5 +43,9 @@
             <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/service-account-roles">{{:: 'service-account-roles' | translate}}</a>
             <kc-tooltip>{{:: 'service-account-roles.tooltip' | translate}}</kc-tooltip>
         </li>
+        <li ng-class="{active: path[4] == 'permissions'}" data-ng-show="client.access.manage && access.manageAuthorization">
+            <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
+            <kc-tooltip>{{:: 'manage-permissions-client.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-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-group.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-group.html
index c242336..e73d998 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-group.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-group.html
@@ -1,7 +1,7 @@
 <div data-ng-controller="GroupTabCtrl">
     <h1>
         {{group.name|capitalize}}
-        <i id="removeGroup" class="pficon pficon-delete clickable" data-ng-show="access.manageUsers" data-ng-click="removeGroup()"></i>
+        <i id="removeGroup" class="pficon pficon-delete clickable" data-ng-show="group.access.manage" data-ng-click="removeGroup()"></i>
     </h1>
 
     <ul class="nav nav-tabs">
@@ -9,5 +9,9 @@
         <li ng-class="{active: path[4] == 'attributes'}"><a href="#/realms/{{realm.realm}}/groups/{{group.id}}/attributes">{{:: 'attributes' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'role-mappings'}" ><a href="#/realms/{{realm.realm}}/groups/{{group.id}}/role-mappings">{{:: 'role-mappings' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'members'}"><a href="#/realms/{{realm.realm}}/groups/{{group.id}}/members">{{:: 'members' | translate}}</a></li>
+        <li ng-class="{active: path[4] == 'permissions'}" data-ng-show="group.access.manage && access.manageAuthorization">
+            <a href="#/realms/{{realm.realm}}/groups/{{group.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
+            <kc-tooltip>{{:: 'manage-permissions-group.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..785c7e9
--- /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'}" data-ng-show="access.manageRealm && access.manageAuthorization">
+            <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-user.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user.html
index 66dad39..9c372e3 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user.html
@@ -8,7 +8,7 @@
     <ul class="nav nav-tabs" data-ng-show="!create">
         <li ng-class="{active: !path[4] && path[0] != 'create'}"><a href="#/realms/{{realm.realm}}/users/{{user.id}}">{{:: 'details' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'user-attributes'}"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/user-attributes">{{:: 'attributes' | translate}}</a></li>
-        <li ng-class="{active: path[4] == 'user-credentials'}" data-ng-show="access.manageUsers"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/user-credentials">{{:: 'credentials' | translate}}</a></li>
+        <li ng-class="{active: path[4] == 'user-credentials'}" data-ng-show="user.access.manage"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/user-credentials">{{:: 'credentials' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'role-mappings'}" ><a href="#/realms/{{realm.realm}}/users/{{user.id}}/role-mappings">{{:: 'role-mappings' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'groups'}" ><a href="#/realms/{{realm.realm}}/users/{{user.id}}/groups">{{:: 'groups' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'consents'}"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/consents">{{:: 'consents' | translate}}</a></li>
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..f641dc0
--- /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'}" data-ng-show="access.manageUsers && access.manageAuthorization">
+            <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