[KEYCLOAK-4125] - Fixing when running in a cluster
This commit is contained in:
parent
3e8d4e4eb6
commit
df7a68b709
9 changed files with 98 additions and 135 deletions
|
@ -21,6 +21,7 @@ package org.keycloak.models.authorization.infinispan;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -51,7 +52,7 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
|
|
||||||
private static final String POLICY_ID_CACHE_PREFIX = "policy-id-";
|
private static final String POLICY_ID_CACHE_PREFIX = "policy-id-";
|
||||||
|
|
||||||
private final Cache<String, List<CachedPolicy>> cache;
|
private final Cache<String, Map<String, List<CachedPolicy>>> cache;
|
||||||
private final KeycloakSession session;
|
private final KeycloakSession session;
|
||||||
private final CacheTransaction transaction;
|
private final CacheTransaction transaction;
|
||||||
private final List<String> cacheKeys;
|
private final List<String> cacheKeys;
|
||||||
|
@ -78,7 +79,7 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
String id = policy.getId();
|
String id = policy.getId();
|
||||||
|
|
||||||
this.transaction.whenRollback(() -> {
|
this.transaction.whenRollback(() -> {
|
||||||
cache.remove(getCacheKeyForPolicy(id));
|
resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForPolicy(id));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.transaction.whenCommit(() -> {
|
this.transaction.whenCommit(() -> {
|
||||||
|
@ -90,14 +91,13 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(String id) {
|
public void delete(String id) {
|
||||||
Policy policy = findById(id, null);
|
Policy policy = getDelegate().findById(id, null);
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ResourceServer resourceServer = policy.getResourceServer();
|
ResourceServer resourceServer = policy.getResourceServer();
|
||||||
getDelegate().delete(id);
|
getDelegate().delete(id);
|
||||||
this.transaction.whenCommit(() -> {
|
this.transaction.whenCommit(() -> {
|
||||||
cache.remove(getCacheKeyForPolicy(id));
|
|
||||||
invalidateCache(resourceServer.getId());
|
invalidateCache(resourceServer.getId());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -105,13 +105,15 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
@Override
|
@Override
|
||||||
public Policy findById(String id, String resourceServerId) {
|
public Policy findById(String id, String resourceServerId) {
|
||||||
String cacheKeyForPolicy = getCacheKeyForPolicy(id);
|
String cacheKeyForPolicy = getCacheKeyForPolicy(id);
|
||||||
List<CachedPolicy> cached = this.cache.get(cacheKeyForPolicy);
|
List<CachedPolicy> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForPolicy);
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
Policy policy = getDelegate().findById(id, resourceServerId);
|
Policy policy = getDelegate().findById(id, resourceServerId);
|
||||||
|
|
||||||
if (policy != null) {
|
if (policy != null) {
|
||||||
return createAdapter(updatePolicyCache(policy));
|
CachedPolicy cachedPolicy = new CachedPolicy(policy);
|
||||||
|
resolveResourceServerCache(resourceServerId).put(cacheKeyForPolicy, Arrays.asList(cachedPolicy));
|
||||||
|
return createAdapter(cachedPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -137,12 +139,12 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Policy> findByResource(String resourceId, String resourceServerId) {
|
public List<Policy> findByResource(String resourceId, String resourceServerId) {
|
||||||
return cacheResult(new StringBuilder("findByResource").append(resourceServerId).append(resourceId).toString(), () -> getDelegate().findByResource(resourceId, resourceServerId));
|
return cacheResult(resourceServerId, new StringBuilder("findByResource").append(resourceId).toString(), () -> getDelegate().findByResource(resourceId, resourceServerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
|
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
|
||||||
return cacheResult(new StringBuilder("findByResourceType").append(resourceServerId).append(resourceType).toString(), () -> getDelegate().findByResourceType(resourceType, resourceServerId));
|
return cacheResult(resourceServerId, new StringBuilder("findByResourceType").append(resourceType).toString(), () -> getDelegate().findByResourceType(resourceType, resourceServerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -150,7 +152,7 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
List<Policy> policies = new ArrayList<>();
|
List<Policy> policies = new ArrayList<>();
|
||||||
|
|
||||||
for (String scopeId : scopeIds) {
|
for (String scopeId : scopeIds) {
|
||||||
policies.addAll(cacheResult(new StringBuilder("findByScopeIds").append(resourceServerId).append(scopeId).toString(), () -> getDelegate().findByScopeIds(Arrays.asList(scopeId), resourceServerId)));
|
policies.addAll(cacheResult(resourceServerId, new StringBuilder("findByScopeIds").append(scopeId).toString(), () -> getDelegate().findByScopeIds(Arrays.asList(scopeId), resourceServerId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return policies;
|
return policies;
|
||||||
|
@ -158,7 +160,7 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Policy> findByType(String type, String resourceServerId) {
|
public List<Policy> findByType(String type, String resourceServerId) {
|
||||||
return cacheResult(new StringBuilder("findByType").append(resourceServerId).append(type).toString(), () -> getDelegate().findByType(type, resourceServerId));
|
return cacheResult(resourceServerId, new StringBuilder("findByType").append(type).toString(), () -> getDelegate().findByType(type, resourceServerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -388,11 +390,10 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
|
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
|
||||||
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
||||||
transaction.whenCommit(() -> {
|
transaction.whenCommit(() -> {
|
||||||
cache.remove(getCacheKeyForPolicy(getId()));
|
|
||||||
invalidateCache(cached.getResourceServerId());
|
invalidateCache(cached.getResourceServerId());
|
||||||
});
|
});
|
||||||
transaction.whenRollback(() -> {
|
transaction.whenRollback(() -> {
|
||||||
cache.remove(getCacheKeyForPolicy(getId()));
|
resolveResourceServerCache(cached.getResourceServerId()).remove(getCacheKeyForPolicy(getId()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,23 +409,12 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
return cachedStoreFactory;
|
return cachedStoreFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CachedPolicy updatePolicyCache(Policy policy) {
|
|
||||||
CachedPolicy cached = new CachedPolicy(policy);
|
|
||||||
List<CachedPolicy> cache = new ArrayList<>();
|
|
||||||
|
|
||||||
cache.add(cached);
|
|
||||||
|
|
||||||
this.cache.put(getCacheKeyForPolicy(policy.getId()), cache);
|
|
||||||
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invalidateCache(String resourceServerId) {
|
private void invalidateCache(String resourceServerId) {
|
||||||
cacheKeys.forEach(cacheKey -> cache.keySet().stream().filter(key -> key.startsWith(cacheKey + resourceServerId)).forEach(cache::remove));
|
cache.remove(resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Policy> cacheResult(String key, Supplier<List<Policy>> provider) {
|
private List<Policy> cacheResult(String resourceServerId, String key, Supplier<List<Policy>> provider) {
|
||||||
List<CachedPolicy> cached = cache.computeIfAbsent(key, (Function<String, List<CachedPolicy>>) o -> {
|
List<CachedPolicy> cached = resolveResourceServerCache(resourceServerId).computeIfAbsent(key, (Function<String, List<CachedPolicy>>) o -> {
|
||||||
List<Policy> result = provider.get();
|
List<Policy> result = provider.get();
|
||||||
|
|
||||||
if (result.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
|
@ -440,4 +430,8 @@ public class CachedPolicyStore implements PolicyStore {
|
||||||
|
|
||||||
return cached.stream().map(cachedPolicy -> createAdapter(cachedPolicy)).collect(Collectors.toList());
|
return cached.stream().map(cachedPolicy -> createAdapter(cachedPolicy)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, List<CachedPolicy>> resolveResourceServerCache(String id) {
|
||||||
|
return cache.computeIfAbsent(id, key -> new HashMap<>());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -18,9 +18,10 @@
|
||||||
|
|
||||||
package org.keycloak.models.authorization.infinispan;
|
package org.keycloak.models.authorization.infinispan;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.infinispan.Cache;
|
import org.infinispan.Cache;
|
||||||
import org.keycloak.authorization.model.ResourceServer;
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
|
@ -44,7 +45,7 @@ public class CachedResourceServerStore implements ResourceServerStore {
|
||||||
private final CacheTransaction transaction;
|
private final CacheTransaction transaction;
|
||||||
private StoreFactory storeFactory;
|
private StoreFactory storeFactory;
|
||||||
private ResourceServerStore delegate;
|
private ResourceServerStore delegate;
|
||||||
private final Cache<String, List> cache;
|
private final Cache<String, Map<String, List<CachedResourceServer>>> cache;
|
||||||
|
|
||||||
public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
@ -58,34 +59,33 @@ public class CachedResourceServerStore implements ResourceServerStore {
|
||||||
public ResourceServer create(String clientId) {
|
public ResourceServer create(String clientId) {
|
||||||
ResourceServer resourceServer = getDelegate().create(clientId);
|
ResourceServer resourceServer = getDelegate().create(clientId);
|
||||||
|
|
||||||
this.transaction.whenRollback(() -> cache.remove(getCacheKeyForResourceServer(resourceServer.getId())));
|
this.transaction.whenRollback(() -> resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForResourceServer(resourceServer.getId())));
|
||||||
|
|
||||||
return createAdapter(new CachedResourceServer(resourceServer));
|
return createAdapter(new CachedResourceServer(resourceServer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(String id) {
|
public void delete(String id) {
|
||||||
|
ResourceServer resourceServer = getDelegate().findById(id);
|
||||||
getDelegate().delete(id);
|
getDelegate().delete(id);
|
||||||
this.transaction.whenCommit(() -> {
|
this.transaction.whenCommit(() -> {
|
||||||
List<CachedResourceServer> servers = cache.remove(getCacheKeyForResourceServer(id));
|
cache.remove(id);
|
||||||
|
cache.remove(resourceServer.getClientId());
|
||||||
if (servers != null) {
|
|
||||||
CachedResourceServer entry = servers.get(0);
|
|
||||||
cache.remove(getCacheKeyForResourceServerClientId(entry.getClientId()));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceServer findById(String id) {
|
public ResourceServer findById(String id) {
|
||||||
String cacheKeyForResourceServer = getCacheKeyForResourceServer(id);
|
String cacheKeyForResourceServer = getCacheKeyForResourceServer(id);
|
||||||
List<ResourceServer> cached = this.cache.get(cacheKeyForResourceServer);
|
List<CachedResourceServer> cached = resolveResourceServerCache(id).get(cacheKeyForResourceServer);
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
ResourceServer resourceServer = getDelegate().findById(id);
|
ResourceServer resourceServer = getDelegate().findById(id);
|
||||||
|
|
||||||
if (resourceServer != null) {
|
if (resourceServer != null) {
|
||||||
return createAdapter(updateResourceServerCache(resourceServer));
|
CachedResourceServer cachedResourceServer = new CachedResourceServer(resourceServer);
|
||||||
|
resolveResourceServerCache(id).put(cacheKeyForResourceServer, Arrays.asList(cachedResourceServer));
|
||||||
|
return createAdapter(cachedResourceServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -97,20 +97,20 @@ public class CachedResourceServerStore implements ResourceServerStore {
|
||||||
@Override
|
@Override
|
||||||
public ResourceServer findByClient(String id) {
|
public ResourceServer findByClient(String id) {
|
||||||
String cacheKeyForResourceServer = getCacheKeyForResourceServerClientId(id);
|
String cacheKeyForResourceServer = getCacheKeyForResourceServerClientId(id);
|
||||||
List<String> cached = this.cache.get(cacheKeyForResourceServer);
|
List<CachedResourceServer> cached = resolveResourceServerCache(id).get(cacheKeyForResourceServer);
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
ResourceServer resourceServer = getDelegate().findByClient(id);
|
ResourceServer resourceServer = getDelegate().findByClient(id);
|
||||||
|
|
||||||
if (resourceServer != null) {
|
if (resourceServer != null) {
|
||||||
cache.put(cacheKeyForResourceServer, Arrays.asList(resourceServer.getId()));
|
resolveResourceServerCache(cacheKeyForResourceServer).put(cacheKeyForResourceServer, Arrays.asList(new CachedResourceServer(resourceServer)));
|
||||||
return findById(resourceServer.getId());
|
return findById(resourceServer.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return findById(cached.get(0));
|
return createAdapter(cached.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCacheKeyForResourceServer(String id) {
|
private String getCacheKeyForResourceServer(String id) {
|
||||||
|
@ -173,7 +173,10 @@ public class CachedResourceServerStore implements ResourceServerStore {
|
||||||
if (this.updated == null) {
|
if (this.updated == null) {
|
||||||
this.updated = getDelegate().findById(getId());
|
this.updated = getDelegate().findById(getId());
|
||||||
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
||||||
transaction.whenCommit(() -> cache.remove(getCacheKeyForResourceServer(getId())));
|
transaction.whenCommit(() -> {
|
||||||
|
cache.remove(getId());
|
||||||
|
cache.remove(getClientId());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.updated;
|
return this.updated;
|
||||||
|
@ -181,14 +184,7 @@ public class CachedResourceServerStore implements ResourceServerStore {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private CachedResourceServer updateResourceServerCache(ResourceServer resourceServer) {
|
private Map<String, List<CachedResourceServer>> resolveResourceServerCache(String id) {
|
||||||
CachedResourceServer cached = new CachedResourceServer(resourceServer);
|
return cache.computeIfAbsent(id, key -> new HashMap<>());
|
||||||
List<ResourceServer> cache = new ArrayList<>();
|
|
||||||
|
|
||||||
cache.add(cached);
|
|
||||||
|
|
||||||
this.cache.put(getCacheKeyForResourceServer(resourceServer.getId()), cache);
|
|
||||||
|
|
||||||
return cached;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.keycloak.models.authorization.infinispan;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -53,7 +54,7 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
private final List<String> cacheKeys;
|
private final List<String> cacheKeys;
|
||||||
private StoreFactory storeFactory;
|
private StoreFactory storeFactory;
|
||||||
private ResourceStore delegate;
|
private ResourceStore delegate;
|
||||||
private final Cache<String, List<CachedResource>> cache;
|
private final Cache<String, Map<String, List<CachedResource>>> cache;
|
||||||
|
|
||||||
public CachedResourceStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
public CachedResourceStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
@ -63,6 +64,7 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
cacheKeys = new ArrayList<>();
|
cacheKeys = new ArrayList<>();
|
||||||
cacheKeys.add("findByOwner");
|
cacheKeys.add("findByOwner");
|
||||||
cacheKeys.add("findByUri");
|
cacheKeys.add("findByUri");
|
||||||
|
cacheKeys.add("findByName");
|
||||||
this.storeFactory = storeFactory;
|
this.storeFactory = storeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,12 +73,11 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
Resource resource = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
|
Resource resource = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
|
||||||
|
|
||||||
this.transaction.whenRollback(() -> {
|
this.transaction.whenRollback(() -> {
|
||||||
cache.remove(getCacheKeyForResource(resource.getId()));
|
resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForResource(resource.getId()));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.transaction.whenCommit(() -> {
|
this.transaction.whenCommit(() -> {
|
||||||
invalidateCache(resourceServer.getId());
|
invalidateCache(resourceServer.getId());
|
||||||
getCachedStoreFactory().getPolicyStore().notifyChange(resource);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return createAdapter(new CachedResource(resource));
|
return createAdapter(new CachedResource(resource));
|
||||||
|
@ -84,35 +85,29 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(String id) {
|
public void delete(String id) {
|
||||||
Resource resource = findById(id, null);
|
Resource resource = getDelegate().findById(id, null);
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ResourceServer resourceServer = resource.getResourceServer();
|
ResourceServer resourceServer = resource.getResourceServer();
|
||||||
getDelegate().delete(id);
|
getDelegate().delete(id);
|
||||||
this.transaction.whenCommit(() -> {
|
this.transaction.whenCommit(() -> {
|
||||||
List<CachedResource> resources = cache.remove(getCacheKeyForResource(id));
|
|
||||||
|
|
||||||
if (resources != null) {
|
|
||||||
CachedResource entry = resources.get(0);
|
|
||||||
cache.remove(getCacheKeyForResourceName(entry.getName(), entry.getResourceServerId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidateCache(resourceServer.getId());
|
invalidateCache(resourceServer.getId());
|
||||||
getCachedStoreFactory().getPolicyStore().notifyChange(resource);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource findById(String id, String resourceServerId) {
|
public Resource findById(String id, String resourceServerId) {
|
||||||
String cacheKeyForResource = getCacheKeyForResource(id);
|
String cacheKeyForResource = getCacheKeyForResource(id);
|
||||||
List<CachedResource> cached = this.cache.get(cacheKeyForResource);
|
List<CachedResource> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForResource);
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
Resource resource = getDelegate().findById(id, resourceServerId);
|
Resource resource = getDelegate().findById(id, resourceServerId);
|
||||||
|
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
return createAdapter(updateResourceCache(resource));
|
CachedResource cachedResource = new CachedResource(resource);
|
||||||
|
resolveResourceServerCache(resourceServerId).put(cacheKeyForResource, Arrays.asList(cachedResource));
|
||||||
|
return createAdapter(cachedResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -123,12 +118,12 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
|
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
|
||||||
return cacheResult(new StringBuilder("findByOwner").append(resourceServerId).append(ownerId).toString(), () -> getDelegate().findByOwner(ownerId, resourceServerId));
|
return cacheResult(resourceServerId, new StringBuilder("findByOwner").append(ownerId).toString(), () -> getDelegate().findByOwner(ownerId, resourceServerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Resource> findByUri(String uri, String resourceServerId) {
|
public List<Resource> findByUri(String uri, String resourceServerId) {
|
||||||
return cacheResult(new StringBuilder("findByUri").append(resourceServerId).append(uri).toString(), () -> getDelegate().findByUri(uri, resourceServerId));
|
return cacheResult(resourceServerId, new StringBuilder("findByUri").append(uri).toString(), () -> getDelegate().findByUri(uri, resourceServerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -149,13 +144,14 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
@Override
|
@Override
|
||||||
public Resource findByName(String name, String resourceServerId) {
|
public Resource findByName(String name, String resourceServerId) {
|
||||||
String cacheKeyForResource = getCacheKeyForResourceName(name, resourceServerId);
|
String cacheKeyForResource = getCacheKeyForResourceName(name, resourceServerId);
|
||||||
List<CachedResource> cached = this.cache.get(cacheKeyForResource);
|
List<CachedResource> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForResource);
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
Resource resource = getDelegate().findByName(name, resourceServerId);
|
Resource resource = getDelegate().findByName(name, resourceServerId);
|
||||||
|
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
cache.put(cacheKeyForResource, Arrays.asList(new CachedResource(resource)));
|
invalidateCache(resourceServerId);
|
||||||
|
resolveResourceServerCache(resourceServerId).put(cacheKeyForResource, Arrays.asList(new CachedResource(resource)));
|
||||||
return findById(resource.getId(), resourceServerId);
|
return findById(resource.getId(), resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,15 +276,14 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
|
|
||||||
private Resource getDelegateForUpdate() {
|
private Resource getDelegateForUpdate() {
|
||||||
if (this.updated == null) {
|
if (this.updated == null) {
|
||||||
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
|
String resourceServerId = cached.getResourceServerId();
|
||||||
|
this.updated = getDelegate().findById(getId(), resourceServerId);
|
||||||
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
||||||
transaction.whenCommit(() -> {
|
transaction.whenCommit(() -> {
|
||||||
cache.remove(getCacheKeyForResource(cached.getId()));
|
invalidateCache(resourceServerId);
|
||||||
invalidateCache(cached.getResourceServerId());
|
|
||||||
getCachedStoreFactory().getPolicyStore().notifyChange(updated);
|
|
||||||
});
|
});
|
||||||
transaction.whenRollback(() -> {
|
transaction.whenRollback(() -> {
|
||||||
cache.remove(getCacheKeyForResource(cached.getId()));
|
resolveResourceServerCache(resourceServerId).remove(getCacheKeyForResource(cached.getId()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,19 +296,8 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
return session.getProvider(CachedStoreFactoryProvider.class);
|
return session.getProvider(CachedStoreFactoryProvider.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CachedResource updateResourceCache(Resource resource) {
|
private List<Resource> cacheResult(String resourceServerId, String key, Supplier<List<Resource>> provider) {
|
||||||
CachedResource cached = new CachedResource(resource);
|
List<CachedResource> cached = resolveResourceServerCache(resourceServerId).computeIfAbsent(key, (Function<String, List<CachedResource>>) o -> {
|
||||||
List cache = new ArrayList<>();
|
|
||||||
|
|
||||||
cache.add(cached);
|
|
||||||
|
|
||||||
this.cache.put(getCacheKeyForResource(resource.getId()), cache);
|
|
||||||
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Resource> cacheResult(String key, Supplier<List<Resource>> provider) {
|
|
||||||
List<CachedResource> cached = cache.computeIfAbsent(key, (Function<String, List<CachedResource>>) o -> {
|
|
||||||
List<Resource> result = provider.get();
|
List<Resource> result = provider.get();
|
||||||
|
|
||||||
if (result.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
|
@ -327,10 +311,20 @@ public class CachedResourceStore implements ResourceStore {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return cached.stream().map(this::createAdapter).collect(Collectors.toList());
|
List<Resource> adapters = new ArrayList<>();
|
||||||
|
|
||||||
|
for (CachedResource resource : cached) {
|
||||||
|
adapters.add(createAdapter(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invalidateCache(String resourceServerId) {
|
private void invalidateCache(String resourceServerId) {
|
||||||
cacheKeys.forEach(cacheKey -> cache.keySet().stream().filter(key -> key.startsWith(cacheKey + resourceServerId)).forEach(cache::remove));
|
cache.remove(resourceServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, List<CachedResource>> resolveResourceServerCache(String id) {
|
||||||
|
return cache.computeIfAbsent(id, key -> new HashMap<>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,12 @@
|
||||||
|
|
||||||
package org.keycloak.models.authorization.infinispan;
|
package org.keycloak.models.authorization.infinispan;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.infinispan.Cache;
|
import org.infinispan.Cache;
|
||||||
import org.keycloak.authorization.model.Resource;
|
|
||||||
import org.keycloak.authorization.model.ResourceServer;
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
import org.keycloak.authorization.model.Scope;
|
import org.keycloak.authorization.model.Scope;
|
||||||
import org.keycloak.authorization.store.ScopeStore;
|
import org.keycloak.authorization.store.ScopeStore;
|
||||||
|
@ -43,7 +42,7 @@ public class CachedScopeStore implements ScopeStore {
|
||||||
private static final String SCOPE_ID_CACHE_PREFIX = "scp-id-";
|
private static final String SCOPE_ID_CACHE_PREFIX = "scp-id-";
|
||||||
private static final String SCOPE_NAME_CACHE_PREFIX = "scp-name-";
|
private static final String SCOPE_NAME_CACHE_PREFIX = "scp-name-";
|
||||||
|
|
||||||
private final Cache<String, List> cache;
|
private final Cache<String, Map<String, List<CachedScope>>> cache;
|
||||||
private final KeycloakSession session;
|
private final KeycloakSession session;
|
||||||
private final CacheTransaction transaction;
|
private final CacheTransaction transaction;
|
||||||
private ScopeStore delegate;
|
private ScopeStore delegate;
|
||||||
|
@ -61,9 +60,9 @@ public class CachedScopeStore implements ScopeStore {
|
||||||
public Scope create(String name, ResourceServer resourceServer) {
|
public Scope create(String name, ResourceServer resourceServer) {
|
||||||
Scope scope = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
|
Scope scope = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
|
||||||
|
|
||||||
this.transaction.whenRollback(() -> cache.remove(getCacheKeyForScope(scope.getId())));
|
this.transaction.whenRollback(() -> resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForScope(scope.getId())));
|
||||||
this.transaction.whenCommit(() -> {
|
this.transaction.whenCommit(() -> {
|
||||||
getCachedStoreFactory().getPolicyStore().notifyChange(scope);
|
invalidateCache(resourceServer.getId());
|
||||||
});
|
});
|
||||||
|
|
||||||
return createAdapter(new CachedScope(scope));
|
return createAdapter(new CachedScope(scope));
|
||||||
|
@ -71,33 +70,29 @@ public class CachedScopeStore implements ScopeStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(String id) {
|
public void delete(String id) {
|
||||||
Scope scope = findById(id, null);
|
Scope scope = getDelegate().findById(id, null);
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ResourceServer resourceServer = scope.getResourceServer();
|
||||||
getDelegate().delete(id);
|
getDelegate().delete(id);
|
||||||
this.transaction.whenCommit(() -> {
|
this.transaction.whenCommit(() -> {
|
||||||
List<CachedScope> scopes = cache.remove(getCacheKeyForScope(id));
|
invalidateCache(resourceServer.getId());
|
||||||
|
|
||||||
if (scopes != null) {
|
|
||||||
CachedScope entry = scopes.get(0);
|
|
||||||
cache.remove(getCacheKeyForScopeName(entry.getName(), entry.getResourceServerId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
getCachedStoreFactory().getPolicyStore().notifyChange(scope);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Scope findById(String id, String resourceServerId) {
|
public Scope findById(String id, String resourceServerId) {
|
||||||
String cacheKeyForScope = getCacheKeyForScope(id);
|
String cacheKeyForScope = getCacheKeyForScope(id);
|
||||||
List<CachedScope> cached = this.cache.get(cacheKeyForScope);
|
List<CachedScope> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForScope);
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
Scope scope = getDelegate().findById(id, resourceServerId);
|
Scope scope = getDelegate().findById(id, resourceServerId);
|
||||||
|
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
return createAdapter(updateScopeCache(scope));
|
CachedScope cachedScope = new CachedScope(scope);
|
||||||
|
resolveResourceServerCache(resourceServerId).put(cacheKeyForScope, Arrays.asList(cachedScope));
|
||||||
|
return createAdapter(cachedScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -108,21 +103,21 @@ public class CachedScopeStore implements ScopeStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Scope findByName(String name, String resourceServerId) {
|
public Scope findByName(String name, String resourceServerId) {
|
||||||
String cacheKeyForScope = getCacheKeyForScopeName(name, resourceServerId);
|
String cacheKeyForScope = getCacheKeyForScopeName(name);
|
||||||
List<String> cached = this.cache.get(cacheKeyForScope);
|
List<CachedScope> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForScope);
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
Scope scope = getDelegate().findByName(name, resourceServerId);
|
Scope scope = getDelegate().findByName(name, resourceServerId);
|
||||||
|
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
cache.put(cacheKeyForScope, Arrays.asList(scope.getId()));
|
resolveResourceServerCache(resourceServerId).put(cacheKeyForScope, Arrays.asList(new CachedScope(scope)));
|
||||||
return findById(scope.getId(), resourceServerId);
|
return findById(scope.getId(), resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return findById(cached.get(0), resourceServerId);
|
return createAdapter(cached.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,8 +134,8 @@ public class CachedScopeStore implements ScopeStore {
|
||||||
return SCOPE_ID_CACHE_PREFIX + id;
|
return SCOPE_ID_CACHE_PREFIX + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCacheKeyForScopeName(String name, String resourceServerId) {
|
private String getCacheKeyForScopeName(String name) {
|
||||||
return SCOPE_NAME_CACHE_PREFIX + name + "-" + resourceServerId;
|
return SCOPE_NAME_CACHE_PREFIX + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScopeStore getDelegate() {
|
private ScopeStore getDelegate() {
|
||||||
|
@ -197,11 +192,11 @@ public class CachedScopeStore implements ScopeStore {
|
||||||
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
|
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
|
||||||
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
if (this.updated == null) throw new IllegalStateException("Not found in database");
|
||||||
transaction.whenCommit(() -> {
|
transaction.whenCommit(() -> {
|
||||||
cache.remove(getCacheKeyForScope(getId()));
|
invalidateCache(cached.getResourceServerId());
|
||||||
getCachedStoreFactory().getPolicyStore().notifyChange(updated);
|
|
||||||
});
|
});
|
||||||
transaction.whenRollback(() -> {
|
transaction.whenRollback(() -> {
|
||||||
cache.remove(getCacheKeyForScope(cached.getId()));
|
resolveResourceServerCache(cached.getResourceServerId()).remove(getCacheKeyForScope(cached.getId()));
|
||||||
|
resolveResourceServerCache(cached.getResourceServerId()).remove(getCacheKeyForScopeName(cached.getName()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,15 +209,11 @@ public class CachedScopeStore implements ScopeStore {
|
||||||
return session.getProvider(CachedStoreFactoryProvider.class);
|
return session.getProvider(CachedStoreFactoryProvider.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CachedScope updateScopeCache(Scope scope) {
|
private void invalidateCache(String resourceServerId) {
|
||||||
CachedScope cached = new CachedScope(scope);
|
cache.remove(resourceServerId);
|
||||||
|
}
|
||||||
|
|
||||||
List cache = new ArrayList();
|
private Map<String, List<CachedScope>> resolveResourceServerCache(String id) {
|
||||||
|
return cache.computeIfAbsent(id, key -> new HashMap<>());
|
||||||
cache.add(cached);
|
|
||||||
|
|
||||||
this.transaction.whenCommit(() -> this.cache.put(getCacheKeyForScope(scope.getId()), cache));
|
|
||||||
|
|
||||||
return cached;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,6 @@ public class InfinispanStoreProviderFactory implements CachedStoreProviderFactor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSupported() {
|
public boolean isSupported() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,9 +58,6 @@
|
||||||
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
||||||
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
||||||
<button data-ng-click="nextPage()" class="next" ng-disabled="policies.length < query.max">{{:: 'next-page' | translate}}</button>
|
<button data-ng-click="nextPage()" class="next" ng-disabled="policies.length < query.max">{{:: 'next-page' | translate}}</button>
|
||||||
<select class="first" data-ng-model="query.max"
|
|
||||||
ng-options="size for size in listSizes" data-ng-change="firstPage()">
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -60,9 +60,6 @@
|
||||||
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
||||||
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
||||||
<button data-ng-click="nextPage()" class="next" ng-disabled="policies.length < query.max">{{:: 'next-page' | translate}}</button>
|
<button data-ng-click="nextPage()" class="next" ng-disabled="policies.length < query.max">{{:: 'next-page' | translate}}</button>
|
||||||
<select class="first" data-ng-model="query.max"
|
|
||||||
ng-options="size for size in listSizes" data-ng-change="firstPage()">
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -67,9 +67,6 @@
|
||||||
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
||||||
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
||||||
<button data-ng-click="nextPage()" class="next" ng-disabled="resources.length < query.max">{{:: 'next-page' | translate}}</button>
|
<button data-ng-click="nextPage()" class="next" ng-disabled="resources.length < query.max">{{:: 'next-page' | translate}}</button>
|
||||||
<select class="first" data-ng-model="query.max"
|
|
||||||
ng-options="size for size in listSizes" data-ng-change="firstPage()">
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -39,9 +39,6 @@
|
||||||
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
|
||||||
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
|
||||||
<button data-ng-click="nextPage()" class="next" ng-disabled="scopes.length < query.max">{{:: 'next-page' | translate}}</button>
|
<button data-ng-click="nextPage()" class="next" ng-disabled="scopes.length < query.max">{{:: 'next-page' | translate}}</button>
|
||||||
<select class="first" data-ng-model="query.max"
|
|
||||||
ng-options="size for size in listSizes" data-ng-change="firstPage()">
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
Loading…
Reference in a new issue