keycloak-aplcache

fix

4/26/2017 3:39:41 PM

Details

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/services/src/main/java/org/keycloak/authorization/admin/permissions/Helper.java b/services/src/main/java/org/keycloak/authorization/admin/permissions/Helper.java
new file mode 100644
index 0000000..a45ea7f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/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.authorization.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 $
+ */
+public 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/authorization/admin/permissions/MgmtPermissions.java b/services/src/main/java/org/keycloak/authorization/admin/permissions/MgmtPermissions.java
new file mode 100644
index 0000000..098c263
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/permissions/MgmtPermissions.java
@@ -0,0 +1,96 @@
+/*
+ * 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.admin.permissions;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationProviderFactory;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.common.UserModelIdentity;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.admin.AdminAuth;
+import org.keycloak.services.resources.admin.RealmAuth;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class MgmtPermissions {
+    public static final String MANAGE_SCOPE = "manage";
+
+    protected RealmModel realm;
+    protected KeycloakSession session;
+    protected AuthorizationProvider authz;
+    protected AdminAuth auth;
+    protected Identity identity;
+
+    public MgmtPermissions(KeycloakSession session, RealmModel realm) {
+        this.session = session;
+        this.realm = realm;
+        AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
+        this.authz = factory.create(session, realm);
+    }
+    public MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
+        this(session, realm);
+        this.auth = auth;
+
+    }
+
+    public boolean isAdminSameRealm() {
+        return realm.getId().equals(auth.getRealm().getId());
+    }
+
+    public RealmAuth getRealmAuth() {
+        RealmManager realmManager = new RealmManager(session);
+        if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
+            return new RealmAuth(auth, realm.getMasterAdminClient());
+        } else {
+            return new RealmAuth(auth, realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())));
+        }
+    }
+
+    public Identity identity() {
+        if (identity != null) return identity;
+        if (auth.getClient().getClientId().equals(Constants.REALM_MANAGEMENT_CLIENT_ID)) {
+            this.identity = new UserModelIdentity(realm, auth.getUser());
+
+        } else {
+            this.identity = new KeycloakIdentity(auth.getToken(), session);
+        }
+        return this.identity;
+    }
+
+
+    public RoleMgmtPermissions roles() {
+        return new RoleMgmtPermissions(session, realm, authz, this);
+    }
+
+    public ResourceServer findOrCreateResourceServer(ClientModel client) {
+        ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+        if (server == null) {
+            server = authz.getStoreFactory().getResourceServerStore().create(client.getId());
+        }
+        return server;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/permissions/RoleMgmtPermissions.java b/services/src/main/java/org/keycloak/authorization/admin/permissions/RoleMgmtPermissions.java
new file mode 100644
index 0000000..a745d56
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/permissions/RoleMgmtPermissions.java
@@ -0,0 +1,177 @@
+/*
+ * 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.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.common.DefaultEvaluationContext;
+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.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.util.Permissions;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RoleMgmtPermissions {
+    private static final Logger logger = Logger.getLogger(RoleMgmtPermissions.class);
+    public static final String MAP_ROLE_SCOPE = "map-role";
+    protected final KeycloakSession session;
+    protected final RealmModel realm;
+    protected final AuthorizationProvider authz;
+    protected final MgmtPermissions root;
+
+    public RoleMgmtPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
+        this.session = session;
+        this.realm = realm;
+        this.authz = authz;
+        this.root = root;
+    }
+
+    public boolean isPermissionsEnabled(RoleModel role) {
+        ClientModel client = getRoleClient(role);
+        ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
+
+        return policy != null;
+    }
+
+    public void setPermissionsEnabled(RoleModel role, boolean enable) {
+       if (enable) {
+           ResourceServer server = getResourceServer(role);
+           if (authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId()) != null) {
+               return;
+           }
+           createResource(role);
+       } else {
+           ClientModel client = getRoleClient(role);
+           ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+           if (server == null) return;
+           Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
+           if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
+           Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
+           if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+       }
+    }
+
+    public boolean canMapRole(RoleModel role) {
+        if (!root.isAdminSameRealm()) {
+            return true;
+        }
+        if (!isPermissionsEnabled(role)) return true;  // no authz permissions set up so just allow it.
+
+        ResourceServer resourceServer = getResourceServer(role);
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), resourceServer.getId());
+        if (policy.getAssociatedPolicies().isEmpty()) {
+            return true; // if no policies applied, just ignore
+        }
+
+
+        Identity identity = root.identity();
+
+        EvaluationContext context = new DefaultEvaluationContext(identity, session);
+        DecisionResult decisionCollector = new DecisionResult();
+        Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), resourceServer.getId());
+        Scope mapRoleScope = getMapRoleScope(resourceServer);
+
+        List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
+        PermissionEvaluator from = authz.evaluators().from(permissions, context);
+        from.evaluate(decisionCollector);
+        if (!decisionCollector.completed()) {
+            logger.error("Failed to run map role policy check", decisionCollector.getError());
+            return false;
+        }
+        return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
+    }
+
+
+    private ClientModel getRoleClient(RoleModel role) {
+        ClientModel client = null;
+        if (role.getContainer() instanceof ClientModel) {
+            client = (ClientModel)role.getContainer();
+        } else {
+            client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        }
+        return client;
+    }
+
+    public Policy getManageUsersPolicy(ResourceServer server) {
+        RoleModel role = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).getRole(AdminRoles.MANAGE_USERS);
+        return getRolePolicy(server, role);
+    }
+
+    public Policy getRolePolicy(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 getMapRoleScope(ResourceServer server) {
+        Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_SCOPE, server.getId());
+        if (scope == null) {
+            scope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_SCOPE, server);
+        }
+        return scope;
+    }
+
+
+    private Resource createResource(RoleModel role) {
+        ResourceServer server = getResourceServer(role);
+        Resource resource =  authz.getStoreFactory().getResourceStore().create(getRoleResourceName(role), server, server.getClientId());
+        resource.setType("Role");
+        Scope mapRoleScope = getMapRoleScope(server);
+        Helper.addEmptyScopePermission(authz, server, getMapRoleScopePermissionName(role), resource, mapRoleScope);
+        return resource;
+    }
+
+    private String getMapRoleScopePermissionName(RoleModel role) {
+        return MAP_ROLE_SCOPE + ".permission." + role.getName();
+    }
+
+    private ResourceServer getResourceServer(RoleModel role) {
+        ClientModel client = getRoleClient(role);
+        return root.findOrCreateResourceServer(client);
+    }
+
+    private static String getRoleResourceName(RoleModel role) {
+        return "role.resource." + role.getName();
+    }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/permissions/UsersPermissions.java b/services/src/main/java/org/keycloak/authorization/admin/permissions/UsersPermissions.java
new file mode 100644
index 0000000..c198885
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/permissions/UsersPermissions.java
@@ -0,0 +1,188 @@
+/*
+ * 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.admin.permissions;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.common.DefaultEvaluationContext;
+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.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.util.Permissions;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.admin.AdminAuth;
+import org.keycloak.services.resources.admin.RealmAuth;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UsersPermissions {
+    private static final Logger logger = Logger.getLogger(UsersPermissions.class);
+    protected final KeycloakSession session;
+    protected final RealmModel realm;
+    protected final AuthorizationProvider authz;
+    protected final MgmtPermissions root;
+
+    public UsersPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
+        this.session = session;
+        this.realm = realm;
+        this.authz = authz;
+        this.root = root;
+    }
+
+    private void initialize() {
+        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        ResourceServer server = root.findOrCreateResourceServer(client);
+        Scope manageScope = authz.getStoreFactory().getScopeStore().findByName(MgmtPermissions.MANAGE_SCOPE, server.getId());
+        if (manageScope == null) {
+            manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
+
+        }
+        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+        if (usersResource == null) {
+            usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
+        }
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+        if (policy == null) {
+            Set<Scope> scopeset = new HashSet<>();
+            scopeset.add(manageScope);
+            usersResource.updateScopes(scopeset);
+            Policy manageUsersPolicy = root.roles().getManageUsersPolicy(server);
+            Helper.addScopePermission(authz, server, "manage.permission.users", usersResource, manageScope, manageUsersPolicy);
+        }
+    }
+
+    public boolean isPermissionsEnabled() {
+        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+        if (server == null) return false;
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+        if (resource == null) return false;
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+
+        return policy != null;
+    }
+
+    public void setPermissionsEnabled(RoleModel role, boolean enable) {
+        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        if (enable) {
+            initialize();
+        } else {
+            ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+            if (server == null) return;
+            Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+            if (usersResource == null) {
+                authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
+            }
+            Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+            if (policy == null) {
+                authz.getStoreFactory().getPolicyStore().delete(policy.getId());
+
+            }
+        }
+    }
+
+    private Resource getUsersResource(ResourceServer server) {
+        Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+        if (usersResource == null) {
+            usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
+        }
+        return usersResource;
+    }
+
+    private Scope getManageScope(ResourceServer server) {
+        Scope manageScope = authz.getStoreFactory().getScopeStore().findByName(MgmtPermissions.MANAGE_SCOPE, server.getId());
+        if (manageScope == null) {
+            manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
+
+        }
+        return manageScope;
+    }
+
+    private ResourceServer getRealmManagementResourceServer() {
+        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        return root.findOrCreateResourceServer(client);
+    }
+
+    private boolean canManageDefault() {
+        RealmAuth auth = root.getRealmAuth();
+        auth.init(RealmAuth.Resource.USER);
+        return auth.hasManage();
+
+    }
+
+    public boolean canManage(UserModel user) {
+        if (!root.isAdminSameRealm()) {
+            return canManageDefault();
+        }
+
+        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+        ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+        if (server == null) return canManageDefault();
+
+        Resource resource =  authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
+        if (resource == null) return canManageDefault();
+
+        Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
+        if (policy == null) {
+            return canManageDefault();
+        }
+
+        Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+        // if no policies attached to permission then just do default behavior
+        if (associatedPolicies == null || associatedPolicies.isEmpty()) {
+            return canManageDefault();
+        }
+
+        Identity identity = root.identity();
+        EvaluationContext context = new DefaultEvaluationContext(identity, session);
+        DecisionResult decisionCollector = new DecisionResult();
+        ResourceServer resourceServer = getRealmManagementResourceServer();
+        Resource roleResource = authz.getStoreFactory().getResourceStore().findByName("Users", resourceServer.getId());
+        Scope manageScope = getManageScope(resourceServer);
+
+        List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, manageScope);
+        PermissionEvaluator from = authz.evaluators().from(permissions, context);
+        from.evaluate(decisionCollector);
+        if (!decisionCollector.completed()) {
+            logger.error("Failed to run Users manage check", decisionCollector.getError());
+            return false;
+        }
+        return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
+
+    }
+}
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 6b5b027..7898f7b 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
@@ -54,6 +54,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/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java
index bcf35fb..f9afdee 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java
@@ -21,6 +21,7 @@ import org.junit.Ignore;
 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.Decision;
 import org.keycloak.authorization.common.DefaultEvaluationContext;
 import org.keycloak.authorization.common.UserModelIdentity;
@@ -79,9 +80,10 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
     public static void setupDefaults(KeycloakSession session) {
         RealmModel realm = session.realms().getRealmByName(TEST);
 
-        ClientModel client = realm.getClientByClientId("realm-management");
+        ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
 
-        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());
         Scope mapRoleScope = authz.getStoreFactory().getScopeStore().create("map-role", resourceServer);
         Scope manageScope = authz.getStoreFactory().getScopeStore().create("manage", resourceServer);
@@ -103,6 +105,7 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
 
             String name = "map.role.permission." + client.getClientId() + "." + role.getName();
             Policy permission = addScopePermission(authz, resourceServer, name, resource, mapRoleScope, policy);
+            addEmptyScopePermission(authz, resourceServer, "empty. " + name, resource, mapRoleScope);
 
         }
         Resource usersResource = authz.getStoreFactory().getResourceStore().create("Users", resourceServer, resourceServer.getClientId());
@@ -125,6 +128,18 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
         return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
     }
 
+    private 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);
+    }
+
     private static Resource createRoleResource(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
         String roleName = getRoleResourceName(role);
         Resource resource =  authz.getStoreFactory().getResourceStore().create(roleName, resourceServer, resourceServer.getClientId());
@@ -179,7 +194,7 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
 
     }
 
-    //@Test
+    @Test
     public void testUI() throws Exception {
         testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
         testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
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 74fcb7b..25382e8 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
@@ -20,6 +20,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;
@@ -66,7 +67,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);