[KEYCLOAK-4913] - Caching more query methods
This commit is contained in:
parent
37a98fba20
commit
1d5bd2567e
18 changed files with 402 additions and 161 deletions
|
@ -92,7 +92,9 @@
|
||||||
<local-cache name="authenticationSessions"/>
|
<local-cache name="authenticationSessions"/>
|
||||||
<local-cache name="offlineSessions"/>
|
<local-cache name="offlineSessions"/>
|
||||||
<local-cache name="loginFailures"/>
|
<local-cache name="loginFailures"/>
|
||||||
<local-cache name="authorization"/>
|
<local-cache name="authorization">
|
||||||
|
<eviction max-entries="10000" strategy="LRU"/>
|
||||||
|
</local-cache>
|
||||||
<local-cache name="actionTokens"/>
|
<local-cache name="actionTokens"/>
|
||||||
<local-cache name="work"/>
|
<local-cache name="work"/>
|
||||||
<local-cache name="keys">
|
<local-cache name="keys">
|
||||||
|
|
|
@ -27,8 +27,6 @@ import org.keycloak.representations.idm.authorization.Logic;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -49,7 +47,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
||||||
@Override
|
@Override
|
||||||
public Policy getDelegateForUpdate() {
|
public Policy getDelegateForUpdate() {
|
||||||
if (updated == null) {
|
if (updated == null) {
|
||||||
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
|
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourcesIds(), cached.getResourceServerId());
|
||||||
updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
|
updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
|
||||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||||
}
|
}
|
||||||
|
@ -98,6 +96,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
||||||
@Override
|
@Override
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
|
cacheSession.registerPolicyInvalidation(cached.getId(), name, cached.getResourcesIds(), cached.getResourceServerId());
|
||||||
updated.setName(name);
|
updated.setName(name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -208,7 +207,6 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
||||||
public void addScope(Scope scope) {
|
public void addScope(Scope scope) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
updated.addScope(scope);
|
updated.addScope(scope);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -235,6 +233,9 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
||||||
@Override
|
@Override
|
||||||
public void addResource(Resource resource) {
|
public void addResource(Resource resource) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
|
HashSet<String> resources = new HashSet<>();
|
||||||
|
resources.add(resource.getId());
|
||||||
|
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getResourceServerId());
|
||||||
updated.addResource(resource);
|
updated.addResource(resource);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -242,6 +243,9 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
||||||
@Override
|
@Override
|
||||||
public void removeResource(Resource resource) {
|
public void removeResource(Resource resource) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
|
HashSet<String> resources = new HashSet<>();
|
||||||
|
resources.add(resource.getId());
|
||||||
|
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getResourceServerId());
|
||||||
updated.removeResource(resource);
|
updated.removeResource(resource);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
|
||||||
@Override
|
@Override
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
|
cacheSession.registerResourceInvalidation(cached.getId(), name, cached.getType(), cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
|
||||||
updated.setName(name);
|
updated.setName(name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -126,8 +127,8 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
|
||||||
@Override
|
@Override
|
||||||
public void setUri(String uri) {
|
public void setUri(String uri) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
|
cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), uri, cached.getScopesIds(), cached.getResourceServerId());
|
||||||
updated.setUri(uri);
|
updated.setUri(uri);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,6 +140,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
|
||||||
@Override
|
@Override
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
|
cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), type, cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
|
||||||
updated.setType(type);
|
updated.setType(type);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.models.cache.infinispan.CacheManager;
|
import org.keycloak.models.cache.infinispan.CacheManager;
|
||||||
import org.keycloak.models.cache.infinispan.RealmCacheManager;
|
import org.keycloak.models.cache.infinispan.RealmCacheManager;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.events.AuthorizationCacheInvalidationEvent;
|
import org.keycloak.models.cache.infinispan.authorization.events.AuthorizationCacheInvalidationEvent;
|
||||||
|
import org.keycloak.models.cache.infinispan.authorization.stream.InResourcePredicate;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.stream.InResourceServerPredicate;
|
import org.keycloak.models.cache.infinispan.authorization.stream.InResourceServerPredicate;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.stream.InScopePredicate;
|
import org.keycloak.models.cache.infinispan.authorization.stream.InScopePredicate;
|
||||||
import org.keycloak.models.cache.infinispan.entities.Revisioned;
|
import org.keycloak.models.cache.infinispan.entities.Revisioned;
|
||||||
|
@ -80,6 +81,7 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
|
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
|
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
|
||||||
|
addInvalidations(InResourcePredicate.create().resource(type), invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
|
@ -89,6 +91,7 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
if (scopes != null) {
|
if (scopes != null) {
|
||||||
for (String scope : scopes) {
|
for (String scope : scopes) {
|
||||||
invalidations.add(StoreFactoryCacheSession.getResourceByScopeCacheKey(scope, serverId));
|
invalidations.add(StoreFactoryCacheSession.getResourceByScopeCacheKey(scope, serverId));
|
||||||
|
addInvalidations(InScopePredicate.create().scope(scope), invalidations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,15 +99,22 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
public void resourceRemoval(String id, String name, String type, String uri, String owner, Set<String> scopes, String serverId, Set<String> invalidations) {
|
public void resourceRemoval(String id, String name, String type, String uri, String owner, Set<String> scopes, String serverId, Set<String> invalidations) {
|
||||||
resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
|
resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
|
||||||
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
|
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
|
||||||
|
addInvalidations(InResourcePredicate.create().resource(id), invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void policyUpdated(String id, String name, String serverId, Set<String> invalidations) {
|
public void policyUpdated(String id, String name, Set<String> resources, String serverId, Set<String> invalidations) {
|
||||||
invalidations.add(id);
|
invalidations.add(id);
|
||||||
invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
|
||||||
|
|
||||||
|
if (resources != null) {
|
||||||
|
for (String resource : resources) {
|
||||||
|
invalidations.add(StoreFactoryCacheSession.getPolicyByResource(resource, serverId));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void policyRemoval(String id, String name, String serverId, Set<String> invalidations) {
|
public void policyRemoval(String id, String name, Set<String> resources, String serverId, Set<String> invalidations) {
|
||||||
policyUpdated(id, name, serverId, invalidations);
|
policyUpdated(id, name, resources, serverId, invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,18 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.models.cache.infinispan.authorization;
|
package org.keycloak.models.cache.infinispan.authorization;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
import org.keycloak.authorization.model.Resource;
|
import org.keycloak.authorization.model.Resource;
|
||||||
|
@ -34,7 +46,11 @@ import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourc
|
||||||
import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
|
import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.entities.CachedScope;
|
import org.keycloak.models.cache.infinispan.authorization.entities.CachedScope;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.entities.PolicyListQuery;
|
import org.keycloak.models.cache.infinispan.authorization.entities.PolicyListQuery;
|
||||||
|
import org.keycloak.models.cache.infinispan.authorization.entities.PolicyQuery;
|
||||||
|
import org.keycloak.models.cache.infinispan.authorization.entities.PolicyResourceListQuery;
|
||||||
|
import org.keycloak.models.cache.infinispan.authorization.entities.PolicyScopeListQuery;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceListQuery;
|
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceListQuery;
|
||||||
|
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceQuery;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceScopeListQuery;
|
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceScopeListQuery;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceServerListQuery;
|
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceServerListQuery;
|
||||||
import org.keycloak.models.cache.infinispan.authorization.entities.ScopeListQuery;
|
import org.keycloak.models.cache.infinispan.authorization.entities.ScopeListQuery;
|
||||||
|
@ -49,17 +65,6 @@ import org.keycloak.models.cache.infinispan.authorization.events.ScopeUpdatedEve
|
||||||
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
|
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
|
||||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -247,12 +252,12 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uri, scopes, serverId));
|
invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uri, scopes, serverId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPolicyInvalidation(String id, String name, String serverId) {
|
public void registerPolicyInvalidation(String id, String name, Set<String> resources, String serverId) {
|
||||||
cache.policyUpdated(id, name, serverId, invalidations);
|
cache.policyUpdated(id, name, resources, serverId, invalidations);
|
||||||
PolicyAdapter adapter = managedPolicies.get(id);
|
PolicyAdapter adapter = managedPolicies.get(id);
|
||||||
if (adapter != null) adapter.invalidateFlag();
|
if (adapter != null) adapter.invalidateFlag();
|
||||||
|
|
||||||
invalidationEvents.add(PolicyUpdatedEvent.create(id, name, serverId));
|
invalidationEvents.add(PolicyUpdatedEvent.create(id, name, resources, serverId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceServerStore getResourceServerStoreDelegate() {
|
public ResourceServerStore getResourceServerStoreDelegate() {
|
||||||
|
@ -303,6 +308,18 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
return "policy.name." + name + "." + serverId;
|
return "policy.name." + name + "." + serverId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPolicyByResource(String resourceId, String serverId) {
|
||||||
|
return "policy.resource." + resourceId + "." + serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPolicyByResourceType(String type, String serverId) {
|
||||||
|
return "policy.resource.type." + type + "." + serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPolicyByScope(String scope, String serverId) {
|
||||||
|
return "policy.scope." + scope + "." + serverId;
|
||||||
|
}
|
||||||
|
|
||||||
public StoreFactory getDelegate() {
|
public StoreFactory getDelegate() {
|
||||||
if (delegate != null) return delegate;
|
if (delegate != null) return delegate;
|
||||||
delegate = session.getProvider(StoreFactory.class);
|
delegate = session.getProvider(StoreFactory.class);
|
||||||
|
@ -520,73 +537,37 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
public Resource findByName(String name, String resourceServerId) {
|
public Resource findByName(String name, String resourceServerId) {
|
||||||
if (name == null) return null;
|
if (name == null) return null;
|
||||||
String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
|
String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
|
||||||
ResourceListQuery query = cache.get(cacheKey, ResourceListQuery.class);
|
List<Resource> result = cacheQuery(cacheKey, ResourceListQuery.class, () -> {
|
||||||
if (query != null) {
|
Resource resource = getResourceStoreDelegate().findByName(name, resourceServerId);
|
||||||
logger.tracev("resource by name cache hit: {0}", name);
|
|
||||||
}
|
if (resource == null) {
|
||||||
if (query == null) {
|
return Collections.emptyList();
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
|
||||||
Resource model = getResourceStoreDelegate().findByName(name, resourceServerId);
|
|
||||||
if (model == null) return null;
|
|
||||||
if (invalidations.contains(model.getId())) return model;
|
|
||||||
query = new ResourceListQuery(loaded, cacheKey, model.getId(), resourceServerId);
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
return model;
|
|
||||||
} else if (invalidations.contains(cacheKey)) {
|
|
||||||
return getResourceStoreDelegate().findByName(name, resourceServerId);
|
|
||||||
} else {
|
|
||||||
String id = query.getResources().iterator().next();
|
|
||||||
if (invalidations.contains(id)) {
|
|
||||||
return getResourceStoreDelegate().findByName(name, resourceServerId);
|
|
||||||
}
|
}
|
||||||
return findById(id, query.getResourceServerId());
|
|
||||||
|
return Arrays.asList(resource);
|
||||||
|
},
|
||||||
|
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
|
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
|
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
|
||||||
if (ownerId == null) return null;
|
|
||||||
String cacheKey = getResourceByOwnerCacheKey(ownerId, resourceServerId);
|
String cacheKey = getResourceByOwnerCacheKey(ownerId, resourceServerId);
|
||||||
ResourceListQuery query = cache.get(cacheKey, ResourceListQuery.class);
|
return cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByOwner(ownerId, resourceServerId),
|
||||||
if (query != null) {
|
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
logger.tracev("resource by owner cache hit: {0}", ownerId);
|
|
||||||
}
|
|
||||||
if (query == null) {
|
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
|
||||||
List<Resource> model = getResourceStoreDelegate().findByOwner(ownerId, resourceServerId);
|
|
||||||
if (model == null) return null;
|
|
||||||
if (invalidations.contains(cacheKey)) return model;
|
|
||||||
query = new ResourceListQuery(loaded, cacheKey, model.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId);
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
return model;
|
|
||||||
} else if (invalidations.contains(cacheKey)) {
|
|
||||||
return getResourceStoreDelegate().findByOwner(ownerId, resourceServerId);
|
|
||||||
} else {
|
|
||||||
return query.getResources().stream().map(resourceId -> findById(resourceId, resourceServerId)).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Resource> findByUri(String uri, String resourceServerId) {
|
public List<Resource> findByUri(String uri, String resourceServerId) {
|
||||||
if (uri == null) return null;
|
if (uri == null) return null;
|
||||||
String cacheKey = getResourceByUriCacheKey(uri, resourceServerId);
|
String cacheKey = getResourceByUriCacheKey(uri, resourceServerId);
|
||||||
ResourceListQuery query = cache.get(cacheKey, ResourceListQuery.class);
|
return cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByUri(uri, resourceServerId),
|
||||||
if (query != null) {
|
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
logger.tracev("resource by uri cache hit: {0}", uri);
|
|
||||||
}
|
|
||||||
if (query == null) {
|
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
|
||||||
List<Resource> model = getResourceStoreDelegate().findByUri(uri, resourceServerId);
|
|
||||||
if (model == null) return null;
|
|
||||||
if (invalidations.contains(cacheKey)) return model;
|
|
||||||
query = new ResourceListQuery(loaded, cacheKey, model.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId);
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
return model;
|
|
||||||
} else if (invalidations.contains(cacheKey)) {
|
|
||||||
return getResourceStoreDelegate().findByUri(uri, resourceServerId);
|
|
||||||
} else {
|
|
||||||
return query.getResources().stream().map(resourceId -> findById(resourceId, resourceServerId)).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -603,30 +584,10 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
public List<Resource> findByScope(List<String> ids, String resourceServerId) {
|
public List<Resource> findByScope(List<String> ids, String resourceServerId) {
|
||||||
if (ids == null) return null;
|
if (ids == null) return null;
|
||||||
List<Resource> result = new ArrayList<>();
|
List<Resource> result = new ArrayList<>();
|
||||||
Iterator<String> iterator = ids.iterator();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
for (String id : ids) {
|
||||||
String id = iterator.next();
|
|
||||||
String cacheKey = getResourceByScopeCacheKey(id, resourceServerId);
|
String cacheKey = getResourceByScopeCacheKey(id, resourceServerId);
|
||||||
ResourceScopeListQuery query = cache.get(cacheKey, ResourceScopeListQuery.class);
|
result.addAll(cacheQuery(cacheKey, ResourceScopeListQuery.class, () -> getResourceStoreDelegate().findByScope(Arrays.asList(id), resourceServerId), (revision, resources) -> new ResourceScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId));
|
||||||
if (query != null) {
|
|
||||||
logger.tracev("resource by scope cache hit: {0}", id);
|
|
||||||
if (invalidations.contains(cacheKey)) {
|
|
||||||
result.addAll(getResourceStoreDelegate().findByScope(ids, resourceServerId));
|
|
||||||
} else {
|
|
||||||
result.addAll(query.getResources().stream().map(resourceId -> findById(resourceId, resourceServerId)).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
} else if (invalidations.contains(id)) {
|
|
||||||
result.addAll(getResourceStoreDelegate().findByScope(ids, resourceServerId));
|
|
||||||
} else {
|
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
|
||||||
List<Resource> model = getResourceStoreDelegate().findByScope(Arrays.asList(id), resourceServerId);
|
|
||||||
if (model == null) return null;
|
|
||||||
if (invalidations.contains(cacheKey)) return model;
|
|
||||||
query = new ResourceScopeListQuery(loaded, cacheKey, id, model.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId);
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
result.addAll(query.getResources().stream().map(resourceId -> findById(resourceId, resourceServerId)).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -636,32 +597,37 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
public List<Resource> findByType(String type, String resourceServerId) {
|
public List<Resource> findByType(String type, String resourceServerId) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
String cacheKey = getResourceByTypeCacheKey(type, resourceServerId);
|
String cacheKey = getResourceByTypeCacheKey(type, resourceServerId);
|
||||||
ResourceListQuery query = cache.get(cacheKey, ResourceListQuery.class);
|
return cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByType(type, resourceServerId),
|
||||||
if (query != null) {
|
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
logger.tracev("resource by type cache hit: {0}", type);
|
}
|
||||||
}
|
|
||||||
if (query == null) {
|
private <R, Q extends ResourceQuery> List<R> cacheQuery(String cacheKey, Class<Q> queryType, Supplier<List<R>> resultSupplier, BiFunction<Long, List<R>, Q> querySupplier, String resourceServerId) {
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
Q query = cache.get(cacheKey, queryType);
|
||||||
List<Resource> model = getResourceStoreDelegate().findByType(type, resourceServerId);
|
if (query != null) {
|
||||||
if (model == null) return null;
|
logger.tracev("cache hit for key: {0}", cacheKey);
|
||||||
if (invalidations.contains(cacheKey)) return model;
|
}
|
||||||
query = new ResourceListQuery(loaded, cacheKey, model.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId);
|
if (query == null) {
|
||||||
cache.addRevisioned(query, startupRevision);
|
Long loaded = cache.getCurrentRevision(cacheKey);
|
||||||
return model;
|
List<R> model = resultSupplier.get();
|
||||||
} else if (invalidations.contains(cacheKey)) {
|
if (model == null) return null;
|
||||||
return getResourceStoreDelegate().findByType(type, resourceServerId);
|
if (invalidations.contains(cacheKey)) return model;
|
||||||
} else {
|
query = querySupplier.apply(loaded, model);
|
||||||
return query.getResources().stream().map(resourceId -> findById(resourceId, resourceServerId)).collect(Collectors.toList());
|
cache.addRevisioned(query, startupRevision);
|
||||||
}
|
return model;
|
||||||
|
} else if (query.isInvalid(invalidations)) {
|
||||||
|
return resultSupplier.get();
|
||||||
|
} else {
|
||||||
|
return query.getResources().stream().map(resourceId -> (R) findById(resourceId, resourceServerId)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class PolicyCache implements PolicyStore {
|
protected class PolicyCache implements PolicyStore {
|
||||||
@Override
|
@Override
|
||||||
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
||||||
Policy resource = getPolicyStoreDelegate().create(representation, resourceServer);
|
Policy policy = getPolicyStoreDelegate().create(representation, resourceServer);
|
||||||
registerPolicyInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
|
registerPolicyInvalidation(policy.getId(), policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), resourceServer.getId());
|
||||||
return resource;
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -671,8 +637,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
if (policy == null) return;
|
if (policy == null) return;
|
||||||
|
|
||||||
cache.invalidateObject(id);
|
cache.invalidateObject(id);
|
||||||
invalidationEvents.add(PolicyRemovedEvent.create(id, policy.getName(), policy.getResourceServer().getId()));
|
invalidationEvents.add(PolicyRemovedEvent.create(id, policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), policy.getResourceServer().getId()));
|
||||||
cache.policyRemoval(id, policy.getName(), policy.getResourceServer().getId(), invalidations);
|
cache.policyRemoval(id, policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), policy.getResourceServer().getId(), invalidations);
|
||||||
getPolicyStoreDelegate().delete(id);
|
getPolicyStoreDelegate().delete(id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -708,27 +674,22 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
public Policy findByName(String name, String resourceServerId) {
|
public Policy findByName(String name, String resourceServerId) {
|
||||||
if (name == null) return null;
|
if (name == null) return null;
|
||||||
String cacheKey = getPolicyByNameCacheKey(name, resourceServerId);
|
String cacheKey = getPolicyByNameCacheKey(name, resourceServerId);
|
||||||
PolicyListQuery query = cache.get(cacheKey, PolicyListQuery.class);
|
List<Policy> result = cacheQuery(cacheKey, PolicyListQuery.class, () -> {
|
||||||
if (query != null) {
|
Policy policy = getPolicyStoreDelegate().findByName(name, resourceServerId);
|
||||||
logger.tracev("policy by name cache hit: {0}", name);
|
|
||||||
}
|
if (policy == null) {
|
||||||
if (query == null) {
|
return Collections.emptyList();
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
|
||||||
Policy model = getPolicyStoreDelegate().findByName(name, resourceServerId);
|
|
||||||
if (model == null) return null;
|
|
||||||
if (invalidations.contains(model.getId())) return model;
|
|
||||||
query = new PolicyListQuery(loaded, cacheKey, model.getId(), resourceServerId);
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
return model;
|
|
||||||
} else if (invalidations.contains(cacheKey)) {
|
|
||||||
return getPolicyStoreDelegate().findByName(name, resourceServerId);
|
|
||||||
} else {
|
|
||||||
String id = query.getPolicies().iterator().next();
|
|
||||||
if (invalidations.contains(id)) {
|
|
||||||
return getPolicyStoreDelegate().findByName(name, resourceServerId);
|
|
||||||
}
|
}
|
||||||
return findById(id, query.getResourceServerId());
|
|
||||||
|
return Arrays.asList(policy);
|
||||||
|
},
|
||||||
|
(revision, policies) -> new PolicyListQuery(revision, cacheKey, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
|
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -743,17 +704,29 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Policy> findByResource(String resourceId, String resourceServerId) {
|
public List<Policy> findByResource(String resourceId, String resourceServerId) {
|
||||||
return getPolicyStoreDelegate().findByResource(resourceId, resourceServerId);
|
String cacheKey = getPolicyByResource(resourceId, resourceServerId);
|
||||||
|
return cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> getPolicyStoreDelegate().findByResource(resourceId, resourceServerId),
|
||||||
|
(revision, policies) -> new PolicyResourceListQuery(revision, cacheKey, resourceId, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
|
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
|
||||||
return getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId);
|
String cacheKey = getPolicyByResourceType(resourceType, resourceServerId);
|
||||||
|
return cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId),
|
||||||
|
(revision, policies) -> new PolicyResourceListQuery(revision, cacheKey, resourceType, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
|
public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
|
||||||
return getPolicyStoreDelegate().findByScopeIds(scopeIds, resourceServerId);
|
if (scopeIds == null) return null;
|
||||||
|
List<Policy> result = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String id : scopeIds) {
|
||||||
|
String cacheKey = getPolicyByScope(id, resourceServerId);
|
||||||
|
result.addAll(cacheQuery(cacheKey, PolicyScopeListQuery.class, () -> getPolicyStoreDelegate().findByScopeIds(Arrays.asList(id), resourceServerId), (revision, resources) -> new PolicyScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -765,6 +738,26 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
public List<Policy> findDependentPolicies(String id, String resourceServerId) {
|
public List<Policy> findDependentPolicies(String id, String resourceServerId) {
|
||||||
return getPolicyStoreDelegate().findDependentPolicies(id, resourceServerId);
|
return getPolicyStoreDelegate().findDependentPolicies(id, resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <R, Q extends PolicyQuery> List<R> cacheQuery(String cacheKey, Class<Q> queryType, Supplier<List<R>> resultSupplier, BiFunction<Long, List<R>, Q> querySupplier, String resourceServerId) {
|
||||||
|
Q query = cache.get(cacheKey, queryType);
|
||||||
|
if (query != null) {
|
||||||
|
logger.tracev("cache hit for key: {0}", cacheKey);
|
||||||
|
}
|
||||||
|
if (query == null) {
|
||||||
|
Long loaded = cache.getCurrentRevision(cacheKey);
|
||||||
|
List<R> model = resultSupplier.get();
|
||||||
|
if (model == null) return null;
|
||||||
|
if (invalidations.contains(cacheKey)) return model;
|
||||||
|
query = querySupplier.apply(loaded, model);
|
||||||
|
cache.addRevisioned(query, startupRevision);
|
||||||
|
return model;
|
||||||
|
} else if (query.isInvalid(invalidations)) {
|
||||||
|
return resultSupplier.get();
|
||||||
|
} else {
|
||||||
|
return query.getPolicies().stream().map(resourceId -> (R) findById(resourceId, resourceServerId)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.models.cache.infinispan.authorization.entities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public interface InResource {
|
||||||
|
String getResourceId();
|
||||||
|
}
|
|
@ -16,11 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.models.cache.infinispan.authorization.entities;
|
package org.keycloak.models.cache.infinispan.authorization.entities;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
*/
|
||||||
public interface InScope {
|
public interface InScope {
|
||||||
String getScopeId();
|
String getScopeId();
|
||||||
|
|
|
@ -9,7 +9,7 @@ import java.util.Set;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class PolicyListQuery extends AbstractRevisioned implements InResourceServer {
|
public class PolicyListQuery extends AbstractRevisioned implements PolicyQuery {
|
||||||
private final Set<String> policies;
|
private final Set<String> policies;
|
||||||
private final String serverId;
|
private final String serverId;
|
||||||
|
|
||||||
|
@ -33,4 +33,9 @@ public class PolicyListQuery extends AbstractRevisioned implements InResourceSer
|
||||||
public Set<String> getPolicies() {
|
public Set<String> getPolicies() {
|
||||||
return policies;
|
return policies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvalid(Set<String> invalidations) {
|
||||||
|
return invalidations.contains(getId()) || invalidations.contains(getResourceServerId());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.models.cache.infinispan.authorization.entities;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.keycloak.models.cache.infinispan.entities.Revisioned;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public interface PolicyQuery extends InResourceServer, Revisioned {
|
||||||
|
|
||||||
|
Set<String> getPolicies();
|
||||||
|
boolean isInvalid(Set<String> invalidations);
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.models.cache.infinispan.authorization.entities;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class PolicyResourceListQuery extends PolicyListQuery implements InResource {
|
||||||
|
|
||||||
|
private final String resourceId;
|
||||||
|
|
||||||
|
public PolicyResourceListQuery(Long revision, String id, String resourceId, Set<String> policies, String serverId) {
|
||||||
|
super(revision, id, policies, serverId);
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvalid(Set<String> invalidations) {
|
||||||
|
return super.isInvalid(invalidations) || invalidations.contains(getResourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResourceId() {
|
||||||
|
return resourceId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.models.cache.infinispan.authorization.entities;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class PolicyScopeListQuery extends PolicyListQuery implements InScope {
|
||||||
|
|
||||||
|
private final String scopeId;
|
||||||
|
|
||||||
|
public PolicyScopeListQuery(Long revision, String id, String scopeId, Set<String> resources, String serverId) {
|
||||||
|
super(revision, id, resources, serverId);
|
||||||
|
this.scopeId = scopeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getScopeId() {
|
||||||
|
return scopeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvalid(Set<String> invalidations) {
|
||||||
|
return super.isInvalid(invalidations) || invalidations.contains(getScopeId());
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import java.util.Set;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class ResourceListQuery extends AbstractRevisioned implements InResourceServer {
|
public class ResourceListQuery extends AbstractRevisioned implements ResourceQuery, InResourceServer {
|
||||||
private final Set<String> resources;
|
private final Set<String> resources;
|
||||||
private final String serverId;
|
private final String serverId;
|
||||||
|
|
||||||
|
@ -33,4 +33,9 @@ public class ResourceListQuery extends AbstractRevisioned implements InResourceS
|
||||||
public Set<String> getResources() {
|
public Set<String> getResources() {
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvalid(Set<String> invalidations) {
|
||||||
|
return invalidations.contains(getId()) || invalidations.contains(getResourceServerId());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.models.cache.infinispan.authorization.entities;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.keycloak.models.cache.infinispan.entities.Revisioned;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public interface ResourceQuery extends Revisioned {
|
||||||
|
|
||||||
|
Set<String> getResources();
|
||||||
|
boolean isInvalid(Set<String> invalidations);
|
||||||
|
}
|
|
@ -1,13 +1,9 @@
|
||||||
package org.keycloak.models.cache.infinispan.authorization.entities;
|
package org.keycloak.models.cache.infinispan.authorization.entities;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
*/
|
||||||
public class ResourceScopeListQuery extends ResourceListQuery implements InScope {
|
public class ResourceScopeListQuery extends ResourceListQuery implements InScope {
|
||||||
|
|
||||||
|
@ -22,4 +18,9 @@ public class ResourceScopeListQuery extends ResourceListQuery implements InScope
|
||||||
public String getScopeId() {
|
public String getScopeId() {
|
||||||
return scopeId;
|
return scopeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvalid(Set<String> invalidations) {
|
||||||
|
return super.isInvalid(invalidations) || invalidations.contains(getScopeId());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
package org.keycloak.models.cache.infinispan.authorization.events;
|
package org.keycloak.models.cache.infinispan.authorization.events;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
|
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
|
||||||
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
|
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
@ -29,12 +29,14 @@ public class PolicyRemovedEvent extends InvalidationEvent implements Authorizati
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
|
private Set<String> resources;
|
||||||
private String serverId;
|
private String serverId;
|
||||||
|
|
||||||
public static PolicyRemovedEvent create(String id, String name, String serverId) {
|
public static PolicyRemovedEvent create(String id, String name, Set<String> resources, String serverId) {
|
||||||
PolicyRemovedEvent event = new PolicyRemovedEvent();
|
PolicyRemovedEvent event = new PolicyRemovedEvent();
|
||||||
event.id = id;
|
event.id = id;
|
||||||
event.name = name;
|
event.name = name;
|
||||||
|
event.resources = resources;
|
||||||
event.serverId = serverId;
|
event.serverId = serverId;
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +53,6 @@ public class PolicyRemovedEvent extends InvalidationEvent implements Authorizati
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
||||||
cache.policyRemoval(id, name, serverId, invalidations);
|
cache.policyRemoval(id, name, resources, serverId, invalidations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,14 @@ public class PolicyUpdatedEvent extends InvalidationEvent implements Authorizati
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
|
private static Set<String> resources;
|
||||||
private String serverId;
|
private String serverId;
|
||||||
|
|
||||||
public static PolicyUpdatedEvent create(String id, String name, String serverId) {
|
public static PolicyUpdatedEvent create(String id, String name, Set<String> resources, String serverId) {
|
||||||
PolicyUpdatedEvent event = new PolicyUpdatedEvent();
|
PolicyUpdatedEvent event = new PolicyUpdatedEvent();
|
||||||
event.id = id;
|
event.id = id;
|
||||||
event.name = name;
|
event.name = name;
|
||||||
|
event.resources = resources;
|
||||||
event.serverId = serverId;
|
event.serverId = serverId;
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +53,6 @@ public class PolicyUpdatedEvent extends InvalidationEvent implements Authorizati
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
||||||
cache.policyUpdated(id, name, serverId, invalidations);
|
cache.policyUpdated(id, name, resources, serverId, invalidations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.models.cache.infinispan.authorization.stream;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import org.keycloak.models.cache.infinispan.authorization.entities.InResource;
|
||||||
|
import org.keycloak.models.cache.infinispan.entities.Revisioned;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class InResourcePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
|
||||||
|
|
||||||
|
private String resourceId;
|
||||||
|
|
||||||
|
public static InResourcePredicate create() {
|
||||||
|
return new InResourcePredicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InResourcePredicate resource(String id) {
|
||||||
|
resourceId = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Map.Entry<String, Revisioned> entry) {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value == null) return false;
|
||||||
|
if (!(value instanceof InResource)) return false;
|
||||||
|
|
||||||
|
return resourceId.equals(((InResource)value).getResourceId());
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,7 @@
|
||||||
<local-cache name="loginFailures"/>
|
<local-cache name="loginFailures"/>
|
||||||
<local-cache name="work"/>
|
<local-cache name="work"/>
|
||||||
<local-cache name="authorization">
|
<local-cache name="authorization">
|
||||||
<eviction max-entries="100" strategy="LRU"/>
|
<eviction max-entries="10000" strategy="LRU"/>
|
||||||
</local-cache>
|
</local-cache>
|
||||||
<local-cache name="keys">
|
<local-cache name="keys">
|
||||||
<eviction max-entries="1000" strategy="LRU"/>
|
<eviction max-entries="1000" strategy="LRU"/>
|
||||||
|
|
Loading…
Reference in a new issue