Merge pull request #4149 from patriot1burke/master

KEYCLOAK-4929
This commit is contained in:
Bill Burke 2017-05-18 18:56:03 -04:00 committed by GitHub
commit d22a284df1
76 changed files with 3340 additions and 2247 deletions

View file

@ -107,7 +107,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
if (clients.isEmpty()) { if (clients.isEmpty()) {
policyStore.delete(policy.getId()); policyStore.delete(policy.getId());
} else { } else {
policy.getConfig().put("clients", JsonSerialization.writeValueAsString(clients)); policy.putConfig("clients", JsonSerialization.writeValueAsString(clients));
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error while synchronizing clients with policy [" + policy.getName() + "].", e); throw new RuntimeException("Error while synchronizing clients with policy [" + policy.getName() + "].", e);
@ -152,11 +152,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
} }
try { try {
Map<String, String> config = policy.getConfig(); policy.putConfig("clients", JsonSerialization.writeValueAsString(updatedClients));
config.put("clients", JsonSerialization.writeValueAsString(updatedClients));
policy.setConfig(config);
} catch (IOException cause) { } catch (IOException cause) {
throw new RuntimeException("Failed to serialize clients", cause); throw new RuntimeException("Failed to serialize clients", cause);
} }

View file

@ -70,9 +70,7 @@ public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRe
} }
private void updatePolicy(Policy policy, String code) { private void updatePolicy(Policy policy, String code) {
Map<String, String> config = policy.getConfig(); policy.putConfig("code", code);
config.put("code", code);
policy.setConfig(config);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package org.keycloak.authorization.policy.provider.resource; package org.keycloak.authorization.policy.provider.resource;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.keycloak.Config; import org.keycloak.Config;
@ -64,7 +65,7 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory<Reso
//TODO: remove this check once we migrate to new API //TODO: remove this check once we migrate to new API
if (ResourcePermissionRepresentation.class.equals(representation.getClass())) { if (ResourcePermissionRepresentation.class.equals(representation.getClass())) {
ResourcePermissionRepresentation resourcePermission = ResourcePermissionRepresentation.class.cast(representation); ResourcePermissionRepresentation resourcePermission = ResourcePermissionRepresentation.class.cast(representation);
Map<String, String> config = policy.getConfig(); Map<String, String> config = new HashMap(policy.getConfig());
config.compute("defaultResourceType", (key, value) -> { config.compute("defaultResourceType", (key, value) -> {
String resourceType = resourcePermission.getResourceType(); String resourceType = resourcePermission.getResourceType();

View file

@ -163,11 +163,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
} }
try { try {
Map<String, String> config = policy.getConfig(); policy.putConfig("roles", JsonSerialization.writeValueAsString(updatedRoles));
config.put("roles", JsonSerialization.writeValueAsString(updatedRoles));
policy.setConfig(config);
} catch (IOException cause) { } catch (IOException cause) {
throw new RuntimeException("Failed to serialize roles", cause); throw new RuntimeException("Failed to serialize roles", cause);
} }
@ -224,9 +220,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
if (roles.isEmpty()) { if (roles.isEmpty()) {
policyStore.delete(policy.getId()); policyStore.delete(policy.getId());
} else { } else {
Map<String, String> config = policy.getConfig(); policy.putConfig("roles", JsonSerialization.writeValueAsString(roles));
config.put("roles", JsonSerialization.writeValueAsString(roles));
policy.setConfig(config);
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error while synchronizing roles with policy [" + policy.getName() + "].", e); throw new RuntimeException("Error while synchronizing roles with policy [" + policy.getName() + "].", e);

View file

@ -1,6 +1,7 @@
package org.keycloak.authorization.policy.provider.time; package org.keycloak.authorization.policy.provider.time;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.keycloak.Config; import org.keycloak.Config;
@ -118,7 +119,7 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory<TimePoli
validateFormat(noa); validateFormat(noa);
} }
Map<String, String> config = policy.getConfig(); Map<String, String> config = new HashMap(policy.getConfig());
config.compute("nbf", (s, s2) -> nbf != null ? nbf : null); config.compute("nbf", (s, s2) -> nbf != null ? nbf : null);
config.compute("noa", (s, s2) -> noa != null ? noa : null); config.compute("noa", (s, s2) -> noa != null ? noa : null);

View file

@ -138,11 +138,8 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
} }
try { try {
Map<String, String> config = policy.getConfig();
config.put("users", JsonSerialization.writeValueAsString(updatedUsers)); policy.putConfig("users", JsonSerialization.writeValueAsString(updatedUsers));
policy.setConfig(config);
} catch (IOException cause) { } catch (IOException cause) {
throw new RuntimeException("Failed to serialize users", cause); throw new RuntimeException("Failed to serialize users", cause);
} }
@ -181,7 +178,7 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
if (users.isEmpty()) { if (users.isEmpty()) {
policyStore.delete(policy.getId()); policyStore.delete(policy.getId());
} else { } else {
policy.getConfig().put("users", JsonSerialization.writeValueAsString(users)); policy.putConfig("users", JsonSerialization.writeValueAsString(users));
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error while synchronizing users with policy [" + policy.getName() + "].", e); throw new RuntimeException("Error while synchronizing users with policy [" + policy.getName() + "].", e);

View file

@ -120,17 +120,15 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory<RulePo
} }
private void updateConfig(Policy policy, RulePolicyRepresentation representation) { private void updateConfig(Policy policy, RulePolicyRepresentation representation) {
Map<String, String> config = policy.getConfig();
config.put("mavenArtifactGroupId", representation.getArtifactGroupId()); policy.putConfig("mavenArtifactGroupId", representation.getArtifactGroupId());
config.put("mavenArtifactId", representation.getArtifactId()); policy.putConfig("mavenArtifactId", representation.getArtifactId());
config.put("mavenArtifactVersion", representation.getArtifactVersion()); policy.putConfig("mavenArtifactVersion", representation.getArtifactVersion());
config.put("scannerPeriod", representation.getScannerPeriod()); policy.putConfig("scannerPeriod", representation.getScannerPeriod());
config.put("scannerPeriodUnit", representation.getScannerPeriodUnit()); policy.putConfig("scannerPeriodUnit", representation.getScannerPeriodUnit());
config.put("sessionName", representation.getSessionName()); policy.putConfig("sessionName", representation.getSessionName());
config.put("moduleName", representation.getModuleName()); policy.putConfig("moduleName", representation.getModuleName());
policy.setConfig(config);
} }
void update(Policy policy) { void update(Policy policy) {

View file

@ -126,6 +126,16 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true); cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true); cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
? 2 * authzRevisionsMaxEntries
: InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
logger.debugv("Using container managed Infinispan cache container, lookup={1}", cacheContainerLookup); logger.debugv("Using container managed Infinispan cache container, lookup={1}", cacheContainerLookup);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Failed to retrieve cache container", e); throw new RuntimeException("Failed to retrieve cache container", e);
@ -157,6 +167,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
Configuration modelCacheConfiguration = modelCacheConfigBuilder.build(); Configuration modelCacheConfiguration = modelCacheConfigBuilder.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, modelCacheConfiguration); cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, modelCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, modelCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_CACHE_NAME, modelCacheConfiguration); cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_CACHE_NAME, modelCacheConfiguration);
ConfigurationBuilder sessionConfigBuilder = new ConfigurationBuilder(); ConfigurationBuilder sessionConfigBuilder = new ConfigurationBuilder();
@ -186,14 +197,12 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration); cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration); cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration); cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, sessionCacheConfiguration); cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, sessionCacheConfiguration);
// Retrieve caches to enforce rebalance // Retrieve caches to enforce rebalance
cacheManager.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME, true); cacheManager.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, true); cacheManager.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, true); cacheManager.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true); cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true);
ConfigurationBuilder replicationConfigBuilder = new ConfigurationBuilder(); ConfigurationBuilder replicationConfigBuilder = new ConfigurationBuilder();
@ -236,6 +245,14 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, getActionTokenCacheConfig()); cacheManager.defineConfiguration(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, getActionTokenCacheConfig());
cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true); cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
? 2 * authzRevisionsMaxEntries
: InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
} }
private Configuration getRevisionCacheConfig(long maxEntries) { private Configuration getRevisionCacheConfig(long maxEntries) {

View file

@ -39,6 +39,8 @@ public interface InfinispanConnectionProvider extends Provider {
String AUTHENTICATION_SESSIONS_CACHE_NAME = "authenticationSessions"; String AUTHENTICATION_SESSIONS_CACHE_NAME = "authenticationSessions";
String WORK_CACHE_NAME = "work"; String WORK_CACHE_NAME = "work";
String AUTHORIZATION_CACHE_NAME = "authorization"; String AUTHORIZATION_CACHE_NAME = "authorization";
String AUTHORIZATION_REVISIONS_CACHE_NAME = "authorizationRevisions";
int AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX = 20000;
String ACTION_TOKEN_CACHE = "actionTokens"; String ACTION_TOKEN_CACHE = "actionTokens";
int ACTION_TOKEN_CACHE_DEFAULT_MAX = -1; int ACTION_TOKEN_CACHE_DEFAULT_MAX = -1;

View file

@ -1,73 +0,0 @@
/*
* Copyright 2016 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.authorization.infinispan;
import java.util.Arrays;
import java.util.List;
import org.keycloak.authorization.store.StoreFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public abstract class AbstractCachedStore {
private final InfinispanStoreFactoryProvider cacheStoreFactory;
private final StoreFactory storeFactory;
AbstractCachedStore(InfinispanStoreFactoryProvider cacheStoreFactory, StoreFactory storeFactory) {
this.cacheStoreFactory = cacheStoreFactory;
this.storeFactory = storeFactory;
}
protected void addInvalidation(String cacheKeyForPolicy) {
getCachedStoreFactory().addInvalidation(cacheKeyForPolicy);
}
protected <E> E putCacheEntry(String resourceServerId, String cacheKeyForPolicy, E cachedPolicy) {
cacheStoreFactory.putCacheEntry(resourceServerId, cacheKeyForPolicy, Arrays.asList(cachedPolicy));
return cachedPolicy;
}
protected List<Object> resolveCacheEntry(String resourceServerId, String cacheKeyForPolicy) {
return cacheStoreFactory.resolveCachedEntry(resourceServerId, cacheKeyForPolicy);
}
protected void removeCachedEntry(String resourceServerId, String key) {
getCachedStoreFactory().removeCachedEntry(resourceServerId, key);
}
protected void invalidate(String resourceServerId) {
cacheStoreFactory.invalidate(resourceServerId);
}
protected StoreFactory getStoreFactory() {
return this.storeFactory;
}
protected boolean isInvalid(String cacheKey) {
return cacheStoreFactory.isInvalid(cacheKey);
}
protected InfinispanStoreFactoryProvider.CacheTransaction getTransaction() {
return cacheStoreFactory.getTransaction();
}
protected InfinispanStoreFactoryProvider getCachedStoreFactory() {
return cacheStoreFactory;
}
}

View file

@ -1,500 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.authorization.infinispan;
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.Function;
import java.util.function.Supplier;
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.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.authorization.infinispan.entities.CachedPolicy;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class CachedPolicyStore extends AbstractCachedStore implements PolicyStore {
private static final String POLICY_CACHE_PREFIX = "pc-";
private PolicyStore delegate;
public CachedPolicyStore(InfinispanStoreFactoryProvider cacheStoreFactory, StoreFactory storeFactory) {
super(cacheStoreFactory, storeFactory);
this.delegate = storeFactory.getPolicyStore();
}
@Override
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
Policy policy = getDelegate().create(representation, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
String id = policy.getId();
addInvalidation(getCacheKeyForPolicy(policy.getId()));
addInvalidation(getCacheKeyForPolicyName(policy.getName()));
addInvalidation(getCacheKeyForPolicyType(policy.getType()));
configureTransaction(resourceServer, id);
return createAdapter(new CachedPolicy(policy));
}
@Override
public void delete(String id) {
Policy policy = getDelegate().findById(id, null);
if (policy == null) {
return;
}
addInvalidation(getCacheKeyForPolicy(policy.getId()));
addInvalidation(getCacheKeyForPolicyName(policy.getName()));
addInvalidation(getCacheKeyForPolicyType(policy.getType()));
getDelegate().delete(id);
configureTransaction(policy.getResourceServer(), policy.getId());
}
@Override
public Policy findById(String id, String resourceServerId) {
if (resourceServerId == null) {
return getDelegate().findById(id, null);
}
if (isInvalid(getCacheKeyForPolicy(id))) {
return getDelegate().findById(id, resourceServerId);
}
String cacheKeyForPolicy = getCacheKeyForPolicy(id);
List<Object> cached = resolveCacheEntry(resourceServerId, cacheKeyForPolicy);
if (cached == null) {
Policy policy = getDelegate().findById(id, resourceServerId);
if (policy != null) {
return createAdapter(putCacheEntry(resourceServerId, cacheKeyForPolicy, new CachedPolicy(policy)));
}
return null;
}
return createAdapter(CachedPolicy.class.cast(cached.get(0)));
}
@Override
public Policy findByName(String name, String resourceServerId) {
String cacheKey = getCacheKeyForPolicyName(name);
if (isInvalid(cacheKey)) {
return getDelegate().findByName(name, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> {
Policy policy = getDelegate().findByName(name, resourceServerId);
if (policy == null) {
return Collections.emptyList();
}
return Arrays.asList(policy);
}).stream().findFirst().orElse(null);
}
@Override
public List<Policy> findByResourceServer(String resourceServerId) {
return getDelegate().findByResourceServer(resourceServerId);
}
@Override
public List<Policy> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
return getDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
}
@Override
public List<Policy> findByResource(String resourceId, String resourceServerId) {
String cacheKey = getCacheKeyForResource(resourceId);
if (isInvalid(cacheKey)) {
return getDelegate().findByResource(resourceId, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> getDelegate().findByResource(resourceId, resourceServerId));
}
@Override
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
String cacheKey = getCacheKeyForResourceType(resourceType);
if (isInvalid(cacheKey)) {
return getDelegate().findByResourceType(resourceType, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> getDelegate().findByResourceType(resourceType, resourceServerId));
}
@Override
public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
List<Policy> policies = new ArrayList<>();
for (String scopeId : scopeIds) {
String cacheKey = getCacheForScope(scopeId);
if (isInvalid(cacheKey)) {
policies.addAll(getDelegate().findByScopeIds(Arrays.asList(scopeId), resourceServerId));
} else {
policies.addAll(cacheResult(resourceServerId, cacheKey, () -> getDelegate().findByScopeIds(Arrays.asList(scopeId), resourceServerId)));
}
}
return policies;
}
@Override
public List<Policy> findByType(String type, String resourceServerId) {
String cacheKey = getCacheKeyForPolicyType(type);
if (isInvalid(cacheKey)) {
return getDelegate().findByType(type, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> getDelegate().findByType(type, resourceServerId));
}
@Override
public List<Policy> findDependentPolicies(String id, String resourceServerId) {
return getDelegate().findDependentPolicies(id, resourceServerId);
}
private String getCacheKeyForPolicy(String id) {
return new StringBuilder().append(POLICY_CACHE_PREFIX).append("id-").append(id).toString();
}
private String getCacheKeyForPolicyType(String type) {
return new StringBuilder().append(POLICY_CACHE_PREFIX).append("findByType-").append(type).toString();
}
private String getCacheKeyForPolicyName(String name) {
return new StringBuilder().append(POLICY_CACHE_PREFIX).append("findByName-").append(name).toString();
}
private String getCacheKeyForResourceType(String resourceType) {
return new StringBuilder().append(POLICY_CACHE_PREFIX).append("findByResourceType-").append(resourceType).toString();
}
private String getCacheForScope(String scopeId) {
return new StringBuilder().append(POLICY_CACHE_PREFIX).append("findByScopeIds-").append(scopeId).toString();
}
private String getCacheKeyForResource(String resourceId) {
return new StringBuilder().append(POLICY_CACHE_PREFIX).append("findByResource-").append(resourceId).toString();
}
private Policy createAdapter(CachedPolicy cached) {
return new Policy() {
private Set<Scope> scopes;
private Set<Resource> resources;
private Set<Policy> associatedPolicies;
private Policy updated;
@Override
public String getId() {
return cached.getId();
}
@Override
public String getType() {
return cached.getType();
}
@Override
public DecisionStrategy getDecisionStrategy() {
return cached.getDecisionStrategy();
}
@Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
getDelegateForUpdate().setDecisionStrategy(decisionStrategy);
cached.setDecisionStrategy(decisionStrategy);
}
@Override
public Logic getLogic() {
return cached.getLogic();
}
@Override
public void setLogic(Logic logic) {
getDelegateForUpdate().setLogic(logic);
cached.setLogic(logic);
}
@Override
public Map<String, String> getConfig() {
return new HashMap<>(cached.getConfig());
}
@Override
public void setConfig(Map<String, String> config) {
String resourceType = config.get("defaultResourceType");
if (resourceType != null) {
addInvalidation(getCacheKeyForResourceType(resourceType));
String cachedResourceType = cached.getConfig().get("defaultResourceType");
if (cachedResourceType != null && !resourceType.equals(cachedResourceType)) {
addInvalidation(getCacheKeyForResourceType(cachedResourceType));
}
}
getDelegateForUpdate().setConfig(config);
cached.setConfig(config);
}
@Override
public String getName() {
return cached.getName();
}
@Override
public void setName(String name) {
addInvalidation(getCacheKeyForPolicyName(name));
addInvalidation(getCacheKeyForPolicyName(cached.getName()));
getDelegateForUpdate().setName(name);
cached.setName(name);
}
@Override
public String getDescription() {
return cached.getDescription();
}
@Override
public void setDescription(String description) {
getDelegateForUpdate().setDescription(description);
cached.setDescription(description);
}
@Override
public ResourceServer getResourceServer() {
return getCachedStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
}
@Override
public void addScope(Scope scope) {
Scope model = getStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId());
addInvalidation(getCacheForScope(model.getId()));
getDelegateForUpdate().addScope(model);
cached.addScope(scope);
scopes.add(scope);
}
@Override
public void removeScope(Scope scope) {
Scope model = getStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId());
addInvalidation(getCacheForScope(scope.getId()));
getDelegateForUpdate().removeScope(model);
cached.removeScope(scope);
scopes.remove(scope);
}
@Override
public void addAssociatedPolicy(Policy associatedPolicy) {
getDelegateForUpdate().addAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId(), cached.getResourceServerId()));
cached.addAssociatedPolicy(associatedPolicy);
}
@Override
public void removeAssociatedPolicy(Policy associatedPolicy) {
getDelegateForUpdate().removeAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId(), cached.getResourceServerId()));
cached.removeAssociatedPolicy(associatedPolicy);
associatedPolicies.remove(associatedPolicy);
}
@Override
public void addResource(Resource resource) {
Resource model = getStoreFactory().getResourceStore().findById(resource.getId(), cached.getResourceServerId());
addInvalidation(getCacheKeyForResource(model.getId()));
if (model.getType() != null) {
addInvalidation(getCacheKeyForResourceType(model.getType()));
}
getDelegateForUpdate().addResource(model);
cached.addResource(resource);
resources.add(resource);
}
@Override
public void removeResource(Resource resource) {
Resource model = getStoreFactory().getResourceStore().findById(resource.getId(), cached.getResourceServerId());
addInvalidation(getCacheKeyForResource(model.getId()));
if (model.getType() != null) {
addInvalidation(getCacheKeyForResourceType(model.getType()));
}
getDelegateForUpdate().removeResource(model);
cached.removeResource(resource);
resources.remove(resource);
}
@Override
public Set<Policy> getAssociatedPolicies() {
if (associatedPolicies == null || updated != null) {
associatedPolicies = new HashSet<>();
for (String id : cached.getAssociatedPoliciesIds()) {
Policy policy = findById(id, cached.getResourceServerId());
if (policy != null) {
associatedPolicies.add(policy);
}
}
}
return associatedPolicies;
}
@Override
public Set<Resource> getResources() {
if (resources == null || updated != null) {
resources = new HashSet<>();
for (String id : cached.getResourcesIds()) {
Resource resource = getCachedStoreFactory().getResourceStore().findById(id, cached.getResourceServerId());
if (resource != null) {
resources.add(resource);
}
}
}
return resources;
}
@Override
public Set<Scope> getScopes() {
if (scopes == null || updated != null) {
scopes = new HashSet<>();
for (String id : cached.getScopesIds()) {
Scope scope = getCachedStoreFactory().getScopeStore().findById(id, cached.getResourceServerId());
if (scope != null) {
scopes.add(scope);
}
}
}
return scopes;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (getId() == null) return false;
if (!Policy.class.isInstance(o)) return false;
Policy that = (Policy) o;
if (!getId().equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return getId()!=null ? getId().hashCode() : super.hashCode();
}
private Policy getDelegateForUpdate() {
if (this.updated == null) {
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
addInvalidation(getCacheKeyForPolicy(updated.getId()));
configureTransaction(updated.getResourceServer(), updated.getId());
}
return this.updated;
}
};
}
private List<Policy> cacheResult(String resourceServerId, String key, Supplier<List<Policy>> provider) {
List<Object> cached = getCachedStoreFactory().computeIfCachedEntryAbsent(resourceServerId, key, (Function<String, List<Object>>) o -> {
List<Policy> result = provider.get();
if (result.isEmpty()) {
return Collections.emptyList();
}
return result.stream().map(policy -> policy.getId()).collect(Collectors.toList());
});
if (cached == null) {
return Collections.emptyList();
}
return cached.stream().map(id -> findById(id.toString(), resourceServerId)).collect(Collectors.toList());
}
private void configureTransaction(ResourceServer resourceServer, String id) {
getTransaction().whenRollback(() -> removeCachedEntry(resourceServer.getId(), getCacheKeyForPolicy(id)));
getTransaction().whenCommit(() -> invalidate(resourceServer.getId()));
}
private PolicyStore getDelegate() {
return delegate;
}
void addInvalidations(Object object) {
if (Resource.class.isInstance(object)) {
Resource resource = (Resource) object;
addInvalidation(getCacheKeyForResource(resource.getId()));
String type = resource.getType();
if (type != null) {
addInvalidation(getCacheKeyForResourceType(type));
}
} else if (Scope.class.isInstance(object)) {
Scope scope = (Scope) object;
addInvalidation(getCacheForScope(scope.getId()));
} else {
throw new RuntimeException("Unexpected notification [" + object + "]");
}
}
}

View file

@ -1,172 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.authorization.infinispan;
import java.util.List;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.authorization.infinispan.entities.CachedResourceServer;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class CachedResourceServerStore extends AbstractCachedStore implements ResourceServerStore {
private static final String RS_PREFIX = "rs-";
private final ResourceServerStore delegate;
public CachedResourceServerStore(InfinispanStoreFactoryProvider cachedStoreFactory, StoreFactory storeFactory) {
super(cachedStoreFactory, storeFactory);
this.delegate = storeFactory.getResourceServerStore();
}
@Override
public ResourceServer create(String clientId) {
ResourceServer resourceServer = getDelegate().create(clientId);
getTransaction().whenCommit(() -> getCachedStoreFactory().removeEntries(resourceServer));
getTransaction().whenRollback(() -> removeCachedEntry(resourceServer.getId(), getCacheKeyForResourceServer(resourceServer.getId())));
return createAdapter(new CachedResourceServer(resourceServer));
}
@Override
public void delete(String id) {
ResourceServer resourceServer = getDelegate().findById(id);
if (resourceServer != null) {
getDelegate().delete(id);
getTransaction().whenCommit(() -> getCachedStoreFactory().removeEntries(resourceServer));
}
}
@Override
public ResourceServer findById(String id) {
String cacheKey = getCacheKeyForResourceServer(id);
if (isInvalid(cacheKey)) {
return getDelegate().findById(id);
}
List<Object> cached = resolveCacheEntry(id, cacheKey);
if (cached == null) {
ResourceServer resourceServer = getDelegate().findById(id);
if (resourceServer != null) {
return createAdapter(putCacheEntry(id, cacheKey, new CachedResourceServer(resourceServer)));
}
return null;
}
return createAdapter(CachedResourceServer.class.cast(cached.get(0)));
}
@Override
public ResourceServer findByClient(String id) {
String cacheKey = getCacheKeyForResourceServerClientId(id);
if (isInvalid(cacheKey)) {
return getDelegate().findByClient(id);
}
List<Object> cached = resolveCacheEntry(id, cacheKey);
if (cached == null) {
ResourceServer resourceServer = getDelegate().findByClient(id);
if (resourceServer != null) {
return findById(putCacheEntry(id, cacheKey, resourceServer.getId()));
}
return null;
}
return findById(cached.get(0).toString());
}
private String getCacheKeyForResourceServer(String id) {
return new StringBuilder(RS_PREFIX).append("id-").append(id).toString();
}
private String getCacheKeyForResourceServerClientId(String id) {
return new StringBuilder(RS_PREFIX).append("findByClientId-").append(id).toString();
}
private ResourceServerStore getDelegate() {
return this.delegate;
}
private ResourceServer createAdapter(ResourceServer cached) {
return new ResourceServer() {
private ResourceServer updated;
@Override
public String getId() {
return cached.getId();
}
@Override
public String getClientId() {
return cached.getClientId();
}
@Override
public boolean isAllowRemoteResourceManagement() {
return cached.isAllowRemoteResourceManagement();
}
@Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
getDelegateForUpdate().setAllowRemoteResourceManagement(allowRemoteResourceManagement);
cached.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
}
@Override
public PolicyEnforcementMode getPolicyEnforcementMode() {
return cached.getPolicyEnforcementMode();
}
@Override
public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
getDelegateForUpdate().setPolicyEnforcementMode(enforcementMode);
cached.setPolicyEnforcementMode(enforcementMode);
}
private ResourceServer getDelegateForUpdate() {
if (this.updated == null) {
this.updated = getDelegate().findById(getId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
addInvalidation(getCacheKeyForResourceServer(updated.getId()));
getTransaction().whenCommit(() -> {
invalidate(updated.getId());
});
}
return this.updated;
}
};
}
}

View file

@ -1,321 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.authorization.infinispan;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.authorization.infinispan.entities.CachedResource;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class CachedResourceStore extends AbstractCachedStore implements ResourceStore {
private static final String RESOURCE_CACHE_PREFIX = "rs-";
private ResourceStore delegate;
public CachedResourceStore(InfinispanStoreFactoryProvider cacheStoreFactory, StoreFactory storeFactory) {
super(cacheStoreFactory, storeFactory);
delegate = storeFactory.getResourceStore();
}
@Override
public Resource create(String name, ResourceServer resourceServer, String owner) {
Resource resource = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
addInvalidation(getCacheKeyForResource(resource.getId()));
addInvalidation(getCacheKeyForResourceName(resource.getName()));
addInvalidation(getCacheKeyForOwner(owner));
getCachedStoreFactory().getPolicyStore().addInvalidations(resource);
getTransaction().whenRollback(() -> removeCachedEntry(resourceServer.getId(), getCacheKeyForResource(resource.getId())));
getTransaction().whenCommit(() -> invalidate(resourceServer.getId()));
return createAdapter(new CachedResource(resource));
}
@Override
public void delete(String id) {
Resource resource = getDelegate().findById(id, null);
if (resource == null) {
return;
}
ResourceServer resourceServer = resource.getResourceServer();
addInvalidation(getCacheKeyForResource(resource.getId()));
addInvalidation(getCacheKeyForResourceName(resource.getName()));
addInvalidation(getCacheKeyForOwner(resource.getOwner()));
addInvalidation(getCacheKeyForUri(resource.getUri()));
getCachedStoreFactory().getPolicyStore().addInvalidations(resource);
getDelegate().delete(id);
getTransaction().whenCommit(() -> {
invalidate(resourceServer.getId());
});
}
@Override
public Resource findById(String id, String resourceServerId) {
String cacheKeyForResource = getCacheKeyForResource(id);
if (isInvalid(cacheKeyForResource)) {
return getDelegate().findById(id, resourceServerId);
}
List<Object> cached = resolveCacheEntry(resourceServerId, cacheKeyForResource);
if (cached == null) {
Resource resource = getDelegate().findById(id, resourceServerId);
if (resource != null) {
return createAdapter(putCacheEntry(resourceServerId, cacheKeyForResource, new CachedResource(resource)));
}
return null;
}
return createAdapter(CachedResource.class.cast(cached.get(0)));
}
@Override
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
String cacheKey = getCacheKeyForOwner(ownerId);
if (isInvalid(cacheKey)) {
return getDelegate().findByOwner(ownerId, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> getDelegate().findByOwner(ownerId, resourceServerId));
}
@Override
public List<Resource> findByUri(String uri, String resourceServerId) {
String cacheKey = getCacheKeyForUri(uri);
if (isInvalid(cacheKey)) {
return getDelegate().findByUri(uri, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> getDelegate().findByUri(uri, resourceServerId));
}
@Override
public List<Resource> findByResourceServer(String resourceServerId) {
return getDelegate().findByResourceServer(resourceServerId);
}
@Override
public List<Resource> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
return getDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
}
@Override
public List<Resource> findByScope(List<String> id, String resourceServerId) {
return getDelegate().findByScope(id, resourceServerId);
}
@Override
public Resource findByName(String name, String resourceServerId) {
String cacheKey = getCacheKeyForResourceName(name);
if (isInvalid(cacheKey)) {
return getDelegate().findByName(name, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> {
Resource resource = getDelegate().findByName(name, resourceServerId);
if (resource == null) {
return Collections.emptyList();
}
return Arrays.asList(resource);
}).stream().findFirst().orElse(null);
}
@Override
public List<Resource> findByType(String type, String resourceServerId) {
return getDelegate().findByType(type, resourceServerId);
}
private String getCacheKeyForResource(String id) {
return new StringBuilder(RESOURCE_CACHE_PREFIX).append("id-").append(id).toString();
}
private String getCacheKeyForResourceName(String name) {
return new StringBuilder(RESOURCE_CACHE_PREFIX).append("findByName-").append(name).toString();
}
private String getCacheKeyForOwner(String name) {
return new StringBuilder(RESOURCE_CACHE_PREFIX).append("findByOwner-").append(name).toString();
}
private String getCacheKeyForUri(String uri) {
return new StringBuilder(RESOURCE_CACHE_PREFIX).append("findByUri-").append(uri).toString();
}
private ResourceStore getDelegate() {
return this.delegate;
}
private List<Resource> cacheResult(String resourceServerId, String key, Supplier<List<Resource>> provider) {
List<Object> cached = getCachedStoreFactory().computeIfCachedEntryAbsent(resourceServerId, key, (Function<String, List<Object>>) o -> {
List<Resource> result = provider.get();
if (result.isEmpty()) {
return Collections.emptyList();
}
return result.stream().map(policy -> policy.getId()).collect(Collectors.toList());
});
if (cached == null) {
return Collections.emptyList();
}
return cached.stream().map(id -> findById(id.toString(), resourceServerId)).collect(Collectors.toList());
}
private Resource createAdapter(CachedResource cached) {
return new Resource() {
private List<Scope> scopes;
private Resource updated;
@Override
public String getId() {
return cached.getId();
}
@Override
public String getName() {
return cached.getName();
}
@Override
public void setName(String name) {
addInvalidation(getCacheKeyForResourceName(name));
addInvalidation(getCacheKeyForResourceName(cached.getName()));
getDelegateForUpdate().setName(name);
cached.setName(name);
}
@Override
public String getUri() {
return cached.getUri();
}
@Override
public void setUri(String uri) {
addInvalidation(getCacheKeyForUri(uri));
addInvalidation(getCacheKeyForUri(cached.getUri()));
getDelegateForUpdate().setUri(uri);
cached.setUri(uri);
}
@Override
public String getType() {
return cached.getType();
}
@Override
public void setType(String type) {
getCachedStoreFactory().getPolicyStore().addInvalidations(cached);
getDelegateForUpdate().setType(type);
cached.setType(type);
}
@Override
public List<Scope> getScopes() {
if (scopes == null) {
scopes = new ArrayList<>();
for (String id : cached.getScopesIds()) {
Scope scope = getCachedStoreFactory().getScopeStore().findById(id, cached.getResourceServerId());
if (scope != null) {
scopes.add(scope);
}
}
}
return scopes;
}
@Override
public String getIconUri() {
return cached.getIconUri();
}
@Override
public void setIconUri(String iconUri) {
getDelegateForUpdate().setIconUri(iconUri);
cached.setIconUri(iconUri);
}
@Override
public ResourceServer getResourceServer() {
return getCachedStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
}
@Override
public String getOwner() {
return cached.getOwner();
}
@Override
public void updateScopes(Set<Scope> scopes) {
getDelegateForUpdate().updateScopes(scopes.stream().map(scope -> getStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId())).collect(Collectors.toSet()));
cached.updateScopes(scopes);
}
private Resource getDelegateForUpdate() {
if (this.updated == null) {
String resourceServerId = cached.getResourceServerId();
this.updated = getDelegate().findById(getId(), resourceServerId);
if (this.updated == null) throw new IllegalStateException("Not found in database");
addInvalidation(getCacheKeyForResource(updated.getId()));
getCachedStoreFactory().getPolicyStore().addInvalidations(updated);
getTransaction().whenCommit(() -> invalidate(resourceServerId));
getTransaction().whenRollback(() -> removeCachedEntry(resourceServerId, getCacheKeyForResource(cached.getId())));
}
return this.updated;
}
};
}
}

View file

@ -1,231 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.authorization.infinispan;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.authorization.infinispan.entities.CachedScope;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class CachedScopeStore extends AbstractCachedStore implements ScopeStore {
private static final String SCOPE_CACHE_PREFIX = "scp-";
private final ScopeStore delegate;
public CachedScopeStore(InfinispanStoreFactoryProvider cacheStoreFactory, StoreFactory storeFactory) {
super(cacheStoreFactory, storeFactory);
this.delegate = storeFactory.getScopeStore();
}
@Override
public Scope create(String name, ResourceServer resourceServer) {
Scope scope = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
addInvalidation(getCacheKeyForScope(scope.getId()));
addInvalidation(getCacheKeyForScopeName(scope.getName()));
getCachedStoreFactory().getPolicyStore().addInvalidations(scope);
getTransaction().whenRollback(() -> removeCachedEntry(resourceServer.getId(), getCacheKeyForScope(scope.getId())));
getTransaction().whenCommit(() -> invalidate(resourceServer.getId()));
return createAdapter(new CachedScope(scope));
}
@Override
public void delete(String id) {
Scope scope = getDelegate().findById(id, null);
if (scope == null) {
return;
}
ResourceServer resourceServer = scope.getResourceServer();
addInvalidation(getCacheKeyForScope(scope.getId()));
addInvalidation(getCacheKeyForScopeName(scope.getName()));
getCachedStoreFactory().getPolicyStore().addInvalidations(scope);
getDelegate().delete(id);
getTransaction().whenCommit(() -> invalidate(resourceServer.getId()));
}
@Override
public Scope findById(String id, String resourceServerId) {
String cacheKey = getCacheKeyForScope(id);
if (isInvalid(cacheKey)) {
return getDelegate().findById(id, resourceServerId);
}
List<Object> cached = resolveCacheEntry(resourceServerId, cacheKey);
if (cached == null) {
Scope scope = getDelegate().findById(id, resourceServerId);
if (scope != null) {
return createAdapter(putCacheEntry(resourceServerId, cacheKey, new CachedScope(scope)));
}
return null;
}
return createAdapter(CachedScope.class.cast(cached.get(0)));
}
@Override
public Scope findByName(String name, String resourceServerId) {
String cacheKey = getCacheKeyForScopeName(name);
if (isInvalid(cacheKey)) {
return getDelegate().findByName(name, resourceServerId);
}
return cacheResult(resourceServerId, cacheKey, () -> {
Scope scope = getDelegate().findByName(name, resourceServerId);
if (scope == null) {
return Collections.emptyList();
}
return Arrays.asList(scope);
}).stream().findFirst().orElse(null);
}
@Override
public List<Scope> findByResourceServer(String id) {
return getDelegate().findByResourceServer(id);
}
@Override
public List<Scope> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
return getDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
}
private String getCacheKeyForScope(String id) {
return new StringBuilder(SCOPE_CACHE_PREFIX).append("id-").append(id).toString();
}
private String getCacheKeyForScopeName(String name) {
return new StringBuilder(SCOPE_CACHE_PREFIX).append("findByName-").append(name).toString();
}
private ScopeStore getDelegate() {
return this.delegate;
}
private List<Scope> cacheResult(String resourceServerId, String key, Supplier<List<Scope>> provider) {
List<Object> cached = getCachedStoreFactory().computeIfCachedEntryAbsent(resourceServerId, key, (Function<String, List<Object>>) o -> {
List<Scope> result = provider.get();
if (result.isEmpty()) {
return Collections.emptyList();
}
return result.stream().map(policy -> policy.getId()).collect(Collectors.toList());
});
if (cached == null) {
return Collections.emptyList();
}
return cached.stream().map(id -> findById(id.toString(), resourceServerId)).collect(Collectors.toList());
}
private Scope createAdapter(CachedScope cached) {
return new Scope() {
private Scope updated;
@Override
public String getId() {
return cached.getId();
}
@Override
public String getName() {
return cached.getName();
}
@Override
public void setName(String name) {
addInvalidation(getCacheKeyForScopeName(name));
addInvalidation(getCacheKeyForScopeName(cached.getName()));
getDelegateForUpdate().setName(name);
cached.setName(name);
}
@Override
public String getIconUri() {
return cached.getIconUri();
}
@Override
public void setIconUri(String iconUri) {
getDelegateForUpdate().setIconUri(iconUri);
cached.setIconUri(iconUri);
}
@Override
public ResourceServer getResourceServer() {
return getCachedStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
}
private Scope getDelegateForUpdate() {
if (this.updated == null) {
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
addInvalidation(getCacheKeyForScope(updated.getId()));
getCachedStoreFactory().getPolicyStore().addInvalidations(updated);
getTransaction().whenCommit(() -> invalidate(cached.getResourceServerId()));
getTransaction().whenRollback(() -> removeCachedEntry(cached.getResourceServerId(), getCacheKeyForScope(cached.getId())));
}
return this.updated;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !Scope.class.isInstance(o)) return false;
Scope that = (Scope) o;
return Objects.equals(getId(), that.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
};
}
}

View file

@ -1,166 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.authorization.infinispan;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class InfinispanStoreFactoryProvider implements CachedStoreFactoryProvider {
private final CacheTransaction transaction;
private final CachedResourceStore resourceStore;
private final CachedScopeStore scopeStore;
private final CachedPolicyStore policyStore;
private final KeycloakSession session;
private final StoreFactoryCacheManager cacheManager;
private ResourceServerStore resourceServerStore;
private Set<String> invalidations = new HashSet<>();
public InfinispanStoreFactoryProvider(KeycloakSession session, StoreFactoryCacheManager cacheManager) {
this.session = session;
this.cacheManager = cacheManager;
this.transaction = new CacheTransaction();
session.getTransactionManager().enlistAfterCompletion(transaction);
StoreFactory delegate = session.getProvider(StoreFactory.class);
resourceStore = new CachedResourceStore(this, delegate);
resourceServerStore = new CachedResourceServerStore(this, delegate);
scopeStore = new CachedScopeStore(this, delegate);
policyStore = new CachedPolicyStore(this, delegate);
}
@Override
public ResourceStore getResourceStore() {
return resourceStore;
}
@Override
public ResourceServerStore getResourceServerStore() {
return resourceServerStore;
}
@Override
public ScopeStore getScopeStore() {
return scopeStore;
}
@Override
public CachedPolicyStore getPolicyStore() {
return policyStore;
}
@Override
public void close() {
}
void addInvalidation(String cacheKey) {
invalidations.add(cacheKey);
}
boolean isInvalid(String cacheKeyForPolicy) {
return invalidations.contains(cacheKeyForPolicy);
}
void invalidate(String resourceServerId) {
cacheManager.invalidate(session, resourceServerId, invalidations);
}
List<Object> resolveCachedEntry(String resourceServerId, String cacheKeyForPolicy) {
return cacheManager.resolveResourceServerCache(resourceServerId).get(cacheKeyForPolicy);
}
void putCacheEntry(String resourceServerId, String key, List<Object> entry) {
cacheManager.resolveResourceServerCache(resourceServerId).put(key, entry);
}
List<Object> computeIfCachedEntryAbsent(String resourceServerId, String key, Function<String, List<Object>> function) {
return cacheManager.resolveResourceServerCache(resourceServerId).computeIfAbsent(key, function);
}
CacheTransaction getTransaction() {
return transaction;
}
void removeCachedEntry(String id, String key) {
cacheManager.resolveResourceServerCache(id).remove(key);
}
void removeEntries(ResourceServer resourceServer) {
cacheManager.removeAll(session, resourceServer);
}
static class CacheTransaction implements KeycloakTransaction {
private List<Runnable> completeTasks = new ArrayList<>();
private List<Runnable> rollbackTasks = new ArrayList<>();
@Override
public void begin() {
}
@Override
public void commit() {
this.completeTasks.forEach(task -> task.run());
}
@Override
public void rollback() {
this.rollbackTasks.forEach(task -> task.run());
}
@Override
public void setRollbackOnly() {
}
@Override
public boolean getRollbackOnly() {
return false;
}
@Override
public boolean isActive() {
return false;
}
protected void whenCommit(Runnable task) {
this.completeTasks.add(task);
}
protected void whenRollback(Runnable task) {
this.rollbackTasks.add(task);
}
}
}

View file

@ -1,89 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.authorization.infinispan;
import java.util.List;
import java.util.Map;
import org.infinispan.Cache;
import org.keycloak.Config;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.authorization.infinispan.events.AuthorizationInvalidationEvent;
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class InfinispanStoreProviderFactory implements CachedStoreProviderFactory, EnvironmentDependentProviderFactory {
private StoreFactoryCacheManager cacheManager;
@Override
public CachedStoreFactoryProvider create(KeycloakSession session) {
return new InfinispanStoreFactoryProvider(session, cacheManager);
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
KeycloakSession session = factory.create();
try {
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, Map<String, List<Object>>> cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
cacheManager = new StoreFactoryCacheManager(cache);
clusterProvider.registerListener(ClusterProvider.ALL, event -> {
if (event instanceof AuthorizationInvalidationEvent) {
cacheManager.invalidate(AuthorizationInvalidationEvent.class.cast(event));
}
});
} finally {
if (session != null) {
session.close();
}
}
}
@Override
public void close() {
}
@Override
public String getId() {
return "infinispan-authz-store-factory";
}
@Override
public boolean isSupported() {
return true;
}
}

View file

@ -1,72 +0,0 @@
/*
* Copyright 2016 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.authorization.infinispan;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.infinispan.Cache;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.authorization.infinispan.events.AuthorizationInvalidationEvent;
import org.keycloak.models.authorization.infinispan.events.ResourceServerRemovedEvent;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class StoreFactoryCacheManager {
private static final String AUTHORIZATION_UPDATE_TASK_KEY = "authorization-update";
private final Cache<String, Map<String, List<Object>>> cache;
StoreFactoryCacheManager(Cache<String, Map<String, List<Object>>> cache) {
this.cache = cache;
}
void invalidate(AuthorizationInvalidationEvent event) {
if (event instanceof ResourceServerRemovedEvent) {
cache.remove(event.getId());
cache.remove(ResourceServerRemovedEvent.class.cast(event).getClientId());
} else {
Map<String, List<Object>> resolveResourceServerCache = resolveResourceServerCache(event.getId());
for (String key : event.getInvalidations()) {
resolveResourceServerCache.remove(key);
}
}
}
public void invalidate(KeycloakSession session, String resourceServerId, Set<String> invalidations) {
getClusterProvider(session).notify(AUTHORIZATION_UPDATE_TASK_KEY, new AuthorizationInvalidationEvent(resourceServerId, invalidations), false);
}
public Map<String, List<Object>> resolveResourceServerCache(String id) {
return cache.computeIfAbsent(id, key -> new HashMap<>());
}
void removeAll(KeycloakSession session, ResourceServer id) {
getClusterProvider(session).notify(AUTHORIZATION_UPDATE_TASK_KEY, new ResourceServerRemovedEvent(id.getId(), id.getClientId()), false);
}
private ClusterProvider getClusterProvider(KeycloakSession session) {
return session.getProvider(ClusterProvider.class);
}
}

View file

@ -1,44 +0,0 @@
/*
* Copyright 2016 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.authorization.infinispan.events;
import java.util.Set;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationInvalidationEvent extends InvalidationEvent {
private final String resourceServerId;
private Set<String> invalidations;
public AuthorizationInvalidationEvent(String resourceServerId, Set<String> invalidations) {
this.resourceServerId = resourceServerId;
this.invalidations = invalidations;
}
public Set<String> getInvalidations() {
return invalidations;
}
@Override
public String getId() {
return resourceServerId;
}
}

View file

@ -215,7 +215,7 @@ public abstract class CacheManager {
} }
protected void invalidationEventReceived(InvalidationEvent event) { public void invalidationEventReceived(InvalidationEvent event) {
Set<String> invalidations = new HashSet<>(); Set<String> invalidations = new HashSet<>();
addInvalidationsFromEvent(event, invalidations); addInvalidationsFromEvent(event, invalidations);

View file

@ -0,0 +1,102 @@
/*
* Copyright 2016 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;
import org.infinispan.Cache;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.CacheRealmProviderFactory;
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import org.keycloak.models.cache.infinispan.RealmCacheSession;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class InfinispanCacheStoreFactoryProviderFactory implements CachedStoreProviderFactory {
private static final Logger log = Logger.getLogger(InfinispanCacheStoreFactoryProviderFactory.class);
public static final String AUTHORIZATION_CLEAR_CACHE_EVENTS = "AUTHORIZATION_CLEAR_CACHE_EVENTS";
protected volatile StoreFactoryCacheManager storeCache;
@Override
public CachedStoreFactoryProvider create(KeycloakSession session) {
lazyInit(session);
return new StoreFactoryCacheSession(storeCache, session);
}
private void lazyInit(KeycloakSession session) {
if (storeCache == null) {
synchronized (this) {
if (storeCache == null) {
Cache<String, Revisioned> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
Cache<String, Long> revisions = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME);
storeCache = new StoreFactoryCacheManager(cache, revisions);
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
cluster.registerListener(ClusterProvider.ALL, (ClusterEvent event) -> {
if (event instanceof InvalidationEvent) {
InvalidationEvent invalidationEvent = (InvalidationEvent) event;
storeCache.invalidationEventReceived(invalidationEvent);
}
});
cluster.registerListener(AUTHORIZATION_CLEAR_CACHE_EVENTS, (ClusterEvent event) -> {
storeCache.clear();
});
log.debug("Registered cluster listeners");
}
}
}
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "default";
}
}

View file

@ -0,0 +1,280 @@
/*
* Copyright 2016 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;
import org.keycloak.authorization.model.CachedModel;
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.models.cache.infinispan.authorization.entities.CachedPolicy;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class PolicyAdapter implements Policy, CachedModel<Policy> {
protected CachedPolicy cached;
protected StoreFactoryCacheSession cacheSession;
protected Policy updated;
public PolicyAdapter(CachedPolicy cached, StoreFactoryCacheSession cacheSession) {
this.cached = cached;
this.cacheSession = cacheSession;
}
@Override
public Policy getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
if (updated == null) throw new IllegalStateException("Not found in database");
}
return updated;
}
protected boolean invalidated;
protected void invalidateFlag() {
invalidated = true;
}
@Override
public void invalidate() {
invalidated = true;
getDelegateForUpdate();
}
@Override
public long getCacheTimestamp() {
return cached.getCacheTimestamp();
}
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
@Override
public String getId() {
if (isUpdated()) return updated.getId();
return cached.getId();
}
@Override
public String getName() {
if (isUpdated()) return updated.getName();
return cached.getName();
}
@Override
public void setName(String name) {
getDelegateForUpdate();
updated.setName(name);
}
@Override
public ResourceServer getResourceServer() {
return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
}
@Override
public String getType() {
if (isUpdated()) return updated.getType();
return cached.getType();
}
@Override
public DecisionStrategy getDecisionStrategy() {
if (isUpdated()) return updated.getDecisionStrategy();
return cached.getDecisionStrategy();
}
@Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
getDelegateForUpdate();
updated.setDecisionStrategy(decisionStrategy);
}
@Override
public Logic getLogic() {
if (isUpdated()) return updated.getLogic();
return cached.getLogic();
}
@Override
public void setLogic(Logic logic) {
getDelegateForUpdate();
updated.setLogic(logic);
}
@Override
public Map<String, String> getConfig() {
if (isUpdated()) return updated.getConfig();
return cached.getConfig();
}
@Override
public void setConfig(Map<String, String> config) {
getDelegateForUpdate();
updated.setConfig(config);
}
@Override
public void removeConfig(String name) {
getDelegateForUpdate();
updated.removeConfig(name);
}
@Override
public void putConfig(String name, String value) {
getDelegateForUpdate();
updated.putConfig(name, value);
}
@Override
public String getDescription() {
if (isUpdated()) return updated.getDescription();
return cached.getDescription();
}
@Override
public void setDescription(String description) {
getDelegateForUpdate();
updated.setDescription(description);
}
protected Set<Policy> associatedPolicies;
@Override
public Set<Policy> getAssociatedPolicies() {
if (isUpdated()) return updated.getAssociatedPolicies();
if (associatedPolicies != null) return associatedPolicies;
associatedPolicies = new HashSet<>();
for (String scopeId : cached.getAssociatedPoliciesIds()) {
associatedPolicies.add(cacheSession.getPolicyStore().findById(scopeId, cached.getResourceServerId()));
}
associatedPolicies = Collections.unmodifiableSet(associatedPolicies);
return associatedPolicies;
}
protected Set<Resource> resources;
@Override
public Set<Resource> getResources() {
if (isUpdated()) return updated.getResources();
if (resources != null) return resources;
resources = new HashSet<>();
for (String resourceId : cached.getResourcesIds()) {
resources.add(cacheSession.getResourceStore().findById(resourceId, cached.getResourceServerId()));
}
resources = Collections.unmodifiableSet(resources);
return resources;
}
@Override
public void addScope(Scope scope) {
getDelegateForUpdate();
updated.addScope(scope);
}
@Override
public void removeScope(Scope scope) {
getDelegateForUpdate();
updated.removeScope(scope);
}
@Override
public void addAssociatedPolicy(Policy associatedPolicy) {
getDelegateForUpdate();
updated.addAssociatedPolicy(associatedPolicy);
}
@Override
public void removeAssociatedPolicy(Policy associatedPolicy) {
getDelegateForUpdate();
updated.removeAssociatedPolicy(associatedPolicy);
}
@Override
public void addResource(Resource resource) {
getDelegateForUpdate();
updated.addResource(resource);
}
@Override
public void removeResource(Resource resource) {
getDelegateForUpdate();
updated.removeResource(resource);
}
protected Set<Scope> scopes;
@Override
public Set<Scope> getScopes() {
if (isUpdated()) return updated.getScopes();
if (scopes != null) return scopes;
scopes = new HashSet<>();
for (String scopeId : cached.getScopesIds()) {
scopes.add(cacheSession.getScopeStore().findById(scopeId, cached.getResourceServerId()));
}
scopes = Collections.unmodifiableSet(scopes);
return scopes;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Policy)) return false;
Policy that = (Policy) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -0,0 +1,184 @@
/*
* Copyright 2016 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;
import org.keycloak.authorization.model.CachedModel;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.models.cache.infinispan.authorization.entities.CachedResource;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceAdapter implements Resource, CachedModel<Resource> {
protected CachedResource cached;
protected StoreFactoryCacheSession cacheSession;
protected Resource updated;
public ResourceAdapter(CachedResource cached, StoreFactoryCacheSession cacheSession) {
this.cached = cached;
this.cacheSession = cacheSession;
}
@Override
public Resource getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
if (updated == null) throw new IllegalStateException("Not found in database");
}
return updated;
}
protected boolean invalidated;
protected void invalidateFlag() {
invalidated = true;
}
@Override
public void invalidate() {
invalidated = true;
getDelegateForUpdate();
}
@Override
public long getCacheTimestamp() {
return cached.getCacheTimestamp();
}
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
@Override
public String getId() {
if (isUpdated()) return updated.getId();
return cached.getId();
}
@Override
public String getName() {
if (isUpdated()) return updated.getName();
return cached.getName();
}
@Override
public void setName(String name) {
getDelegateForUpdate();
updated.setName(name);
}
@Override
public String getIconUri() {
if (isUpdated()) return updated.getIconUri();
return cached.getIconUri();
}
@Override
public void setIconUri(String iconUri) {
getDelegateForUpdate();
updated.setIconUri(iconUri);
}
@Override
public ResourceServer getResourceServer() {
return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
}
@Override
public String getUri() {
if (isUpdated()) return updated.getUri();
return cached.getUri();
}
@Override
public void setUri(String uri) {
getDelegateForUpdate();
updated.setUri(uri);
}
@Override
public String getType() {
if (isUpdated()) return updated.getType();
return cached.getType();
}
@Override
public void setType(String type) {
getDelegateForUpdate();
updated.setType(type);
}
protected List<Scope> scopes;
@Override
public List<Scope> getScopes() {
if (isUpdated()) return updated.getScopes();
if (scopes != null) return scopes;
scopes = new LinkedList<>();
for (String scopeId : cached.getScopesIds()) {
scopes.add(cacheSession.getScopeStore().findById(scopeId, cached.getResourceServerId()));
}
scopes = Collections.unmodifiableList(scopes);
return scopes;
}
@Override
public String getOwner() {
if (isUpdated()) return updated.getOwner();
return cached.getOwner();
}
@Override
public void updateScopes(Set<Scope> scopes) {
getDelegateForUpdate();
updated.updateScopes(scopes);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Resource)) return false;
Resource that = (Resource) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright 2016 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;
import org.keycloak.authorization.model.CachedModel;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceServerAdapter implements ResourceServer, CachedModel<ResourceServer> {
protected CachedResourceServer cached;
protected StoreFactoryCacheSession cacheSession;
protected ResourceServer updated;
public ResourceServerAdapter(CachedResourceServer cached, StoreFactoryCacheSession cacheSession) {
this.cached = cached;
this.cacheSession = cacheSession;
}
@Override
public ResourceServer getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerResourceServerInvalidation(cached.getId(), cached.getClientId());
updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
if (updated == null) throw new IllegalStateException("Not found in database");
}
return updated;
}
protected boolean invalidated;
protected void invalidateFlag() {
invalidated = true;
}
@Override
public void invalidate() {
invalidated = true;
getDelegateForUpdate();
}
@Override
public long getCacheTimestamp() {
return cached.getCacheTimestamp();
}
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
@Override
public String getId() {
if (isUpdated()) return updated.getId();
return cached.getId();
}
@Override
public String getClientId() {
if (isUpdated()) return updated.getClientId();
return cached.getClientId();
}
@Override
public boolean isAllowRemoteResourceManagement() {
if (isUpdated()) return updated.isAllowRemoteResourceManagement();
return cached.isAllowRemoteResourceManagement();
}
@Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
getDelegateForUpdate();
updated.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
}
@Override
public PolicyEnforcementMode getPolicyEnforcementMode() {
if (isUpdated()) return updated.getPolicyEnforcementMode();
return cached.getPolicyEnforcementMode();
}
@Override
public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
getDelegateForUpdate();
updated.setPolicyEnforcementMode(enforcementMode);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof ResourceServer)) return false;
ResourceServer that = (ResourceServer) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright 2016 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;
import org.keycloak.authorization.model.CachedModel;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.models.cache.infinispan.authorization.entities.CachedScope;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ScopeAdapter implements Scope, CachedModel<Scope> {
protected CachedScope cached;
protected StoreFactoryCacheSession cacheSession;
protected Scope updated;
public ScopeAdapter(CachedScope cached, StoreFactoryCacheSession cacheSession) {
this.cached = cached;
this.cacheSession = cacheSession;
}
@Override
public Scope getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerScopeInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
updated = cacheSession.getScopeStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
if (updated == null) throw new IllegalStateException("Not found in database");
}
return updated;
}
protected boolean invalidated;
protected void invalidateFlag() {
invalidated = true;
}
@Override
public void invalidate() {
invalidated = true;
getDelegateForUpdate();
}
@Override
public long getCacheTimestamp() {
return cached.getCacheTimestamp();
}
protected boolean isUpdated() {
if (updated != null) return true;
if (!invalidated) return false;
updated = cacheSession.getScopeStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
if (updated == null) throw new IllegalStateException("Not found in database");
return true;
}
@Override
public String getId() {
if (isUpdated()) return updated.getId();
return cached.getId();
}
@Override
public String getName() {
if (isUpdated()) return updated.getName();
return cached.getName();
}
@Override
public void setName(String name) {
getDelegateForUpdate();
updated.setName(name);
}
@Override
public String getIconUri() {
if (isUpdated()) return updated.getIconUri();
return cached.getIconUri();
}
@Override
public void setIconUri(String iconUri) {
getDelegateForUpdate();
updated.setIconUri(iconUri);
}
@Override
public ResourceServer getResourceServer() {
return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Scope)) return false;
Scope that = (Scope) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright 2016 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;
import org.infinispan.Cache;
import org.jboss.logging.Logger;
import org.keycloak.models.cache.infinispan.CacheManager;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import org.keycloak.models.cache.infinispan.authorization.events.AuthorizationCacheInvalidationEvent;
import org.keycloak.models.cache.infinispan.authorization.stream.InResourceServerPredicate;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class StoreFactoryCacheManager extends CacheManager {
private static final Logger logger = Logger.getLogger(RealmCacheManager.class);
public StoreFactoryCacheManager(Cache<String, Revisioned> cache, Cache<String, Long> revisions) {
super(cache, revisions);
}
@Override
protected Logger getLogger() {
return logger;
}
@Override
protected void addInvalidationsFromEvent(InvalidationEvent event, Set<String> invalidations) {
if (event instanceof AuthorizationCacheInvalidationEvent) {
invalidations.add(event.getId());
((AuthorizationCacheInvalidationEvent) event).addInvalidations(this, invalidations);
}
}
public void resourceServerUpdated(String id, String clientId, Set<String> invalidations) {
invalidations.add(id);
invalidations.add(StoreFactoryCacheSession.getResourceServerByClientCacheKey(clientId));
}
public void resourceServerRemoval(String id, String name, Set<String> invalidations) {
resourceServerUpdated(id, name, invalidations);
addInvalidations(InResourceServerPredicate.create().resourceServer(id), invalidations);
}
public void scopeUpdated(String id, String name, String serverId, Set<String> invalidations) {
invalidations.add(id);
invalidations.add(StoreFactoryCacheSession.getScopeByNameCacheKey(name, serverId));
}
public void scopeRemoval(String id, String name, String serverId, Set<String> invalidations) {
scopeUpdated(id, name, serverId, invalidations);
}
public void resourceUpdated(String id, String name, String serverId, Set<String> invalidations) {
invalidations.add(id);
invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
}
public void resourceRemoval(String id, String name, String serverId, Set<String> invalidations) {
resourceUpdated(id, name, serverId, invalidations);
}
public void policyUpdated(String id, String name, String serverId, Set<String> invalidations) {
invalidations.add(id);
invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
}
public void policyRemoval(String id, String name, String serverId, Set<String> invalidations) {
policyUpdated(id, name, serverId, invalidations);
}
}

View file

@ -0,0 +1,667 @@
/*
* Copyright 2016 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;
import org.jboss.logging.Logger;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
import org.keycloak.models.cache.infinispan.authorization.entities.CachedPolicy;
import org.keycloak.models.cache.infinispan.authorization.entities.CachedResource;
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.PolicyListQuery;
import org.keycloak.models.cache.infinispan.authorization.entities.ResourceListQuery;
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.events.PolicyRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.PolicyUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ScopeRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ScopeUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
protected static final Logger logger = Logger.getLogger(StoreFactoryCacheSession.class);
protected StoreFactoryCacheManager cache;
protected boolean transactionActive;
protected boolean setRollbackOnly;
protected Map<String, ResourceServerAdapter> managedResourceServers = new HashMap<>();
protected Map<String, ScopeAdapter> managedScopes = new HashMap<>();
protected Map<String, ResourceAdapter> managedResources = new HashMap<>();
protected Map<String, PolicyAdapter> managedPolicies = new HashMap<>();
protected Set<String> invalidations = new HashSet<>();
protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
protected boolean clearAll;
protected final long startupRevision;
protected StoreFactory delegate;
protected KeycloakSession session;
protected ResourceServerCache resourceServerCache;
protected ScopeCache scopeCache;
protected ResourceCache resourceCache;
protected PolicyCache policyCache;
public StoreFactoryCacheSession(StoreFactoryCacheManager cache, KeycloakSession session) {
this.cache = cache;
this.startupRevision = cache.getCurrentCounter();
this.session = session;
this.resourceServerCache = new ResourceServerCache();
this.scopeCache = new ScopeCache();
this.resourceCache = new ResourceCache();
this.policyCache = new PolicyCache();
session.getTransactionManager().enlistPrepare(getPrepareTransaction());
session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
}
@Override
public ResourceServerStore getResourceServerStore() {
return resourceServerCache;
}
@Override
public ScopeStore getScopeStore() {
return scopeCache;
}
@Override
public ResourceStore getResourceStore() {
return resourceCache;
}
@Override
public PolicyStore getPolicyStore() {
return policyCache;
}
public void close() {
}
private KeycloakTransaction getPrepareTransaction() {
return new KeycloakTransaction() {
@Override
public void begin() {
transactionActive = true;
}
@Override
public void commit() {
}
@Override
public void rollback() {
setRollbackOnly = true;
transactionActive = false;
}
@Override
public void setRollbackOnly() {
setRollbackOnly = true;
}
@Override
public boolean getRollbackOnly() {
return setRollbackOnly;
}
@Override
public boolean isActive() {
return transactionActive;
}
};
}
private KeycloakTransaction getAfterTransaction() {
return new KeycloakTransaction() {
@Override
public void begin() {
transactionActive = true;
}
@Override
public void commit() {
try {
if (getDelegate() == null) return;
if (clearAll) {
cache.clear();
}
runInvalidations();
transactionActive = false;
} finally {
cache.endRevisionBatch();
}
}
@Override
public void rollback() {
try {
setRollbackOnly = true;
runInvalidations();
transactionActive = false;
} finally {
cache.endRevisionBatch();
}
}
@Override
public void setRollbackOnly() {
setRollbackOnly = true;
}
@Override
public boolean getRollbackOnly() {
return setRollbackOnly;
}
@Override
public boolean isActive() {
return transactionActive;
}
};
}
protected void runInvalidations() {
for (String id : invalidations) {
cache.invalidateObject(id);
}
cache.sendInvalidationEvents(session, invalidationEvents);
}
public long getStartupRevision() {
return startupRevision;
}
public boolean isInvalid(String id) {
return invalidations.contains(id);
}
public void registerResourceServerInvalidation(String id, String clientId) {
cache.resourceServerUpdated(id, clientId, invalidations);
ResourceServerAdapter adapter = managedResourceServers.get(id);
if (adapter != null) adapter.invalidateFlag();
invalidationEvents.add(ResourceServerUpdatedEvent.create(id, clientId));
}
public void registerScopeInvalidation(String id, String name, String serverId) {
cache.scopeUpdated(id, name, serverId, invalidations);
ScopeAdapter adapter = managedScopes.get(id);
if (adapter != null) adapter.invalidateFlag();
invalidationEvents.add(ScopeUpdatedEvent.create(id, name, serverId));
}
public void registerResourceInvalidation(String id, String name, String serverId) {
cache.resourceUpdated(id, name, serverId, invalidations);
ResourceAdapter adapter = managedResources.get(id);
if (adapter != null) adapter.invalidateFlag();
invalidationEvents.add(ResourceUpdatedEvent.create(id, name, serverId));
}
public void registerPolicyInvalidation(String id, String name, String serverId) {
cache.policyUpdated(id, name, serverId, invalidations);
PolicyAdapter adapter = managedPolicies.get(id);
if (adapter != null) adapter.invalidateFlag();
invalidationEvents.add(PolicyUpdatedEvent.create(id, name, serverId));
}
public ResourceServerStore getResourceServerStoreDelegate() {
return getDelegate().getResourceServerStore();
}
public ScopeStore getScopeStoreDelegate() {
return getDelegate().getScopeStore();
}
public ResourceStore getResourceStoreDelegate() {
return getDelegate().getResourceStore();
}
public PolicyStore getPolicyStoreDelegate() {
return getDelegate().getPolicyStore();
}
public static String getResourceServerByClientCacheKey(String clientId) {
return "resource.server.client.id." + clientId;
}
public static String getScopeByNameCacheKey(String name, String serverId) {
return "scope.name." + name + "." + serverId;
}
public static String getResourceByNameCacheKey(String name, String serverId) {
return "resource.name." + name + "." + serverId;
}
public static String getPolicyByNameCacheKey(String name, String serverId) {
return "policy.name." + name + "." + serverId;
}
public StoreFactory getDelegate() {
if (delegate != null) return delegate;
delegate = session.getProvider(StoreFactory.class);
return delegate;
}
protected class ResourceServerCache implements ResourceServerStore {
@Override
public ResourceServer create(String clientId) {
ResourceServer server = getResourceServerStoreDelegate().create(clientId);
registerResourceServerInvalidation(server.getId(), server.getClientId());
return server;
}
@Override
public void delete(String id) {
if (id == null) return;
ResourceServer server = findById(id);
if (server == null) return;
cache.invalidateObject(id);
invalidationEvents.add(ResourceServerRemovedEvent.create(id, server.getClientId()));
cache.resourceServerRemoval(id, server.getClientId(), invalidations);
getResourceServerStoreDelegate().delete(id);
}
@Override
public ResourceServer findById(String id) {
if (id == null) return null;
CachedResourceServer cached = cache.get(id, CachedResourceServer.class);
if (cached != null) {
logger.tracev("by id cache hit: {0}", cached.getId());
}
boolean wasCached = false;
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
ResourceServer model = getResourceServerStoreDelegate().findById(id);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedResourceServer(loaded, model);
cache.addRevisioned(cached, startupRevision);
wasCached =true;
} else if (invalidations.contains(id)) {
return getResourceServerStoreDelegate().findById(id);
} else if (managedResourceServers.containsKey(id)) {
return managedResourceServers.get(id);
}
ResourceServerAdapter adapter = new ResourceServerAdapter(cached, StoreFactoryCacheSession.this);
managedResourceServers.put(id, adapter);
return adapter;
}
@Override
public ResourceServer findByClient(String clientId) {
String cacheKey = getResourceServerByClientCacheKey(clientId);
ResourceServerListQuery query = cache.get(cacheKey, ResourceServerListQuery.class);
if (query != null) {
logger.tracev("ResourceServer by clientId cache hit: {0}", clientId);
}
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
ResourceServer model = getResourceServerStoreDelegate().findByClient(clientId);
if (model == null) return null;
if (invalidations.contains(model.getId())) return model;
query = new ResourceServerListQuery(loaded, cacheKey, model.getId());
cache.addRevisioned(query, startupRevision);
return model;
} else if (invalidations.contains(cacheKey)) {
return getResourceServerStoreDelegate().findByClient(clientId);
} else {
String serverId = query.getResourceServers().iterator().next();
if (invalidations.contains(serverId)) {
return getResourceServerStoreDelegate().findByClient(clientId);
}
return findById(serverId);
}
}
}
protected class ScopeCache implements ScopeStore {
@Override
public Scope create(String name, ResourceServer resourceServer) {
Scope scope = getScopeStoreDelegate().create(name, resourceServer);
registerScopeInvalidation(scope.getId(), scope.getName(), resourceServer.getId());
return scope;
}
@Override
public void delete(String id) {
if (id == null) return;
Scope scope = findById(id, null);
if (scope == null) return;
cache.invalidateObject(id);
invalidationEvents.add(ScopeRemovedEvent.create(id, scope.getName(), scope.getResourceServer().getId()));
cache.scopeRemoval(id, scope.getName(), scope.getResourceServer().getId(), invalidations);
getScopeStoreDelegate().delete(id);
}
@Override
public Scope findById(String id, String resourceServerId) {
if (id == null) return null;
CachedScope cached = cache.get(id, CachedScope.class);
if (cached != null) {
logger.tracev("by id cache hit: {0}", cached.getId());
}
boolean wasCached = false;
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
Scope model = getScopeStoreDelegate().findById(id, resourceServerId);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedScope(loaded, model);
cache.addRevisioned(cached, startupRevision);
wasCached =true;
} else if (invalidations.contains(id)) {
return getScopeStoreDelegate().findById(id, resourceServerId);
} else if (managedScopes.containsKey(id)) {
return managedScopes.get(id);
}
ScopeAdapter adapter = new ScopeAdapter(cached, StoreFactoryCacheSession.this);
managedScopes.put(id, adapter);
return adapter;
}
@Override
public Scope findByName(String name, String resourceServerId) {
if (name == null) return null;
String cacheKey = getScopeByNameCacheKey(name, resourceServerId);
ScopeListQuery query = cache.get(cacheKey, ScopeListQuery.class);
if (query != null) {
logger.tracev("scope by name cache hit: {0}", name);
}
if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
Scope model = getScopeStoreDelegate().findByName(name, resourceServerId);
if (model == null) return null;
if (invalidations.contains(model.getId())) return model;
query = new ScopeListQuery(loaded, cacheKey, model.getId(), resourceServerId);
cache.addRevisioned(query, startupRevision);
return model;
} else if (invalidations.contains(cacheKey)) {
return getScopeStoreDelegate().findByName(name, resourceServerId);
} else {
String id = query.getScopes().iterator().next();
if (invalidations.contains(id)) {
return getScopeStoreDelegate().findByName(name, resourceServerId);
}
return findById(id, query.getResourceServerId());
}
}
@Override
public List<Scope> findByResourceServer(String id) {
return getScopeStoreDelegate().findByResourceServer(id);
}
@Override
public List<Scope> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
return getScopeStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
}
}
protected class ResourceCache implements ResourceStore {
@Override
public Resource create(String name, ResourceServer resourceServer, String owner) {
Resource resource = getResourceStoreDelegate().create(name, resourceServer, owner);
registerResourceInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
return resource;
}
@Override
public void delete(String id) {
if (id == null) return;
Resource resource = findById(id, null);
if (resource == null) return;
cache.invalidateObject(id);
invalidationEvents.add(ResourceRemovedEvent.create(id, resource.getName(), resource.getResourceServer().getId()));
cache.resourceRemoval(id, resource.getName(), resource.getResourceServer().getId(), invalidations);
getResourceStoreDelegate().delete(id);
}
@Override
public Resource findById(String id, String resourceServerId) {
if (id == null) return null;
CachedResource cached = cache.get(id, CachedResource.class);
if (cached != null) {
logger.tracev("by id cache hit: {0}", cached.getId());
}
boolean wasCached = false;
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
Resource model = getResourceStoreDelegate().findById(id, resourceServerId);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedResource(loaded, model);
cache.addRevisioned(cached, startupRevision);
wasCached =true;
} else if (invalidations.contains(id)) {
return getResourceStoreDelegate().findById(id, resourceServerId);
} else if (managedResources.containsKey(id)) {
return managedResources.get(id);
}
ResourceAdapter adapter = new ResourceAdapter(cached, StoreFactoryCacheSession.this);
managedResources.put(id, adapter);
return adapter;
}
@Override
public Resource findByName(String name, String resourceServerId) {
if (name == null) return null;
String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
ResourceListQuery query = cache.get(cacheKey, ResourceListQuery.class);
if (query != null) {
logger.tracev("resource by name cache hit: {0}", name);
}
if (query == null) {
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());
}
}
@Override
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
return getResourceStoreDelegate().findByOwner(ownerId, resourceServerId);
}
@Override
public List<Resource> findByUri(String uri, String resourceServerId) {
return getResourceStoreDelegate().findByUri(uri, resourceServerId);
}
@Override
public List<Resource> findByResourceServer(String resourceServerId) {
return getResourceStoreDelegate().findByResourceServer(resourceServerId);
}
@Override
public List<Resource> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
return getResourceStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
}
@Override
public List<Resource> findByScope(List<String> ids, String resourceServerId) {
return getResourceStoreDelegate().findByScope(ids, resourceServerId);
}
@Override
public List<Resource> findByType(String type, String resourceServerId) {
return getResourceStoreDelegate().findByType(type, resourceServerId);
}
}
protected class PolicyCache implements PolicyStore {
@Override
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
Policy resource = getPolicyStoreDelegate().create(representation, resourceServer);
registerPolicyInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
return resource;
}
@Override
public void delete(String id) {
if (id == null) return;
Policy policy = findById(id, null);
if (policy == null) return;
cache.invalidateObject(id);
invalidationEvents.add(PolicyRemovedEvent.create(id, policy.getName(), policy.getResourceServer().getId()));
cache.policyRemoval(id, policy.getName(), policy.getResourceServer().getId(), invalidations);
getPolicyStoreDelegate().delete(id);
}
@Override
public Policy findById(String id, String resourceServerId) {
if (id == null) return null;
CachedPolicy cached = cache.get(id, CachedPolicy.class);
if (cached != null) {
logger.tracev("by id cache hit: {0}", cached.getId());
}
boolean wasCached = false;
if (cached == null) {
Long loaded = cache.getCurrentRevision(id);
Policy model = getPolicyStoreDelegate().findById(id, resourceServerId);
if (model == null) return null;
if (invalidations.contains(id)) return model;
cached = new CachedPolicy(loaded, model);
cache.addRevisioned(cached, startupRevision);
wasCached =true;
} else if (invalidations.contains(id)) {
return getPolicyStoreDelegate().findById(id, resourceServerId);
} else if (managedPolicies.containsKey(id)) {
return managedPolicies.get(id);
}
PolicyAdapter adapter = new PolicyAdapter(cached, StoreFactoryCacheSession.this);
managedPolicies.put(id, adapter);
return adapter;
}
@Override
public Policy findByName(String name, String resourceServerId) {
if (name == null) return null;
String cacheKey = getPolicyByNameCacheKey(name, resourceServerId);
PolicyListQuery query = cache.get(cacheKey, PolicyListQuery.class);
if (query != null) {
logger.tracev("policy by name cache hit: {0}", name);
}
if (query == null) {
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());
}
}
@Override
public List<Policy> findByResourceServer(String resourceServerId) {
return getPolicyStoreDelegate().findByResourceServer(resourceServerId);
}
@Override
public List<Policy> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
return getPolicyStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
}
@Override
public List<Policy> findByResource(String resourceId, String resourceServerId) {
return getPolicyStoreDelegate().findByResource(resourceId, resourceServerId);
}
@Override
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
return getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId);
}
@Override
public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
return getPolicyStoreDelegate().findByScopeIds(scopeIds, resourceServerId);
}
@Override
public List<Policy> findByType(String type, String resourceServerId) {
return getPolicyStoreDelegate().findByType(type, resourceServerId);
}
@Override
public List<Policy> findDependentPolicies(String id, String resourceServerId) {
return getPolicyStoreDelegate().findDependentPolicies(id, resourceServerId);
}
}
}

View file

@ -16,12 +16,13 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.models.authorization.infinispan.entities; package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource; 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.models.cache.infinispan.entities.AbstractRevisioned;
import org.keycloak.representations.idm.authorization.DecisionStrategy; import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic; import org.keycloak.representations.idm.authorization.Logic;
@ -34,11 +35,8 @@ import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public class CachedPolicy implements Policy, Serializable { public class CachedPolicy extends AbstractRevisioned implements InResourceServer {
private static final long serialVersionUID = -144247681046298128L;
private String id;
private String type; private String type;
private DecisionStrategy decisionStrategy; private DecisionStrategy decisionStrategy;
private Logic logic; private Logic logic;
@ -50,8 +48,8 @@ public class CachedPolicy implements Policy, Serializable {
private Set<String> resourcesIds; private Set<String> resourcesIds;
private Set<String> scopesIds; private Set<String> scopesIds;
public CachedPolicy(Policy policy) { public CachedPolicy(Long revision, Policy policy) {
this.id = policy.getId(); super(revision, policy.getId());
this.type = policy.getType(); this.type = policy.getType();
this.decisionStrategy = policy.getDecisionStrategy(); this.decisionStrategy = policy.getDecisionStrategy();
this.logic = policy.getLogic(); this.logic = policy.getLogic();
@ -64,120 +62,30 @@ public class CachedPolicy implements Policy, Serializable {
this.scopesIds = policy.getScopes().stream().map(Scope::getId).collect(Collectors.toSet()); this.scopesIds = policy.getScopes().stream().map(Scope::getId).collect(Collectors.toSet());
} }
public CachedPolicy(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getType() { public String getType() {
return this.type; return this.type;
} }
@Override
public DecisionStrategy getDecisionStrategy() { public DecisionStrategy getDecisionStrategy() {
return this.decisionStrategy; return this.decisionStrategy;
} }
@Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
this.decisionStrategy = decisionStrategy;
}
@Override
public Logic getLogic() { public Logic getLogic() {
return this.logic; return this.logic;
} }
@Override
public void setLogic(Logic logic) {
this.logic = logic;
}
@Override
public Map<String, String> getConfig() { public Map<String, String> getConfig() {
return this.config; return this.config;
} }
@Override
public void setConfig(Map<String, String> config) {
this.config = config;
}
@Override
public String getName() { public String getName() {
return this.name; return this.name;
} }
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getDescription() { public String getDescription() {
return this.description; return this.description;
} }
@Override
public void setDescription(String description) {
this.description = description;
}
@Override
public ResourceServer getResourceServer() {
throw new RuntimeException("Not implemented");
}
@Override
public void addScope(Scope scope) {
this.scopesIds.add(scope.getId());
}
@Override
public void removeScope(Scope scope) {
this.scopesIds.remove(scope.getId());
}
@Override
public void addAssociatedPolicy(Policy associatedPolicy) {
this.associatedPoliciesIds.add(associatedPolicy.getId());
}
@Override
public void removeAssociatedPolicy(Policy associatedPolicy) {
this.associatedPoliciesIds.remove(associatedPolicy.getId());
}
@Override
public void addResource(Resource resource) {
this.resourcesIds.add(resource.getId());
}
@Override
public void removeResource(Resource resource) {
this.resourcesIds.remove(resource.getId());
}
@Override
public Set<Policy> getAssociatedPolicies() {
throw new RuntimeException("Not implemented");
}
@Override
public Set<Resource> getResources() {
throw new RuntimeException("Not implemented");
}
@Override
public Set<Scope> getScopes() {
throw new RuntimeException("Not implemented");
}
public Set<String> getAssociatedPoliciesIds() { public Set<String> getAssociatedPoliciesIds() {
return this.associatedPoliciesIds; return this.associatedPoliciesIds;
} }
@ -194,24 +102,4 @@ public class CachedPolicy implements Policy, Serializable {
return this.resourceServerId; return this.resourceServerId;
} }
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (this.id == null) return false;
if (o == null || getClass() != o.getClass()) return false;
Policy that = (Policy) o;
if (!getId().equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return id!=null ? id.hashCode() : super.hashCode();
}
} }

View file

@ -16,11 +16,12 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.models.authorization.infinispan.entities; package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.authorization.model.Resource; 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.models.cache.infinispan.entities.AbstractRevisioned;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@ -30,11 +31,8 @@ import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public class CachedResource implements Resource, Serializable { public class CachedResource extends AbstractRevisioned implements InResourceServer {
private static final long serialVersionUID = -6886179034626995165L;
private final String id;
private String resourceServerId; private String resourceServerId;
private String iconUri; private String iconUri;
private String owner; private String owner;
@ -43,8 +41,8 @@ public class CachedResource implements Resource, Serializable {
private String uri; private String uri;
private Set<String> scopesIds; private Set<String> scopesIds;
public CachedResource(Resource resource) { public CachedResource(Long revision, Resource resource) {
this.id = resource.getId(); super(revision, resource.getId());
this.name = resource.getName(); this.name = resource.getName();
this.uri = resource.getUri(); this.uri = resource.getUri();
this.type = resource.getType(); this.type = resource.getType();
@ -54,76 +52,27 @@ public class CachedResource implements Resource, Serializable {
this.scopesIds = resource.getScopes().stream().map(Scope::getId).collect(Collectors.toSet()); this.scopesIds = resource.getScopes().stream().map(Scope::getId).collect(Collectors.toSet());
} }
public CachedResource(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getName() { public String getName() {
return this.name; return this.name;
} }
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getUri() { public String getUri() {
return this.uri; return this.uri;
} }
@Override
public void setUri(String uri) {
this.uri = uri;
}
@Override
public String getType() { public String getType() {
return this.type; return this.type;
} }
@Override
public void setType(String type) {
this.type = type;
}
@Override
public List<Scope> getScopes() {
throw new RuntimeException("Not implemented");
}
@Override
public String getIconUri() { public String getIconUri() {
return this.iconUri; return this.iconUri;
} }
@Override
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
@Override
public ResourceServer getResourceServer() {
throw new RuntimeException("Not implemented");
}
@Override
public String getOwner() { public String getOwner() {
return this.owner; return this.owner;
} }
@Override
public void updateScopes(Set<Scope> scopes) {
this.scopesIds.clear();
this.scopesIds.addAll(scopes.stream().map(Scope::getId).collect(Collectors.toSet()));
}
public String getResourceServerId() { public String getResourceServerId() {
return this.resourceServerId; return this.resourceServerId;
} }

View file

@ -16,9 +16,10 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.models.authorization.infinispan.entities; package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode; import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
import java.io.Serializable; import java.io.Serializable;
@ -26,53 +27,30 @@ import java.io.Serializable;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public class CachedResourceServer implements ResourceServer, Serializable { public class CachedResourceServer extends AbstractRevisioned {
private static final long serialVersionUID = 5054253390723121289L;
private final String id;
private String clientId; private String clientId;
private boolean allowRemoteResourceManagement; private boolean allowRemoteResourceManagement;
private PolicyEnforcementMode policyEnforcementMode; private PolicyEnforcementMode policyEnforcementMode;
public CachedResourceServer(ResourceServer resourceServer) { public CachedResourceServer(Long revision, ResourceServer resourceServer) {
this.id = resourceServer.getId(); super(revision, resourceServer.getId());
this.clientId = resourceServer.getClientId(); this.clientId = resourceServer.getClientId();
this.allowRemoteResourceManagement = resourceServer.isAllowRemoteResourceManagement(); this.allowRemoteResourceManagement = resourceServer.isAllowRemoteResourceManagement();
this.policyEnforcementMode = resourceServer.getPolicyEnforcementMode(); this.policyEnforcementMode = resourceServer.getPolicyEnforcementMode();
} }
public CachedResourceServer(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getClientId() { public String getClientId() {
return this.clientId; return this.clientId;
} }
@Override
public boolean isAllowRemoteResourceManagement() { public boolean isAllowRemoteResourceManagement() {
return this.allowRemoteResourceManagement; return this.allowRemoteResourceManagement;
} }
@Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
this.allowRemoteResourceManagement = allowRemoteResourceManagement;
}
@Override
public PolicyEnforcementMode getPolicyEnforcementMode() { public PolicyEnforcementMode getPolicyEnforcementMode() {
return this.policyEnforcementMode; return this.policyEnforcementMode;
} }
@Override
public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
this.policyEnforcementMode = enforcementMode;
}
} }

View file

@ -16,10 +16,11 @@
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.models.authorization.infinispan.entities; package org.keycloak.models.cache.infinispan.authorization.entities;
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.models.cache.infinispan.entities.AbstractRevisioned;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects; import java.util.Objects;
@ -27,70 +28,30 @@ import java.util.Objects;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public class CachedScope implements Scope, Serializable { public class CachedScope extends AbstractRevisioned implements InResourceServer {
private static final long serialVersionUID = -3919706923417065454L;
private final String id;
private String resourceServerId; private String resourceServerId;
private String name; private String name;
private String iconUri; private String iconUri;
public CachedScope(Scope scope) { public CachedScope(Long revision, Scope scope) {
this.id = scope.getId(); super(revision, scope.getId());
this.name = scope.getName(); this.name = scope.getName();
this.iconUri = scope.getIconUri(); this.iconUri = scope.getIconUri();
this.resourceServerId = scope.getResourceServer().getId(); this.resourceServerId = scope.getResourceServer().getId();
} }
public CachedScope(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getName() { public String getName() {
return this.name; return this.name;
} }
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getIconUri() { public String getIconUri() {
return this.iconUri; return this.iconUri;
} }
@Override @Override
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
@Override
public ResourceServer getResourceServer() {
throw new RuntimeException("Not implemented");
}
public String getResourceServerId() { public String getResourceServerId() {
return this.resourceServerId; return this.resourceServerId;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !Scope.class.isInstance(o)) return false;
Scope that = (Scope) o;
return Objects.equals(id, that.getId());
}
@Override
public int hashCode() {
return Objects.hash(id);
}
} }

View file

@ -0,0 +1,25 @@
/*
* Copyright 2016 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:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface InResourceServer {
String getResourceServerId();
}

View file

@ -0,0 +1,36 @@
package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class PolicyListQuery extends AbstractRevisioned implements InResourceServer {
private final Set<String> policies;
private final String serverId;
public PolicyListQuery(Long revision, String id, String policyId, String serverId) {
super(revision, id);
this.serverId = serverId;
policies = new HashSet<>();
policies.add(policyId);
}
public PolicyListQuery(Long revision, String id, Set<String> policies, String serverId) {
super(revision, id);
this.serverId = serverId;
this.policies = policies;
}
@Override
public String getResourceServerId() {
return serverId;
}
public Set<String> getPolicies() {
return policies;
}
}

View file

@ -0,0 +1,36 @@
package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceListQuery extends AbstractRevisioned implements InResourceServer {
private final Set<String> resources;
private final String serverId;
public ResourceListQuery(Long revision, String id, String resourceId, String serverId) {
super(revision, id);
this.serverId = serverId;
resources = new HashSet<>();
resources.add(resourceId);
}
public ResourceListQuery(Long revision, String id, Set<String> resources, String serverId) {
super(revision, id);
this.serverId = serverId;
this.resources = resources;
}
@Override
public String getResourceServerId() {
return serverId;
}
public Set<String> getResources() {
return resources;
}
}

View file

@ -0,0 +1,29 @@
package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import org.keycloak.models.cache.infinispan.entities.RealmQuery;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceServerListQuery extends AbstractRevisioned {
private final Set<String> servers;
public ResourceServerListQuery(Long revision, String id, String serverId) {
super(revision, id);
servers = new HashSet<>();
servers.add(serverId);
}
public ResourceServerListQuery(Long revision, String id, Set<String> servers) {
super(revision, id);
this.servers = servers;
}
public Set<String> getResourceServers() {
return servers;
}
}

View file

@ -0,0 +1,36 @@
package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ScopeListQuery extends AbstractRevisioned implements InResourceServer {
private final Set<String> scopes;
private final String serverId;
public ScopeListQuery(Long revision, String id, String scopeId, String serverId) {
super(revision, id);
this.serverId = serverId;
scopes = new HashSet<>();
scopes.add(scopeId);
}
public ScopeListQuery(Long revision, String id, Set<String> scopes, String serverId) {
super(revision, id);
this.serverId = serverId;
this.scopes = scopes;
}
@Override
public String getResourceServerId() {
return serverId;
}
public Set<String> getScopes() {
return scopes;
}
}

View file

@ -14,23 +14,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.keycloak.models.authorization.infinispan.events; package org.keycloak.models.cache.infinispan.authorization.events;
import java.util.Collections; import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import java.util.Set;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/ */
public class ResourceServerRemovedEvent extends AuthorizationInvalidationEvent { public interface AuthorizationCacheInvalidationEvent {
void addInvalidations(StoreFactoryCacheManager realmCache, Set<String> invalidations);
private final String clientId;
public ResourceServerRemovedEvent(String id, String clientId) {
super(id, Collections.emptySet());
this.clientId = clientId;
}
public String getClientId() {
return clientId;
}
} }

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PolicyRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String name;
private String serverId;
public static PolicyRemovedEvent create(String id, String name, String serverId) {
PolicyRemovedEvent event = new PolicyRemovedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("PolicyRemovedEvent [ id=%s, name=%s]", id, name);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyRemoval(id, name, serverId, invalidations);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PolicyUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String name;
private String serverId;
public static PolicyUpdatedEvent create(String id, String name, String serverId) {
PolicyUpdatedEvent event = new PolicyUpdatedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("PolicyUpdatedEvent [ id=%s, name=%s ]", id, name);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyUpdated(id, name, serverId, invalidations);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ResourceRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String name;
private String serverId;
public static ResourceRemovedEvent create(String id, String name, String serverId) {
ResourceRemovedEvent event = new ResourceRemovedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ResourceRemovedEvent [ id=%s, name=%s ]", id, name);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceRemoval(id, name, serverId, invalidations);
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ResourceServerRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String clientId;
public static ResourceServerRemovedEvent create(String id, String clientId) {
ResourceServerRemovedEvent event = new ResourceServerRemovedEvent();
event.id = id;
event.clientId = clientId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceServerRemoval(id, clientId, invalidations);
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ResourceServerUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String clientId;
public static ResourceServerUpdatedEvent create(String id, String clientId) {
ResourceServerUpdatedEvent event = new ResourceServerUpdatedEvent();
event.id = id;
event.clientId = clientId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceServerUpdated(id, clientId, invalidations);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ResourceUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String name;
private String serverId;
public static ResourceUpdatedEvent create(String id, String name, String serverId) {
ResourceUpdatedEvent event = new ResourceUpdatedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ResourceUpdatedEvent [ id=%s, name=%s ]", id, name);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceUpdated(id, name, serverId, invalidations);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ScopeRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String name;
private String serverId;
public static ScopeRemovedEvent create(String id, String name, String serverId) {
ScopeRemovedEvent event = new ScopeRemovedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ScopeRemovedEvent [ id=%s, name=%s]", id, name);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.scopeRemoval(id, name, serverId, invalidations);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ScopeUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String name;
private String serverId;
public static ScopeUpdatedEvent create(String id, String name, String serverId) {
ScopeUpdatedEvent event = new ScopeUpdatedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ScopeUpdatedEvent [ id=%s, name=%s ]", id, name);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.scopeUpdated(id, name, serverId, invalidations);
}
}

View file

@ -0,0 +1,35 @@
package org.keycloak.models.cache.infinispan.authorization.stream;
import org.keycloak.models.cache.infinispan.authorization.entities.InResourceServer;
import org.keycloak.models.cache.infinispan.entities.InRealm;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class InResourceServerPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
private String serverId;
public static InResourceServerPredicate create() {
return new InResourceServerPredicate();
}
public InResourceServerPredicate resourceServer(String id) {
serverId = id;
return this;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof InResourceServer)) return false;
return serverId.equals(((InResourceServer)value).getResourceServerId());
}
}

View file

@ -16,4 +16,4 @@
# limitations under the License. # limitations under the License.
# #
org.keycloak.models.authorization.infinispan.InfinispanStoreProviderFactory org.keycloak.models.cache.infinispan.authorization.InfinispanCacheStoreFactoryProviderFactory

View file

@ -35,6 +35,8 @@ import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn; import javax.persistence.MapKeyColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
@ -52,11 +54,25 @@ import org.keycloak.representations.idm.authorization.Logic;
@Table(name = "RESOURCE_SERVER_POLICY", uniqueConstraints = { @Table(name = "RESOURCE_SERVER_POLICY", uniqueConstraints = {
@UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"}) @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
}) })
public class PolicyEntity implements Policy { @NamedQueries(
{
@NamedQuery(name="findPolicyIdByServerId", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId "),
@NamedQuery(name="findPolicyIdByName", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.name = :name"),
@NamedQuery(name="findPolicyIdByResource", query="select p.id from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
@NamedQuery(name="findPolicyIdByScope", query="select pe.id from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))"),
@NamedQuery(name="findPolicyIdByType", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type"),
@NamedQuery(name="findPolicyIdByResourceType", query="select p.id from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type"),
@NamedQuery(name="findPolicyIdByDependentPolices", query="select p.id from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)"),
@NamedQuery(name="deletePolicyByResourceServer", query="delete from PolicyEntity p where p.resourceServer.id = :serverId")
}
)
public class PolicyEntity {
@Id @Id
@Column(name="ID", length = 36) @Column(name = "ID", length = 36)
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL @Access(AccessType.PROPERTY)
// we do this because relationships often fetch id, but not entity. This avoids an extra SQL
private String id; private String id;
@Column(name = "NAME") @Column(name = "NAME")
@ -75,9 +91,9 @@ public class PolicyEntity implements Policy {
private Logic logic = Logic.POSITIVE; private Logic logic = Logic.POSITIVE;
@ElementCollection(fetch = FetchType.LAZY) @ElementCollection(fetch = FetchType.LAZY)
@MapKeyColumn(name="NAME") @MapKeyColumn(name = "NAME")
@Column(name="VALUE", columnDefinition = "TEXT") @Column(name = "VALUE", columnDefinition = "TEXT")
@CollectionTable(name="POLICY_CONFIG", joinColumns={ @JoinColumn(name="POLICY_ID") }) @CollectionTable(name = "POLICY_CONFIG", joinColumns = {@JoinColumn(name = "POLICY_ID")})
private Map<String, String> config = new HashMap(); private Map<String, String> config = new HashMap();
@ManyToOne(optional = false, fetch = FetchType.LAZY) @ManyToOne(optional = false, fetch = FetchType.LAZY)
@ -96,7 +112,6 @@ public class PolicyEntity implements Policy {
@JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID")) @JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
private Set<ScopeEntity> scopes = new HashSet<>(); private Set<ScopeEntity> scopes = new HashSet<>();
@Override
public String getId() { public String getId() {
return this.id; return this.id;
} }
@ -105,7 +120,6 @@ public class PolicyEntity implements Policy {
this.id = id; this.id = id;
} }
@Override
public String getType() { public String getType() {
return this.type; return this.type;
} }
@ -114,57 +128,46 @@ public class PolicyEntity implements Policy {
this.type = type; this.type = type;
} }
@Override
public DecisionStrategy getDecisionStrategy() { public DecisionStrategy getDecisionStrategy() {
return this.decisionStrategy; return this.decisionStrategy;
} }
@Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) { public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
this.decisionStrategy = decisionStrategy; this.decisionStrategy = decisionStrategy;
} }
@Override
public Logic getLogic() { public Logic getLogic() {
return this.logic; return this.logic;
} }
@Override
public void setLogic(Logic logic) { public void setLogic(Logic logic) {
this.logic = logic; this.logic = logic;
} }
@Override
public Map<String, String> getConfig() { public Map<String, String> getConfig() {
return this.config; return this.config;
} }
@Override
public void setConfig(Map<String, String> config) { public void setConfig(Map<String, String> config) {
this.config = config; this.config = config;
} }
@Override
public String getName() { public String getName() {
return this.name; return this.name;
} }
@Override
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
@Override
public String getDescription() { public String getDescription() {
return this.description; return this.description;
} }
@Override
public void setDescription(String description) { public void setDescription(String description) {
this.description = description; this.description = description;
} }
@Override
public ResourceServerEntity getResourceServer() { public ResourceServerEntity getResourceServer() {
return this.resourceServer; return this.resourceServer;
} }
@ -173,16 +176,6 @@ public class PolicyEntity implements Policy {
this.resourceServer = resourceServer; this.resourceServer = resourceServer;
} }
@Override
public <P extends Policy> Set<P> getAssociatedPolicies() {
return (Set<P>) this.associatedPolicies;
}
public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
this.associatedPolicies = associatedPolicies;
}
@Override
public Set<ResourceEntity> getResources() { public Set<ResourceEntity> getResources() {
return this.resources; return this.resources;
} }
@ -191,7 +184,6 @@ public class PolicyEntity implements Policy {
this.resources = resources; this.resources = resources;
} }
@Override
public Set<ScopeEntity> getScopes() { public Set<ScopeEntity> getScopes() {
return this.scopes; return this.scopes;
} }
@ -200,54 +192,26 @@ public class PolicyEntity implements Policy {
this.scopes = scopes; this.scopes = scopes;
} }
@Override public Set<PolicyEntity> getAssociatedPolicies() {
public void addScope(Scope scope) { return associatedPolicies;
getScopes().add((ScopeEntity) scope);
} }
@Override public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
public void removeScope(Scope scope) { this.associatedPolicies = associatedPolicies;
getScopes().remove(scope);
}
@Override
public void addAssociatedPolicy(Policy associatedPolicy) {
getAssociatedPolicies().add(associatedPolicy);
}
@Override
public void removeAssociatedPolicy(Policy associatedPolicy) {
getAssociatedPolicies().remove(associatedPolicy);
}
@Override
public void addResource(Resource resource) {
getResources().add((ResourceEntity) resource);
}
@Override
public void removeResource(Resource resource) {
getResources().remove(resource);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this.id == null) return false; PolicyEntity that = (PolicyEntity) o;
if (!Policy.class.isInstance(o)) return false;
Policy that = (Policy) o;
if (!getId().equals(that.getId())) return false;
return true;
return getId().equals(that.getId());
} }
@Override @Override
public int hashCode() { public int hashCode() {
return id!=null ? id.hashCode() : super.hashCode(); return getId().hashCode();
} }
} }

View file

@ -31,10 +31,13 @@ import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.ManyToMany; import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -45,7 +48,18 @@ import java.util.Set;
@Table(name = "RESOURCE_SERVER_RESOURCE", uniqueConstraints = { @Table(name = "RESOURCE_SERVER_RESOURCE", uniqueConstraints = {
@UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID", "OWNER"}) @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID", "OWNER"})
}) })
public class ResourceEntity implements Resource { @NamedQueries(
{
@NamedQuery(name="findResourceIdByOwner", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner"),
@NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.uri = :uri"),
@NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.name = :name"),
@NamedQuery(name="findResourceIdByType", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.type = :type"),
@NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId "),
@NamedQuery(name="findResourceIdByScope", query="select r.id from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
@NamedQuery(name="deleteResourceByResourceServer", query="delete from ResourceEntity r where r.resourceServer.id = :serverId")
}
)
public class ResourceEntity {
@Id @Id
@Column(name="ID", length = 36) @Column(name="ID", length = 36)
@ -73,13 +87,12 @@ public class ResourceEntity implements Resource {
@ManyToMany(fetch = FetchType.LAZY, cascade = {}) @ManyToMany(fetch = FetchType.LAZY, cascade = {})
@JoinTable(name = "RESOURCE_SCOPE", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID")) @JoinTable(name = "RESOURCE_SCOPE", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
private List<ScopeEntity> scopes = new ArrayList<>(); private List<ScopeEntity> scopes = new LinkedList<>();
@ManyToMany(fetch = FetchType.LAZY, cascade = {}) @ManyToMany(fetch = FetchType.LAZY, cascade = {})
@JoinTable(name = "RESOURCE_POLICY", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID")) @JoinTable(name = "RESOURCE_POLICY", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
private List<PolicyEntity> policies = new ArrayList<>(); private List<PolicyEntity> policies = new LinkedList<>();
@Override
public String getId() { public String getId() {
return id; return id;
} }
@ -88,52 +101,42 @@ public class ResourceEntity implements Resource {
this.id = id; this.id = id;
} }
@Override
public String getName() { public String getName() {
return name; return name;
} }
@Override
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
@Override
public String getUri() { public String getUri() {
return uri; return uri;
} }
@Override
public void setUri(String uri) { public void setUri(String uri) {
this.uri = uri; this.uri = uri;
} }
@Override
public String getType() { public String getType() {
return type; return type;
} }
@Override
public void setType(String type) { public void setType(String type) {
this.type = type; this.type = type;
} }
@Override
public List<ScopeEntity> getScopes() { public List<ScopeEntity> getScopes() {
return this.scopes; return this.scopes;
} }
@Override
public String getIconUri() { public String getIconUri() {
return iconUri; return iconUri;
} }
@Override
public void setIconUri(String iconUri) { public void setIconUri(String iconUri) {
this.iconUri = iconUri; this.iconUri = iconUri;
} }
@Override
public ResourceServerEntity getResourceServer() { public ResourceServerEntity getResourceServer() {
return resourceServer; return resourceServer;
} }
@ -154,37 +157,23 @@ public class ResourceEntity implements Resource {
return this.policies; return this.policies;
} }
public void updateScopes(Set<Scope> toUpdate) {
for (Scope scope : toUpdate) {
boolean hasScope = false;
for (Scope existingScope : this.scopes) {
if (existingScope.equals(scope)) {
hasScope = true;
}
}
if (!hasScope) {
this.scopes.add((ScopeEntity) scope);
}
}
for (Scope scopeModel : new HashSet<Scope>(this.scopes)) {
boolean hasScope = false;
for (Scope scope : toUpdate) {
if (scopeModel.equals(scope)) {
hasScope = true;
}
}
if (!hasScope) {
this.scopes.remove(scopeModel);
}
}
}
public void setPolicies(List<PolicyEntity> policies) { public void setPolicies(List<PolicyEntity> policies) {
this.policies = policies; this.policies = policies;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ResourceEntity that = (ResourceEntity) o;
return getId().equals(that.getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
} }

View file

@ -26,6 +26,8 @@ import javax.persistence.AccessType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
@ -36,7 +38,12 @@ import java.util.List;
*/ */
@Entity @Entity
@Table(name = "RESOURCE_SERVER", uniqueConstraints = {@UniqueConstraint(columnNames = "CLIENT_ID")}) @Table(name = "RESOURCE_SERVER", uniqueConstraints = {@UniqueConstraint(columnNames = "CLIENT_ID")})
public class ResourceServerEntity implements ResourceServer { @NamedQueries(
{
@NamedQuery(name="findResourceServerIdByClient", query="select r.id from ResourceServerEntity r where r.clientId = :clientId"),
}
)
public class ResourceServerEntity {
@Id @Id
@Column(name="ID", length = 36) @Column(name="ID", length = 36)
@ -58,7 +65,6 @@ public class ResourceServerEntity implements ResourceServer {
@OneToMany (mappedBy = "resourceServer") @OneToMany (mappedBy = "resourceServer")
private List<ScopeEntity> scopes; private List<ScopeEntity> scopes;
@Override
public String getId() { public String getId() {
return this.id; return this.id;
} }
@ -67,7 +73,6 @@ public class ResourceServerEntity implements ResourceServer {
this.id = id; this.id = id;
} }
@Override
public String getClientId() { public String getClientId() {
return this.clientId; return this.clientId;
} }
@ -76,22 +81,18 @@ public class ResourceServerEntity implements ResourceServer {
this.clientId = clientId; this.clientId = clientId;
} }
@Override
public boolean isAllowRemoteResourceManagement() { public boolean isAllowRemoteResourceManagement() {
return this.allowRemoteResourceManagement; return this.allowRemoteResourceManagement;
} }
@Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) { public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
this.allowRemoteResourceManagement = allowRemoteResourceManagement; this.allowRemoteResourceManagement = allowRemoteResourceManagement;
} }
@Override
public PolicyEnforcementMode getPolicyEnforcementMode() { public PolicyEnforcementMode getPolicyEnforcementMode() {
return this.policyEnforcementMode; return this.policyEnforcementMode;
} }
@Override
public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) { public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) {
this.policyEnforcementMode = policyEnforcementMode; this.policyEnforcementMode = policyEnforcementMode;
} }
@ -111,4 +112,19 @@ public class ResourceServerEntity implements ResourceServer {
public void setScopes(final List<ScopeEntity> scopes) { public void setScopes(final List<ScopeEntity> scopes) {
this.scopes = scopes; this.scopes = scopes;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ResourceServerEntity that = (ResourceServerEntity) o;
return getId().equals(that.getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
} }

View file

@ -31,6 +31,8 @@ import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.ManyToMany; import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import java.util.ArrayList; import java.util.ArrayList;
@ -44,7 +46,14 @@ import java.util.Objects;
@Table(name = "RESOURCE_SERVER_SCOPE", uniqueConstraints = { @Table(name = "RESOURCE_SERVER_SCOPE", uniqueConstraints = {
@UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"}) @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
}) })
public class ScopeEntity implements Scope { @NamedQueries(
{
@NamedQuery(name="findScopeIdByName", query="select s.id from ScopeEntity s where s.resourceServer.id = :serverId and s.name = :name"),
@NamedQuery(name="findScopeIdByResourceServer", query="select s.id from ScopeEntity s where s.resourceServer.id = :serverId"),
@NamedQuery(name="deleteScopeByResourceServer", query="delete from ScopeEntity s where s.resourceServer.id = :serverId")
}
)
public class ScopeEntity {
@Id @Id
@Column(name="ID", length = 36) @Column(name="ID", length = 36)
@ -65,7 +74,6 @@ public class ScopeEntity implements Scope {
@JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "SCOPE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID")) @JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "SCOPE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
private List<PolicyEntity> policies = new ArrayList<>(); private List<PolicyEntity> policies = new ArrayList<>();
@Override
public String getId() { public String getId() {
return id; return id;
} }
@ -74,33 +82,28 @@ public class ScopeEntity implements Scope {
this.id = id; this.id = id;
} }
@Override
public String getName() { public String getName() {
return name; return name;
} }
@Override
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
@Override
public String getIconUri() { public String getIconUri() {
return iconUri; return iconUri;
} }
@Override
public void setIconUri(String iconUri) { public void setIconUri(String iconUri) {
this.iconUri = iconUri; this.iconUri = iconUri;
} }
@Override
public ResourceServerEntity getResourceServer() { public ResourceServerEntity getResourceServer() {
return resourceServer; return resourceServer;
} }
public List<? extends Policy> getPolicies() { public List<PolicyEntity> getPolicies() {
return this.policies; return policies;
} }
public void setPolicies(List<PolicyEntity> policies) { public void setPolicies(List<PolicyEntity> policies) {
@ -114,13 +117,15 @@ public class ScopeEntity implements Scope {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || !Scope.class.isInstance(o)) return false; if (o == null || getClass() != o.getClass()) return false;
Scope that = (Scope) o;
return Objects.equals(id, that.getId()); ScopeEntity that = (ScopeEntity) o;
return getId().equals(that.getId());
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id); return getId().hashCode();
} }
} }

View file

@ -32,8 +32,9 @@ import org.keycloak.models.KeycloakSession;
*/ */
public class JPAAuthorizationStoreFactory implements AuthorizationStoreFactory { public class JPAAuthorizationStoreFactory implements AuthorizationStoreFactory {
@Override @Override
public StoreFactory create(KeycloakSession session) { public StoreFactory create(KeycloakSession session) {
return new JPAStoreFactory(getEntityManager(session)); AuthorizationProvider provider = session.getProvider(AuthorizationProvider.class);
return new JPAStoreFactory(getEntityManager(session), provider);
} }
@Override @Override

View file

@ -19,23 +19,29 @@ package org.keycloak.authorization.jpa.store;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.NoResultException; import javax.persistence.NoResultException;
import javax.persistence.Query; import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.PolicyEntity; import org.keycloak.authorization.jpa.entities.PolicyEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity; import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
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.store.PolicyStore; import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
/** /**
@ -44,9 +50,10 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
public class JPAPolicyStore implements PolicyStore { public class JPAPolicyStore implements PolicyStore {
private final EntityManager entityManager; private final EntityManager entityManager;
private final AuthorizationProvider provider;
public JPAPolicyStore(EntityManager entityManager) { public JPAPolicyStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.provider = provider;
} }
@Override @Override
@ -56,17 +63,17 @@ public class JPAPolicyStore implements PolicyStore {
entity.setId(KeycloakModelUtils.generateId()); entity.setId(KeycloakModelUtils.generateId());
entity.setType(representation.getType()); entity.setType(representation.getType());
entity.setName(representation.getName()); entity.setName(representation.getName());
entity.setResourceServer((ResourceServerEntity) resourceServer); entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
this.entityManager.persist(entity); this.entityManager.persist(entity);
this.entityManager.flush(); this.entityManager.flush();
return entity; Policy model = new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
return model;
} }
@Override @Override
public void delete(String id) { public void delete(String id) {
Policy policy = entityManager.find(PolicyEntity.class, id); PolicyEntity policy = entityManager.find(PolicyEntity.class, id);
if (policy != null) { if (policy != null) {
this.entityManager.remove(policy); this.entityManager.remove(policy);
} }
@ -79,39 +86,38 @@ public class JPAPolicyStore implements PolicyStore {
return null; return null;
} }
if (resourceServerId == null) { PolicyEntity entity = entityManager.find(PolicyEntity.class, id);
return entityManager.find(PolicyEntity.class, id); if (entity == null) return null;
}
Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId and id = :id"); return new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
query.setParameter("serverId", resourceServerId);
query.setParameter("id", id);
return entityManager.find(PolicyEntity.class, id);
} }
@Override @Override
public Policy findByName(String name, String resourceServerId) { public Policy findByName(String name, String resourceServerId) {
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByName", String.class);
query.setParameter("serverId", resourceServerId);
query.setParameter("name", name);
try { try {
Query query = entityManager.createQuery("from PolicyEntity where name = :name and resourceServer.id = :serverId"); String id = query.getSingleResult();
return provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId);
query.setParameter("name", name); } catch (NoResultException ex) {
query.setParameter("serverId", resourceServerId);
return (Policy) query.getSingleResult();
} catch (NoResultException nre) {
return null; return null;
} }
} }
@Override @Override
public List<Policy> findByResourceServer(final String resourceServerId) { public List<Policy> findByResourceServer(final String resourceServerId) {
Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId"); TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
@ -120,6 +126,7 @@ public class JPAPolicyStore implements PolicyStore {
CriteriaQuery<PolicyEntity> querybuilder = builder.createQuery(PolicyEntity.class); CriteriaQuery<PolicyEntity> querybuilder = builder.createQuery(PolicyEntity.class);
Root<PolicyEntity> root = querybuilder.from(PolicyEntity.class); Root<PolicyEntity> root = querybuilder.from(PolicyEntity.class);
List<Predicate> predicates = new ArrayList(); List<Predicate> predicates = new ArrayList();
querybuilder.select(root.get("id"));
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId)); predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@ -148,27 +155,42 @@ public class JPAPolicyStore implements PolicyStore {
query.setMaxResults(maxResult); query.setMaxResults(maxResult);
} }
return query.getResultList(); List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List<Policy> findByResource(final String resourceId, String resourceServerId) { public List<Policy> findByResource(final String resourceId, String resourceServerId) {
Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"); TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByResource", String.class);
query.setParameter("resourceId", resourceId); query.setParameter("resourceId", resourceId);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List<Policy> findByResourceType(final String resourceType, String resourceServerId) { public List<Policy> findByResourceType(final String resourceType, String resourceServerId) {
Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type"); TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByResourceType", String.class);
query.setParameter("serverId", resourceServerId);
query.setParameter("type", resourceType); query.setParameter("type", resourceType);
query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
@ -178,31 +200,47 @@ public class JPAPolicyStore implements PolicyStore {
} }
// Use separate subquery to handle DB2 and MSSSQL // Use separate subquery to handle DB2 and MSSSQL
Query query = entityManager.createQuery("select pe from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))"); TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByScope", String.class);
query.setParameter("serverId", resourceServerId);
query.setParameter("scopeIds", scopeIds); query.setParameter("scopeIds", scopeIds);
query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List<Policy> findByType(String type, String resourceServerId) { public List<Policy> findByType(String type, String resourceServerId) {
Query query = entityManager.createQuery("select p from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type"); TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByType", String.class);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
query.setParameter("type", type); query.setParameter("type", type);
return query.getResultList(); List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List<Policy> findDependentPolicies(String policyId, String resourceServerId) { public List<Policy> findDependentPolicies(String policyId, String resourceServerId) {
Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)");
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByDependentPolices", String.class);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
query.setParameter("policyId", policyId); query.setParameter("policyId", policyId);
return query.getResultList(); List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
}
return list;
} }
} }

View file

@ -17,13 +17,19 @@
*/ */
package org.keycloak.authorization.jpa.store; package org.keycloak.authorization.jpa.store;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.PolicyEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity; import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.ResourceServerStore; import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query; import javax.persistence.Query;
import javax.persistence.TypedQuery;
import java.util.LinkedList;
import java.util.List; import java.util.List;
/** /**
@ -32,9 +38,11 @@ import java.util.List;
public class JPAResourceServerStore implements ResourceServerStore { public class JPAResourceServerStore implements ResourceServerStore {
private final EntityManager entityManager; private final EntityManager entityManager;
private final AuthorizationProvider provider;
public JPAResourceServerStore(EntityManager entityManager) { public JPAResourceServerStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.provider = provider;
} }
@Override @Override
@ -46,30 +54,54 @@ public class JPAResourceServerStore implements ResourceServerStore {
this.entityManager.persist(entity); this.entityManager.persist(entity);
return entity; return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
} }
@Override @Override
public void delete(String id) { public void delete(String id) {
this.entityManager.remove(findById(id)); ResourceServerEntity entity = entityManager.find(ResourceServerEntity.class, id);
if (entity == null) return;
//This didn't work, had to loop through and remove each policy individually
//entityManager.createNamedQuery("deletePolicyByResourceServer")
// .setParameter("serverId", id).executeUpdate();
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
query.setParameter("serverId", id);
List<String> result = query.getResultList();
List<Policy> list = new LinkedList<>();
for (String policyId : result) {
entityManager.remove(entityManager.getReference(PolicyEntity.class, policyId));
}
entityManager.flush();
entityManager.createNamedQuery("deleteResourceByResourceServer")
.setParameter("serverId", id).executeUpdate();
entityManager.flush();
entityManager.createNamedQuery("deleteScopeByResourceServer")
.setParameter("serverId", id).executeUpdate();
entityManager.flush();
this.entityManager.remove(entity);
entityManager.flush();
} }
@Override @Override
public ResourceServer findById(String id) { public ResourceServer findById(String id) {
return entityManager.find(ResourceServerEntity.class, id); ResourceServerEntity entity = entityManager.find(ResourceServerEntity.class, id);
if (entity == null) return null;
return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
} }
@Override @Override
public ResourceServer findByClient(final String clientId) { public ResourceServer findByClient(final String clientId) {
Query query = entityManager.createQuery("from ResourceServerEntity where clientId = :clientId"); TypedQuery<String> query = entityManager.createNamedQuery("findResourceServerIdByClient", String.class);
query.setParameter("clientId", clientId); query.setParameter("clientId", clientId);
List result = query.getResultList(); try {
String id = query.getSingleResult();
if (result.isEmpty()) { return provider.getStoreFactory().getResourceServerStore().findById(id);
} catch (NoResultException ex) {
return null; return null;
} }
return (ResourceServer) result.get(0);
} }
} }

View file

@ -17,6 +17,7 @@
*/ */
package org.keycloak.authorization.jpa.store; package org.keycloak.authorization.jpa.store;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ResourceEntity; import org.keycloak.authorization.jpa.entities.ResourceEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity; import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.model.Resource; import org.keycloak.authorization.model.Resource;
@ -25,13 +26,16 @@ import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query; import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -41,38 +45,34 @@ import java.util.Map;
public class JPAResourceStore implements ResourceStore { public class JPAResourceStore implements ResourceStore {
private final EntityManager entityManager; private final EntityManager entityManager;
private final AuthorizationProvider provider;
public JPAResourceStore(EntityManager entityManager) { public JPAResourceStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.provider = provider;
} }
@Override @Override
public Resource create(String name, ResourceServer resourceServer, String owner) { public Resource create(String name, ResourceServer resourceServer, String owner) {
if (!(resourceServer instanceof ResourceServerEntity)) {
throw new RuntimeException("Unexpected type [" + resourceServer.getClass() + "].");
}
ResourceEntity entity = new ResourceEntity(); ResourceEntity entity = new ResourceEntity();
entity.setId(KeycloakModelUtils.generateId()); entity.setId(KeycloakModelUtils.generateId());
entity.setName(name); entity.setName(name);
entity.setResourceServer((ResourceServerEntity) resourceServer); entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
entity.setOwner(owner); entity.setOwner(owner);
this.entityManager.persist(entity); this.entityManager.persist(entity);
return entity; return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
} }
@Override @Override
public void delete(String id) { public void delete(String id) {
Resource resource = entityManager.find(ResourceEntity.class, id); ResourceEntity resource = entityManager.find(ResourceEntity.class, id);
if (resource == null) return;
resource.getScopes().clear(); resource.getScopes().clear();
this.entityManager.remove(resource);
if (resource != null) {
this.entityManager.remove(resource);
}
} }
@Override @Override
@ -81,52 +81,61 @@ public class JPAResourceStore implements ResourceStore {
return null; return null;
} }
if (resourceServerId == null) { ResourceEntity entity = entityManager.find(ResourceEntity.class, id);
return entityManager.find(ResourceEntity.class, id); if (entity == null) return null;
} return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and id = :id");
query.setParameter("serverId", resourceServerId);
query.setParameter("id", id);
return entityManager.find(ResourceEntity.class, id);
} }
@Override @Override
public List<Resource> findByOwner(String ownerId, String resourceServerId) { public List<Resource> findByOwner(String ownerId, String resourceServerId) {
Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and owner = :ownerId"); TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByOwner", String.class);
query.setParameter("ownerId", ownerId); query.setParameter("owner", ownerId);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Resource> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List<Resource> findByUri(String uri, String resourceServerId) { public List<Resource> findByUri(String uri, String resourceServerId) {
Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and uri = :uri"); TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByUri", String.class);
query.setParameter("uri", uri); query.setParameter("uri", uri);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Resource> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List findByResourceServer(String resourceServerId) { public List<Resource> findByResourceServer(String resourceServerId) {
Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId"); TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByServerId", String.class);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Resource> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) { public List<Resource> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<ResourceEntity> querybuilder = builder.createQuery(ResourceEntity.class); CriteriaQuery<ResourceEntity> querybuilder = builder.createQuery(ResourceEntity.class);
Root<ResourceEntity> root = querybuilder.from(ResourceEntity.class); Root<ResourceEntity> root = querybuilder.from(ResourceEntity.class);
querybuilder.select(root.get("id"));
List<Predicate> predicates = new ArrayList(); List<Predicate> predicates = new ArrayList();
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId)); predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@ -152,42 +161,55 @@ public class JPAResourceStore implements ResourceStore {
query.setMaxResults(maxResult); query.setMaxResults(maxResult);
} }
return query.getResultList(); List<String> result = query.getResultList();
List<Resource> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public List<Resource> findByScope(List<String> id, String resourceServerId) { public List<Resource> findByScope(List<String> scopes, String resourceServerId) {
Query query = entityManager.createQuery("select r from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"); TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByScope", String.class);
query.setParameter("scopeIds", id); query.setParameter("scopeIds", scopes);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Resource> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
}
return list;
} }
@Override @Override
public Resource findByName(String name, String resourceServerId) { public Resource findByName(String name, String resourceServerId) {
Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and name = :name"); TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByName", String.class);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
query.setParameter("name", name); query.setParameter("name", name);
try {
List<Resource> result = query.getResultList(); String id = query.getSingleResult();
return provider.getStoreFactory().getResourceStore().findById(id, resourceServerId);
if (!result.isEmpty()) { } catch (NoResultException ex) {
return result.get(0); return null;
} }
return null;
} }
@Override @Override
public List<Resource> findByType(String type, String resourceServerId) { public List<Resource> findByType(String type, String resourceServerId) {
Query query = entityManager.createQuery("from ResourceEntity r where r.resourceServer.id = :serverId and type = :type"); TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByType", String.class);
query.setParameter("type", type); query.setParameter("type", type);
query.setParameter("serverId", resourceServerId); query.setParameter("serverId", resourceServerId);
return query.getResultList(); List<String> result = query.getResultList();
List<Resource> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
}
return list;
} }
} }

View file

@ -18,17 +18,20 @@
package org.keycloak.authorization.jpa.store; package org.keycloak.authorization.jpa.store;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.NoResultException; import javax.persistence.NoResultException;
import javax.persistence.Query; import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity; import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.jpa.entities.ScopeEntity; import org.keycloak.authorization.jpa.entities.ScopeEntity;
import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.ResourceServer;
@ -42,9 +45,11 @@ import org.keycloak.models.utils.KeycloakModelUtils;
public class JPAScopeStore implements ScopeStore { public class JPAScopeStore implements ScopeStore {
private final EntityManager entityManager; private final EntityManager entityManager;
private final AuthorizationProvider provider;
public JPAScopeStore(EntityManager entityManager) { public JPAScopeStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.provider = provider;
} }
@Override @Override
@ -53,16 +58,16 @@ public class JPAScopeStore implements ScopeStore {
entity.setId(KeycloakModelUtils.generateId()); entity.setId(KeycloakModelUtils.generateId());
entity.setName(name); entity.setName(name);
entity.setResourceServer((ResourceServerEntity) resourceServer); entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
this.entityManager.persist(entity); this.entityManager.persist(entity);
return entity; return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
} }
@Override @Override
public void delete(String id) { public void delete(String id) {
Scope scope = entityManager.find(ScopeEntity.class, id); ScopeEntity scope = entityManager.find(ScopeEntity.class, id);
if (scope != null) { if (scope != null) {
this.entityManager.remove(scope); this.entityManager.remove(scope);
@ -75,28 +80,21 @@ public class JPAScopeStore implements ScopeStore {
return null; return null;
} }
if (resourceServerId == null) { ScopeEntity entity = entityManager.find(ScopeEntity.class, id);
return entityManager.find(ScopeEntity.class, id); if (entity == null) return null;
}
Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId and id = :id");
query.setParameter("serverId", resourceServerId);
query.setParameter("id", id);
return entityManager.find(ScopeEntity.class, id);
return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
} }
@Override @Override
public Scope findByName(String name, String resourceServerId) { public Scope findByName(String name, String resourceServerId) {
try { try {
Query query = entityManager.createQuery("select s from ScopeEntity s inner join s.resourceServer rs where rs.id = :resourceServerId and name = :name"); TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByName", String.class);
query.setParameter("resourceServerId", resourceServerId); query.setParameter("serverId", resourceServerId);
query.setParameter("name", name); query.setParameter("name", name);
String id = query.getSingleResult();
return (Scope) query.getSingleResult(); return provider.getStoreFactory().getScopeStore().findById(id, resourceServerId);
} catch (NoResultException nre) { } catch (NoResultException nre) {
return null; return null;
} }
@ -104,11 +102,16 @@ public class JPAScopeStore implements ScopeStore {
@Override @Override
public List<Scope> findByResourceServer(final String serverId) { public List<Scope> findByResourceServer(final String serverId) {
Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId"); TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByResourceServer", String.class);
query.setParameter("serverId", serverId); query.setParameter("serverId", serverId);
return query.getResultList(); List<String> result = query.getResultList();
List<Scope> list = new LinkedList<>();
for (String id : result) {
list.add(provider.getStoreFactory().getScopeStore().findById(id, serverId));
}
return list;
} }
@Override @Override
@ -116,6 +119,7 @@ public class JPAScopeStore implements ScopeStore {
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<ScopeEntity> querybuilder = builder.createQuery(ScopeEntity.class); CriteriaQuery<ScopeEntity> querybuilder = builder.createQuery(ScopeEntity.class);
Root<ScopeEntity> root = querybuilder.from(ScopeEntity.class); Root<ScopeEntity> root = querybuilder.from(ScopeEntity.class);
querybuilder.select(root.get("id"));
List<Predicate> predicates = new ArrayList(); List<Predicate> predicates = new ArrayList();
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId)); predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@ -139,6 +143,12 @@ public class JPAScopeStore implements ScopeStore {
query.setMaxResults(maxResult); query.setMaxResults(maxResult);
} }
return query.getResultList(); List result = query.getResultList();
List<Scope> list = new LinkedList<>();
for (Object id : result) {
list.add(provider.getStoreFactory().getScopeStore().findById((String)id, resourceServerId));
}
return list;
} }
} }

View file

@ -20,6 +20,7 @@ package org.keycloak.authorization.jpa.store;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import org.keycloak.authorization.AuthorizationProvider;
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;
@ -36,11 +37,11 @@ public class JPAStoreFactory implements StoreFactory {
private final ResourceStore resourceStore; private final ResourceStore resourceStore;
private final ScopeStore scopeStore; private final ScopeStore scopeStore;
public JPAStoreFactory(EntityManager entityManager) { public JPAStoreFactory(EntityManager entityManager, AuthorizationProvider provider) {
policyStore = new JPAPolicyStore(entityManager); policyStore = new JPAPolicyStore(entityManager, provider);
resourceServerStore = new JPAResourceServerStore(entityManager); resourceServerStore = new JPAResourceServerStore(entityManager, provider);
resourceStore = new JPAResourceStore(entityManager); resourceStore = new JPAResourceStore(entityManager, provider);
scopeStore = new JPAScopeStore(entityManager); scopeStore = new JPAScopeStore(entityManager, provider);
} }
@Override @Override

View file

@ -0,0 +1,235 @@
/*
* Copyright 2016 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.authorization.jpa.store;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.PolicyEntity;
import org.keycloak.authorization.jpa.entities.ResourceEntity;
import org.keycloak.authorization.jpa.entities.ScopeEntity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.jpa.JpaModel;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
import javax.persistence.EntityManager;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class PolicyAdapter implements Policy, JpaModel<PolicyEntity> {
private PolicyEntity entity;
private EntityManager em;
private StoreFactory storeFactory;
public PolicyAdapter(PolicyEntity entity, EntityManager em, StoreFactory storeFactory) {
this.entity = entity;
this.em = em;
this.storeFactory = storeFactory;
}
@Override
public PolicyEntity getEntity() {
return entity;
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getType() {
return entity.getType();
}
@Override
public DecisionStrategy getDecisionStrategy() {
return entity.getDecisionStrategy();
}
@Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
entity.setDecisionStrategy(decisionStrategy);
}
@Override
public Logic getLogic() {
return entity.getLogic();
}
@Override
public void setLogic(Logic logic) {
entity.setLogic(logic);
}
@Override
public Map<String, String> getConfig() {
Map<String, String> result = new HashMap<String, String>();
if (entity.getConfig() != null) result.putAll(entity.getConfig());
return Collections.unmodifiableMap(result);
}
@Override
public void setConfig(Map<String, String> config) {
if (entity.getConfig() == null) {
entity.setConfig(new HashMap<>());
} else {
entity.getConfig().clear();
}
entity.getConfig().putAll(config);
}
@Override
public void removeConfig(String name) {
if (entity.getConfig() == null) {
return;
}
entity.getConfig().remove(name);
}
@Override
public void putConfig(String name, String value) {
if (entity.getConfig() == null) {
entity.setConfig(new HashMap<>());
}
entity.getConfig().put(name, value);
}
@Override
public String getName() {
return entity.getName();
}
@Override
public void setName(String name) {
entity.setName(name);
}
@Override
public String getDescription() {
return entity.getDescription();
}
@Override
public void setDescription(String description) {
entity.setDescription(description);
}
@Override
public ResourceServer getResourceServer() {
return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
}
@Override
public Set<Policy> getAssociatedPolicies() {
Set<Policy> result = new HashSet<>();
for (PolicyEntity policy : entity.getAssociatedPolicies()) {
Policy p = storeFactory.getPolicyStore().findById(policy.getId(), entity.getResourceServer().getId());
result.add(p);
}
return Collections.unmodifiableSet(result);
}
@Override
public Set<Resource> getResources() {
Set<Resource> set = new HashSet<>();
for (ResourceEntity res : entity.getResources()) {
set.add(storeFactory.getResourceStore().findById(res.getId(), entity.getResourceServer().getId()));
}
return Collections.unmodifiableSet(set);
}
@Override
public Set<Scope> getScopes() {
Set<Scope> set = new HashSet<>();
for (ScopeEntity res : entity.getScopes()) {
set.add(storeFactory.getScopeStore().findById(res.getId(), entity.getResourceServer().getId()));
}
return Collections.unmodifiableSet(set);
}
@Override
public void addScope(Scope scope) {
entity.getScopes().add(ScopeAdapter.toEntity(em, scope));
}
@Override
public void removeScope(Scope scope) {
entity.getScopes().remove(ScopeAdapter.toEntity(em, scope));
}
@Override
public void addAssociatedPolicy(Policy associatedPolicy) {
entity.getAssociatedPolicies().add(toEntity(em, associatedPolicy));
}
@Override
public void removeAssociatedPolicy(Policy associatedPolicy) {
entity.getAssociatedPolicies().remove(toEntity(em, associatedPolicy));
}
@Override
public void addResource(Resource resource) {
entity.getResources().add(ResourceAdapter.toEntity(em, resource));
}
@Override
public void removeResource(Resource resource) {
entity.getResources().remove(ResourceAdapter.toEntity(em, resource));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Policy)) return false;
Policy that = (Policy) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
public static PolicyEntity toEntity(EntityManager em, Policy policy) {
if (policy instanceof PolicyAdapter) {
return ((PolicyAdapter)policy).getEntity();
} else {
return em.getReference(PolicyEntity.class, policy.getId());
}
}
}

View file

@ -0,0 +1,166 @@
/*
* Copyright 2016 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.authorization.jpa.store;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ResourceEntity;
import org.keycloak.authorization.jpa.entities.ScopeEntity;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.jpa.JpaModel;
import javax.persistence.EntityManager;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceAdapter implements Resource, JpaModel<ResourceEntity> {
private ResourceEntity entity;
private EntityManager em;
private StoreFactory storeFactory;
public ResourceAdapter(ResourceEntity entity, EntityManager em, StoreFactory storeFactory) {
this.entity = entity;
this.em = em;
this.storeFactory = storeFactory;
}
@Override
public ResourceEntity getEntity() {
return entity;
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();
}
@Override
public void setName(String name) {
entity.setName(name);
}
@Override
public String getUri() {
return entity.getUri();
}
@Override
public void setUri(String uri) {
entity.setUri(uri);
}
@Override
public String getType() {
return entity.getType();
}
@Override
public void setType(String type) {
entity.setType(type);
}
@Override
public List<Scope> getScopes() {
List<Scope> scopes = new LinkedList<>();
for (ScopeEntity scope : entity.getScopes()) {
scopes.add(storeFactory.getScopeStore().findById(scope.getId(), entity.getResourceServer().getId()));
}
return Collections.unmodifiableList(scopes);
}
@Override
public String getIconUri() {
return entity.getIconUri();
}
@Override
public void setIconUri(String iconUri) {
entity.setIconUri(iconUri);
}
@Override
public ResourceServer getResourceServer() {
return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
}
@Override
public String getOwner() {
return entity.getOwner();
}
@Override
public void updateScopes(Set<Scope> toUpdate) {
Set<String> ids = new HashSet<>();
for (Scope scope : toUpdate) {
ids.add(scope.getId());
}
Iterator<ScopeEntity> it = entity.getScopes().iterator();
while (it.hasNext()) {
ScopeEntity next = it.next();
if (!ids.contains(next.getId())) it.remove();
else ids.remove(next.getId());
}
for (String addId : ids) {
entity.getScopes().add(em.getReference(ScopeEntity.class, addId));
}
}
public static ResourceEntity toEntity(EntityManager em, Resource resource) {
if (resource instanceof ResourceAdapter) {
return ((ResourceAdapter)resource).getEntity();
} else {
return em.getReference(ResourceEntity.class, resource.getId());
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Resource)) return false;
Resource that = (Resource) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright 2016 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.authorization.jpa.store;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ResourceEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.jpa.JpaModel;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
import javax.persistence.EntityManager;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceServerAdapter implements ResourceServer, JpaModel<ResourceServerEntity> {
private ResourceServerEntity entity;
private EntityManager em;
private StoreFactory storeFactory;
public ResourceServerAdapter(ResourceServerEntity entity, EntityManager em, StoreFactory storeFactory) {
this.entity = entity;
this.em = em;
this.storeFactory = storeFactory;
}
@Override
public ResourceServerEntity getEntity() {
return entity;
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getClientId() {
return entity.getClientId();
}
@Override
public boolean isAllowRemoteResourceManagement() {
return entity.isAllowRemoteResourceManagement();
}
@Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
entity.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
}
@Override
public PolicyEnforcementMode getPolicyEnforcementMode() {
return entity.getPolicyEnforcementMode();
}
@Override
public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
entity.setPolicyEnforcementMode(enforcementMode);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof ResourceServer)) return false;
ResourceServer that = (ResourceServer) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
public static ResourceServerEntity toEntity(EntityManager em, ResourceServer resource) {
if (resource instanceof ResourceAdapter) {
return ((ResourceServerAdapter)resource).getEntity();
} else {
return em.getReference(ResourceServerEntity.class, resource.getId());
}
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright 2016 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.authorization.jpa.store;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ScopeEntity;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.jpa.JpaModel;
import javax.persistence.EntityManager;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ScopeAdapter implements Scope, JpaModel<ScopeEntity> {
private ScopeEntity entity;
private EntityManager em;
private StoreFactory storeFactory;
public ScopeAdapter(ScopeEntity entity, EntityManager em, StoreFactory storeFactory) {
this.entity = entity;
this.em = em;
this.storeFactory = storeFactory;
}
@Override
public ScopeEntity getEntity() {
return entity;
}
@Override
public String getId() {
return entity.getId();
}
@Override
public String getName() {
return entity.getName();
}
@Override
public void setName(String name) {
entity.setName(name);
}
@Override
public String getIconUri() {
return entity.getIconUri();
}
@Override
public void setIconUri(String iconUri) {
entity.setIconUri(iconUri);
}
@Override
public ResourceServer getResourceServer() {
return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
}
public static ScopeEntity toEntity(EntityManager em, Scope scope) {
if (scope instanceof ScopeAdapter) {
return ((ScopeAdapter)scope).getEntity();
} else {
return em.getReference(ScopeEntity.class, scope.getId());
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Scope)) return false;
Scope that = (Scope) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -28,6 +28,7 @@ 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;
@ -35,13 +36,15 @@ import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory; 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.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;
/** /**
* <p>The main contract here is the creation of {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances. Usually * <p>The main contract here is the creation of {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances. Usually
* an application has a single {@link AuthorizationProvider} instance and threads servicing client requests obtain {@link org.keycloak.authorization.core.permission.evaluator.PermissionEvaluator} * an application has a single {@link AuthorizationProvider} instance and threads servicing client requests obtain {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator}
* from the {@link #evaluators()} method. * from the {@link #evaluators()} method.
* *
* <p>The internal state of a {@link AuthorizationProvider} is immutable. This internal state includes all of the metadata * <p>The internal state of a {@link AuthorizationProvider} is immutable. This internal state includes all of the metadata
@ -69,14 +72,14 @@ public final class AuthorizationProvider implements Provider {
private final DefaultPolicyEvaluator policyEvaluator; private final DefaultPolicyEvaluator policyEvaluator;
private StoreFactory storeFactory; private StoreFactory storeFactory;
private StoreFactory storeFactoryDelegate;
private final Map<String, PolicyProviderFactory> policyProviderFactories; private final Map<String, PolicyProviderFactory> policyProviderFactories;
private final KeycloakSession keycloakSession; private final KeycloakSession keycloakSession;
private final RealmModel realm; private final RealmModel realm;
public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Map<String, PolicyProviderFactory> policyProviderFactories) { public AuthorizationProvider(KeycloakSession session, RealmModel realm, Map<String, PolicyProviderFactory> policyProviderFactories) {
this.keycloakSession = session; this.keycloakSession = session;
this.realm = realm; this.realm = realm;
this.storeFactory = storeFactory;
this.policyProviderFactories = policyProviderFactories; this.policyProviderFactories = policyProviderFactories;
this.policyEvaluator = new DefaultPolicyEvaluator(this); this.policyEvaluator = new DefaultPolicyEvaluator(this);
} }
@ -92,15 +95,32 @@ public final class AuthorizationProvider implements Provider {
} }
/** /**
* Cache sits in front of this
*
* Returns a {@link StoreFactory}. * Returns a {@link StoreFactory}.
* *
* @return the {@link StoreFactory} * @return the {@link StoreFactory}
*/ */
public StoreFactory getStoreFactory() { public StoreFactory getStoreFactory() {
return createStoreFactory(); if (storeFactory != null) return storeFactory;
storeFactory = keycloakSession.getProvider(CachedStoreFactoryProvider.class);
if (storeFactory == null) storeFactory = getLocalStoreFactory();
storeFactory = createStoreFactory(storeFactory);
return storeFactory;
} }
private StoreFactory createStoreFactory() { /**
* No cache sits in front of this
*
* @return
*/
public StoreFactory getLocalStoreFactory() {
if (storeFactoryDelegate != null) return storeFactoryDelegate;
storeFactoryDelegate = keycloakSession.getProvider(StoreFactory.class);
return storeFactoryDelegate;
}
private StoreFactory createStoreFactory(StoreFactory storeFactory) {
return new StoreFactory() { return new StoreFactory() {
@Override @Override
public ResourceStore getResourceStore() { public ResourceStore getResourceStore() {
@ -222,7 +242,7 @@ public final class AuthorizationProvider implements Provider {
* Returns a {@link PolicyProviderFactory} given a <code>type</code>. * Returns a {@link PolicyProviderFactory} given a <code>type</code>.
* *
* @param type the type of the policy provider * @param type the type of the policy provider
* @param <F> the expected type of the provider * @param <P> the expected type of the provider
* @return a {@link PolicyProvider} with the given <code>type</code> * @return a {@link PolicyProvider} with the given <code>type</code>
*/ */
public <P extends PolicyProvider> P getProvider(String type) { public <P extends PolicyProvider> P getProvider(String type) {

View file

@ -0,0 +1,45 @@
/*
* Copyright 2016 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.authorization.model;
/**
* Cached authorization model classes will implement this interface.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface CachedModel<Model> {
/**
* Invalidates the cache for this model and returns a delegate that represents the actual data provider
*
* @return
*/
Model getDelegateForUpdate();
/**
* Invalidate the cache for this model
*
*/
void invalidate();
/**
* When was the model was loaded from database.
*
* @return
*/
long getCacheTimestamp();
}

View file

@ -76,10 +76,11 @@ public interface Policy {
/** /**
* Returns a {@link Map} holding string-based key/value pairs representing any additional configuration for this policy. * Returns a {@link Map} holding string-based key/value pairs representing any additional configuration for this policy.
* *
* @return a map with any additional configuration defined for this policy. * @return a unmodifiable map with any additional configuration defined for this policy.
*/ */
Map<String, String> getConfig(); Map<String, String> getConfig();
/** /**
* Sets a {@link Map} with string-based key/value pairs representing any additional configuration for this policy. * Sets a {@link Map} with string-based key/value pairs representing any additional configuration for this policy.
* *
@ -87,6 +88,9 @@ public interface Policy {
*/ */
void setConfig(Map<String, String> config); void setConfig(Map<String, String> config);
void removeConfig(String name);
void putConfig(String name, String value);
/** /**
* Returns the name of this policy. * Returns the name of this policy.
* *
@ -120,7 +124,7 @@ public interface Policy {
* *
* @return a resource server * @return a resource server
*/ */
<R extends ResourceServer> R getResourceServer(); ResourceServer getResourceServer();
/** /**
* Returns the {@link Policy} instances associated with this policy and used to evaluate authorization decisions when * Returns the {@link Policy} instances associated with this policy and used to evaluate authorization decisions when
@ -128,21 +132,21 @@ public interface Policy {
* *
* @return the associated policies or an empty set if no policy is associated with this policy * @return the associated policies or an empty set if no policy is associated with this policy
*/ */
<P extends Policy> Set<P> getAssociatedPolicies(); Set<Policy> getAssociatedPolicies();
/** /**
* Returns the {@link Resource} instances where this policy applies. * Returns the {@link Resource} instances where this policy applies.
* *
* @return a set with all resource instances where this policy applies. Or an empty set if there is no resource associated with this policy * @return a set with all resource instances where this policy applies. Or an empty set if there is no resource associated with this policy
*/ */
<R extends Resource> Set<R> getResources(); Set<Resource> getResources();
/** /**
* Returns the {@link Scope} instances where this policy applies. * Returns the {@link Scope} instances where this policy applies.
* *
* @return a set with all scope instances where this policy applies. Or an empty set if there is no scope associated with this policy * @return a set with all scope instances where this policy applies. Or an empty set if there is no scope associated with this policy
*/ */
<S extends Scope> Set<S> getScopes(); Set<Scope> getScopes();
void addScope(Scope scope); void addScope(Scope scope);

View file

@ -82,7 +82,7 @@ public interface Resource {
* *
* @return a list with all scopes associated with this resource * @return a list with all scopes associated with this resource
*/ */
<S extends Scope> List<S> getScopes(); List<Scope> getScopes();
/** /**
* Returns an icon {@link java.net.URI} for this resource. * Returns an icon {@link java.net.URI} for this resource.
@ -103,7 +103,7 @@ public interface Resource {
* *
* @return the resource server associated with this resource * @return the resource server associated with this resource
*/ */
<R extends ResourceServer> R getResourceServer(); ResourceServer getResourceServer();
/** /**
* Returns the resource's owner, which is usually an identifier that uniquely identifies the resource's owner. * Returns the resource's owner, which is usually an identifier that uniquely identifies the resource's owner.

View file

@ -21,10 +21,12 @@ package org.keycloak.authorization.store;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer; import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer;
import org.keycloak.authorization.store.syncronization.RealmSynchronizer; import org.keycloak.authorization.store.syncronization.RealmSynchronizer;
import org.keycloak.authorization.store.syncronization.Synchronizer; import org.keycloak.authorization.store.syncronization.Synchronizer;
import org.keycloak.authorization.store.syncronization.UserSynchronizer; import org.keycloak.authorization.store.syncronization.UserSynchronizer;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel.ClientRemovedEvent; import org.keycloak.models.RealmModel.ClientRemovedEvent;
import org.keycloak.models.RealmModel.RealmRemovedEvent; import org.keycloak.models.RealmModel.RealmRemovedEvent;

View file

@ -66,7 +66,7 @@ public interface ResourceStore {
/** /**
* Finds all {@link Resource} instances with the given uri. * Finds all {@link Resource} instances with the given uri.
* *
* @param ownerId the identifier of the owner * @param uri the identifier of the uri
* @return a list with all resource instances owned by the given owner * @return a list with all resource instances owned by the given owner
*/ */
List<Resource> findByUri(String uri, String resourceServerId); List<Resource> findByUri(String uri, String resourceServerId);

View file

@ -41,9 +41,9 @@ public class ClientApplicationSynchronizer implements Synchronizer<ClientRemoved
if (resourceServer != null) { if (resourceServer != null) {
String id = resourceServer.getId(); String id = resourceServer.getId();
storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId())); //storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId())); //storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId())); //storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
storeFactory.getResourceServerStore().delete(id); storeFactory.getResourceServerStore().delete(id);
} }
} }

View file

@ -71,7 +71,7 @@ public class MigrateTo2_1_0 implements Migration {
if (resourceServer != null) { if (resourceServer != null) {
policyStore.findByType("role", resourceServer.getId()).forEach(policy -> { policyStore.findByType("role", resourceServer.getId()).forEach(policy -> {
Map<String, String> config = policy.getConfig(); Map<String, String> config = new HashMap(policy.getConfig());
String roles = config.get("roles"); String roles = config.get("roles");
List roleConfig; List roleConfig;

View file

@ -18,6 +18,9 @@
package org.keycloak.models.cache.authorization; package org.keycloak.models.cache.authorization;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
/** /**

View file

@ -2110,7 +2110,7 @@ public class RepresentationToModel {
} }
} }
policy.getConfig().remove("scopes"); policy.removeConfig("scopes");
} }
private static void updateAssociatedPolicies(Set<String> policyIds, Policy policy, StoreFactory storeFactory) { private static void updateAssociatedPolicies(Set<String> policyIds, Policy policy, StoreFactory storeFactory) {
@ -2163,7 +2163,7 @@ public class RepresentationToModel {
} }
} }
policy.getConfig().remove("applyPolicies"); policy.removeConfig("applyPolicies");
} }
private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) { private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) {
@ -2209,7 +2209,7 @@ public class RepresentationToModel {
} }
} }
policy.getConfig().remove("resources"); policy.removeConfig("resources");
} }
public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) { public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {

View file

@ -65,11 +65,7 @@ public class DefaultAuthorizationProviderFactory implements AuthorizationProvide
@Override @Override
public AuthorizationProvider create(KeycloakSession session, RealmModel realm) { public AuthorizationProvider create(KeycloakSession session, RealmModel realm) {
StoreFactory storeFactory = session.getProvider(CachedStoreFactoryProvider.class); return new AuthorizationProvider(session, realm, policyProviderFactories);
if (storeFactory == null) {
storeFactory = session.getProvider(StoreFactory.class);
}
return new AuthorizationProvider(session, realm, storeFactory, policyProviderFactories);
} }
private Map<String, PolicyProviderFactory> configurePolicyProviderFactories(KeycloakSessionFactory keycloakSessionFactory) { private Map<String, PolicyProviderFactory> configurePolicyProviderFactories(KeycloakSessionFactory keycloakSessionFactory) {

View file

@ -16,6 +16,7 @@
*/ */
package org.keycloak.authorization.authorization; package org.keycloak.authorization.authorization;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException; import org.keycloak.OAuthErrorException;
@ -46,6 +47,7 @@ import org.keycloak.representations.idm.authorization.Permission;
import org.keycloak.representations.idm.authorization.ScopeRepresentation; import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.Cors; import org.keycloak.services.resources.Cors;
import org.keycloak.services.resources.RealmsResource;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.OPTIONS; import javax.ws.rs.OPTIONS;
@ -72,6 +74,7 @@ import java.util.stream.Stream;
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public class AuthorizationTokenService { public class AuthorizationTokenService {
protected static final Logger logger = Logger.getLogger(AuthorizationTokenService.class);
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
@ -131,6 +134,7 @@ public class AuthorizationTokenService {
@Override @Override
public void onError(Throwable cause) { public void onError(Throwable cause) {
logger.error("failed authorize", cause);
asyncResponse.resume(cause); asyncResponse.resume(cause);
} }
}); });

View file

@ -41,10 +41,12 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException; import org.keycloak.OAuthErrorException;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.authorization.AuthorizationTokenService;
import org.keycloak.authorization.common.KeycloakEvaluationContext; import org.keycloak.authorization.common.KeycloakEvaluationContext;
import org.keycloak.authorization.common.KeycloakIdentity; import org.keycloak.authorization.common.KeycloakIdentity;
import org.keycloak.authorization.entitlement.representation.EntitlementRequest; import org.keycloak.authorization.entitlement.representation.EntitlementRequest;
@ -79,6 +81,7 @@ import org.keycloak.services.resources.Cors;
*/ */
public class EntitlementService { public class EntitlementService {
protected static final Logger logger = Logger.getLogger(EntitlementService.class);
private final AuthorizationProvider authorization; private final AuthorizationProvider authorization;
@Context @Context
@ -122,6 +125,7 @@ public class EntitlementService {
@Override @Override
public void onError(Throwable cause) { public void onError(Throwable cause) {
logger.error("failed", cause);
asyncResponse.resume(cause); asyncResponse.resume(cause);
} }
@ -175,6 +179,7 @@ public class EntitlementService {
authorization.evaluators().from(createPermissions(entitlementRequest, resourceServer, authorization), new KeycloakEvaluationContext(this.authorization.getKeycloakSession())).evaluate(new DecisionResultCollector() { authorization.evaluators().from(createPermissions(entitlementRequest, resourceServer, authorization), new KeycloakEvaluationContext(this.authorization.getKeycloakSession())).evaluate(new DecisionResultCollector() {
@Override @Override
public void onError(Throwable cause) { public void onError(Throwable cause) {
logger.error("failed", cause);
asyncResponse.resume(cause); asyncResponse.resume(cause);
} }

View file

@ -21,6 +21,7 @@ package org.keycloak.authorization.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -61,8 +62,8 @@ public final class Permissions {
StoreFactory storeFactory = authorization.getStoreFactory(); StoreFactory storeFactory = authorization.getStoreFactory();
ResourceStore resourceStore = storeFactory.getResourceStore(); ResourceStore resourceStore = storeFactory.getResourceStore();
resourceStore.findByOwner(resourceServer.getClientId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, resource.getScopes(), authorization))); resourceStore.findByOwner(resourceServer.getClientId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
resourceStore.findByOwner(identity.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, resource.getScopes(), authorization))); resourceStore.findByOwner(identity.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
return permissions; return permissions;
} }
@ -74,7 +75,7 @@ public final class Permissions {
List<Scope> scopes; List<Scope> scopes;
if (requestedScopes.isEmpty()) { if (requestedScopes.isEmpty()) {
scopes = resource.getScopes(); scopes = new LinkedList<>(resource.getScopes());
// check if there is a typed resource whose scopes are inherited by the resource being requested. In this case, we assume that parent resource // check if there is a typed resource whose scopes are inherited by the resource being requested. In this case, we assume that parent resource
// is owned by the resource server itself // is owned by the resource server itself
if (type != null && !resource.getOwner().equals(resourceServer.getClientId())) { if (type != null && !resource.getOwner().equals(resourceServer.getClientId())) {
@ -102,7 +103,6 @@ public final class Permissions {
return byName; return byName;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
permissions.add(new ResourcePermission(resource, scopes, resource.getResourceServer())); permissions.add(new ResourcePermission(resource, scopes, resource.getResourceServer()));
return permissions; return permissions;

View file

@ -213,7 +213,7 @@ public class ConflictingScopePermissionTest extends AbstractKeycloakTest {
} }
representation.addScope(scopes.toArray(new String[scopes.size()])); representation.addScope(scopes.toArray(new String[scopes.size()]));
representation.addPolicy(scopes.toArray(new String[policies.size()])); representation.addPolicy(policies.toArray(new String[policies.size()]));
authorization.permissions().scope().create(representation); authorization.permissions().scope().create(representation);
} }

View file

@ -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"/>