getDependentPolicies() {
- return this.dependentPolicies;
- }
}
\ No newline at end of file
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
index 8f3c7957ef..86f6f98bed 100644
--- a/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
@@ -16,14 +16,14 @@
*/
package org.keycloak.representations.idm.authorization;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import java.net.URI;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
-import java.util.function.Predicate;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
/**
* One or more resources that the resource server manages as a set of protected resources.
@@ -159,18 +159,6 @@ public class ResourceRepresentation {
this.owner = owner;
}
- public List getPolicies() {
- return this.policies;
- }
-
- public void setPolicies(List policies) {
- this.policies = policies;
- }
-
- T test(Predicate t) {
- return null;
- }
-
public void setTypedScopes(List typedScopes) {
this.typedScopes = typedScopes;
}
@@ -178,4 +166,15 @@ public class ResourceRepresentation {
public List getTypedScopes() {
return typedScopes;
}
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ResourceRepresentation scope = (ResourceRepresentation) o;
+ return Objects.equals(getName(), scope.getName());
+ }
+
+ public int hashCode() {
+ return Objects.hash(getName());
+ }
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PolicyResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PolicyResource.java
index 9a450452b5..28202f5676 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PolicyResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PolicyResource.java
@@ -16,16 +16,21 @@
*/
package org.keycloak.admin.client.resource;
-import org.jboss.resteasy.annotations.cache.NoCache;
-import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
/**
* @author Pedro Igor
*/
@@ -42,4 +47,28 @@ public interface PolicyResource {
@DELETE
void remove();
+
+ @Path("/associatedPolicies")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @NoCache
+ List associatedPolicies();
+
+ @Path("/dependentPolicies")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @NoCache
+ List dependentPolicies();
+
+ @Path("/scopes")
+ @GET
+ @Produces("application/json")
+ @NoCache
+ List scopes();
+
+ @Path("/resources")
+ @GET
+ @Produces("application/json")
+ @NoCache
+ List resources();
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceResource.java
index 834cb0602e..28e57a7e27 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceResource.java
@@ -16,13 +16,17 @@
*/
package org.keycloak.admin.client.resource;
+import java.util.List;
+
import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@@ -42,4 +46,10 @@ public interface ResourceResource {
@DELETE
void remove();
+
+ @Path("permissions")
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ List permissions();
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopeResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopeResource.java
index 6975574111..87b285bb4d 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopeResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopeResource.java
@@ -16,13 +16,17 @@
*/
package org.keycloak.admin.client.resource;
+import java.util.List;
+
import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@@ -42,4 +46,9 @@ public interface ResourceScopeResource {
@DELETE
void remove();
+
+ @Path("/permissions")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ List permissions();
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
index b503bcef77..c93465eaff 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
@@ -18,6 +18,17 @@
package org.keycloak.models.authorization.infinispan;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
import org.infinispan.Cache;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
@@ -29,17 +40,10 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
import org.keycloak.models.authorization.infinispan.entities.CachedPolicy;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.stream.Collectors;
-
/**
* @author Pedro Igor
*/
@@ -47,41 +51,58 @@ public class CachedPolicyStore implements PolicyStore {
private static final String POLICY_ID_CACHE_PREFIX = "policy-id-";
- private final Cache cache;
+ private final Cache> cache;
private final KeycloakSession session;
private final CacheTransaction transaction;
+ private final List cacheKeys;
private StoreFactory storeFactory;
private PolicyStore delegate;
+ private CachedStoreFactoryProvider cachedStoreFactory;
- public CachedPolicyStore(KeycloakSession session, CacheTransaction transaction) {
+ public CachedPolicyStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
this.session = session;
this.transaction = transaction;
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
+ cacheKeys = new ArrayList<>();
+ cacheKeys.add("findByResource");
+ cacheKeys.add("findByResourceType");
+ cacheKeys.add("findByScopeIds");
+ cacheKeys.add("findByType");
+ this.storeFactory = storeFactory;
}
@Override
public Policy create(String name, String type, ResourceServer resourceServer) {
Policy policy = getDelegate().create(name, type, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
+ String id = policy.getId();
- this.transaction.whenRollback(() -> cache.remove(getCacheKeyForPolicy(policy.getId())));
+ this.transaction.whenCommit(() -> {
+ cache.remove(getCacheKeyForPolicy(id));
+ invalidateCache(resourceServer.getId());
+ });
return createAdapter(new CachedPolicy(policy));
}
@Override
public void delete(String id) {
+ Policy policy = findById(id, null);
+ ResourceServer resourceServer = policy.getResourceServer();
getDelegate().delete(id);
- this.transaction.whenCommit(() -> cache.remove(getCacheKeyForPolicy(id)));
+ this.transaction.whenCommit(() -> {
+ cache.remove(getCacheKeyForPolicy(id));
+ invalidateCache(resourceServer.getId());
+ });
}
@Override
- public Policy findById(String id) {
+ public Policy findById(String id, String resourceServerId) {
String cacheKeyForPolicy = getCacheKeyForPolicy(id);
List cached = this.cache.get(cacheKeyForPolicy);
if (cached == null) {
- Policy policy = getDelegate().findById(id);
+ Policy policy = getDelegate().findById(id, resourceServerId);
if (policy != null) {
return createAdapter(updatePolicyCache(policy));
@@ -100,7 +121,7 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public List findByResourceServer(String resourceServerId) {
- return getDelegate().findByResourceServer(resourceServerId).stream().map(policy -> findById(policy.getId())).collect(Collectors.toList());
+ return getDelegate().findByResourceServer(resourceServerId);
}
@Override
@@ -109,88 +130,49 @@ public class CachedPolicyStore implements PolicyStore {
}
@Override
- public List findByResource(String resourceId) {
- List cache = new ArrayList<>();
-
- for (Entry entry : this.cache.entrySet()) {
- String cacheKey = (String) entry.getKey();
-
- if (cacheKey.startsWith(POLICY_ID_CACHE_PREFIX)) {
- List value = (List) entry.getValue();
- CachedPolicy policy = value.get(0);
-
- if (policy.getResourcesIds().contains(resourceId)) {
- cache.add(findById(policy.getId()));
- }
- }
- }
-
- if (cache.isEmpty()) {
- getDelegate().findByResource(resourceId).forEach(policy -> cache.add(findById(updatePolicyCache(policy).getId())));
- }
-
- return cache;
+ public List findByResource(String resourceId, String resourceServerId) {
+ return cacheResult(new StringBuilder("findByResource").append(resourceServerId).append(resourceId).toString(), () -> getDelegate().findByResource(resourceId, resourceServerId));
}
@Override
public List findByResourceType(String resourceType, String resourceServerId) {
- List cache = new ArrayList<>();
-
- for (Entry entry : this.cache.entrySet()) {
- String cacheKey = (String) entry.getKey();
-
- if (cacheKey.startsWith(POLICY_ID_CACHE_PREFIX)) {
- List value = (List) entry.getValue();
- CachedPolicy policy = value.get(0);
-
- if (policy.getResourceServerId().equals(resourceServerId) && policy.getConfig().getOrDefault("defaultResourceType", "").equals(resourceType)) {
- cache.add(findById(policy.getId()));
- }
- }
- }
-
- if (cache.isEmpty()) {
- getDelegate().findByResourceType(resourceType, resourceServerId).forEach(policy -> cache.add(findById(updatePolicyCache(policy).getId())));
- }
-
- return cache;
+ return cacheResult(new StringBuilder("findByResourceType").append(resourceServerId).append(resourceType).toString(), () -> getDelegate().findByResourceType(resourceType, resourceServerId));
}
@Override
public List findByScopeIds(List scopeIds, String resourceServerId) {
- List cache = new ArrayList<>();
+ List policies = new ArrayList<>();
- for (Entry entry : this.cache.entrySet()) {
- String cacheKey = (String) entry.getKey();
-
- if (cacheKey.startsWith(POLICY_ID_CACHE_PREFIX)) {
- List value = (List) entry.getValue();
- CachedPolicy policy = value.get(0);
-
- for (String scopeId : policy.getScopesIds()) {
- if (scopeIds.contains(scopeId)) {
- cache.add(findById(policy.getId()));
- break;
- }
- }
- }
+ for (String scopeId : scopeIds) {
+ policies.addAll(cacheResult(new StringBuilder("findByScopeIds").append(resourceServerId).append(scopeId).toString(), () -> getDelegate().findByScopeIds(Arrays.asList(scopeId), resourceServerId)));
}
- if (cache.isEmpty()) {
- getDelegate().findByScopeIds(scopeIds, resourceServerId).forEach(policy -> cache.add(findById(updatePolicyCache(policy).getId())));
- }
-
- return cache;
+ return policies;
}
@Override
- public List findByType(String type) {
- return getDelegate().findByType(type).stream().map(policy -> findById(policy.getId())).collect(Collectors.toList());
+ public List findByType(String type, String resourceServerId) {
+ return cacheResult(new StringBuilder("findByType").append(resourceServerId).append(type).toString(), () -> getDelegate().findByType(type, resourceServerId));
}
@Override
- public List findDependentPolicies(String id) {
- return getDelegate().findDependentPolicies(id).stream().map(policy -> findById(policy.getId())).collect(Collectors.toList());
+ public List findDependentPolicies(String id, String resourceServerId) {
+ return getDelegate().findDependentPolicies(id, resourceServerId);
+ }
+
+ @Override
+ public void notifyChange(Object cached) {
+ String resourceServerId;
+
+ if (Resource.class.isInstance(cached)) {
+ resourceServerId = ((Resource) cached).getResourceServer().getId();
+ } else if (Scope.class.isInstance(cached)){
+ resourceServerId = ((Scope) cached).getResourceServer().getId();
+ } else {
+ throw new RuntimeException("Unexpected notification [" + cached + "]");
+ }
+
+ invalidateCache(resourceServerId);
}
private String getCacheKeyForPolicy(String policyId) {
@@ -198,10 +180,6 @@ public class CachedPolicyStore implements PolicyStore {
}
private StoreFactory getStoreFactory() {
- if (this.storeFactory == null) {
- this.storeFactory = this.session.getProvider(StoreFactory.class);
- }
-
return this.storeFactory;
}
@@ -216,6 +194,9 @@ public class CachedPolicyStore implements PolicyStore {
private Policy createAdapter(CachedPolicy cached) {
return new Policy() {
+ private Set scopes;
+ private Set resources;
+ private Set associatedPolicies;
private Policy updated;
@Override
@@ -285,54 +266,56 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public ResourceServer getResourceServer() {
- return getStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
+ return getCachedStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
}
@Override
public void addScope(Scope scope) {
- getDelegateForUpdate().addScope(getStoreFactory().getScopeStore().findById(scope.getId()));
+ getDelegateForUpdate().addScope(getStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId()));
cached.addScope(scope);
}
@Override
public void removeScope(Scope scope) {
- getDelegateForUpdate().removeScope(getStoreFactory().getScopeStore().findById(scope.getId()));
+ getDelegateForUpdate().removeScope(scope);
cached.removeScope(scope);
}
@Override
public void addAssociatedPolicy(Policy associatedPolicy) {
- getDelegateForUpdate().addAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId()));
+ getDelegateForUpdate().addAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId(), cached.getResourceServerId()));
cached.addAssociatedPolicy(associatedPolicy);
}
@Override
public void removeAssociatedPolicy(Policy associatedPolicy) {
- getDelegateForUpdate().removeAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId()));
+ getDelegateForUpdate().removeAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId(), cached.getResourceServerId()));
cached.removeAssociatedPolicy(associatedPolicy);
}
@Override
public void addResource(Resource resource) {
- getDelegateForUpdate().addResource(getStoreFactory().getResourceStore().findById(resource.getId()));
+ getDelegateForUpdate().addResource(getStoreFactory().getResourceStore().findById(resource.getId(), cached.getResourceServerId()));
cached.addResource(resource);
}
@Override
public void removeResource(Resource resource) {
- getDelegateForUpdate().removeResource(getStoreFactory().getResourceStore().findById(resource.getId()));
+ getDelegateForUpdate().removeResource(getStoreFactory().getResourceStore().findById(resource.getId(), cached.getResourceServerId()));
cached.removeResource(resource);
}
@Override
public Set getAssociatedPolicies() {
- Set associatedPolicies = new HashSet<>();
+ if (associatedPolicies == null) {
+ associatedPolicies = new HashSet<>();
- for (String id : cached.getAssociatedPoliciesIds()) {
- Policy cached = findById(id);
+ for (String id : cached.getAssociatedPoliciesIds()) {
+ Policy policy = findById(id, cached.getResourceServerId());
- if (cached != null) {
- associatedPolicies.add(cached);
+ if (policy != null) {
+ associatedPolicies.add(policy);
+ }
}
}
@@ -341,13 +324,15 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public Set getResources() {
- Set resources = new HashSet<>();
+ if (resources == null) {
+ resources = new HashSet<>();
- for (String id : cached.getResourcesIds()) {
- Resource cached = getStoreFactory().getResourceStore().findById(id);
+ for (String id : cached.getResourcesIds()) {
+ Resource resource = getCachedStoreFactory().getResourceStore().findById(id, cached.getResourceServerId());
- if (cached != null) {
- resources.add(cached);
+ if (resource != null) {
+ resources.add(resource);
+ }
}
}
@@ -356,13 +341,15 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public Set getScopes() {
- Set scopes = new HashSet<>();
+ if (scopes == null) {
+ scopes = new HashSet<>();
- for (String id : cached.getScopesIds()) {
- Scope cached = getStoreFactory().getScopeStore().findById(id);
+ for (String id : cached.getScopesIds()) {
+ Scope scope = getCachedStoreFactory().getScopeStore().findById(id, cached.getResourceServerId());
- if (cached != null) {
- scopes.add(cached);
+ if (scope != null) {
+ scopes.add(scope);
+ }
}
}
@@ -392,9 +379,12 @@ public class CachedPolicyStore implements PolicyStore {
private Policy getDelegateForUpdate() {
if (this.updated == null) {
- this.updated = getDelegate().findById(getId());
+ this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
- transaction.whenCommit(() -> cache.remove(getCacheKeyForPolicy(getId())));
+ transaction.whenCommit(() -> {
+ cache.remove(getCacheKeyForPolicy(getId()));
+ invalidateCache(cached.getResourceServerId());
+ });
}
return this.updated;
@@ -402,9 +392,16 @@ public class CachedPolicyStore implements PolicyStore {
};
}
+ private CachedStoreFactoryProvider getCachedStoreFactory() {
+ if (cachedStoreFactory == null) {
+ cachedStoreFactory = session.getProvider(CachedStoreFactoryProvider.class);
+ }
+ return cachedStoreFactory;
+ }
+
private CachedPolicy updatePolicyCache(Policy policy) {
CachedPolicy cached = new CachedPolicy(policy);
- List cache = new ArrayList<>();
+ List cache = new ArrayList<>();
cache.add(cached);
@@ -413,4 +410,30 @@ public class CachedPolicyStore implements PolicyStore {
return cached;
}
+ private void invalidateCache(String resourceServerId) {
+ cacheKeys.forEach(cacheKey -> cache.keySet().stream().filter(key -> key.startsWith(cacheKey + resourceServerId)).forEach(cache::remove));
+ }
+
+ private List cacheResult(String key, Supplier> provider) {
+ List cached = cache.computeIfAbsent(key, (Function>) o -> {
+ List result = provider.get();
+
+ if (result.isEmpty()) {
+ return null;
+ }
+
+ return result.stream().map(policy -> new CachedPolicy(policy)).collect(Collectors.toList());
+ });
+
+ if (cached == null) {
+ return Collections.emptyList();
+ }
+
+ return cached.stream().map(new Function() {
+ @Override
+ public Policy apply(CachedPolicy cachedPolicy) {
+ return findById(cachedPolicy.getId(), cachedPolicy.getResourceServerId());
+ }
+ }).collect(Collectors.toList());
+ }
}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java
index 2685135784..ed98500706 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java
@@ -18,6 +18,10 @@
package org.keycloak.models.authorization.infinispan;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
import org.infinispan.Cache;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.ResourceServerStore;
@@ -28,16 +32,13 @@ import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvid
import org.keycloak.models.authorization.infinispan.entities.CachedResourceServer;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
/**
* @author Pedro Igor
*/
public class CachedResourceServerStore implements ResourceServerStore {
private static final String RS_ID_CACHE_PREFIX = "rs-id-";
+ private static final String RS_CLIENT_ID_CACHE_PREFIX = "rs-client-id-";
private final KeycloakSession session;
private final CacheTransaction transaction;
@@ -45,11 +46,12 @@ public class CachedResourceServerStore implements ResourceServerStore {
private ResourceServerStore delegate;
private final Cache cache;
- public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction) {
+ public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
this.session = session;
this.transaction = transaction;
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
+ this.storeFactory = storeFactory;
}
@Override
@@ -64,7 +66,14 @@ public class CachedResourceServerStore implements ResourceServerStore {
@Override
public void delete(String id) {
getDelegate().delete(id);
- this.transaction.whenCommit(() -> this.cache.remove(getCacheKeyForResourceServer(id)));
+ this.transaction.whenCommit(() -> {
+ List servers = cache.remove(getCacheKeyForResourceServer(id));
+
+ if (servers != null) {
+ CachedResourceServer entry = servers.get(0);
+ cache.remove(getCacheKeyForResourceServerClientId(entry.getClientId()));
+ }
+ });
}
@Override
@@ -87,32 +96,31 @@ public class CachedResourceServerStore implements ResourceServerStore {
@Override
public ResourceServer findByClient(String id) {
- for (Map.Entry entry : this.cache.entrySet()) {
- String cacheKey = (String) entry.getKey();
+ String cacheKeyForResourceServer = getCacheKeyForResourceServerClientId(id);
+ List cached = this.cache.get(cacheKeyForResourceServer);
- if (cacheKey.startsWith(RS_ID_CACHE_PREFIX)) {
- List cache = (List) entry.getValue();
- ResourceServer resourceServer = cache.get(0);
+ if (cached == null) {
+ ResourceServer resourceServer = getDelegate().findByClient(id);
- if (resourceServer.getClientId().equals(id)) {
- return findById(resourceServer.getId());
- }
+ if (resourceServer != null) {
+ cache.put(cacheKeyForResourceServer, Arrays.asList(resourceServer.getId()));
+ return findById(resourceServer.getId());
}
+
+ return null;
}
- ResourceServer resourceServer = getDelegate().findByClient(id);
-
- if (resourceServer != null) {
- return findById(updateResourceServerCache(resourceServer).getId());
- }
-
- return null;
+ return findById(cached.get(0));
}
private String getCacheKeyForResourceServer(String id) {
return RS_ID_CACHE_PREFIX + id;
}
+ private String getCacheKeyForResourceServerClientId(String id) {
+ return RS_CLIENT_ID_CACHE_PREFIX + id;
+ }
+
private ResourceServerStore getDelegate() {
if (this.delegate == null) {
this.delegate = getStoreFactory().getResourceServerStore();
@@ -122,10 +130,6 @@ public class CachedResourceServerStore implements ResourceServerStore {
}
private StoreFactory getStoreFactory() {
- if (this.storeFactory == null) {
- this.storeFactory = session.getProvider(StoreFactory.class);
- }
-
return this.storeFactory;
}
private ResourceServer createAdapter(ResourceServer cached) {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java
index 8696d8d11e..742f2e4f41 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java
@@ -18,6 +18,16 @@
package org.keycloak.models.authorization.infinispan;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
import org.infinispan.Cache;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
@@ -28,14 +38,7 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
import org.keycloak.models.authorization.infinispan.entities.CachedResource;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.stream.Collectors;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
/**
* @author Pedro Igor
@@ -43,60 +46,63 @@ import java.util.stream.Collectors;
public class CachedResourceStore implements ResourceStore {
private static final String RESOURCE_ID_CACHE_PREFIX = "rsc-id-";
- private static final String RESOURCE_OWNER_CACHE_PREFIX = "rsc-owner-";
+ private static final String RESOURCE_NAME_CACHE_PREFIX = "rsc-name-";
private final KeycloakSession session;
private final CacheTransaction transaction;
+ private final List cacheKeys;
private StoreFactory storeFactory;
private ResourceStore delegate;
- private final Cache cache;
+ private final Cache> cache;
- public CachedResourceStore(KeycloakSession session, CacheTransaction transaction) {
+ public CachedResourceStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
this.session = session;
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
this.transaction = transaction;
+ cacheKeys = new ArrayList<>();
+ cacheKeys.add("findByOwner");
+ this.storeFactory = storeFactory;
}
@Override
public Resource create(String name, ResourceServer resourceServer, String owner) {
Resource resource = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
- this.transaction.whenRollback(() -> cache.remove(getCacheKeyForResource(resource.getId())));
+ this.transaction.whenRollback(() -> {
+ cache.remove(getCacheKeyForResource(resource.getId()));
+ invalidateCache(resourceServer.getId());
+ });
return createAdapter(new CachedResource(resource));
}
@Override
public void delete(String id) {
- List removed = this.cache.remove(getCacheKeyForResource(id));
-
- if (removed != null) {
- CachedResource cachedResource = removed.get(0);
- List byOwner = this.cache.get(getResourceOwnerCacheKey(cachedResource.getOwner()));
-
- if (byOwner != null) {
- byOwner.remove(id);
-
- if (byOwner.isEmpty()) {
- this.cache.remove(getResourceOwnerCacheKey(cachedResource.getOwner()));
- }
- }
- }
-
+ Resource resource = findById(id, null);
+ ResourceServer resourceServer = resource.getResourceServer();
getDelegate().delete(id);
+ this.transaction.whenCommit(() -> {
+ List resources = cache.remove(getCacheKeyForResource(id));
+
+ if (resources != null) {
+ CachedResource entry = resources.get(0);
+ cache.remove(getCacheKeyForResourceName(entry.getName(), entry.getResourceServerId()));
+ }
+
+ invalidateCache(resourceServer.getId());
+ });
}
@Override
- public Resource findById(String id) {
+ public Resource findById(String id, String resourceServerId) {
String cacheKeyForResource = getCacheKeyForResource(id);
List cached = this.cache.get(cacheKeyForResource);
if (cached == null) {
- Resource resource = getDelegate().findById(id);
+ Resource resource = getDelegate().findById(id, resourceServerId);
if (resource != null) {
- updateCachedIds(getResourceOwnerCacheKey(resource.getOwner()), resource, false);
return createAdapter(updateResourceCache(resource));
}
@@ -107,20 +113,13 @@ public class CachedResourceStore implements ResourceStore {
}
@Override
- public List findByOwner(String ownerId) {
-
- for (Resource resource : getDelegate().findByOwner(ownerId)) {
- updateCachedIds(getResourceOwnerCacheKey(ownerId), resource, true);
- }
-
- return ((List) this.cache.getOrDefault(getResourceOwnerCacheKey(ownerId), Collections.emptyList())).stream().map(this::findById)
- .filter(resource -> resource != null)
- .collect(Collectors.toList());
+ public List findByOwner(String ownerId, String resourceServerId) {
+ return cacheResult(new StringBuilder("findByOwner").append(resourceServerId).append(ownerId).toString(), () -> getDelegate().findByOwner(ownerId, resourceServerId));
}
@Override
public List findByResourceServer(String resourceServerId) {
- return getDelegate().findByResourceServer(resourceServerId).stream().map(resource -> findById(resource.getId())).collect(Collectors.toList());
+ return getDelegate().findByResourceServer(resourceServerId);
}
@Override
@@ -129,43 +128,42 @@ public class CachedResourceStore implements ResourceStore {
}
@Override
- public List findByScope(String... id) {
- return getDelegate().findByScope(id).stream().map(resource -> findById(resource.getId())).collect(Collectors.toList());
+ public List findByScope(List id, String resourceServerId) {
+ return getDelegate().findByScope(id, resourceServerId);
}
@Override
public Resource findByName(String name, String resourceServerId) {
- for (Entry entry : this.cache.entrySet()) {
- String cacheKey = (String) entry.getKey();
+ String cacheKeyForResource = getCacheKeyForResourceName(name, resourceServerId);
+ List cached = this.cache.get(cacheKeyForResource);
- if (cacheKey.startsWith(RESOURCE_ID_CACHE_PREFIX)) {
- List value = (List) entry.getValue();
- CachedResource resource = value.get(0);
+ if (cached == null) {
+ Resource resource = getDelegate().findByName(name, resourceServerId);
- if (resource.getResourceServerId().equals(resourceServerId) && resource.getName().equals(name)) {
- return findById(resource.getId());
- }
+ if (resource != null) {
+ cache.put(cacheKeyForResource, Arrays.asList(new CachedResource(resource)));
+ return findById(resource.getId(), resourceServerId);
}
+
+ return null;
}
- Resource resource = getDelegate().findByName(name, resourceServerId);
-
- if (resource != null) {
- return findById(updateResourceCache(resource).getId());
- }
-
- return null;
+ return createAdapter(cached.get(0));
}
@Override
- public List findByType(String type) {
- return getDelegate().findByType(type).stream().map(resource -> findById(resource.getId())).collect(Collectors.toList());
+ public List findByType(String type, String resourceServerId) {
+ return getDelegate().findByType(type, resourceServerId);
}
private String getCacheKeyForResource(String id) {
return RESOURCE_ID_CACHE_PREFIX + id;
}
+ private String getCacheKeyForResourceName(String name, String resourceServerId) {
+ return RESOURCE_NAME_CACHE_PREFIX + name + "-" + resourceServerId;
+ }
+
private ResourceStore getDelegate() {
if (this.delegate == null) {
this.delegate = getStoreFactory().getResourceStore();
@@ -175,10 +173,6 @@ public class CachedResourceStore implements ResourceStore {
}
private StoreFactory getStoreFactory() {
- if (this.storeFactory == null) {
- this.storeFactory = session.getProvider(StoreFactory.class);
- }
-
return this.storeFactory;
}
@@ -228,13 +222,15 @@ public class CachedResourceStore implements ResourceStore {
@Override
public List getScopes() {
- List scopes = new ArrayList<>();
+ if (scopes == null) {
+ scopes = new ArrayList<>();
- for (String id : cached.getScopesIds()) {
- Scope cached = getStoreFactory().getScopeStore().findById(id);
+ for (String id : cached.getScopesIds()) {
+ Scope scope = getCachedStoreFactory().getScopeStore().findById(id, cached.getResourceServerId());
- if (cached != null) {
- scopes.add(cached);
+ if (scope != null) {
+ scopes.add(scope);
+ }
}
}
@@ -254,7 +250,7 @@ public class CachedResourceStore implements ResourceStore {
@Override
public ResourceServer getResourceServer() {
- return getStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
+ return getCachedStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
}
@Override
@@ -264,15 +260,19 @@ public class CachedResourceStore implements ResourceStore {
@Override
public void updateScopes(Set scopes) {
- getDelegateForUpdate().updateScopes(scopes.stream().map(scope -> getStoreFactory().getScopeStore().findById(scope.getId())).collect(Collectors.toSet()));
+ getDelegateForUpdate().updateScopes(scopes.stream().map(scope -> getStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId())).collect(Collectors.toSet()));
cached.updateScopes(scopes);
}
private Resource getDelegateForUpdate() {
if (this.updated == null) {
- this.updated = getDelegate().findById(getId());
+ this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
- transaction.whenCommit(() -> cache.remove(getCacheKeyForResource(getId())));
+ transaction.whenRollback(() -> {
+ cache.remove(getCacheKeyForResource(cached.getId()));
+ invalidateCache(cached.getResourceServerId());
+ getCachedStoreFactory().getPolicyStore().notifyChange(cached);
+ });
}
return this.updated;
@@ -280,6 +280,10 @@ public class CachedResourceStore implements ResourceStore {
};
}
+ private CachedStoreFactoryProvider getCachedStoreFactory() {
+ return session.getProvider(CachedStoreFactoryProvider.class);
+ }
+
private CachedResource updateResourceCache(Resource resource) {
CachedResource cached = new CachedResource(resource);
List cache = new ArrayList<>();
@@ -291,23 +295,30 @@ public class CachedResourceStore implements ResourceStore {
return cached;
}
- private void updateCachedIds(String cacheKey, Resource resource, boolean create) {
- List cached = this.cache.get(cacheKey);
+ private List cacheResult(String key, Supplier> provider) {
+ List cached = cache.computeIfAbsent(key, (Function>) o -> {
+ List result = provider.get();
+
+ if (result.isEmpty()) {
+ return null;
+ }
+
+ return result.stream().map(resource -> new CachedResource(resource)).collect(Collectors.toList());
+ });
if (cached == null) {
- if (!create) {
- return;
- }
- cached = new ArrayList<>();
- this.cache.put(cacheKey, cached);
+ return Collections.emptyList();
}
- if (cached != null && !cached.contains(resource.getId())) {
- cached.add(resource.getId());
- }
+ return cached.stream().map(new Function() {
+ @Override
+ public Resource apply(CachedResource cached) {
+ return findById(cached.getId(), cached.getResourceServerId());
+ }
+ }).collect(Collectors.toList());
}
- private String getResourceOwnerCacheKey(String ownerId) {
- return RESOURCE_OWNER_CACHE_PREFIX + ownerId;
+ private void invalidateCache(String resourceServerId) {
+ cacheKeys.forEach(cacheKey -> cache.keySet().stream().filter(key -> key.startsWith(cacheKey + resourceServerId)).forEach(cache::remove));
}
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java
index f86a7d1bb8..77a6970936 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java
@@ -18,6 +18,11 @@
package org.keycloak.models.authorization.infinispan;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
import org.infinispan.Cache;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
@@ -27,11 +32,7 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
import org.keycloak.models.authorization.infinispan.entities.CachedScope;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
/**
* @author Pedro Igor
@@ -39,6 +40,7 @@ import java.util.Map.Entry;
public class CachedScopeStore implements ScopeStore {
private static final String SCOPE_ID_CACHE_PREFIX = "scp-id-";
+ private static final String SCOPE_NAME_CACHE_PREFIX = "scp-name-";
private final Cache cache;
private final KeycloakSession session;
@@ -46,11 +48,12 @@ public class CachedScopeStore implements ScopeStore {
private ScopeStore delegate;
private StoreFactory storeFactory;
- public CachedScopeStore(KeycloakSession session, CacheTransaction transaction) {
+ public CachedScopeStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
this.session = session;
this.transaction = transaction;
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
+ this.storeFactory = storeFactory;
}
@Override
@@ -65,16 +68,23 @@ public class CachedScopeStore implements ScopeStore {
@Override
public void delete(String id) {
getDelegate().delete(id);
- this.transaction.whenCommit(() -> cache.remove(getCacheKeyForScope(id)));
+ this.transaction.whenCommit(() -> {
+ List scopes = cache.remove(getCacheKeyForScope(id));
+
+ if (scopes != null) {
+ CachedScope entry = scopes.get(0);
+ cache.remove(getCacheKeyForScopeName(entry.getName(), entry.getResourceServerId()));
+ }
+ });
}
@Override
- public Scope findById(String id) {
+ public Scope findById(String id, String resourceServerId) {
String cacheKeyForScope = getCacheKeyForScope(id);
List cached = this.cache.get(cacheKeyForScope);
if (cached == null) {
- Scope scope = getDelegate().findById(id);
+ Scope scope = getDelegate().findById(id, resourceServerId);
if (scope != null) {
return createAdapter(updateScopeCache(scope));
@@ -88,26 +98,21 @@ public class CachedScopeStore implements ScopeStore {
@Override
public Scope findByName(String name, String resourceServerId) {
- for (Entry entry : this.cache.entrySet()) {
- String cacheKey = (String) entry.getKey();
+ String cacheKeyForScope = getCacheKeyForScopeName(name, resourceServerId);
+ List cached = this.cache.get(cacheKeyForScope);
- if (cacheKey.startsWith(SCOPE_ID_CACHE_PREFIX)) {
- List cache = (List) entry.getValue();
- CachedScope scope = cache.get(0);
+ if (cached == null) {
+ Scope scope = getDelegate().findByName(name, resourceServerId);
- if (scope.getResourceServerId().equals(resourceServerId) && scope.getName().equals(name)) {
- return findById(scope.getId());
- }
+ if (scope != null) {
+ cache.put(cacheKeyForScope, Arrays.asList(scope.getId()));
+ return findById(scope.getId(), resourceServerId);
}
+
+ return null;
}
- Scope scope = getDelegate().findByName(name, resourceServerId);
-
- if (scope != null) {
- return findById(updateScopeCache(scope).getId());
- }
-
- return null;
+ return findById(cached.get(0), resourceServerId);
}
@Override
@@ -124,6 +129,10 @@ public class CachedScopeStore implements ScopeStore {
return SCOPE_ID_CACHE_PREFIX + id;
}
+ private String getCacheKeyForScopeName(String name, String resourceServerId) {
+ return SCOPE_NAME_CACHE_PREFIX + name + "-" + resourceServerId;
+ }
+
private ScopeStore getDelegate() {
if (this.delegate == null) {
this.delegate = getStoreFactory().getScopeStore();
@@ -133,10 +142,6 @@ public class CachedScopeStore implements ScopeStore {
}
private StoreFactory getStoreFactory() {
- if (this.storeFactory == null) {
- this.storeFactory = session.getProvider(StoreFactory.class);
- }
-
return this.storeFactory;
}
@@ -174,14 +179,17 @@ public class CachedScopeStore implements ScopeStore {
@Override
public ResourceServer getResourceServer() {
- return getStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
+ return getCachedStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
}
private Scope getDelegateForUpdate() {
if (this.updated == null) {
- this.updated = getDelegate().findById(getId());
+ this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
- transaction.whenCommit(() -> cache.remove(getCacheKeyForScope(getId())));
+ transaction.whenCommit(() -> {
+ cache.remove(getCacheKeyForScope(getId()));
+ getCachedStoreFactory().getPolicyStore().notifyChange(updated);
+ });
}
return this.updated;
@@ -189,6 +197,10 @@ public class CachedScopeStore implements ScopeStore {
};
}
+ private CachedStoreFactoryProvider getCachedStoreFactory() {
+ return session.getProvider(CachedStoreFactoryProvider.class);
+ }
+
private CachedScope updateScopeCache(Scope scope) {
CachedScope cached = new CachedScope(scope);
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java
index 56a385fe12..ff66da6fac 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java
@@ -22,6 +22,7 @@ import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
@@ -36,31 +37,41 @@ public class InfinispanStoreFactoryProvider implements CachedStoreFactoryProvide
private final KeycloakSession session;
private final CacheTransaction transaction;
+ private final StoreFactory storeFactory;
+ private final CachedResourceStore resourceStore;
+ private final CachedScopeStore scopeStore;
+ private final CachedPolicyStore policyStore;
+ private ResourceServerStore resourceServerStore;
InfinispanStoreFactoryProvider(KeycloakSession delegate) {
this.session = delegate;
this.transaction = new CacheTransaction();
this.session.getTransactionManager().enlistAfterCompletion(transaction);
+ storeFactory = this.session.getProvider(StoreFactory.class);
+ resourceStore = new CachedResourceStore(this.session, this.transaction, storeFactory);
+ resourceServerStore = new CachedResourceServerStore(this.session, this.transaction, storeFactory);
+ scopeStore = new CachedScopeStore(this.session, this.transaction, storeFactory);
+ policyStore = new CachedPolicyStore(this.session, this.transaction, storeFactory);
}
@Override
public ResourceStore getResourceStore() {
- return new CachedResourceStore(this.session, this.transaction);
+ return resourceStore;
}
@Override
public ResourceServerStore getResourceServerStore() {
- return new CachedResourceServerStore(this.session, this.transaction);
+ return resourceServerStore;
}
@Override
public ScopeStore getScopeStore() {
- return new CachedScopeStore(this.session, this.transaction);
+ return scopeStore;
}
@Override
public PolicyStore getPolicyStore() {
- return new CachedPolicyStore(this.session, this.transaction);
+ return policyStore;
}
@Override
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
index b57cd1efd5..544018da0a 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
@@ -19,8 +19,10 @@ package org.keycloak.authorization.jpa.store;
import org.keycloak.authorization.jpa.entities.PolicyEntity;
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.ResourceServer;
+import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.models.utils.KeycloakModelUtils;
@@ -68,17 +70,30 @@ public class JPAPolicyStore implements PolicyStore {
@Override
public void delete(String id) {
- Policy policy = findById(id);
+ Policy policy = entityManager.find(PolicyEntity.class, id);
if (policy != null) {
- getEntityManager().remove(policy);
+ this.entityManager.remove(policy);
}
}
@Override
- public Policy findById(String id) {
- return getEntityManager().find(PolicyEntity.class, id);
+ public Policy findById(String id, String resourceServerId) {
+ if (id == null) {
+ return null;
+ }
+
+ if (resourceServerId == null) {
+ return entityManager.find(PolicyEntity.class, id);
+ }
+
+ Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId and id = :id");
+
+ query.setParameter("serverId", resourceServerId);
+ query.setParameter("id", id);
+
+ return entityManager.find(PolicyEntity.class, id);
}
@Override
@@ -142,32 +157,23 @@ public class JPAPolicyStore implements PolicyStore {
}
@Override
- public List findByResource(final String resourceId) {
- Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.resources r where r.id = :resourceId");
+ public List findByResource(final String resourceId, String resourceServerId) {
+ Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)");
query.setParameter("resourceId", resourceId);
+ query.setParameter("serverId", resourceServerId);
return query.getResultList();
}
@Override
public List findByResourceType(final String resourceType, String resourceServerId) {
- List policies = new ArrayList<>();
- Query query = getEntityManager().createQuery("from PolicyEntity where resourceServer.id = :serverId");
+ Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c = :type");
query.setParameter("serverId", resourceServerId);
+ query.setParameter("type", resourceType);
- List models = query.getResultList();
-
- for (Policy policy : models) {
- String defaultType = policy.getConfig().get("defaultResourceType");
-
- if (defaultType != null && defaultType.equals(resourceType) && policy.getResources().isEmpty()) {
- policies.add(policy);
- }
- }
-
- return policies;
+ return query.getResultList();
}
@Override
@@ -177,7 +183,7 @@ public class JPAPolicyStore implements PolicyStore {
}
// Use separate subquery to handle DB2 and MSSSQL
- Query query = getEntityManager().createQuery("select pe from PolicyEntity pe where pe.id IN (select p.id from PolicyEntity p inner join p.scopes s where p.resourceServer.id = :serverId and s.id in (:scopeIds) and p.resources is empty group by p.id) order by pe.name");
+ Query query = getEntityManager().createQuery("select pe from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))");
query.setParameter("serverId", resourceServerId);
query.setParameter("scopeIds", scopeIds);
@@ -186,19 +192,21 @@ public class JPAPolicyStore implements PolicyStore {
}
@Override
- public List findByType(String type) {
- Query query = getEntityManager().createQuery("select p from PolicyEntity p where p.type = :type");
+ public List findByType(String type, String resourceServerId) {
+ Query query = getEntityManager().createQuery("select p from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type");
+ query.setParameter("serverId", resourceServerId);
query.setParameter("type", type);
return query.getResultList();
}
@Override
- public List findDependentPolicies(String policyId) {
- Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where ap.id in (:policyId)");
+ public List findDependentPolicies(String policyId, String resourceServerId) {
+ Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)");
- query.setParameter("policyId", Arrays.asList(policyId));
+ query.setParameter("serverId", resourceServerId);
+ query.setParameter("policyId", policyId);
return query.getResultList();
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
index 6d00bb66d4..9f5346da50 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
@@ -66,7 +66,7 @@ public class JPAResourceStore implements ResourceStore {
@Override
public void delete(String id) {
- Resource resource = findById(id);
+ Resource resource = entityManager.find(ResourceEntity.class, id);
resource.getScopes().clear();
@@ -76,19 +76,29 @@ public class JPAResourceStore implements ResourceStore {
}
@Override
- public Resource findById(String id) {
+ public Resource findById(String id, String resourceServerId) {
if (id == null) {
return null;
}
+ if (resourceServerId == null) {
+ return entityManager.find(ResourceEntity.class, id);
+ }
+
+ Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and id = :id");
+
+ query.setParameter("serverId", resourceServerId);
+ query.setParameter("id", id);
+
return entityManager.find(ResourceEntity.class, id);
}
@Override
- public List findByOwner(String ownerId) {
- Query query = entityManager.createQuery("from ResourceEntity where owner = :ownerId");
+ public List findByOwner(String ownerId, String resourceServerId) {
+ Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and owner = :ownerId");
query.setParameter("ownerId", ownerId);
+ query.setParameter("serverId", resourceServerId);
return query.getResultList();
}
@@ -112,7 +122,9 @@ public class JPAResourceStore implements ResourceStore {
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
attributes.forEach((name, value) -> {
- if ("scope".equals(name)) {
+ if ("id".equals(name)) {
+ predicates.add(root.get(name).in(value));
+ } else if ("scope".equals(name)) {
predicates.add(root.join("scopes").get("id").in(value));
} else {
predicates.add(builder.like(builder.lower(root.get(name)), "%" + value[0].toLowerCase() + "%"));
@@ -134,10 +146,11 @@ public class JPAResourceStore implements ResourceStore {
}
@Override
- public List findByScope(String... id) {
- Query query = entityManager.createQuery("select r from ResourceEntity r inner join r.scopes s where s.id in (:scopeIds)");
+ public List findByScope(List id, String resourceServerId) {
+ Query query = entityManager.createQuery("select r from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))");
- query.setParameter("scopeIds", Arrays.asList(id));
+ query.setParameter("scopeIds", id);
+ query.setParameter("serverId", resourceServerId);
return query.getResultList();
}
@@ -159,10 +172,11 @@ public class JPAResourceStore implements ResourceStore {
}
@Override
- public List findByType(String type) {
- Query query = entityManager.createQuery("from ResourceEntity where type = :type");
+ public List findByType(String type, String resourceServerId) {
+ Query query = entityManager.createQuery("from ResourceEntity r where r.resourceServer.id = :serverId and type = :type");
query.setParameter("type", type);
+ query.setParameter("serverId", resourceServerId);
return query.getResultList();
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
index d468314374..30869d3d72 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
@@ -17,12 +17,9 @@
*/
package org.keycloak.authorization.jpa.store;
-import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
-import org.keycloak.authorization.jpa.entities.ScopeEntity;
-import org.keycloak.authorization.model.ResourceServer;
-import org.keycloak.authorization.model.Scope;
-import org.keycloak.authorization.store.ScopeStore;
-import org.keycloak.models.utils.KeycloakModelUtils;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
@@ -31,9 +28,13 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+
+import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.models.utils.KeycloakModelUtils;
/**
* @author Pedro Igor
@@ -61,12 +62,30 @@ public class JPAScopeStore implements ScopeStore {
@Override
public void delete(String id) {
- this.entityManager.remove(findById(id));
+ Scope scope = entityManager.find(ScopeEntity.class, id);
+
+ if (scope != null) {
+ this.entityManager.remove(scope);
+ }
}
@Override
- public Scope findById(String id) {
+ public Scope findById(String id, String resourceServerId) {
+ if (id == null) {
+ return null;
+ }
+
+ if (true) {
+ return entityManager.find(ScopeEntity.class, id);
+ }
+
+ Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId and id = :id");
+
+ query.setParameter("serverId", resourceServerId);
+ query.setParameter("id", id);
+
return entityManager.find(ScopeEntity.class, id);
+
}
@Override
@@ -74,8 +93,8 @@ public class JPAScopeStore implements ScopeStore {
try {
Query query = entityManager.createQuery("select s from ScopeEntity s inner join s.resourceServer rs where rs.id = :resourceServerId and name = :name");
- query.setParameter("name", name);
query.setParameter("resourceServerId", resourceServerId);
+ query.setParameter("name", name);
return (Scope) query.getSingleResult();
} catch (NoResultException nre) {
@@ -102,7 +121,11 @@ public class JPAScopeStore implements ScopeStore {
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
attributes.forEach((name, value) -> {
- predicates.add(builder.like(builder.lower(root.get(name)), "%" + value[0].toLowerCase() + "%"));
+ if ("id".equals(name)) {
+ predicates.add(root.get(name).in(value));
+ } else {
+ predicates.add(builder.like(builder.lower(root.get(name)), "%" + value[0].toLowerCase() + "%"));
+ }
});
querybuilder.where(predicates.toArray(new Predicate[predicates.size()])).orderBy(builder.asc(root.get("name")));
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/PolicyAdapter.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/PolicyAdapter.java
index 2b28f16463..928bba9bba 100644
--- a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/PolicyAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/PolicyAdapter.java
@@ -124,21 +124,21 @@ public class PolicyAdapter extends AbstractMongoAdapter implements
@Override
public Set getAssociatedPolicies() {
return getMongoEntity().getAssociatedPolicies().stream()
- .map((Function) id -> authorizationProvider.getStoreFactory().getPolicyStore().findById(id))
+ .map((Function) id -> authorizationProvider.getStoreFactory().getPolicyStore().findById(id, getMongoEntity().getResourceServerId()))
.collect(Collectors.toSet());
}
@Override
public Set getResources() {
return getMongoEntity().getResources().stream()
- .map((Function) id -> authorizationProvider.getStoreFactory().getResourceStore().findById(id))
+ .map((Function) id -> authorizationProvider.getStoreFactory().getResourceStore().findById(id, getMongoEntity().getResourceServerId()))
.collect(Collectors.toSet());
}
@Override
public Set getScopes() {
return getMongoEntity().getScopes().stream()
- .map((Function) id -> authorizationProvider.getStoreFactory().getScopeStore().findById(id))
+ .map((Function) id -> authorizationProvider.getStoreFactory().getScopeStore().findById(id, getMongoEntity().getResourceServerId()))
.collect(Collectors.toSet());
}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceAdapter.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceAdapter.java
index 7c67f6ea75..8138a2479d 100644
--- a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceAdapter.java
@@ -68,7 +68,7 @@ public class ResourceAdapter extends AbstractMongoAdapter implem
@Override
public List getScopes() {
return getMongoEntity().getScopes().stream()
- .map(id -> authorizationProvider.getStoreFactory().getScopeStore().findById(id))
+ .map(id -> authorizationProvider.getStoreFactory().getScopeStore().findById(id, getResourceServer().getId()))
.collect(toList());
}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoPolicyStore.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoPolicyStore.java
index 04a3d9ac4b..c7227f699a 100644
--- a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoPolicyStore.java
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoPolicyStore.java
@@ -70,7 +70,7 @@ public class MongoPolicyStore implements PolicyStore {
}
@Override
- public Policy findById(String id) {
+ public Policy findById(String id, String resourceServerId) {
PolicyEntity entity = getMongoStore().loadEntity(PolicyEntity.class, id, getInvocationContext());
if (entity == null) {
@@ -89,7 +89,7 @@ public class MongoPolicyStore implements PolicyStore {
.get();
return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId())).findFirst().orElse(null);
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId)).findFirst().orElse(null);
}
@Override
@@ -99,7 +99,7 @@ public class MongoPolicyStore implements PolicyStore {
.get();
return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
@@ -125,17 +125,18 @@ public class MongoPolicyStore implements PolicyStore {
DBObject sort = new BasicDBObject("name", 1);
return getMongoStore().loadEntities(PolicyEntity.class, queryBuilder.get(), sort, firstResult, maxResult, invocationContext).stream()
- .map(policy -> findById(policy.getId())).collect(toList());
+ .map(policy -> findById(policy.getId(), resourceServerId)).collect(toList());
}
@Override
- public List findByResource(String resourceId) {
+ public List findByResource(String resourceId, String resourceServerId) {
DBObject query = new QueryBuilder()
+ .and("resourceServerId").is(resourceServerId)
.and("resources").is(resourceId)
.get();
return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
@@ -150,7 +151,7 @@ public class MongoPolicyStore implements PolicyStore {
String defaultResourceType = policyEntity.getConfig().get("defaultResourceType");
return defaultResourceType != null && defaultResourceType.equals(resourceType);
})
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
@@ -162,29 +163,31 @@ public class MongoPolicyStore implements PolicyStore {
.get();
return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
@Override
- public List findByType(String type) {
+ public List findByType(String type, String resourceServerId) {
DBObject query = new QueryBuilder()
+ .and("resourceServerId").is(resourceServerId)
.and("type").is(type)
.get();
return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
@Override
- public List findDependentPolicies(String policyId) {
+ public List findDependentPolicies(String policyId, String resourceServerId) {
DBObject query = new QueryBuilder()
+ .and("resourceServerId").is(resourceServerId)
.and("associatedPolicies").is(policyId)
.get();
return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceStore.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceStore.java
index a85de72970..79f6a9ec71 100644
--- a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceStore.java
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceStore.java
@@ -70,7 +70,7 @@ public class MongoResourceStore implements ResourceStore {
}
@Override
- public Resource findById(String id) {
+ public Resource findById(String id, String resourceServerId) {
ResourceEntity entity = getMongoStore().loadEntity(ResourceEntity.class, id, getInvocationContext());
if (entity == null) {
@@ -81,13 +81,14 @@ public class MongoResourceStore implements ResourceStore {
}
@Override
- public List findByOwner(String ownerId) {
+ public List findByOwner(String ownerId, String resourceServerId) {
DBObject query = new QueryBuilder()
+ .and("resourceServerId").is(resourceServerId)
.and("owner").is(ownerId)
.get();
return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
- .map(scope -> findById(scope.getId())).collect(toList());
+ .map(scope -> findById(scope.getId(), resourceServerId)).collect(toList());
}
@Override
@@ -97,7 +98,7 @@ public class MongoResourceStore implements ResourceStore {
.get();
return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
- .map(scope -> findById(scope.getId())).collect(toList());
+ .map(scope -> findById(scope.getId(), resourceServerId)).collect(toList());
}
@Override
@@ -116,39 +117,41 @@ public class MongoResourceStore implements ResourceStore {
DBObject sort = new BasicDBObject("name", 1);
return getMongoStore().loadEntities(ResourceEntity.class, queryBuilder.get(), sort, firstResult, maxResult, invocationContext).stream()
- .map(scope -> findById(scope.getId())).collect(toList());
+ .map(scope -> findById(scope.getId(), resourceServerId)).collect(toList());
}
@Override
- public List findByScope(String... id) {
+ public List findByScope(List id, String resourceServerId) {
DBObject query = new QueryBuilder()
+ .and("resourceServerId").is(resourceServerId)
.and("scopes").in(id)
.get();
return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
@Override
public Resource findByName(String name, String resourceServerId) {
DBObject query = new QueryBuilder()
- .and("name").is(name)
.and("resourceServerId").is(resourceServerId)
+ .and("name").is(name)
.get();
return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId())).findFirst().orElse(null);
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId)).findFirst().orElse(null);
}
@Override
- public List findByType(String type) {
+ public List findByType(String type, String resourceServerId) {
DBObject query = new QueryBuilder()
+ .and("resourceServerId").is(resourceServerId)
.and("type").is(type)
.get();
return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(policyEntity -> findById(policyEntity.getId(), resourceServerId))
.collect(toList());
}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoScopeStore.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoScopeStore.java
index 4b7edd6a2f..04decb291f 100644
--- a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoScopeStore.java
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoScopeStore.java
@@ -69,7 +69,7 @@ public class MongoScopeStore implements ScopeStore {
}
@Override
- public Scope findById(String id) {
+ public Scope findById(String id, String resourceServerId) {
ScopeEntity entity = getMongoStore().loadEntity(ScopeEntity.class, id, getInvocationContext());
if (entity == null) {
@@ -87,7 +87,7 @@ public class MongoScopeStore implements ScopeStore {
.get();
return getMongoStore().loadEntities(ScopeEntity.class, query, getInvocationContext()).stream()
- .map(scope -> findById(scope.getId())).findFirst().orElse(null);
+ .map(scope -> findById(scope.getId(), scope.getResourceServerId())).findFirst().orElse(null);
}
@Override
@@ -97,7 +97,7 @@ public class MongoScopeStore implements ScopeStore {
.get();
return getMongoStore().loadEntities(ScopeEntity.class, query, getInvocationContext()).stream()
- .map(policyEntity -> findById(policyEntity.getId()))
+ .map(scope -> findById(scope.getId(), scope.getResourceServerId()))
.collect(toList());
}
@@ -113,7 +113,7 @@ public class MongoScopeStore implements ScopeStore {
DBObject sort = new BasicDBObject("name", 1);
return getMongoStore().loadEntities(ScopeEntity.class, queryBuilder.get(), sort, firstResult, maxResult, invocationContext).stream()
- .map(scope -> findById(scope.getId())).collect(toList());
+ .map(scope -> findById(scope.getId(), scope.getResourceServerId())).collect(toList());
}
private MongoStoreInvocationContext getInvocationContext() {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
index fb7c91b796..3aafae31b5 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
@@ -18,6 +18,12 @@
package org.keycloak.authorization;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Supplier;
+
import org.keycloak.authorization.permission.evaluator.Evaluators;
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
import org.keycloak.authorization.policy.provider.PolicyProvider;
@@ -26,11 +32,6 @@ import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.Provider;
-import org.keycloak.provider.ProviderFactory;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.stream.Collectors;
/**
* The main contract here is the creation of {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances. Usually
@@ -62,22 +63,22 @@ public final class AuthorizationProvider implements Provider {
private final DefaultPolicyEvaluator policyEvaluator;
private final Executor scheduller;
- private final StoreFactory storeFactory;
- private final List policyProviderFactories;
+ private final Supplier storeFactory;
+ private final Map policyProviderFactories;
private final KeycloakSession keycloakSession;
private final RealmModel realm;
- public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Executor scheduller) {
+ public AuthorizationProvider(KeycloakSession session, RealmModel realm, Supplier storeFactory, Map policyProviderFactories, Executor scheduller) {
this.keycloakSession = session;
this.realm = realm;
this.storeFactory = storeFactory;
this.scheduller = scheduller;
- this.policyProviderFactories = configurePolicyProviderFactories(session);
- this.policyEvaluator = new DefaultPolicyEvaluator(this, this.policyProviderFactories);
+ this.policyProviderFactories = policyProviderFactories;
+ this.policyEvaluator = new DefaultPolicyEvaluator(this);
}
- public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory) {
- this(session, realm, storeFactory, Runnable::run);
+ public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Map policyProviderFactories) {
+ this(session, realm, () -> storeFactory, policyProviderFactories, Runnable::run);
}
/**
@@ -87,7 +88,7 @@ public final class AuthorizationProvider implements Provider {
* @return a {@link Evaluators} instance
*/
public Evaluators evaluators() {
- return new Evaluators(this.policyProviderFactories, this.policyEvaluator, this.scheduller);
+ return new Evaluators(this.policyEvaluator, this.scheduller);
}
/**
@@ -96,7 +97,7 @@ public final class AuthorizationProvider implements Provider {
* @return the {@link StoreFactory}
*/
public StoreFactory getStoreFactory() {
- return this.storeFactory;
+ return this.storeFactory.get();
}
/**
@@ -104,8 +105,8 @@ public final class AuthorizationProvider implements Provider {
*
* @return a {@link List} containing all registered {@link PolicyProviderFactory}
*/
- public List getProviderFactories() {
- return this.policyProviderFactories;
+ public Collection getProviderFactories() {
+ return this.policyProviderFactories.values();
}
/**
@@ -116,7 +117,24 @@ public final class AuthorizationProvider implements Provider {
* @return a {@link PolicyProviderFactory} with the given type
*/
public F getProviderFactory(String type) {
- return (F) getProviderFactories().stream().filter(policyProviderFactory -> policyProviderFactory.getId().equals(type)).findFirst().orElse(null);
+ return (F) policyProviderFactories.get(type);
+ }
+
+ /**
+ * Returns a {@link PolicyProviderFactory} given a type
.
+ *
+ * @param type the type of the policy provider
+ * @param the expected type of the provider
+ * @return a {@link PolicyProvider} with the given type
+ */
+ public P getProvider(String type) {
+ PolicyProviderFactory policyProviderFactory = policyProviderFactories.get(type);
+
+ if (policyProviderFactory == null) {
+ return null;
+ }
+
+ return (P) policyProviderFactory.create(this);
}
public KeycloakSession getKeycloakSession() {
@@ -127,16 +145,6 @@ public final class AuthorizationProvider implements Provider {
return realm;
}
- private List configurePolicyProviderFactories(KeycloakSession session) {
- List providerFactories = session.getKeycloakSessionFactory().getProviderFactories(PolicyProvider.class);
-
- if (providerFactories.isEmpty()) {
- throw new RuntimeException("Could not find any policy provider.");
- }
-
- return providerFactories.stream().map(providerFactory -> (PolicyProviderFactory) providerFactory).collect(Collectors.toList());
- }
-
@Override
public void close() {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/Evaluators.java b/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/Evaluators.java
index e26ad1c87e..ed1aa89172 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/Evaluators.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/Evaluators.java
@@ -18,13 +18,12 @@
package org.keycloak.authorization.permission.evaluator;
+import java.util.List;
+import java.util.concurrent.Executor;
+
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
-import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
-
-import java.util.List;
-import java.util.concurrent.Executor;
/**
* A factory for the different {@link PermissionEvaluator} implementations.
@@ -33,12 +32,10 @@ import java.util.concurrent.Executor;
*/
public final class Evaluators {
- private final List policyProviderFactories;
private final DefaultPolicyEvaluator policyEvaluator;
private final Executor scheduler;
- public Evaluators(List policyProviderFactories, DefaultPolicyEvaluator policyEvaluator, Executor scheduler) {
- this.policyProviderFactories = policyProviderFactories;
+ public Evaluators(DefaultPolicyEvaluator policyEvaluator, Executor scheduler) {
this.policyEvaluator = policyEvaluator;
this.scheduler = scheduler;
}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/ScheduledPermissionEvaluator.java b/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/ScheduledPermissionEvaluator.java
index 13e08e4ebc..463050746d 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/ScheduledPermissionEvaluator.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/permission/evaluator/ScheduledPermissionEvaluator.java
@@ -17,11 +17,10 @@
*/
package org.keycloak.authorization.permission.evaluator;
-import org.keycloak.authorization.Decision;
-
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
+import org.keycloak.authorization.Decision;
+
/**
* @author Pedro Igor
* @see PermissionEvaluator
@@ -38,6 +37,6 @@ class ScheduledPermissionEvaluator implements PermissionEvaluator {
@Override
public void evaluate(Decision decision) {
- CompletableFuture.runAsync(() -> publisher.evaluate(decision), scheduler);
+ publisher.evaluate(decision);
}
}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResultCollector.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResultCollector.java
index abd3f935ce..286636057a 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResultCollector.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResultCollector.java
@@ -37,8 +37,10 @@ public abstract class DecisionResultCollector implements DecisionPedro Igor
*/
public class DefaultPolicyEvaluator implements PolicyEvaluator {
private final AuthorizationProvider authorization;
- private Map policyProviders = new HashMap<>();
+ private final StoreFactory storeFactory;
+ private final PolicyStore policyStore;
- public DefaultPolicyEvaluator(AuthorizationProvider authorization, List policyProviderFactories) {
+ public DefaultPolicyEvaluator(AuthorizationProvider authorization) {
this.authorization = authorization;
-
- for (PolicyProviderFactory providerFactory : policyProviderFactories) {
- this.policyProviders.put(providerFactory.getId(), providerFactory);
- }
+ storeFactory = this.authorization.getStoreFactory();
+ policyStore = storeFactory.getPolicyStore();
}
@Override
public void evaluate(ResourcePermission permission, EvaluationContext executionContext, Decision decision) {
ResourceServer resourceServer = permission.getResourceServer();
+ PolicyEnforcementMode enforcementMode = resourceServer.getPolicyEnforcementMode();
- if (PolicyEnforcementMode.DISABLED.equals(resourceServer.getPolicyEnforcementMode())) {
+ if (PolicyEnforcementMode.DISABLED.equals(enforcementMode)) {
createEvaluation(permission, executionContext, decision, null, null).grant();
return;
}
- StoreFactory storeFactory = this.authorization.getStoreFactory();
- PolicyStore policyStore = storeFactory.getPolicyStore();
- AtomicInteger policiesCount = new AtomicInteger(0);
- Consumer consumer = createDecisionConsumer(permission, executionContext, decision, policiesCount);
+ AtomicBoolean verified = new AtomicBoolean(false);
+ Consumer consumer = createDecisionConsumer(permission, executionContext, decision, verified);
Resource resource = permission.getResource();
+ List scopes = permission.getScopes();
if (resource != null) {
- List extends Policy> resourcePolicies = policyStore.findByResource(resource.getId());
-
- if (!resourcePolicies.isEmpty()) {
- resourcePolicies.forEach(consumer);
- }
+ evaluatePolicies(() -> policyStore.findByResource(resource.getId(), resourceServer.getId()), consumer);
if (resource.getType() != null) {
- policyStore.findByResourceType(resource.getType(), resourceServer.getId()).forEach(consumer);
+ evaluatePolicies(() -> policyStore.findByResourceType(resource.getType(), resourceServer.getId()), consumer);
}
- if (permission.getScopes().isEmpty() && !resource.getScopes().isEmpty()) {
- policyStore.findByScopeIds(resource.getScopes().stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId()).forEach(consumer);
+ if (scopes.isEmpty() && !resource.getScopes().isEmpty()) {
+ scopes.removeAll(resource.getScopes());
+ evaluatePolicies(() -> policyStore.findByScopeIds(resource.getScopes().stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId()), consumer);
}
}
- if (!permission.getScopes().isEmpty()) {
- policyStore.findByScopeIds(permission.getScopes().stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId()).forEach(consumer);
+ if (!scopes.isEmpty()) {
+ evaluatePolicies(() -> policyStore.findByScopeIds(scopes.stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId()), consumer);
}
- if (PolicyEnforcementMode.PERMISSIVE.equals(resourceServer.getPolicyEnforcementMode()) && policiesCount.get() == 0) {
+ if (PolicyEnforcementMode.PERMISSIVE.equals(enforcementMode) && verified.get()) {
createEvaluation(permission, executionContext, decision, null, null).grant();
}
}
- private Consumer createDecisionConsumer(ResourcePermission permission, EvaluationContext executionContext, Decision decision, AtomicInteger policiesCount) {
+ private void evaluatePolicies(Supplier> supplier, Consumer consumer) {
+ List policies = supplier.get();
+
+ if (!policies.isEmpty()) {
+ policies.forEach(consumer);
+ }
+ }
+
+ private Consumer createDecisionConsumer(ResourcePermission permission, EvaluationContext executionContext, Decision decision, AtomicBoolean verified) {
return (parentPolicy) -> {
- if (hasRequestedScopes(permission, parentPolicy)) {
- for (Policy associatedPolicy : parentPolicy.getAssociatedPolicies()) {
- PolicyProviderFactory providerFactory = policyProviders.get(associatedPolicy.getType());
-
- if (providerFactory == null) {
- throw new RuntimeException("Could not find a policy provider for policy type [" + associatedPolicy.getType() + "].");
- }
-
- PolicyProvider policyProvider = providerFactory.create(associatedPolicy, this.authorization);
-
- if (policyProvider == null) {
- throw new RuntimeException("Unknown parentPolicy provider for type [" + associatedPolicy.getType() + "].");
- }
-
- DefaultEvaluation evaluation = createEvaluation(permission, executionContext, decision, parentPolicy, associatedPolicy);
-
- policyProvider.evaluate(evaluation);
- evaluation.denyIfNoEffect();
-
- policiesCount.incrementAndGet();
- }
+ if (!hasRequestedScopes(permission, parentPolicy)) {
+ return;
}
+
+ for (Policy associatedPolicy : parentPolicy.getAssociatedPolicies()) {
+ PolicyProvider policyProvider = authorization.getProvider(associatedPolicy.getType());
+
+ if (policyProvider == null) {
+ throw new RuntimeException("Unknown parentPolicy provider for type [" + associatedPolicy.getType() + "].");
+ }
+
+ DefaultEvaluation evaluation = createEvaluation(permission, executionContext, decision, parentPolicy, associatedPolicy);
+
+ policyProvider.evaluate(evaluation);
+ evaluation.denyIfNoEffect();
+ }
+
+ verified.compareAndSet(false, true);
};
}
private DefaultEvaluation createEvaluation(ResourcePermission permission, EvaluationContext executionContext, Decision decision, Policy parentPolicy, Policy associatedPolicy) {
- return new DefaultEvaluation(permission, executionContext, parentPolicy, associatedPolicy, decision);
+ return new DefaultEvaluation(permission, executionContext, parentPolicy, associatedPolicy, decision, authorization);
}
private boolean hasRequestedScopes(final ResourcePermission permission, final Policy policy) {
@@ -136,7 +134,7 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
Set policyResources = policy.getResources();
if (resourcePermission != null && !policyResources.isEmpty()) {
- if (!policyResources.stream().filter(resource -> resource.getId().equals(resourcePermission.getId())).findFirst().isPresent()) {
+ if (!policyResources.stream().filter(resource -> resource.getId().equals(resourcePermission.getId())).findFirst().isPresent()) {
return false;
}
}
@@ -161,7 +159,7 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
String type = resource.getType();
if (type != null) {
- List resourcesByType = authorization.getStoreFactory().getResourceStore().findByType(type);
+ List resourcesByType = authorization.getStoreFactory().getResourceStore().findByType(type, resource.getResourceServer().getId());
for (Resource resourceType : resourcesByType) {
if (resourceType.getOwner().equals(resource.getResourceServer().getClientId())) {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
index f5b08682b7..4ac0264b34 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
@@ -18,6 +18,8 @@
package org.keycloak.authorization.policy.evaluation;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.permission.ResourcePermission;
/**
@@ -42,6 +44,15 @@ public interface Evaluation {
*/
EvaluationContext getContext();
+ /**
+ * Returns the {@link Policy}. being evaluated.
+ *
+ * @return the evaluation context
+ */
+ Policy getPolicy();
+
+ AuthorizationProvider getAuthorizationProvider();
+
/**
* Grants the requested permission to the caller.
*/
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
index f82bdb7573..f7041b58ae 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
@@ -32,7 +32,7 @@ public interface PolicyProviderFactory extends ProviderFactory {
String getGroup();
- PolicyProvider create(Policy policy, AuthorizationProvider authorization);
+ PolicyProvider create(AuthorizationProvider authorization);
PolicyProviderAdminService getAdminResource(ResourceServer resourceServer);
}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/PolicyStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/PolicyStore.java
index 51c7dd71ec..626e31704b 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/PolicyStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/PolicyStore.java
@@ -53,9 +53,10 @@ public interface PolicyStore {
* Returns a {@link Policy} with the given id
*
* @param id the identifier of the policy
+ * @param resourceServerId the resource server id
* @return a policy with the given identifier.
*/
- Policy findById(String id);
+ Policy findById(String id, String resourceServerId);
/**
* Returns a {@link Policy} with the given name
@@ -87,9 +88,10 @@ public interface PolicyStore {
* Returns a list of {@link Policy} associated with a {@link org.keycloak.authorization.core.model.Resource} with the given resourceId
.
*
* @param resourceId the identifier of a resource
+ * @param resourceServerId the resource server id
* @return a list of policies associated with the given resource
*/
- List findByResource(String resourceId);
+ List findByResource(String resourceId, String resourceServerId);
/**
* Returns a list of {@link Policy} associated with a {@link org.keycloak.authorization.core.model.Resource} with the given type
.
@@ -113,15 +115,26 @@ public interface PolicyStore {
* Returns a list of {@link Policy} with the given type
.
*
* @param type the type of the policy
+ * @param resourceServerId the resource server id
* @return a list of policies with the given type
*/
- List findByType(String type);
+ List findByType(String type, String resourceServerId);
/**
* Returns a list of {@link Policy} that depends on another policy with the given id
.
*
* @param id the id of the policy to query its dependents
+ * @param resourceServerId the resource server id
* @return a list of policies that depends on the a policy with the given identifier
*/
- List findDependentPolicies(String id);
+ List findDependentPolicies(String id, String resourceServerId);
+
+ /**
+ * Notify this store about changes to data associated with policies. E.g.: resources and scopes..
+ *
+ * TODO: need a better strategy to handle cross-references between stores, specially in cases where the store is caching data. Use some event-based solution here.
+ *
+ * @param cached
+ */
+ default void notifyChange(Object cached) {}
}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
index f06be7853f..e897664669 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
@@ -53,7 +53,7 @@ public interface ResourceStore {
* @param id the identifier of an existing resource instance
* @return the resource instance with the given identifier or null if no instance was found
*/
- Resource findById(String id);
+ Resource findById(String id, String resourceServerId);
/**
* Finds all {@link Resource} instances with the given {@code ownerId}.
@@ -61,7 +61,7 @@ public interface ResourceStore {
* @param ownerId the identifier of the owner
* @return a list with all resource instances owned by the given owner
*/
- List findByOwner(String ownerId);
+ List findByOwner(String ownerId, String resourceServerId);
/**
* Finds all {@link Resource} instances associated with a given resource server.
@@ -86,7 +86,7 @@ public interface ResourceStore {
* @param id one or more scope identifiers
* @return a list of resources associated with the given scope(s)
*/
- List findByScope(String... id);
+ List findByScope(List id, String resourceServerId);
/**
* Find a {@link Resource} by its name.
@@ -103,5 +103,5 @@ public interface ResourceStore {
* @param type the type of the resource
* @return a list of resources with the given type
*/
- List findByType(String type);
+ List findByType(String type, String resourceServerId);
}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/ScopeStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/ScopeStore.java
index 81a7064fc7..fa9e70d9af 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/ScopeStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/ScopeStore.java
@@ -53,17 +53,17 @@ public interface ScopeStore {
* Returns a {@link Scope} with the given id
*
* @param id the identifier of the scope
- *
+ * @param resourceServerId the resource server id
* @return a scope with the given identifier.
*/
- Scope findById(String id);
+ Scope findById(String id, String resourceServerId);
/**
* Returns a {@link Scope} with the given name
*
* @param name the name of the scope
*
- * @param resourceServerId
+ * @param resourceServerId the resource server id
* @return a scope with the given name.
*/
Scope findByName(String name, String resourceServerId);
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 4f0ef32cd6..ed24c53d50 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
@@ -36,7 +36,7 @@ public class RealmSynchronizer implements Synchronizer {
StoreFactory storeFactory = authorizationProvider.getStoreFactory();
event.getRealm().getClients().forEach(clientModel -> {
- ResourceServer resourceServer = storeFactory.getResourceServerStore().findByClient(clientModel.getClientId());
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findByClient(clientModel.getId());
if (resourceServer != null) {
String id = resourceServer.getId();
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java
index 01830ff07a..03a2cda718 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java
@@ -17,11 +17,16 @@
package org.keycloak.authorization.store.syncronization;
+import java.util.function.Consumer;
+
import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.UserRemovedEvent;
import org.keycloak.provider.ProviderFactory;
@@ -39,17 +44,25 @@ public class UserSynchronizer implements Synchronizer {
UserModel userModel = event.getUser();
ResourceStore resourceStore = storeFactory.getResourceStore();
PolicyStore policyStore = storeFactory.getPolicyStore();
+ ResourceServerStore resourceServerStore = storeFactory.getResourceServerStore();
+ RealmModel realm = event.getRealm();
- resourceStore.findByOwner(userModel.getId()).forEach(resource -> {
- String resourceId = resource.getId();
- policyStore.findByResource(resourceId).forEach(policy -> {
- if (policy.getResources().size() == 1) {
- policyStore.delete(policy.getId());
- } else {
- policy.removeResource(resource);
- }
- });
- resourceStore.delete(resourceId);
+ realm.getClients().forEach(clientModel -> {
+ ResourceServer resourceServer = resourceServerStore.findByClient(clientModel.getId());
+
+ if (resourceServer != null) {
+ resourceStore.findByOwner(userModel.getId(), resourceServer.getId()).forEach(resource -> {
+ String resourceId = resource.getId();
+ policyStore.findByResource(resourceId, resourceServer.getId()).forEach(policy -> {
+ if (policy.getResources().size() == 1) {
+ policyStore.delete(policy.getId());
+ } else {
+ policy.removeResource(resource);
+ }
+ });
+ resourceStore.delete(resourceId);
+ });
+ }
});
}
}
diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
index 995dafb3fb..f8844f15bb 100644
--- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
+++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
@@ -70,7 +70,7 @@ public class MigrateTo2_1_0 implements Migration {
ResourceServer resourceServer = storeFactory.getResourceServerStore().findByClient(clientModel.getId());
if (resourceServer != null) {
- policyStore.findByType("role").forEach(policy -> {
+ policyStore.findByType("role", resourceServer.getId()).forEach(policy -> {
Map config = policy.getConfig();
String roles = config.get("roles");
List roleConfig;
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 27dd6dc64f..b03f8e6055 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
@@ -17,14 +17,23 @@
package org.keycloak.models.utils;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
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.PolicyStore;
import org.keycloak.authorization.store.ResourceStore;
-import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time;
import org.keycloak.component.ComponentModel;
@@ -84,20 +93,6 @@ import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.storage.StorageId;
-import org.keycloak.util.JsonSerialization;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
/**
* @author Bill Burke
@@ -770,34 +765,16 @@ public class ModelToRepresentation {
}
public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider) {
+ return toRepresentation(model, authorizationProvider, true);
+ }
+
+ public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider, boolean deep) {
ScopeRepresentation scope = new ScopeRepresentation();
scope.setId(model.getId());
scope.setName(model.getName());
scope.setIconUri(model.getIconUri());
- StoreFactory storeFactory = authorizationProvider.getStoreFactory();
-
- scope.setResources(new ArrayList<>());
-
- storeFactory.getResourceStore().findByScope(model.getId()).forEach(resource -> scope.getResources().add(toRepresentation(resource, resource.getResourceServer(), authorizationProvider)));
-
- PolicyStore policyStore = storeFactory.getPolicyStore();
-
- scope.setPolicies(new ArrayList<>());
-
- policyStore.findByScopeIds(Arrays.asList(model.getId()), model.getResourceServer().getId()).forEach(policyModel -> {
- PolicyRepresentation policy = new PolicyRepresentation();
-
- policy.setId(policyModel.getId());
- policy.setName(policyModel.getName());
- policy.setType(policyModel.getType());
-
- if (!scope.getPolicies().contains(policy)) {
- scope.getPolicies().add(policy);
- }
- });
-
return scope;
}
@@ -813,7 +790,7 @@ public class ModelToRepresentation {
return server;
}
- public static PolicyRepresentation toRepresentation(Policy model, AuthorizationProvider authorization) {
+ public static PolicyRepresentation toRepresentation(Policy model) {
PolicyRepresentation representation = new PolicyRepresentation();
representation.setId(model.getId());
@@ -822,45 +799,16 @@ public class ModelToRepresentation {
representation.setType(model.getType());
representation.setDecisionStrategy(model.getDecisionStrategy());
representation.setLogic(model.getLogic());
- representation.setConfig(new HashMap<>(model.getConfig()));
-
- List policies = authorization.getStoreFactory().getPolicyStore().findDependentPolicies(model.getId());
-
- representation.setDependentPolicies(policies.stream().map(policy -> {
- PolicyRepresentation representation1 = new PolicyRepresentation();
-
- representation1.setId(policy.getId());
- representation1.setName(policy.getName());
-
- return representation1;
- }).collect(Collectors.toList()));
-
- List associatedPolicies = new ArrayList<>();
-
- List obj = model.getAssociatedPolicies().stream().map(policy -> {
- PolicyRepresentation representation1 = new PolicyRepresentation();
-
- representation1.setId(policy.getId());
- representation1.setName(policy.getName());
- representation1.setType(policy.getType());
-
- associatedPolicies.add(representation1);
-
- return policy.getId();
- }).collect(Collectors.toList());
-
- representation.setAssociatedPolicies(associatedPolicies);
-
- try {
- representation.getConfig().put("applyPolicies", JsonSerialization.writeValueAsString(obj));
- } catch (IOException e) {
- e.printStackTrace();
- }
+ representation.setConfig(model.getConfig());
return representation;
}
public static ResourceRepresentation toRepresentation(Resource model, ResourceServer resourceServer, AuthorizationProvider authorization) {
+ return toRepresentation(model, resourceServer, authorization, true);
+ }
+
+ public static ResourceRepresentation toRepresentation(Resource model, ResourceServer resourceServer, AuthorizationProvider authorization, Boolean deep) {
ResourceRepresentation resource = new ResourceRepresentation();
resource.setId(model.getId());
@@ -891,55 +839,36 @@ public class ModelToRepresentation {
resource.setOwner(owner);
- resource.setScopes(model.getScopes().stream().map(model1 -> {
- ScopeRepresentation scope = new ScopeRepresentation();
- scope.setId(model1.getId());
- scope.setName(model1.getName());
- String iconUri = model1.getIconUri();
- if (iconUri != null) {
- scope.setIconUri(iconUri);
- }
- return scope;
- }).collect(Collectors.toSet()));
-
- resource.setTypedScopes(new ArrayList<>());
-
- if (resource.getType() != null) {
- ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
- for (Resource typed : resourceStore.findByType(resource.getType())) {
- if (typed.getOwner().equals(resourceServer.getClientId()) && !typed.getId().equals(resource.getId())) {
- resource.setTypedScopes(typed.getScopes().stream().map(model1 -> {
- ScopeRepresentation scope = new ScopeRepresentation();
- scope.setId(model1.getId());
- scope.setName(model1.getName());
- String iconUri = model1.getIconUri();
- if (iconUri != null) {
- scope.setIconUri(iconUri);
- }
- return scope;
- }).filter(scopeRepresentation -> !resource.getScopes().contains(scopeRepresentation)).collect(Collectors.toList()));
+ if (deep) {
+ resource.setScopes(model.getScopes().stream().map(model1 -> {
+ ScopeRepresentation scope = new ScopeRepresentation();
+ scope.setId(model1.getId());
+ scope.setName(model1.getName());
+ String iconUri = model1.getIconUri();
+ if (iconUri != null) {
+ scope.setIconUri(iconUri);
}
- }
- }
+ return scope;
+ }).collect(Collectors.toSet()));
- resource.setPolicies(new ArrayList<>());
+ resource.setTypedScopes(new ArrayList<>());
- Set policies = new HashSet<>();
- PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
-
- policies.addAll(policyStore.findByResource(resource.getId()));
- policies.addAll(policyStore.findByResourceType(resource.getType(), resourceServer.getId()));
- policies.addAll(policyStore.findByScopeIds(resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toList()), resourceServer.getId()));
-
- for (Policy policyModel : policies) {
- PolicyRepresentation policy = new PolicyRepresentation();
-
- policy.setId(policyModel.getId());
- policy.setName(policyModel.getName());
- policy.setType(policyModel.getType());
-
- if (!resource.getPolicies().contains(policy)) {
- resource.getPolicies().add(policy);
+ if (resource.getType() != null) {
+ ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+ for (Resource typed : resourceStore.findByType(resource.getType(), resourceServer.getId())) {
+ if (typed.getOwner().equals(resourceServer.getClientId()) && !typed.getId().equals(resource.getId())) {
+ resource.setTypedScopes(typed.getScopes().stream().map(model1 -> {
+ ScopeRepresentation scope = new ScopeRepresentation();
+ scope.setId(model1.getId());
+ scope.setName(model1.getName());
+ String iconUri = model1.getIconUri();
+ if (iconUri != null) {
+ scope.setIconUri(iconUri);
+ }
+ return scope;
+ }).filter(scopeRepresentation -> !resource.getScopes().contains(scopeRepresentation)).collect(Collectors.toList()));
+ }
+ }
}
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index d8b934fef9..6b33ffb9d0 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -1894,7 +1894,7 @@ public class RepresentationToModel {
if (roles != null && !roles.isEmpty()) {
try {
- List