Missing invalidation for some queries cache

This commit is contained in:
Pedro Igor 2017-06-08 18:09:44 -03:00
parent 9be9e30ad6
commit 84d2d7b431
7 changed files with 123 additions and 23 deletions

View file

@ -47,7 +47,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
@Override
public Policy getDelegateForUpdate() {
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());
if (updated == null) throw new IllegalStateException("Not found in database");
}
@ -96,7 +96,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
@Override
public void setName(String name) {
getDelegateForUpdate();
cacheSession.registerPolicyInvalidation(cached.getId(), name, cached.getResourcesIds(), cached.getResourceServerId());
cacheSession.registerPolicyInvalidation(cached.getId(), name, cached.getResourcesIds(), cached.getScopesIds(), cached.getResourceServerId());
updated.setName(name);
}
@ -235,7 +235,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
getDelegateForUpdate();
HashSet<String> resources = new HashSet<>();
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);
}
@ -245,7 +245,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
getDelegateForUpdate();
HashSet<String> resources = new HashSet<>();
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);
}

View file

@ -102,7 +102,7 @@ public class StoreFactoryCacheManager extends CacheManager {
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(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
@ -111,10 +111,22 @@ public class StoreFactoryCacheManager extends CacheManager {
invalidations.add(StoreFactoryCacheSession.getPolicyByResource(resource, serverId));
}
}
if (resourceTypes != null) {
for (String type : resourceTypes) {
invalidations.add(StoreFactoryCacheSession.getPolicyByResourceType(type, serverId));
}
}
if (scopes != null) {
for (String scope : scopes) {
invalidations.add(StoreFactoryCacheSession.getPolicyByScope(scope, serverId));
}
}
}
public void policyRemoval(String id, String name, Set<String> resources, String serverId, Set<String> invalidations) {
policyUpdated(id, name, resources, serverId, invalidations);
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);
}

View file

@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Supplier;
@ -252,12 +253,30 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uri, scopes, serverId));
}
public void registerPolicyInvalidation(String id, String name, Set<String> resources, String serverId) {
cache.policyUpdated(id, name, resources, serverId, invalidations);
public void registerPolicyInvalidation(String id, String name, Set<String> resources, Set<String> scopes, String serverId) {
Set<String> resourceTypes = getResourceTypes(resources, serverId);
cache.policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
PolicyAdapter adapter = managedPolicies.get(id);
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() {
@ -626,7 +645,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
@Override
public Policy create(AbstractPolicyRepresentation representation, ResourceServer 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;
}
@ -637,8 +656,12 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
if (policy == null) return;
cache.invalidateObject(id);
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.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), policy.getResourceServer().getId(), invalidations);
Set<String> resources = policy.getResources().stream().map(resource -> resource.getId()).collect(Collectors.toSet());
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);
}

View file

@ -30,13 +30,17 @@ public class PolicyRemovedEvent extends InvalidationEvent implements Authorizati
private String id;
private String name;
private Set<String> resources;
private Set<String> resourceTypes;
private Set<String> scopes;
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();
event.id = id;
event.name = name;
event.resources = resources;
event.resourceTypes = resourceTypes;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@ -53,6 +57,6 @@ public class PolicyRemovedEvent extends InvalidationEvent implements Authorizati
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyRemoval(id, name, resources, serverId, invalidations);
cache.policyRemoval(id, name, resources, resourceTypes, scopes, serverId, invalidations);
}
}

View file

@ -30,13 +30,17 @@ public class PolicyUpdatedEvent extends InvalidationEvent implements Authorizati
private String id;
private String name;
private static Set<String> resources;
private Set<String> resourceTypes;
private Set<String> scopes;
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();
event.id = id;
event.name = name;
event.resources = resources;
event.resourceTypes = resourceTypes;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@ -53,6 +57,6 @@ public class PolicyUpdatedEvent extends InvalidationEvent implements Authorizati
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyUpdated(id, name, resources, serverId, invalidations);
cache.policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
}
}

View file

@ -21,14 +21,17 @@ package org.keycloak.authorization;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.permission.evaluator.Evaluators;
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.AuthorizationStoreFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
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.RealmModel;
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.provider.Provider;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
@ -143,6 +145,61 @@ public final class AuthorizationProvider implements Provider {
return new PolicyStore() {
@Override
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));
}

View file

@ -2171,13 +2171,13 @@ public class RepresentationToModel {
private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) {
if (resourceIds != null) {
if (resourceIds.isEmpty()) {
for (Scope scope : new HashSet<Scope>(policy.getScopes())) {
policy.removeScope(scope);
for (Resource resource : new HashSet<>(policy.getResources())) {
policy.removeResource(resource);
}
}
for (String resourceId : resourceIds) {
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)) {
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;
for (String resourceId : resourceIds) {