KEYCLOAK-4929

This commit is contained in:
Bill Burke 2017-05-18 16:48:04 -04:00
parent 789722ec6a
commit c291748f43
76 changed files with 3340 additions and 2247 deletions

View file

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

View file

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

View file

@ -163,11 +163,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
}
try {
Map<String, String> config = policy.getConfig();
config.put("roles", JsonSerialization.writeValueAsString(updatedRoles));
policy.setConfig(config);
policy.putConfig("roles", JsonSerialization.writeValueAsString(updatedRoles));
} catch (IOException cause) {
throw new RuntimeException("Failed to serialize roles", cause);
}
@ -224,9 +220,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
if (roles.isEmpty()) {
policyStore.delete(policy.getId());
} else {
Map<String, String> config = policy.getConfig();
config.put("roles", JsonSerialization.writeValueAsString(roles));
policy.setConfig(config);
policy.putConfig("roles", JsonSerialization.writeValueAsString(roles));
}
} catch (IOException 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;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import org.keycloak.Config;
@ -118,7 +119,7 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory<TimePoli
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("noa", (s, s2) -> noa != null ? noa : null);

View file

@ -138,11 +138,8 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
}
try {
Map<String, String> config = policy.getConfig();
config.put("users", JsonSerialization.writeValueAsString(updatedUsers));
policy.setConfig(config);
policy.putConfig("users", JsonSerialization.writeValueAsString(updatedUsers));
} catch (IOException cause) {
throw new RuntimeException("Failed to serialize users", cause);
}
@ -181,7 +178,7 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
if (users.isEmpty()) {
policyStore.delete(policy.getId());
} else {
policy.getConfig().put("users", JsonSerialization.writeValueAsString(users));
policy.putConfig("users", JsonSerialization.writeValueAsString(users));
}
} catch (IOException 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) {
Map<String, String> config = policy.getConfig();
config.put("mavenArtifactGroupId", representation.getArtifactGroupId());
config.put("mavenArtifactId", representation.getArtifactId());
config.put("mavenArtifactVersion", representation.getArtifactVersion());
config.put("scannerPeriod", representation.getScannerPeriod());
config.put("scannerPeriodUnit", representation.getScannerPeriodUnit());
config.put("sessionName", representation.getSessionName());
config.put("moduleName", representation.getModuleName());
policy.putConfig("mavenArtifactGroupId", representation.getArtifactGroupId());
policy.putConfig("mavenArtifactId", representation.getArtifactId());
policy.putConfig("mavenArtifactVersion", representation.getArtifactVersion());
policy.putConfig("scannerPeriod", representation.getScannerPeriod());
policy.putConfig("scannerPeriodUnit", representation.getScannerPeriodUnit());
policy.putConfig("sessionName", representation.getSessionName());
policy.putConfig("moduleName", representation.getModuleName());
policy.setConfig(config);
}
void update(Policy policy) {

View file

@ -118,9 +118,18 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, getRevisionCacheConfig(userRevisionsMaxEntries));
cacheManager.getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, 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);
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve cache container", e);
@ -151,6 +160,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
Configuration modelCacheConfiguration = modelCacheConfigBuilder.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, modelCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, modelCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_CACHE_NAME, modelCacheConfiguration);
ConfigurationBuilder sessionConfigBuilder = new ConfigurationBuilder();
@ -180,7 +190,6 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, sessionCacheConfiguration);
ConfigurationBuilder replicationConfigBuilder = new ConfigurationBuilder();
if (clustered) {
@ -219,6 +228,14 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.KEYS_CACHE_NAME, getKeysCacheConfig());
cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, 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) {

View file

@ -38,6 +38,8 @@ public interface InfinispanConnectionProvider extends Provider {
String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
String WORK_CACHE_NAME = "work";
String AUTHORIZATION_CACHE_NAME = "authorization";
String AUTHORIZATION_REVISIONS_CACHE_NAME = "authorizationRevisions";
int AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX = 20000;
String KEYS_CACHE_NAME = "keys";
int KEYS_CACHE_DEFAULT_MAX = 1000;

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<>();
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.
*/
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.Resource;
import org.keycloak.authorization.model.ResourceServer;
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.Logic;
@ -34,11 +35,8 @@ import java.util.stream.Collectors;
/**
* @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 DecisionStrategy decisionStrategy;
private Logic logic;
@ -50,8 +48,8 @@ public class CachedPolicy implements Policy, Serializable {
private Set<String> resourcesIds;
private Set<String> scopesIds;
public CachedPolicy(Policy policy) {
this.id = policy.getId();
public CachedPolicy(Long revision, Policy policy) {
super(revision, policy.getId());
this.type = policy.getType();
this.decisionStrategy = policy.getDecisionStrategy();
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());
}
public CachedPolicy(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getType() {
return this.type;
}
@Override
public DecisionStrategy getDecisionStrategy() {
return this.decisionStrategy;
}
@Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
this.decisionStrategy = decisionStrategy;
}
@Override
public Logic getLogic() {
return this.logic;
}
@Override
public void setLogic(Logic logic) {
this.logic = logic;
}
@Override
public Map<String, String> getConfig() {
return this.config;
}
@Override
public void setConfig(Map<String, String> config) {
this.config = config;
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getDescription() {
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() {
return this.associatedPoliciesIds;
}
@ -194,24 +102,4 @@ public class CachedPolicy implements Policy, Serializable {
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.
*/
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.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import java.io.Serializable;
import java.util.List;
@ -30,11 +31,8 @@ import java.util.stream.Collectors;
/**
* @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 iconUri;
private String owner;
@ -43,8 +41,8 @@ public class CachedResource implements Resource, Serializable {
private String uri;
private Set<String> scopesIds;
public CachedResource(Resource resource) {
this.id = resource.getId();
public CachedResource(Long revision, Resource resource) {
super(revision, resource.getId());
this.name = resource.getName();
this.uri = resource.getUri();
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());
}
public CachedResource(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getUri() {
return this.uri;
}
@Override
public void setUri(String uri) {
this.uri = uri;
}
@Override
public String getType() {
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() {
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() {
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() {
return this.resourceServerId;
}

View file

@ -16,9 +16,10 @@
* 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.models.cache.infinispan.entities.AbstractRevisioned;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
import java.io.Serializable;
@ -26,53 +27,30 @@ import java.io.Serializable;
/**
* @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 boolean allowRemoteResourceManagement;
private PolicyEnforcementMode policyEnforcementMode;
public CachedResourceServer(ResourceServer resourceServer) {
this.id = resourceServer.getId();
public CachedResourceServer(Long revision, ResourceServer resourceServer) {
super(revision, resourceServer.getId());
this.clientId = resourceServer.getClientId();
this.allowRemoteResourceManagement = resourceServer.isAllowRemoteResourceManagement();
this.policyEnforcementMode = resourceServer.getPolicyEnforcementMode();
}
public CachedResourceServer(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getClientId() {
return this.clientId;
}
@Override
public boolean isAllowRemoteResourceManagement() {
return this.allowRemoteResourceManagement;
}
@Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
this.allowRemoteResourceManagement = allowRemoteResourceManagement;
}
@Override
public PolicyEnforcementMode getPolicyEnforcementMode() {
return this.policyEnforcementMode;
}
@Override
public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
this.policyEnforcementMode = enforcementMode;
}
}

View file

@ -16,10 +16,11 @@
* 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.Scope;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import java.io.Serializable;
import java.util.Objects;
@ -27,70 +28,30 @@ import java.util.Objects;
/**
* @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 name;
private String iconUri;
public CachedScope(Scope scope) {
this.id = scope.getId();
public CachedScope(Long revision, Scope scope) {
super(revision, scope.getId());
this.name = scope.getName();
this.iconUri = scope.getIconUri();
this.resourceServerId = scope.getResourceServer().getId();
}
public CachedScope(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getIconUri() {
return this.iconUri;
}
@Override
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
@Override
public ResourceServer getResourceServer() {
throw new RuntimeException("Not implemented");
}
public String getResourceServerId() {
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
* 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 {
private final String clientId;
public ResourceServerRemovedEvent(String id, String clientId) {
super(id, Collections.emptySet());
this.clientId = clientId;
}
public String getClientId() {
return clientId;
}
public interface AuthorizationCacheInvalidationEvent {
void addInvalidations(StoreFactoryCacheManager realmCache, Set<String> 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 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.
#
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.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@ -52,11 +54,25 @@ import org.keycloak.representations.idm.authorization.Logic;
@Table(name = "RESOURCE_SERVER_POLICY", uniqueConstraints = {
@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
@Column(name="ID", length = 36)
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
@Column(name = "ID", length = 36)
@Access(AccessType.PROPERTY)
// we do this because relationships often fetch id, but not entity. This avoids an extra SQL
private String id;
@Column(name = "NAME")
@ -75,9 +91,9 @@ public class PolicyEntity implements Policy {
private Logic logic = Logic.POSITIVE;
@ElementCollection(fetch = FetchType.LAZY)
@MapKeyColumn(name="NAME")
@Column(name="VALUE", columnDefinition = "TEXT")
@CollectionTable(name="POLICY_CONFIG", joinColumns={ @JoinColumn(name="POLICY_ID") })
@MapKeyColumn(name = "NAME")
@Column(name = "VALUE", columnDefinition = "TEXT")
@CollectionTable(name = "POLICY_CONFIG", joinColumns = {@JoinColumn(name = "POLICY_ID")})
private Map<String, String> config = new HashMap();
@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"))
private Set<ScopeEntity> scopes = new HashSet<>();
@Override
public String getId() {
return this.id;
}
@ -105,7 +120,6 @@ public class PolicyEntity implements Policy {
this.id = id;
}
@Override
public String getType() {
return this.type;
}
@ -114,57 +128,46 @@ public class PolicyEntity implements Policy {
this.type = type;
}
@Override
public DecisionStrategy getDecisionStrategy() {
return this.decisionStrategy;
}
@Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
this.decisionStrategy = decisionStrategy;
}
@Override
public Logic getLogic() {
return this.logic;
}
@Override
public void setLogic(Logic logic) {
this.logic = logic;
}
@Override
public Map<String, String> getConfig() {
return this.config;
}
@Override
public void setConfig(Map<String, String> config) {
this.config = config;
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getDescription() {
return this.description;
}
@Override
public void setDescription(String description) {
this.description = description;
}
@Override
public ResourceServerEntity getResourceServer() {
return this.resourceServer;
}
@ -173,16 +176,6 @@ public class PolicyEntity implements Policy {
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() {
return this.resources;
}
@ -191,7 +184,6 @@ public class PolicyEntity implements Policy {
this.resources = resources;
}
@Override
public Set<ScopeEntity> getScopes() {
return this.scopes;
}
@ -200,54 +192,26 @@ public class PolicyEntity implements Policy {
this.scopes = scopes;
}
@Override
public void addScope(Scope scope) {
getScopes().add((ScopeEntity) scope);
public Set<PolicyEntity> getAssociatedPolicies() {
return associatedPolicies;
}
@Override
public void removeScope(Scope scope) {
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);
public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
this.associatedPolicies = associatedPolicies;
}
@Override
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;
if (!Policy.class.isInstance(o)) return false;
Policy that = (Policy) o;
if (!getId().equals(that.getId())) return false;
return true;
PolicyEntity that = (PolicyEntity) o;
return getId().equals(that.getId());
}
@Override
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.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@ -45,7 +48,18 @@ import java.util.Set;
@Table(name = "RESOURCE_SERVER_RESOURCE", uniqueConstraints = {
@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
@Column(name="ID", length = 36)
@ -73,13 +87,12 @@ public class ResourceEntity implements Resource {
@ManyToMany(fetch = FetchType.LAZY, cascade = {})
@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 = {})
@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() {
return id;
}
@ -88,52 +101,42 @@ public class ResourceEntity implements Resource {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getUri() {
return uri;
}
@Override
public void setUri(String uri) {
this.uri = uri;
}
@Override
public String getType() {
return type;
}
@Override
public void setType(String type) {
this.type = type;
}
@Override
public List<ScopeEntity> getScopes() {
return this.scopes;
}
@Override
public String getIconUri() {
return iconUri;
}
@Override
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
@Override
public ResourceServerEntity getResourceServer() {
return resourceServer;
}
@ -154,37 +157,23 @@ public class ResourceEntity implements Resource {
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) {
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.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@ -36,7 +38,12 @@ import java.util.List;
*/
@Entity
@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
@Column(name="ID", length = 36)
@ -58,7 +65,6 @@ public class ResourceServerEntity implements ResourceServer {
@OneToMany (mappedBy = "resourceServer")
private List<ScopeEntity> scopes;
@Override
public String getId() {
return this.id;
}
@ -67,7 +73,6 @@ public class ResourceServerEntity implements ResourceServer {
this.id = id;
}
@Override
public String getClientId() {
return this.clientId;
}
@ -76,22 +81,18 @@ public class ResourceServerEntity implements ResourceServer {
this.clientId = clientId;
}
@Override
public boolean isAllowRemoteResourceManagement() {
return this.allowRemoteResourceManagement;
}
@Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
this.allowRemoteResourceManagement = allowRemoteResourceManagement;
}
@Override
public PolicyEnforcementMode getPolicyEnforcementMode() {
return this.policyEnforcementMode;
}
@Override
public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) {
this.policyEnforcementMode = policyEnforcementMode;
}
@ -111,4 +112,19 @@ public class ResourceServerEntity implements ResourceServer {
public void setScopes(final List<ScopeEntity> 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.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
@ -44,7 +46,14 @@ import java.util.Objects;
@Table(name = "RESOURCE_SERVER_SCOPE", uniqueConstraints = {
@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
@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"))
private List<PolicyEntity> policies = new ArrayList<>();
@Override
public String getId() {
return id;
}
@ -74,33 +82,28 @@ public class ScopeEntity implements Scope {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getIconUri() {
return iconUri;
}
@Override
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
@Override
public ResourceServerEntity getResourceServer() {
return resourceServer;
}
public List<? extends Policy> getPolicies() {
return this.policies;
public List<PolicyEntity> getPolicies() {
return policies;
}
public void setPolicies(List<PolicyEntity> policies) {
@ -114,13 +117,15 @@ public class ScopeEntity implements Scope {
@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());
if (o == null || getClass() != o.getClass()) return false;
ScopeEntity that = (ScopeEntity) o;
return getId().equals(that.getId());
}
@Override
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 {
@Override
public StoreFactory create(KeycloakSession session) {
return new JPAStoreFactory(getEntityManager(session));
public StoreFactory create(KeycloakSession session) {
AuthorizationProvider provider = session.getProvider(AuthorizationProvider.class);
return new JPAStoreFactory(getEntityManager(session), provider);
}
@Override

View file

@ -19,23 +19,29 @@ package org.keycloak.authorization.jpa.store;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.PolicyEntity;
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.PolicyStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
/**
@ -44,9 +50,10 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
public class JPAPolicyStore implements PolicyStore {
private final EntityManager entityManager;
public JPAPolicyStore(EntityManager entityManager) {
private final AuthorizationProvider provider;
public JPAPolicyStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
this.provider = provider;
}
@Override
@ -56,17 +63,17 @@ public class JPAPolicyStore implements PolicyStore {
entity.setId(KeycloakModelUtils.generateId());
entity.setType(representation.getType());
entity.setName(representation.getName());
entity.setResourceServer((ResourceServerEntity) resourceServer);
entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
this.entityManager.persist(entity);
this.entityManager.flush();
return entity;
Policy model = new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
return model;
}
@Override
public void delete(String id) {
Policy policy = entityManager.find(PolicyEntity.class, id);
PolicyEntity policy = entityManager.find(PolicyEntity.class, id);
if (policy != null) {
this.entityManager.remove(policy);
}
@ -79,39 +86,38 @@ public class JPAPolicyStore implements PolicyStore {
return null;
}
if (resourceServerId == null) {
return entityManager.find(PolicyEntity.class, id);
}
PolicyEntity entity = entityManager.find(PolicyEntity.class, id);
if (entity == null) return null;
Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId and id = :id");
query.setParameter("serverId", resourceServerId);
query.setParameter("id", id);
return entityManager.find(PolicyEntity.class, id);
return new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public Policy findByName(String name, String resourceServerId) {
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByName", String.class);
query.setParameter("serverId", resourceServerId);
query.setParameter("name", name);
try {
Query query = entityManager.createQuery("from PolicyEntity where name = :name and resourceServer.id = :serverId");
query.setParameter("name", name);
query.setParameter("serverId", resourceServerId);
return (Policy) query.getSingleResult();
} catch (NoResultException nre) {
String id = query.getSingleResult();
return provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId);
} catch (NoResultException ex) {
return null;
}
}
@Override
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);
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
@ -120,6 +126,7 @@ public class JPAPolicyStore implements PolicyStore {
CriteriaQuery<PolicyEntity> querybuilder = builder.createQuery(PolicyEntity.class);
Root<PolicyEntity> root = querybuilder.from(PolicyEntity.class);
List<Predicate> predicates = new ArrayList();
querybuilder.select(root.get("id"));
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@ -148,27 +155,42 @@ public class JPAPolicyStore implements PolicyStore {
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
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("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
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("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
@ -178,31 +200,47 @@ public class JPAPolicyStore implements PolicyStore {
}
// 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("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
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("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
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("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;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.PolicyEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import java.util.LinkedList;
import java.util.List;
/**
@ -32,9 +38,11 @@ import java.util.List;
public class JPAResourceServerStore implements ResourceServerStore {
private final EntityManager entityManager;
private final AuthorizationProvider provider;
public JPAResourceServerStore(EntityManager entityManager) {
public JPAResourceServerStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
this.provider = provider;
}
@Override
@ -46,30 +54,54 @@ public class JPAResourceServerStore implements ResourceServerStore {
this.entityManager.persist(entity);
return entity;
return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
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
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
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);
List result = query.getResultList();
if (result.isEmpty()) {
try {
String id = query.getSingleResult();
return provider.getStoreFactory().getResourceServerStore().findById(id);
} catch (NoResultException ex) {
return null;
}
return (ResourceServer) result.get(0);
}
}

View file

@ -17,6 +17,7 @@
*/
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.Resource;
@ -25,13 +26,16 @@ import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -41,38 +45,34 @@ import java.util.Map;
public class JPAResourceStore implements ResourceStore {
private final EntityManager entityManager;
private final AuthorizationProvider provider;
public JPAResourceStore(EntityManager entityManager) {
public JPAResourceStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
this.provider = provider;
}
@Override
public Resource create(String name, ResourceServer resourceServer, String owner) {
if (!(resourceServer instanceof ResourceServerEntity)) {
throw new RuntimeException("Unexpected type [" + resourceServer.getClass() + "].");
}
ResourceEntity entity = new ResourceEntity();
entity.setId(KeycloakModelUtils.generateId());
entity.setName(name);
entity.setResourceServer((ResourceServerEntity) resourceServer);
entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
entity.setOwner(owner);
this.entityManager.persist(entity);
return entity;
return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
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();
if (resource != null) {
this.entityManager.remove(resource);
}
this.entityManager.remove(resource);
}
@Override
@ -81,52 +81,61 @@ public class JPAResourceStore implements ResourceStore {
return null;
}
if (resourceServerId == null) {
return entityManager.find(ResourceEntity.class, id);
}
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);
ResourceEntity entity = entityManager.find(ResourceEntity.class, id);
if (entity == null) return null;
return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
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);
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
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("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
public List findByResourceServer(String resourceServerId) {
Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId");
public List<Resource> findByResourceServer(String resourceServerId) {
TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByServerId", String.class);
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
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();
CriteriaQuery<ResourceEntity> querybuilder = builder.createQuery(ResourceEntity.class);
Root<ResourceEntity> root = querybuilder.from(ResourceEntity.class);
querybuilder.select(root.get("id"));
List<Predicate> predicates = new ArrayList();
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@ -152,42 +161,55 @@ public class JPAResourceStore implements ResourceStore {
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
public List<Resource> findByScope(List<String> id, 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))");
public List<Resource> findByScope(List<String> scopes, String resourceServerId) {
TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByScope", String.class);
query.setParameter("scopeIds", id);
query.setParameter("scopeIds", scopes);
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
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("name", name);
List<Resource> result = query.getResultList();
if (!result.isEmpty()) {
return result.get(0);
try {
String id = query.getSingleResult();
return provider.getStoreFactory().getResourceStore().findById(id, resourceServerId);
} catch (NoResultException ex) {
return null;
}
return null;
}
@Override
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("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;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.jpa.entities.ScopeEntity;
import org.keycloak.authorization.model.ResourceServer;
@ -42,9 +45,11 @@ import org.keycloak.models.utils.KeycloakModelUtils;
public class JPAScopeStore implements ScopeStore {
private final EntityManager entityManager;
private final AuthorizationProvider provider;
public JPAScopeStore(EntityManager entityManager) {
public JPAScopeStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
this.provider = provider;
}
@Override
@ -53,16 +58,16 @@ public class JPAScopeStore implements ScopeStore {
entity.setId(KeycloakModelUtils.generateId());
entity.setName(name);
entity.setResourceServer((ResourceServerEntity) resourceServer);
entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
this.entityManager.persist(entity);
return entity;
return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public void delete(String id) {
Scope scope = entityManager.find(ScopeEntity.class, id);
ScopeEntity scope = entityManager.find(ScopeEntity.class, id);
if (scope != null) {
this.entityManager.remove(scope);
@ -75,28 +80,21 @@ public class JPAScopeStore implements ScopeStore {
return null;
}
if (resourceServerId == null) {
return entityManager.find(ScopeEntity.class, id);
}
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);
ScopeEntity entity = entityManager.find(ScopeEntity.class, id);
if (entity == null) return null;
return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public Scope findByName(String name, String resourceServerId) {
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);
return (Scope) query.getSingleResult();
String id = query.getSingleResult();
return provider.getStoreFactory().getScopeStore().findById(id, resourceServerId);
} catch (NoResultException nre) {
return null;
}
@ -104,11 +102,16 @@ public class JPAScopeStore implements ScopeStore {
@Override
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);
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
@ -116,6 +119,7 @@ public class JPAScopeStore implements ScopeStore {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<ScopeEntity> querybuilder = builder.createQuery(ScopeEntity.class);
Root<ScopeEntity> root = querybuilder.from(ScopeEntity.class);
querybuilder.select(root.get("id"));
List<Predicate> predicates = new ArrayList();
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@ -139,6 +143,12 @@ public class JPAScopeStore implements ScopeStore {
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 org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
@ -36,11 +37,11 @@ public class JPAStoreFactory implements StoreFactory {
private final ResourceStore resourceStore;
private final ScopeStore scopeStore;
public JPAStoreFactory(EntityManager entityManager) {
policyStore = new JPAPolicyStore(entityManager);
resourceServerStore = new JPAResourceServerStore(entityManager);
resourceStore = new JPAResourceStore(entityManager);
scopeStore = new JPAScopeStore(entityManager);
public JPAStoreFactory(EntityManager entityManager, AuthorizationProvider provider) {
policyStore = new JPAPolicyStore(entityManager, provider);
resourceServerStore = new JPAResourceServerStore(entityManager, provider);
resourceStore = new JPAResourceStore(entityManager, provider);
scopeStore = new JPAScopeStore(entityManager, provider);
}
@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.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.AuthorizationStoreFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
@ -35,13 +36,15 @@ import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.provider.Provider;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
/**
* <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.
*
* <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 StoreFactory storeFactory;
private StoreFactory storeFactoryDelegate;
private final Map<String, PolicyProviderFactory> policyProviderFactories;
private final KeycloakSession keycloakSession;
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.realm = realm;
this.storeFactory = storeFactory;
this.policyProviderFactories = policyProviderFactories;
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}.
*
* @return the {@link StoreFactory}
*/
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() {
@Override
public ResourceStore getResourceStore() {
@ -222,7 +242,7 @@ public final class AuthorizationProvider implements Provider {
* Returns a {@link PolicyProviderFactory} given a <code>type</code>.
*
* @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>
*/
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.
*
* @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();
/**
* 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 removeConfig(String name);
void putConfig(String name, String value);
/**
* Returns the name of this policy.
*
@ -120,7 +124,7 @@ public interface Policy {
*
* @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
@ -128,21 +132,21 @@ public interface 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.
*
* @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.
*
* @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);

View file

@ -82,7 +82,7 @@ public interface 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.
@ -103,7 +103,7 @@ public interface 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.

View file

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

View file

@ -66,7 +66,7 @@ public interface ResourceStore {
/**
* 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
*/
List<Resource> findByUri(String uri, String resourceServerId);

View file

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

View file

@ -71,7 +71,7 @@ public class MigrateTo2_1_0 implements Migration {
if (resourceServer != null) {
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");
List roleConfig;

View file

@ -18,6 +18,9 @@
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;
/**

View file

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

View file

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

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.authorization.authorization;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants;
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.services.ErrorResponseException;
import org.keycloak.services.resources.Cors;
import org.keycloak.services.resources.RealmsResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.OPTIONS;
@ -72,6 +74,7 @@ import java.util.stream.Stream;
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationTokenService {
protected static final Logger logger = Logger.getLogger(AuthorizationTokenService.class);
private final AuthorizationProvider authorization;
@ -131,6 +134,7 @@ public class AuthorizationTokenService {
@Override
public void onError(Throwable cause) {
logger.error("failed authorize", 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.Status;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.authorization.AuthorizationTokenService;
import org.keycloak.authorization.common.KeycloakEvaluationContext;
import org.keycloak.authorization.common.KeycloakIdentity;
import org.keycloak.authorization.entitlement.representation.EntitlementRequest;
@ -79,6 +81,7 @@ import org.keycloak.services.resources.Cors;
*/
public class EntitlementService {
protected static final Logger logger = Logger.getLogger(EntitlementService.class);
private final AuthorizationProvider authorization;
@Context
@ -122,6 +125,7 @@ public class EntitlementService {
@Override
public void onError(Throwable cause) {
logger.error("failed", 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() {
@Override
public void onError(Throwable cause) {
logger.error("failed", cause);
asyncResponse.resume(cause);
}

View file

@ -21,6 +21,7 @@ package org.keycloak.authorization.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -61,8 +62,8 @@ public final class Permissions {
StoreFactory storeFactory = authorization.getStoreFactory();
ResourceStore resourceStore = storeFactory.getResourceStore();
resourceStore.findByOwner(resourceServer.getClientId(), 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, 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, new LinkedList(resource.getScopes()), authorization)));
return permissions;
}
@ -74,7 +75,7 @@ public final class Permissions {
List<Scope> scopes;
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
// is owned by the resource server itself
if (type != null && !resource.getOwner().equals(resourceServer.getClientId())) {
@ -102,7 +103,6 @@ public final class Permissions {
return byName;
}).collect(Collectors.toList());
}
permissions.add(new ResourcePermission(resource, scopes, resource.getResourceServer()));
return permissions;

View file

@ -214,7 +214,7 @@ public class ConflictingScopePermissionTest extends AbstractKeycloakTest {
}
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);
}

View file

@ -36,7 +36,7 @@
<local-cache name="loginFailures"/>
<local-cache name="work"/>
<local-cache name="authorization">
<eviction max-entries="100" strategy="LRU"/>
<eviction max-entries="10000" strategy="LRU"/>
</local-cache>
<local-cache name="keys">
<eviction max-entries="1000" strategy="LRU"/>