Merge pull request #4213 from pedroigor/cache-fixes
Missing invalidation for some queries cache
This commit is contained in:
commit
2b55cd7902
7 changed files with 123 additions and 23 deletions
|
@ -47,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.getResourcesIds(), cached.getResourceServerId());
|
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourcesIds(), cached.getScopesIds(), 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");
|
||||||
}
|
}
|
||||||
|
@ -96,7 +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());
|
cacheSession.registerPolicyInvalidation(cached.getId(), name, cached.getResourcesIds(), cached.getScopesIds(), cached.getResourceServerId());
|
||||||
updated.setName(name);
|
updated.setName(name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
HashSet<String> resources = new HashSet<>();
|
HashSet<String> resources = new HashSet<>();
|
||||||
resources.add(resource.getId());
|
resources.add(resource.getId());
|
||||||
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getResourceServerId());
|
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getScopesIds(), cached.getResourceServerId());
|
||||||
updated.addResource(resource);
|
updated.addResource(resource);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
HashSet<String> resources = new HashSet<>();
|
HashSet<String> resources = new HashSet<>();
|
||||||
resources.add(resource.getId());
|
resources.add(resource.getId());
|
||||||
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getResourceServerId());
|
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getScopesIds(), cached.getResourceServerId());
|
||||||
updated.removeResource(resource);
|
updated.removeResource(resource);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
addInvalidations(InResourcePredicate.create().resource(id), invalidations);
|
addInvalidations(InResourcePredicate.create().resource(id), invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void policyUpdated(String id, String name, Set<String> resources, String serverId, Set<String> invalidations) {
|
public void policyUpdated(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId, Set<String> invalidations) {
|
||||||
invalidations.add(id);
|
invalidations.add(id);
|
||||||
invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
|
||||||
|
|
||||||
|
@ -111,10 +111,22 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
invalidations.add(StoreFactoryCacheSession.getPolicyByResource(resource, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPolicyByResource(resource, serverId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resourceTypes != null) {
|
||||||
|
for (String type : resourceTypes) {
|
||||||
|
invalidations.add(StoreFactoryCacheSession.getPolicyByResourceType(type, serverId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void policyRemoval(String id, String name, Set<String> resources, String serverId, Set<String> invalidations) {
|
if (scopes != null) {
|
||||||
policyUpdated(id, name, resources, serverId, invalidations);
|
for (String scope : scopes) {
|
||||||
|
invalidations.add(StoreFactoryCacheSession.getPolicyByScope(scope, serverId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void policyRemoval(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId, Set<String> invalidations) {
|
||||||
|
policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ 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;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -252,12 +253,30 @@ 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, Set<String> resources, String serverId) {
|
public void registerPolicyInvalidation(String id, String name, Set<String> resources, Set<String> scopes, String serverId) {
|
||||||
cache.policyUpdated(id, name, resources, serverId, invalidations);
|
Set<String> resourceTypes = getResourceTypes(resources, serverId);
|
||||||
|
cache.policyUpdated(id, name, resources, resourceTypes, scopes, 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, resources, serverId));
|
invalidationEvents.add(PolicyUpdatedEvent.create(id, name, resources, resourceTypes, scopes, serverId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getResourceTypes(Set<String> resources, String serverId) {
|
||||||
|
if (resources == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return resources.stream().map(resourceId -> {
|
||||||
|
Resource resource = getResourceStore().findById(resourceId, serverId);
|
||||||
|
String type = resource.getType();
|
||||||
|
|
||||||
|
if (type != null) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceServerStore getResourceServerStoreDelegate() {
|
public ResourceServerStore getResourceServerStoreDelegate() {
|
||||||
|
@ -626,7 +645,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
@Override
|
@Override
|
||||||
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
||||||
Policy policy = getPolicyStoreDelegate().create(representation, resourceServer);
|
Policy policy = getPolicyStoreDelegate().create(representation, resourceServer);
|
||||||
registerPolicyInvalidation(policy.getId(), policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), resourceServer.getId());
|
registerPolicyInvalidation(policy.getId(), representation.getName(), representation.getResources(), representation.getScopes(), resourceServer.getId());
|
||||||
return policy;
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,8 +656,12 @@ 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.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), policy.getResourceServer().getId()));
|
Set<String> resources = policy.getResources().stream().map(resource -> resource.getId()).collect(Collectors.toSet());
|
||||||
cache.policyRemoval(id, policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), policy.getResourceServer().getId(), invalidations);
|
ResourceServer resourceServer = policy.getResourceServer();
|
||||||
|
Set<String> resourceTypes = getResourceTypes(resources, resourceServer.getId());
|
||||||
|
Set<String> scopes = policy.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet());
|
||||||
|
invalidationEvents.add(PolicyRemovedEvent.create(id, policy.getName(), resources, resourceTypes, scopes, resourceServer.getId()));
|
||||||
|
cache.policyRemoval(id, policy.getName(), resources, resourceTypes, scopes, resourceServer.getId(), invalidations);
|
||||||
getPolicyStoreDelegate().delete(id);
|
getPolicyStoreDelegate().delete(id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,17 @@ public class PolicyRemovedEvent extends InvalidationEvent implements Authorizati
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
private Set<String> resources;
|
private Set<String> resources;
|
||||||
|
private Set<String> resourceTypes;
|
||||||
|
private Set<String> scopes;
|
||||||
private String serverId;
|
private String serverId;
|
||||||
|
|
||||||
public static PolicyRemovedEvent create(String id, String name, Set<String> resources, String serverId) {
|
public static PolicyRemovedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, 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.resources = resources;
|
||||||
|
event.resourceTypes = resourceTypes;
|
||||||
|
event.scopes = scopes;
|
||||||
event.serverId = serverId;
|
event.serverId = serverId;
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +57,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, resources, serverId, invalidations);
|
cache.policyRemoval(id, name, resources, resourceTypes, scopes, serverId, invalidations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,17 @@ 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 static Set<String> resources;
|
||||||
|
private Set<String> resourceTypes;
|
||||||
|
private Set<String> scopes;
|
||||||
private String serverId;
|
private String serverId;
|
||||||
|
|
||||||
public static PolicyUpdatedEvent create(String id, String name, Set<String> resources, String serverId) {
|
public static PolicyUpdatedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, 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.resources = resources;
|
||||||
|
event.resourceTypes = resourceTypes;
|
||||||
|
event.scopes = scopes;
|
||||||
event.serverId = serverId;
|
event.serverId = serverId;
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +57,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, resources, serverId, invalidations);
|
cache.policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,17 @@ package org.keycloak.authorization;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
|
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.permission.evaluator.Evaluators;
|
import org.keycloak.authorization.permission.evaluator.Evaluators;
|
||||||
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
|
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||||
import org.keycloak.authorization.store.AuthorizationStoreFactory;
|
|
||||||
import org.keycloak.authorization.store.PolicyStore;
|
import org.keycloak.authorization.store.PolicyStore;
|
||||||
import org.keycloak.authorization.store.ResourceServerStore;
|
import org.keycloak.authorization.store.ResourceServerStore;
|
||||||
import org.keycloak.authorization.store.ResourceStore;
|
import org.keycloak.authorization.store.ResourceStore;
|
||||||
|
@ -37,7 +40,6 @@ import org.keycloak.authorization.store.StoreFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
|
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
|
||||||
import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
|
|
||||||
import org.keycloak.models.utils.RepresentationToModel;
|
import org.keycloak.models.utils.RepresentationToModel;
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||||
|
@ -143,6 +145,61 @@ public final class AuthorizationProvider implements Provider {
|
||||||
return new PolicyStore() {
|
return new PolicyStore() {
|
||||||
@Override
|
@Override
|
||||||
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
||||||
|
Set<String> resources = representation.getResources();
|
||||||
|
|
||||||
|
if (resources != null) {
|
||||||
|
representation.setResources(resources.stream().map(id -> {
|
||||||
|
Resource resource = getResourceStore().findById(id, resourceServer.getId());
|
||||||
|
|
||||||
|
if (resource == null) {
|
||||||
|
resource = getResourceStore().findByName(id, resourceServer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource == null) {
|
||||||
|
throw new RuntimeException("Resource [" + id + "] does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource.getId();
|
||||||
|
}).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> scopes = representation.getScopes();
|
||||||
|
|
||||||
|
if (scopes != null) {
|
||||||
|
representation.setScopes(scopes.stream().map(id -> {
|
||||||
|
Scope scope = getScopeStore().findById(id, resourceServer.getId());
|
||||||
|
|
||||||
|
if (scope == null) {
|
||||||
|
scope = getScopeStore().findByName(id, resourceServer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope == null) {
|
||||||
|
throw new RuntimeException("Scope [" + id + "] does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.getId();
|
||||||
|
}).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Set<String> policies = representation.getPolicies();
|
||||||
|
|
||||||
|
if (policies != null) {
|
||||||
|
representation.setPolicies(policies.stream().map(id -> {
|
||||||
|
Policy policy = getPolicyStore().findById(id, resourceServer.getId());
|
||||||
|
|
||||||
|
if (policy == null) {
|
||||||
|
policy = getPolicyStore().findByName(id, resourceServer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (policy == null) {
|
||||||
|
throw new RuntimeException("Policy [" + id + "] does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
return policy.getId();
|
||||||
|
}).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
return RepresentationToModel.toModel(representation, AuthorizationProvider.this, policyStore.create(representation, resourceServer));
|
return RepresentationToModel.toModel(representation, AuthorizationProvider.this, policyStore.create(representation, resourceServer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2171,13 +2171,13 @@ public class RepresentationToModel {
|
||||||
private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) {
|
private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) {
|
||||||
if (resourceIds != null) {
|
if (resourceIds != null) {
|
||||||
if (resourceIds.isEmpty()) {
|
if (resourceIds.isEmpty()) {
|
||||||
for (Scope scope : new HashSet<Scope>(policy.getScopes())) {
|
for (Resource resource : new HashSet<>(policy.getResources())) {
|
||||||
policy.removeScope(scope);
|
policy.removeResource(resource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String resourceId : resourceIds) {
|
for (String resourceId : resourceIds) {
|
||||||
boolean hasResource = false;
|
boolean hasResource = false;
|
||||||
for (Resource resourceModel : new HashSet<Resource>(policy.getResources())) {
|
for (Resource resourceModel : new HashSet<>(policy.getResources())) {
|
||||||
if (resourceModel.getId().equals(resourceId) || resourceModel.getName().equals(resourceId)) {
|
if (resourceModel.getId().equals(resourceId) || resourceModel.getName().equals(resourceId)) {
|
||||||
hasResource = true;
|
hasResource = true;
|
||||||
}
|
}
|
||||||
|
@ -2196,7 +2196,7 @@ public class RepresentationToModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Resource resourceModel : new HashSet<Resource>(policy.getResources())) {
|
for (Resource resourceModel : new HashSet<>(policy.getResources())) {
|
||||||
boolean hasResource = false;
|
boolean hasResource = false;
|
||||||
|
|
||||||
for (String resourceId : resourceIds) {
|
for (String resourceId : resourceIds) {
|
||||||
|
|
Loading…
Reference in a new issue