Enhance Map authz entities with REALM_ID (ResourceServer with CLIENT_ID) searchable field
Co-authored-by Michal Hajas <mhajas@redhat.com> Closes #10883
This commit is contained in:
parent
1b1cf266eb
commit
0d83b51b20
42 changed files with 477 additions and 235 deletions
|
@ -42,7 +42,7 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
|
|||
@Override
|
||||
public PermissionTicket getDelegateForUpdate() {
|
||||
if (updated == null) {
|
||||
ResourceServer resourceServer = cacheSession.getResourceServerStoreDelegate().findById(cached.getResourceServerId());
|
||||
ResourceServer resourceServer = cacheSession.getResourceServerStoreDelegate().findById(null, cached.getResourceServerId());
|
||||
updated = cacheSession.getPermissionTicketStoreDelegate().findById(resourceServer, cached.getId());
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), updated.getResource().getName(), cached.getScopeId(), cached.getResourceServerId());
|
||||
|
@ -70,7 +70,7 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
|
|||
protected boolean isUpdated() {
|
||||
if (updated != null) return true;
|
||||
if (!invalidated) return false;
|
||||
ResourceServer resourceServer = cacheSession.getResourceServerStoreDelegate().findById(cached.getResourceServerId());
|
||||
ResourceServer resourceServer = cacheSession.getResourceServerStoreDelegate().findById(null, cached.getResourceServerId());
|
||||
updated = cacheSession.getPermissionTicketStoreDelegate().findById(resourceServer, cached.getId());
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
return true;
|
||||
|
@ -122,13 +122,13 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
|
||||
return cacheSession.getResourceServerStore().findById(null, cached.getResourceServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy getPolicy() {
|
||||
if (isUpdated()) return updated.getPolicy();
|
||||
return cacheSession.getPolicyStore().findById(cacheSession.getResourceServerStore().findById(cached.getResourceServerId()), cached.getPolicy());
|
||||
return cacheSession.getPolicyStore().findById(cacheSession.getResourceServerStore().findById(null, cached.getResourceServerId()), cached.getPolicy());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -85,7 +85,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
|||
protected boolean isUpdated() {
|
||||
if (updated != null) return true;
|
||||
if (!invalidated) return false;
|
||||
updated = cacheSession.getPolicyStoreDelegate().findById(cacheSession.getResourceServerStore().findById(cached.getResourceServerId()), cached.getId());
|
||||
updated = cacheSession.getPolicyStoreDelegate().findById(cacheSession.getResourceServerStore().findById(null, cached.getResourceServerId()), cached.getId());
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
return true;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
|
||||
return cacheSession.getResourceServerStore().findById(null, cached.getResourceServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -208,7 +208,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
|||
PolicyStore policyStore = cacheSession.getPolicyStore();
|
||||
String resourceServerId = cached.getResourceServerId();
|
||||
for (String id : cached.getAssociatedPoliciesIds(modelSupplier)) {
|
||||
Policy policy = policyStore.findById(cacheSession.getResourceServerStore().findById(resourceServerId), id);
|
||||
Policy policy = policyStore.findById(cacheSession.getResourceServerStore().findById(null, resourceServerId), id);
|
||||
cacheSession.cachePolicy(policy);
|
||||
associatedPolicies.add(policy);
|
||||
}
|
||||
|
@ -325,6 +325,6 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
|
|||
}
|
||||
|
||||
private Policy getPolicyModel() {
|
||||
return cacheSession.getPolicyStoreDelegate().findById(cacheSession.getResourceServerStore().findById(cached.getResourceServerId()), cached.getId());
|
||||
return cacheSession.getPolicyStoreDelegate().findById(cacheSession.getResourceServerStore().findById(null, cached.getResourceServerId()), cached.getId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return cacheSession.getResourceServerStoreDelegate().findById(cached.getResourceServerId());
|
||||
return cacheSession.getResourceServerStoreDelegate().findById(null, cached.getResourceServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.keycloak.models.cache.infinispan.authorization;
|
|||
|
||||
import org.keycloak.authorization.model.CachedModel;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
|
||||
|
@ -40,7 +42,7 @@ public class ResourceServerAdapter implements ResourceServer, CachedModel<Resour
|
|||
public ResourceServer getDelegateForUpdate() {
|
||||
if (updated == null) {
|
||||
cacheSession.registerResourceServerInvalidation(cached.getId());
|
||||
updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
|
||||
updated = cacheSession.getResourceServerStoreDelegate().findById(null, cached.getId());
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
}
|
||||
return updated;
|
||||
|
@ -67,7 +69,7 @@ public class ResourceServerAdapter implements ResourceServer, CachedModel<Resour
|
|||
protected boolean isUpdated() {
|
||||
if (updated != null) return true;
|
||||
if (!invalidated) return false;
|
||||
updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
|
||||
updated = cacheSession.getResourceServerStoreDelegate().findById(null, cached.getId());
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
return true;
|
||||
}
|
||||
|
@ -116,6 +118,16 @@ public class ResourceServerAdapter implements ResourceServer, CachedModel<Resour
|
|||
updated.setDecisionStrategy(decisionStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return getDelegateForUpdate().getRealm();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -118,7 +118,7 @@ public class ScopeAdapter implements Scope, CachedModel<Scope> {
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
|
||||
return cacheSession.getResourceServerStore().findById(null, cached.getResourceServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.keycloak.models.ClientModel;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
|
||||
import org.keycloak.models.cache.infinispan.authorization.entities.CachedPermissionTicket;
|
||||
import org.keycloak.models.cache.infinispan.authorization.entities.CachedPolicy;
|
||||
|
@ -309,7 +310,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
|||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
ResourceServer resourceServer = getResourceServerStore().findById(serverId);
|
||||
ResourceServer resourceServer = getResourceServerStore().findById(null, serverId);
|
||||
return resources.stream().map(resourceId -> {
|
||||
Resource resource = getResourceStore().findById(resourceServer, resourceId);
|
||||
String type = resource.getType();
|
||||
|
@ -450,7 +451,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
|||
public void delete(ClientModel client) {
|
||||
String id = client.getId();
|
||||
if (id == null) return;
|
||||
ResourceServer server = findById(id);
|
||||
ResourceServer server = findById(null, id);
|
||||
if (server == null) return;
|
||||
|
||||
cache.invalidateObject(id);
|
||||
|
@ -461,7 +462,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResourceServer findById(String id) {
|
||||
public ResourceServer findById(RealmModel realm, String id) {
|
||||
if (id == null) return null;
|
||||
CachedResourceServer cached = cache.get(id, CachedResourceServer.class);
|
||||
if (cached != null) {
|
||||
|
@ -471,7 +472,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
|||
if (cached == null) {
|
||||
Long loaded = cache.getCurrentRevision(id);
|
||||
if (! modelMightExist(id)) return null;
|
||||
ResourceServer model = getResourceServerStoreDelegate().findById(id);
|
||||
ResourceServer model = getResourceServerStoreDelegate().findById(realm, id);
|
||||
if (model == null) {
|
||||
setModelDoesNotExists(id, loaded);
|
||||
return null;
|
||||
|
@ -480,7 +481,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
|||
cached = new CachedResourceServer(loaded, model);
|
||||
cache.addRevisioned(cached, startupRevision);
|
||||
} else if (invalidations.contains(id)) {
|
||||
return getResourceServerStoreDelegate().findById(id);
|
||||
return getResourceServerStoreDelegate().findById(realm, id);
|
||||
} else if (managedResourceServers.containsKey(id)) {
|
||||
return managedResourceServers.get(id);
|
||||
}
|
||||
|
@ -491,7 +492,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
|||
|
||||
@Override
|
||||
public ResourceServer findByClient(ClientModel client) {
|
||||
return findById(client.getId());
|
||||
return findById(null, client.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1238,13 +1239,13 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> findGrantedResources(String requester, String name, Integer first, Integer max) {
|
||||
return getPermissionTicketStoreDelegate().findGrantedResources(requester, name, first, max);
|
||||
public List<Resource> findGrantedResources(RealmModel realm, String requester, String name, Integer first, Integer max) {
|
||||
return getPermissionTicketStoreDelegate().findGrantedResources(realm, requester, name, first, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> findGrantedOwnerResources(String owner, Integer firstResult, Integer maxResults) {
|
||||
return getPermissionTicketStoreDelegate().findGrantedOwnerResources(owner, firstResult, maxResults);
|
||||
public List<Resource> findGrantedOwnerResources(RealmModel realm, String owner, Integer firstResult, Integer maxResults) {
|
||||
return getPermissionTicketStoreDelegate().findGrantedOwnerResources(realm, owner, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.keycloak.authorization.model.Scope;
|
|||
import org.keycloak.authorization.store.PermissionTicketStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
|
@ -290,7 +291,7 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> findGrantedResources(String requester, String name, Integer first, Integer max) {
|
||||
public List<Resource> findGrantedResources(RealmModel realm, String requester, String name, Integer first, Integer max) {
|
||||
TypedQuery<String> query = name == null ?
|
||||
entityManager.createNamedQuery("findGrantedResources", String.class) :
|
||||
entityManager.createNamedQuery("findGrantedResourcesByName", String.class);
|
||||
|
@ -318,7 +319,7 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> findGrantedOwnerResources(String owner, Integer firstResult, Integer maxResults) {
|
||||
public List<Resource> findGrantedOwnerResources(RealmModel realm, String owner, Integer firstResult, Integer maxResults) {
|
||||
TypedQuery<String> query = entityManager.createNamedQuery("findGrantedOwnerResources", String.class);
|
||||
|
||||
query.setFlushMode(FlushModeType.COMMIT);
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.keycloak.authorization.jpa.entities.ScopeEntity;
|
|||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.storage.StorageId;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
@ -58,7 +59,7 @@ public class JPAResourceServerStore implements ResourceServerStore {
|
|||
|
||||
this.entityManager.persist(entity);
|
||||
|
||||
return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
|
||||
return new ResourceServerAdapter(client.getRealm(), entity, entityManager, provider.getStoreFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -122,14 +123,14 @@ public class JPAResourceServerStore implements ResourceServerStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResourceServer findById(String id) {
|
||||
public ResourceServer findById(RealmModel realm, String id) {
|
||||
ResourceServerEntity entity = entityManager.find(ResourceServerEntity.class, id);
|
||||
if (entity == null) return null;
|
||||
return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
|
||||
return new ResourceServerAdapter(provider.getRealm(), entity, entityManager, provider.getStoreFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServer findByClient(ClientModel client) {
|
||||
return findById(client.getId());
|
||||
return findById(null, client.getId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import static org.keycloak.authorization.UserManagedPermissionUtil.updatePolicy;
|
|||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.jpa.entities.PermissionTicketEntity;
|
||||
import org.keycloak.authorization.jpa.entities.PolicyEntity;
|
||||
import org.keycloak.authorization.jpa.entities.ScopeEntity;
|
||||
|
@ -91,7 +90,7 @@ public class PermissionTicketAdapter implements PermissionTicket, JpaModel<Permi
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
|
||||
return storeFactory.getResourceServerStore().findById(null, entity.getResourceServer().getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,7 +101,7 @@ public class PermissionTicketAdapter implements PermissionTicket, JpaModel<Permi
|
|||
return null;
|
||||
}
|
||||
|
||||
ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
|
||||
ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(null, entity.getResourceServer().getId());
|
||||
return storeFactory.getPolicyStore().findById(resourceServer, policy.getId());
|
||||
}
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ public class PolicyAdapter extends AbstractAuthorizationModel implements Policy,
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
|
||||
return storeFactory.getResourceServerStore().findById(null, entity.getResourceServer().getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -138,7 +138,7 @@ public class ResourceAdapter extends AbstractAuthorizationModel implements Resou
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServer());
|
||||
return storeFactory.getResourceServerStore().findById(null, entity.getResourceServer());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
|
|||
import org.keycloak.authorization.model.AbstractAuthorizationModel;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.jpa.JpaModel;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
|
||||
|
@ -35,7 +36,7 @@ public class ResourceServerAdapter extends AbstractAuthorizationModel implements
|
|||
private EntityManager em;
|
||||
private StoreFactory storeFactory;
|
||||
|
||||
public ResourceServerAdapter(ResourceServerEntity entity, EntityManager em, StoreFactory storeFactory) {
|
||||
public ResourceServerAdapter(RealmModel realm, ResourceServerEntity entity, EntityManager em, StoreFactory storeFactory) {
|
||||
super(storeFactory);
|
||||
this.entity = entity;
|
||||
this.em = em;
|
||||
|
@ -87,6 +88,16 @@ public class ResourceServerAdapter extends AbstractAuthorizationModel implements
|
|||
entity.setDecisionStrategy(decisionStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -88,7 +88,7 @@ public class ScopeAdapter extends AbstractAuthorizationModel implements Scope, J
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
|
||||
return storeFactory.getResourceServerStore().findById(null, entity.getResourceServer().getId());
|
||||
}
|
||||
|
||||
public static ScopeEntity toEntity(EntityManager em, Scope scope) {
|
||||
|
|
|
@ -18,23 +18,8 @@
|
|||
package org.keycloak.models.map.authorization;
|
||||
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.PermissionTicket;
|
||||
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.PermissionTicketStore;
|
||||
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.map.authorization.entity.MapPermissionTicketEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapPolicyEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceServerEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapScopeEntity;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
|
||||
|
||||
|
@ -43,13 +28,14 @@ import org.keycloak.models.map.storage.MapStorage;
|
|||
*/
|
||||
public class MapAuthorizationStore implements StoreFactory {
|
||||
|
||||
private final PolicyStore policyStore;
|
||||
private final ResourceServerStore resourceServerStore;
|
||||
private final ResourceStore resourceStore;
|
||||
private final ScopeStore scopeStore;
|
||||
private final PermissionTicketStore permissionTicketStore;
|
||||
private final MapPolicyStore policyStore;
|
||||
private final MapResourceServerStore resourceServerStore;
|
||||
private final MapResourceStore resourceStore;
|
||||
private final MapScopeStore scopeStore;
|
||||
private final MapPermissionTicketStore permissionTicketStore;
|
||||
private boolean readOnly;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MapAuthorizationStore(KeycloakSession session, MapStorage permissionTicketStore, MapStorage policyStore, MapStorage resourceServerStore, MapStorage resourceStore, MapStorage scopeStore, AuthorizationProvider provider) {
|
||||
this.permissionTicketStore = new MapPermissionTicketStore(session, permissionTicketStore, provider);
|
||||
this.policyStore = new MapPolicyStore(session, policyStore, provider);
|
||||
|
@ -59,27 +45,27 @@ public class MapAuthorizationStore implements StoreFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResourceStore getResourceStore() {
|
||||
public MapResourceStore getResourceStore() {
|
||||
return resourceStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServerStore getResourceServerStore() {
|
||||
public MapResourceServerStore getResourceServerStore() {
|
||||
return resourceServerStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScopeStore getScopeStore() {
|
||||
public MapScopeStore getScopeStore() {
|
||||
return scopeStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolicyStore getPolicyStore() {
|
||||
public MapPolicyStore getPolicyStore() {
|
||||
return policyStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionTicketStore getPermissionTicketStore() {
|
||||
public MapPermissionTicketStore getPermissionTicketStore() {
|
||||
return permissionTicketStore;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.models.map.authorization;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.PermissionTicket;
|
||||
|
@ -29,56 +30,58 @@ import org.keycloak.authorization.store.StoreFactory;
|
|||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.component.AmphibianProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.map.authorization.entity.MapPermissionTicketEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapPolicyEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceServerEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapScopeEntity;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.common.AbstractMapProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.MapStorageProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageSpi;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.provider.InvalidationHandler;
|
||||
|
||||
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
|
||||
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.RESOURCE_SERVER_BEFORE_REMOVE;
|
||||
import static org.keycloak.models.map.common.AbstractMapProviderFactory.uniqueCounter;
|
||||
import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory;
|
||||
|
||||
/**
|
||||
* @author mhajas
|
||||
*/
|
||||
public class MapAuthorizationStoreFactory implements AmphibianProviderFactory<StoreFactory>, AuthorizationStoreFactory, EnvironmentDependentProviderFactory {
|
||||
public class MapAuthorizationStoreFactory implements AmphibianProviderFactory<StoreFactory>, AuthorizationStoreFactory, EnvironmentDependentProviderFactory, InvalidationHandler {
|
||||
|
||||
public static final String PROVIDER_ID = AbstractMapProviderFactory.PROVIDER_ID;
|
||||
|
||||
private Config.Scope storageConfigScope;
|
||||
private final String uniqueKey = MapAuthorizationStoreFactory.class.getName() + uniqueCounter.incrementAndGet();
|
||||
|
||||
@Override
|
||||
public StoreFactory create(KeycloakSession session) {
|
||||
MapAuthorizationStore authzStore = session.getAttribute(uniqueKey, MapAuthorizationStore.class);
|
||||
|
||||
if (authzStore != null) return authzStore;
|
||||
|
||||
MapStorageProviderFactory storageProviderFactory = (MapStorageProviderFactory) getComponentFactory(session.getKeycloakSessionFactory(),
|
||||
MapStorageProvider.class, storageConfigScope, MapStorageSpi.NAME);
|
||||
final MapStorageProvider mapStorageProvider = storageProviderFactory.create(session);
|
||||
AuthorizationProvider provider = session.getProvider(AuthorizationProvider.class);
|
||||
|
||||
MapStorage permissionTicketStore = mapStorageProvider.getStorage(PermissionTicket.class);
|
||||
MapStorage policyStore = mapStorageProvider.getStorage(Policy.class);
|
||||
MapStorage resourceServerStore = mapStorageProvider.getStorage(ResourceServer.class);
|
||||
MapStorage resourceStore = mapStorageProvider.getStorage(Resource.class);
|
||||
MapStorage scopeStore = mapStorageProvider.getStorage(Scope.class);
|
||||
|
||||
MapStorage permissionTicketStore;
|
||||
MapStorage policyStore;
|
||||
MapStorage resourceServerStore;
|
||||
MapStorage resourceStore;
|
||||
MapStorage scopeStore;
|
||||
authzStore = new MapAuthorizationStore(session,
|
||||
permissionTicketStore,
|
||||
policyStore,
|
||||
resourceServerStore,
|
||||
resourceStore,
|
||||
scopeStore,
|
||||
provider
|
||||
);
|
||||
|
||||
permissionTicketStore = mapStorageProvider.getStorage(PermissionTicket.class);
|
||||
policyStore = mapStorageProvider.getStorage(Policy.class);
|
||||
resourceServerStore = mapStorageProvider.getStorage(ResourceServer.class);
|
||||
resourceStore = mapStorageProvider.getStorage(Resource.class);
|
||||
scopeStore = mapStorageProvider.getStorage(Scope.class);
|
||||
|
||||
return new MapAuthorizationStore(session,
|
||||
permissionTicketStore,
|
||||
policyStore,
|
||||
resourceServerStore,
|
||||
resourceStore,
|
||||
scopeStore,
|
||||
provider
|
||||
);
|
||||
session.setAttribute(uniqueKey, authzStore);
|
||||
return authzStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -86,11 +89,6 @@ public class MapAuthorizationStoreFactory implements AmphibianProviderFactory<St
|
|||
this.storageConfigScope = config.scope("storage");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
|
@ -105,4 +103,26 @@ public class MapAuthorizationStoreFactory implements AmphibianProviderFactory<St
|
|||
public boolean isSupported() {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
|
||||
if (type == REALM_BEFORE_REMOVE) {
|
||||
MapAuthorizationStore authorizationStore = (MapAuthorizationStore) session.getProvider(StoreFactory.class);
|
||||
RealmModel realm = (RealmModel) params[0];
|
||||
|
||||
authorizationStore.getScopeStore().preRemove(realm);
|
||||
authorizationStore.getPolicyStore().preRemove(realm);
|
||||
authorizationStore.getResourceStore().preRemove(realm);
|
||||
authorizationStore.getPermissionTicketStore().preRemove(realm);
|
||||
authorizationStore.getResourceServerStore().preRemove(realm);
|
||||
} else if (type == RESOURCE_SERVER_BEFORE_REMOVE) {
|
||||
MapAuthorizationStore authorizationStore = (MapAuthorizationStore) session.getProvider(StoreFactory.class);
|
||||
ResourceServer resourceServer = (ResourceServer) params[0];
|
||||
|
||||
authorizationStore.getScopeStore().preRemove(resourceServer);
|
||||
authorizationStore.getPolicyStore().preRemove(resourceServer);
|
||||
authorizationStore.getResourceStore().preRemove(resourceServer);
|
||||
authorizationStore.getPermissionTicketStore().preRemove(resourceServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,14 +31,15 @@ import org.keycloak.authorization.store.ResourceStore;
|
|||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.authorization.adapter.MapPermissionTicketAdapter;
|
||||
import org.keycloak.models.map.authorization.entity.MapPermissionTicketEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapPermissionTicketEntityImpl;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
@ -59,17 +60,22 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
private static final Logger LOG = Logger.getLogger(MapPermissionTicketStore.class);
|
||||
private final AuthorizationProvider authorizationProvider;
|
||||
final MapKeycloakTransaction<MapPermissionTicketEntity, PermissionTicket> tx;
|
||||
private final KeycloakSession session;
|
||||
|
||||
public MapPermissionTicketStore(KeycloakSession session, MapStorage<MapPermissionTicketEntity, PermissionTicket> permissionTicketStore, AuthorizationProvider provider) {
|
||||
this.authorizationProvider = provider;
|
||||
this.tx = permissionTicketStore.createTransaction(session);
|
||||
session.getTransactionManager().enlist(tx);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private PermissionTicket entityToAdapter(MapPermissionTicketEntity origEntity) {
|
||||
if (origEntity == null) return null;
|
||||
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
|
||||
return new MapPermissionTicketAdapter(origEntity, authorizationProvider.getStoreFactory());
|
||||
private Function<MapPermissionTicketEntity, PermissionTicket> entityToAdapterFunc(ResourceServer resourceServer) {
|
||||
return origEntity -> new MapPermissionTicketAdapter(resourceServer == null ? findResourceServer(origEntity) : resourceServer, origEntity, authorizationProvider.getStoreFactory());
|
||||
}
|
||||
|
||||
private ResourceServer findResourceServer(MapPermissionTicketEntity entity) {
|
||||
RealmModel realm = session.realms().getRealm(entity.getRealmId());
|
||||
return authorizationProvider.getStoreFactory().getResourceServerStore().findById(realm, entity.getResourceServerId());
|
||||
}
|
||||
|
||||
private DefaultModelCriteria<PermissionTicket> forResourceServer(ResourceServer resourceServer) {
|
||||
|
@ -124,10 +130,11 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
|
||||
entity.setOwner(owner);
|
||||
entity.setResourceServerId(resourceServer.getId());
|
||||
entity.setRealmId(resourceServer.getRealm().getId());
|
||||
|
||||
entity = tx.create(entity);
|
||||
|
||||
return entityToAdapter(entity);
|
||||
return entity == null ? null : entityToAdapterFunc(resourceServer).apply(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -148,7 +155,7 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -157,7 +164,7 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
LOG.tracef("findByResourceServer(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -167,7 +174,7 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.OWNER, Operator.EQ, owner)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -177,7 +184,7 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.RESOURCE_ID, Operator.EQ, resource.getId())))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -187,7 +194,7 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.EQ, scope.getId())))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -216,7 +223,7 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
);
|
||||
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResult, SearchableFields.ID))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -272,10 +279,11 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> findGrantedResources(String requester, String name, Integer first, Integer max) {
|
||||
public List<Resource> findGrantedResources(RealmModel realm, String requester, String name, Integer first, Integer max) {
|
||||
DefaultModelCriteria<PermissionTicket> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.REQUESTER, Operator.EQ, requester)
|
||||
.compare(SearchableFields.GRANTED_TIMESTAMP, Operator.EXISTS);
|
||||
.compare(SearchableFields.GRANTED_TIMESTAMP, Operator.EXISTS)
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
Function<MapPermissionTicketEntity, Resource> ticketResourceMapper;
|
||||
|
||||
|
@ -288,13 +296,13 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
filterOptionMap.put(Resource.FilterOption.ID, new String[] {ticket.getResourceId()});
|
||||
filterOptionMap.put(Resource.FilterOption.NAME, new String[] {name});
|
||||
|
||||
List<Resource> resource = resourceStore.findByResourceServer(resourceServerStore.findById(ticket.getResourceServerId()), filterOptionMap, -1, 1);
|
||||
List<Resource> resource = resourceStore.findByResourceServer(resourceServerStore.findById(realm, ticket.getResourceServerId()), filterOptionMap, -1, 1);
|
||||
|
||||
return resource.isEmpty() ? null : resource.get(0);
|
||||
};
|
||||
} else {
|
||||
ticketResourceMapper = ticket -> resourceStore
|
||||
.findById(resourceServerStore.findById(ticket.getResourceServerId()), ticket.getResourceId());
|
||||
.findById(resourceServerStore.findById(realm, ticket.getResourceServerId()), ticket.getResourceId());
|
||||
}
|
||||
|
||||
return paginatedStream(tx.read(withCriteria(mcb).orderBy(SearchableFields.RESOURCE_ID, ASCENDING))
|
||||
|
@ -305,16 +313,32 @@ public class MapPermissionTicketStore implements PermissionTicketStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> findGrantedOwnerResources(String owner, Integer firstResult, Integer maxResults) {
|
||||
public List<Resource> findGrantedOwnerResources(RealmModel realm, String owner, Integer firstResult, Integer maxResults) {
|
||||
DefaultModelCriteria<PermissionTicket> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.OWNER, Operator.EQ, owner);
|
||||
mcb = mcb.compare(SearchableFields.OWNER, Operator.EQ, owner)
|
||||
.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
ResourceStore resourceStore = authorizationProvider.getStoreFactory().getResourceStore();
|
||||
ResourceServerStore resourceServerStore = authorizationProvider.getStoreFactory().getResourceServerStore();
|
||||
|
||||
return paginatedStream(tx.read(withCriteria(mcb).orderBy(SearchableFields.RESOURCE_ID, ASCENDING))
|
||||
.filter(distinctByKey(MapPermissionTicketEntity::getResourceId)), firstResult, maxResults)
|
||||
.map(ticket -> resourceStore.findById(resourceServerStore.findById(ticket.getResourceServerId()), ticket.getResourceId()))
|
||||
.map(ticket -> resourceStore.findById(resourceServerStore.findById(realm, ticket.getResourceServerId()), ticket.getResourceId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void preRemove(RealmModel realm) {
|
||||
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
|
||||
|
||||
DefaultModelCriteria<PermissionTicket> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
tx.delete(withCriteria(mcb));
|
||||
}
|
||||
|
||||
public void preRemove(ResourceServer resourceServer) {
|
||||
LOG.tracef("preRemove(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
tx.delete(withCriteria(forResourceServer(resourceServer)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.keycloak.authorization.model.Scope;
|
|||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.authorization.adapter.MapPolicyAdapter;
|
||||
import org.keycloak.models.map.authorization.entity.MapPolicyEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapPolicyEntityImpl;
|
||||
|
@ -41,6 +42,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
|
@ -52,17 +54,22 @@ public class MapPolicyStore implements PolicyStore {
|
|||
private static final Logger LOG = Logger.getLogger(MapPolicyStore.class);
|
||||
private final AuthorizationProvider authorizationProvider;
|
||||
final MapKeycloakTransaction<MapPolicyEntity, Policy> tx;
|
||||
private final KeycloakSession session;
|
||||
|
||||
public MapPolicyStore(KeycloakSession session, MapStorage<MapPolicyEntity, Policy> policyStore, AuthorizationProvider provider) {
|
||||
this.authorizationProvider = provider;
|
||||
this.tx = policyStore.createTransaction(session);
|
||||
session.getTransactionManager().enlist(tx);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private Policy entityToAdapter(MapPolicyEntity origEntity) {
|
||||
if (origEntity == null) return null;
|
||||
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
|
||||
return new MapPolicyAdapter(origEntity, authorizationProvider.getStoreFactory());
|
||||
private Function<MapPolicyEntity, Policy> entityToAdapterFunc(ResourceServer resourceServer) {
|
||||
return origEntity -> new MapPolicyAdapter(resourceServer == null ? findResourceServer(origEntity) : resourceServer, origEntity, authorizationProvider.getStoreFactory());
|
||||
}
|
||||
|
||||
private ResourceServer findResourceServer(MapPolicyEntity entity) {
|
||||
RealmModel realm = session.realms().getRealm(entity.getRealmId());
|
||||
return authorizationProvider.getStoreFactory().getResourceServerStore().findById(realm, entity.getResourceServerId());
|
||||
}
|
||||
|
||||
private DefaultModelCriteria<Policy> forResourceServer(ResourceServer resourceServer) {
|
||||
|
@ -92,10 +99,11 @@ public class MapPolicyStore implements PolicyStore {
|
|||
entity.setType(representation.getType());
|
||||
entity.setName(representation.getName());
|
||||
entity.setResourceServerId(resourceServer.getId());
|
||||
|
||||
entity.setRealmId(resourceServer.getRealm().getId());
|
||||
|
||||
entity = tx.create(entity);
|
||||
|
||||
return entityToAdapter(entity);
|
||||
return entity == null ? null : entityToAdapterFunc(resourceServer).apply(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +119,7 @@ public class MapPolicyStore implements PolicyStore {
|
|||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -122,7 +130,7 @@ public class MapPolicyStore implements PolicyStore {
|
|||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -131,7 +139,7 @@ public class MapPolicyStore implements PolicyStore {
|
|||
LOG.tracef("findByResourceServer(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -201,7 +209,7 @@ public class MapPolicyStore implements PolicyStore {
|
|||
|
||||
tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.RESOURCE_ID, Operator.EQ, resource.getId())))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
|
@ -209,7 +217,7 @@ public class MapPolicyStore implements PolicyStore {
|
|||
public void findByResourceType(ResourceServer resourceServer, String type, Consumer<Policy> policyConsumer) {
|
||||
tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.CONFIG, Operator.LIKE, (Object[]) new String[]{"defaultResourceType", type})))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.forEach(policyConsumer);
|
||||
}
|
||||
|
||||
|
@ -217,7 +225,7 @@ public class MapPolicyStore implements PolicyStore {
|
|||
public List<Policy> findByScopes(ResourceServer resourceServer, List<Scope> scopes) {
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopes.stream().map(Scope::getId))))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -235,14 +243,14 @@ public class MapPolicyStore implements PolicyStore {
|
|||
.compare(SearchableFields.CONFIG, Operator.NOT_EXISTS, (Object[]) new String[] {"defaultResourceType"});
|
||||
}
|
||||
|
||||
tx.read(withCriteria(mcb)).map(this::entityToAdapter).forEach(consumer);
|
||||
tx.read(withCriteria(mcb)).map(entityToAdapterFunc(resourceServer)).forEach(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByType(ResourceServer resourceServer, String type) {
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -250,7 +258,22 @@ public class MapPolicyStore implements PolicyStore {
|
|||
public List<Policy> findDependentPolicies(ResourceServer resourceServer, String id) {
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.ASSOCIATED_POLICY_ID, Operator.EQ, id)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void preRemove(RealmModel realm) {
|
||||
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
|
||||
|
||||
DefaultModelCriteria<Policy> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
tx.delete(withCriteria(mcb));
|
||||
}
|
||||
|
||||
public void preRemove(ResourceServer resourceServer) {
|
||||
LOG.tracef("preRemove(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
tx.delete(withCriteria(forResourceServer(resourceServer)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,28 +19,31 @@ package org.keycloak.models.map.authorization;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.PermissionTicket;
|
||||
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.PermissionTicketStore;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.model.ResourceServer.SearchableFields;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.authorization.store.ScopeStore;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.authorization.adapter.MapResourceServerAdapter;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceServerEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceServerEntityImpl;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
import org.keycloak.storage.StorageId;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.RESOURCE_SERVER_AFTER_REMOVE;
|
||||
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.RESOURCE_SERVER_BEFORE_REMOVE;
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
|
||||
|
||||
public class MapResourceServerStore implements ResourceServerStore {
|
||||
|
||||
|
@ -54,10 +57,8 @@ public class MapResourceServerStore implements ResourceServerStore {
|
|||
session.getTransactionManager().enlist(tx);
|
||||
}
|
||||
|
||||
private ResourceServer entityToAdapter(MapResourceServerEntity origEntity) {
|
||||
if (origEntity == null) return null;
|
||||
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
|
||||
return new MapResourceServerAdapter(origEntity, authorizationProvider.getStoreFactory());
|
||||
private Function<MapResourceServerEntity, ResourceServer> entityToAdapterFunc(RealmModel realmModel) {
|
||||
return origEntity -> new MapResourceServerAdapter(realmModel, origEntity, authorizationProvider.getStoreFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,47 +77,29 @@ public class MapResourceServerStore implements ResourceServerStore {
|
|||
}
|
||||
|
||||
MapResourceServerEntity entity = new MapResourceServerEntityImpl();
|
||||
entity.setId(clientId);
|
||||
entity.setClientId(clientId);
|
||||
entity.setRealmId(client.getRealm().getId());
|
||||
|
||||
entity = tx.create(entity);
|
||||
return entityToAdapter(entity);
|
||||
return entity == null ? null : entityToAdapterFunc(client.getRealm()).apply(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(ClientModel client) {
|
||||
LOG.tracef("delete(%s, %s)%s", client.getClientId(), getShortStackTrace());
|
||||
LOG.tracef("delete(%s)%s", client.getClientId(), getShortStackTrace());
|
||||
|
||||
ResourceServer resourceServer = findByClient(client);
|
||||
if (resourceServer == null) return;
|
||||
|
||||
String id = resourceServer.getId();
|
||||
authorizationProvider.getKeycloakSession().invalidate(RESOURCE_SERVER_BEFORE_REMOVE, resourceServer);
|
||||
|
||||
// TODO: Simplify the following, ideally by leveraging triggers, stored procedures or ref integrity
|
||||
PolicyStore policyStore = authorizationProvider.getStoreFactory().getPolicyStore();
|
||||
policyStore.findByResourceServer(resourceServer).stream()
|
||||
.map(Policy::getId)
|
||||
.forEach(policyStore::delete);
|
||||
tx.delete(resourceServer.getId());
|
||||
|
||||
PermissionTicketStore permissionTicketStore = authorizationProvider.getStoreFactory().getPermissionTicketStore();
|
||||
permissionTicketStore.findByResourceServer(resourceServer).stream()
|
||||
.map(PermissionTicket::getId)
|
||||
.forEach(permissionTicketStore::delete);
|
||||
|
||||
ResourceStore resourceStore = authorizationProvider.getStoreFactory().getResourceStore();
|
||||
resourceStore.findByResourceServer(resourceServer).stream()
|
||||
.map(Resource::getId)
|
||||
.forEach(resourceStore::delete);
|
||||
|
||||
ScopeStore scopeStore = authorizationProvider.getStoreFactory().getScopeStore();
|
||||
scopeStore.findByResourceServer(resourceServer).stream()
|
||||
.map(Scope::getId)
|
||||
.forEach(scopeStore::delete);
|
||||
|
||||
tx.delete(id);
|
||||
authorizationProvider.getKeycloakSession().invalidate(RESOURCE_SERVER_AFTER_REMOVE, resourceServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServer findById(String id) {
|
||||
public ResourceServer findById(RealmModel realm, String id) {
|
||||
LOG.tracef("findById(%s)%s", id, getShortStackTrace());
|
||||
|
||||
if (id == null) {
|
||||
|
@ -124,11 +107,29 @@ public class MapResourceServerStore implements ResourceServerStore {
|
|||
}
|
||||
|
||||
MapResourceServerEntity entity = tx.read(id);
|
||||
return entityToAdapter(entity);
|
||||
return (entity == null || !Objects.equals(realm.getId(), entity.getRealmId())) ? null : entityToAdapterFunc(realm).apply(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServer findByClient(ClientModel client) {
|
||||
return findById(client.getId());
|
||||
LOG.tracef("findByClient(%s) in realm(%s)%s", client.getClientId(), client.getRealm().getName(), getShortStackTrace());
|
||||
|
||||
DefaultModelCriteria<ResourceServer> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.CLIENT_ID, Operator.EQ, client.getId());
|
||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, client.getRealm().getId());
|
||||
|
||||
return tx.read(withCriteria(mcb))
|
||||
.map(entityToAdapterFunc(client.getRealm()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public void preRemove(RealmModel realm) {
|
||||
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
|
||||
|
||||
DefaultModelCriteria<ResourceServer> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
tx.delete(withCriteria(mcb));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,20 +26,22 @@ import org.keycloak.authorization.model.Scope;
|
|||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.authorization.adapter.MapResourceAdapter;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceEntityImpl;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
|
@ -51,17 +53,22 @@ public class MapResourceStore implements ResourceStore {
|
|||
private static final Logger LOG = Logger.getLogger(MapResourceStore.class);
|
||||
private final AuthorizationProvider authorizationProvider;
|
||||
final MapKeycloakTransaction<MapResourceEntity, Resource> tx;
|
||||
private final KeycloakSession session;
|
||||
|
||||
public MapResourceStore(KeycloakSession session, MapStorage<MapResourceEntity, Resource> resourceStore, AuthorizationProvider provider) {
|
||||
this.tx = resourceStore.createTransaction(session);
|
||||
session.getTransactionManager().enlist(tx);
|
||||
authorizationProvider = provider;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private Resource entityToAdapter(MapResourceEntity origEntity) {
|
||||
if (origEntity == null) return null;
|
||||
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
|
||||
return new MapResourceAdapter(origEntity, authorizationProvider.getStoreFactory());
|
||||
private Function<MapResourceEntity, Resource> entityToAdapterFunc(final ResourceServer resourceServer) {
|
||||
return origEntity -> new MapResourceAdapter(resourceServer == null ? findResourceServer(origEntity) : resourceServer, origEntity, authorizationProvider.getStoreFactory());
|
||||
}
|
||||
|
||||
private ResourceServer findResourceServer(MapResourceEntity entity) {
|
||||
RealmModel realm = session.realms().getRealm(entity.getRealmId());
|
||||
return authorizationProvider.getStoreFactory().getResourceServerStore().findById(realm, entity.getResourceServerId());
|
||||
}
|
||||
|
||||
private DefaultModelCriteria<Resource> forResourceServer(ResourceServer resourceServer) {
|
||||
|
@ -90,10 +97,11 @@ public class MapResourceStore implements ResourceStore {
|
|||
entity.setName(name);
|
||||
entity.setResourceServerId(resourceServer.getId());
|
||||
entity.setOwner(owner);
|
||||
entity.setRealmId(resourceServer.getRealm().getId());
|
||||
|
||||
entity = tx.create(entity);
|
||||
|
||||
return entityToAdapter(entity);
|
||||
return entity == null ? null : entityToAdapterFunc(resourceServer).apply(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,7 +118,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -124,7 +132,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
|
||||
tx.read(withCriteria(forResourceServer(resourceServer).compare(SearchableFields.OWNER, Operator.EQ, ownerId))
|
||||
.pagination(firstResult, maxResult, SearchableFields.ID)
|
||||
).map(this::entityToAdapter)
|
||||
).map(entityToAdapterFunc(resourceServer))
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
|
@ -143,7 +151,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.URI, Operator.EQ, uri)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -152,7 +160,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
LOG.tracef("findByResourceServer(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -166,7 +174,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
);
|
||||
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.NAME))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -203,7 +211,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
|
||||
tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.SCOPE_ID, Operator.IN, scopes.stream().map(Scope::getId))))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
|
@ -214,7 +222,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
.compare(SearchableFields.OWNER, Operator.EQ, ownerId)
|
||||
.compare(SearchableFields.NAME, Operator.EQ, name)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -223,7 +231,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
LOG.tracef("findByType(%s, %s, %s)%s", type, resourceServer, consumer, getShortStackTrace());
|
||||
tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
|
@ -239,7 +247,7 @@ public class MapResourceStore implements ResourceStore {
|
|||
}
|
||||
|
||||
tx.read(withCriteria(mcb))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
|
@ -249,7 +257,22 @@ public class MapResourceStore implements ResourceStore {
|
|||
tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.OWNER, Operator.NE, resourceServer.getClientId())
|
||||
.compare(SearchableFields.TYPE, Operator.EQ, type)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.forEach(consumer);
|
||||
}
|
||||
|
||||
public void preRemove(RealmModel realm) {
|
||||
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
|
||||
|
||||
DefaultModelCriteria<Resource> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
tx.delete(withCriteria(mcb));
|
||||
}
|
||||
|
||||
public void preRemove(ResourceServer resourceServer) {
|
||||
LOG.tracef("preRemove(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
tx.delete(withCriteria(forResourceServer(resourceServer)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,17 +25,19 @@ import org.keycloak.authorization.model.Scope.SearchableFields;
|
|||
import org.keycloak.authorization.store.ScopeStore;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.authorization.adapter.MapScopeAdapter;
|
||||
import org.keycloak.models.map.authorization.entity.MapScopeEntity;
|
||||
import org.keycloak.models.map.authorization.entity.MapScopeEntityImpl;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
|
@ -47,17 +49,22 @@ public class MapScopeStore implements ScopeStore {
|
|||
private static final Logger LOG = Logger.getLogger(MapScopeStore.class);
|
||||
private final AuthorizationProvider authorizationProvider;
|
||||
final MapKeycloakTransaction<MapScopeEntity, Scope> tx;
|
||||
private final KeycloakSession session;
|
||||
|
||||
public MapScopeStore(KeycloakSession session, MapStorage<MapScopeEntity, Scope> scopeStore, AuthorizationProvider provider) {
|
||||
this.authorizationProvider = provider;
|
||||
this.tx = scopeStore.createTransaction(session);
|
||||
session.getTransactionManager().enlist(tx);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private Scope entityToAdapter(MapScopeEntity origEntity) {
|
||||
if (origEntity == null) return null;
|
||||
// Clone entity before returning back, to avoid giving away a reference to the live object to the caller
|
||||
return new MapScopeAdapter(origEntity, authorizationProvider.getStoreFactory());
|
||||
private Function<MapScopeEntity, Scope> entityToAdapterFunc(ResourceServer resourceServer) {
|
||||
return origEntity -> new MapScopeAdapter(resourceServer == null ? findResourceServer(origEntity) : resourceServer, origEntity, authorizationProvider.getStoreFactory());
|
||||
}
|
||||
|
||||
private ResourceServer findResourceServer(MapScopeEntity entity) {
|
||||
RealmModel realm = session.realms().getRealm(entity.getRealmId());
|
||||
return authorizationProvider.getStoreFactory().getResourceServerStore().findById(realm, entity.getResourceServerId());
|
||||
}
|
||||
|
||||
private DefaultModelCriteria<Scope> forResourceServer(ResourceServer resourceServer) {
|
||||
|
@ -86,10 +93,11 @@ public class MapScopeStore implements ScopeStore {
|
|||
entity.setId(id);
|
||||
entity.setName(name);
|
||||
entity.setResourceServerId(resourceServer.getId());
|
||||
entity.setRealmId(resourceServer.getRealm().getId());
|
||||
|
||||
entity = tx.create(entity);
|
||||
|
||||
return entityToAdapter(entity);
|
||||
return entity == null ? null : entityToAdapterFunc(resourceServer).apply(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,7 +113,7 @@ public class MapScopeStore implements ScopeStore {
|
|||
return tx.read(withCriteria(forResourceServer(resourceServer)
|
||||
.compare(SearchableFields.ID, Operator.EQ, id)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -116,7 +124,7 @@ public class MapScopeStore implements ScopeStore {
|
|||
return tx.read(withCriteria(forResourceServer(resourceServer).compare(SearchableFields.NAME,
|
||||
Operator.EQ, name)))
|
||||
.findFirst()
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -125,7 +133,7 @@ public class MapScopeStore implements ScopeStore {
|
|||
LOG.tracef("findByResourceServer(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
return tx.read(withCriteria(forResourceServer(resourceServer)))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -149,7 +157,22 @@ public class MapScopeStore implements ScopeStore {
|
|||
}
|
||||
|
||||
return tx.read(withCriteria(mcb).pagination(firstResult, maxResults, SearchableFields.NAME))
|
||||
.map(this::entityToAdapter)
|
||||
.map(entityToAdapterFunc(resourceServer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void preRemove(RealmModel realm) {
|
||||
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
|
||||
|
||||
DefaultModelCriteria<Scope> mcb = criteria();
|
||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
|
||||
|
||||
tx.delete(withCriteria(mcb));
|
||||
}
|
||||
|
||||
public void preRemove(ResourceServer resourceServer) {
|
||||
LOG.tracef("preRemove(%s)%s", resourceServer, getShortStackTrace());
|
||||
|
||||
tx.delete(withCriteria(forResourceServer(resourceServer)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.models.map.authorization.adapter;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
|
@ -29,9 +30,13 @@ import org.keycloak.models.map.authorization.entity.MapPermissionTicketEntity;
|
|||
import static org.keycloak.authorization.UserManagedPermissionUtil.updatePolicy;
|
||||
|
||||
public class MapPermissionTicketAdapter extends AbstractPermissionTicketModel<MapPermissionTicketEntity> {
|
||||
|
||||
public MapPermissionTicketAdapter(MapPermissionTicketEntity entity, StoreFactory storeFactory) {
|
||||
|
||||
private final ResourceServer resourceServer;
|
||||
|
||||
public MapPermissionTicketAdapter(ResourceServer resourceServer, MapPermissionTicketEntity entity, StoreFactory storeFactory) {
|
||||
super(entity, storeFactory);
|
||||
Objects.requireNonNull(resourceServer);
|
||||
this.resourceServer = resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,13 +56,13 @@ public class MapPermissionTicketAdapter extends AbstractPermissionTicketModel<Ma
|
|||
|
||||
@Override
|
||||
public Resource getResource() {
|
||||
return storeFactory.getResourceStore().findById(getResourceServer(), entity.getResourceId());
|
||||
return storeFactory.getResourceStore().findById(resourceServer, entity.getResourceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope getScope() {
|
||||
if (entity.getScopeId() == null) return null;
|
||||
return storeFactory.getScopeStore().findById(getResourceServer(), entity.getScopeId());
|
||||
return storeFactory.getScopeStore().findById(resourceServer, entity.getScopeId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,13 +88,12 @@ public class MapPermissionTicketAdapter extends AbstractPermissionTicketModel<Ma
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServerId());
|
||||
return resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy getPolicy() {
|
||||
if (entity.getPolicyId() == null) return null;
|
||||
ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(entity.getResourceServerId());
|
||||
return storeFactory.getPolicyStore().findById(resourceServer, entity.getPolicyId());
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,18 @@ import org.keycloak.representations.idm.authorization.Logic;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MapPolicyAdapter extends AbstractPolicyModel<MapPolicyEntity> {
|
||||
|
||||
public MapPolicyAdapter(MapPolicyEntity entity, StoreFactory storeFactory) {
|
||||
|
||||
private final ResourceServer resourceServer;
|
||||
|
||||
public MapPolicyAdapter(ResourceServer resourceServer, MapPolicyEntity entity, StoreFactory storeFactory) {
|
||||
super(entity, storeFactory);
|
||||
Objects.requireNonNull(resourceServer);
|
||||
this.resourceServer = resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,21 +124,19 @@ public class MapPolicyAdapter extends AbstractPolicyModel<MapPolicyEntity> {
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServerId());
|
||||
return resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Policy> getAssociatedPolicies() {
|
||||
String resourceServerId = entity.getResourceServerId();
|
||||
Set<String> ids = entity.getAssociatedPolicyIds();
|
||||
return ids == null ? Collections.emptySet() : ids.stream()
|
||||
.map(policyId -> storeFactory.getPolicyStore().findById(storeFactory.getResourceServerStore().findById(resourceServerId), policyId))
|
||||
.map(policyId -> storeFactory.getPolicyStore().findById(resourceServer, policyId))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Resource> getResources() {
|
||||
ResourceServer resourceServer = getResourceServer();
|
||||
Set<String> ids = entity.getResourceIds();
|
||||
return ids == null ? Collections.emptySet() : ids.stream()
|
||||
.map(resourceId -> storeFactory.getResourceStore().findById(resourceServer, resourceId))
|
||||
|
@ -142,7 +145,6 @@ public class MapPolicyAdapter extends AbstractPolicyModel<MapPolicyEntity> {
|
|||
|
||||
@Override
|
||||
public Set<Scope> getScopes() {
|
||||
ResourceServer resourceServer = getResourceServer();
|
||||
Set<String> ids = entity.getScopeIds();
|
||||
return ids == null ? Collections.emptySet() : ids.stream()
|
||||
.map(scopeId -> storeFactory.getScopeStore().findById(resourceServer, scopeId))
|
||||
|
|
|
@ -29,13 +29,18 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MapResourceAdapter extends AbstractResourceModel<MapResourceEntity> {
|
||||
|
||||
public MapResourceAdapter(MapResourceEntity entity, StoreFactory storeFactory) {
|
||||
private final ResourceServer resourceServer;
|
||||
|
||||
public MapResourceAdapter(ResourceServer resourceServer, MapResourceEntity entity, StoreFactory storeFactory) {
|
||||
super(entity, storeFactory);
|
||||
Objects.requireNonNull(resourceServer);
|
||||
this.resourceServer = resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +116,7 @@ public class MapResourceAdapter extends AbstractResourceModel<MapResourceEntity>
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServerId());
|
||||
return resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -143,13 +148,13 @@ public class MapResourceAdapter extends AbstractResourceModel<MapResourceEntity>
|
|||
// The scope^ was removed from the Resource
|
||||
|
||||
// Remove permission tickets based on the scope
|
||||
List<PermissionTicket> permissions = permissionStore.findByScope(getResourceServer(), scope);
|
||||
List<PermissionTicket> permissions = permissionStore.findByScope(resourceServer, scope);
|
||||
for (PermissionTicket permission : permissions) {
|
||||
permissionStore.delete(permission.getId());
|
||||
}
|
||||
|
||||
// Remove the scope from each Policy for this Resource
|
||||
policyStore.findByResource(getResourceServer(), this, policy -> policy.removeScope(scope));
|
||||
policyStore.findByResource(resourceServer, this, policy -> policy.removeScope(scope));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,15 +18,21 @@
|
|||
package org.keycloak.models.map.authorization.adapter;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.map.authorization.entity.MapResourceServerEntity;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
|
||||
|
||||
public class MapResourceServerAdapter extends AbstractResourceServerModel<MapResourceServerEntity> {
|
||||
|
||||
public MapResourceServerAdapter(MapResourceServerEntity entity, StoreFactory storeFactory) {
|
||||
private final RealmModel realmModel;
|
||||
|
||||
public MapResourceServerAdapter(RealmModel realmModel, MapResourceServerEntity entity, StoreFactory storeFactory) {
|
||||
super(entity, storeFactory);
|
||||
Objects.requireNonNull(realmModel);
|
||||
this.realmModel = realmModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,6 +76,16 @@ public class MapResourceServerAdapter extends AbstractResourceServerModel<MapRes
|
|||
return ds == null ? DecisionStrategy.UNANIMOUS : ds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return entity.getClientId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return realmModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s@%08x", getId(), System.identityHashCode(this));
|
||||
|
|
|
@ -18,14 +18,19 @@
|
|||
package org.keycloak.models.map.authorization.adapter;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.map.authorization.entity.MapScopeEntity;
|
||||
|
||||
public class MapScopeAdapter extends AbstractScopeModel<MapScopeEntity> {
|
||||
|
||||
public MapScopeAdapter(MapScopeEntity entity, StoreFactory storeFactory) {
|
||||
private final ResourceServer resourceServer;
|
||||
|
||||
public MapScopeAdapter(ResourceServer resourceServer, MapScopeEntity entity, StoreFactory storeFactory) {
|
||||
super(entity, storeFactory);
|
||||
Objects.requireNonNull(resourceServer);
|
||||
this.resourceServer = resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,7 +73,7 @@ public class MapScopeAdapter extends AbstractScopeModel<MapScopeEntity> {
|
|||
|
||||
@Override
|
||||
public ResourceServer getResourceServer() {
|
||||
return storeFactory.getResourceServerStore().findById(entity.getResourceServerId());
|
||||
return resourceServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -45,6 +45,9 @@ public interface MapPermissionTicketEntity extends UpdatableEntity, AbstractEnti
|
|||
}
|
||||
}
|
||||
|
||||
String getRealmId();
|
||||
void setRealmId(String realmId);
|
||||
|
||||
String getOwner();
|
||||
void setOwner(String owner);
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ public interface MapPolicyEntity extends UpdatableEntity, AbstractEntity {
|
|||
}
|
||||
}
|
||||
|
||||
String getRealmId();
|
||||
void setRealmId(String realmId);
|
||||
|
||||
String getName();
|
||||
void setName(String name);
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@ public interface MapResourceEntity extends UpdatableEntity, AbstractEntity, Enti
|
|||
}
|
||||
}
|
||||
|
||||
String getRealmId();
|
||||
void setRealmId(String realmId);
|
||||
|
||||
String getName();
|
||||
void setName(String name);
|
||||
|
||||
|
|
|
@ -47,6 +47,12 @@ public interface MapResourceServerEntity extends UpdatableEntity, AbstractEntity
|
|||
}
|
||||
}
|
||||
|
||||
String getRealmId();
|
||||
void setRealmId(String realmId);
|
||||
|
||||
String getClientId();
|
||||
void setClientId(String clientId);
|
||||
|
||||
Boolean isAllowRemoteResourceManagement();
|
||||
void setAllowRemoteResourceManagement(Boolean allowRemoteResourceManagement);
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ public interface MapScopeEntity extends UpdatableEntity, AbstractEntity {
|
|||
}
|
||||
}
|
||||
|
||||
String getRealmId();
|
||||
void setRealmId(String realmId);
|
||||
|
||||
String getName();
|
||||
void setName(String name);
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ public abstract class AbstractMapProviderFactory<T extends Provider, V extends A
|
|||
GROUP_AFTER_REMOVE,
|
||||
REALM_BEFORE_REMOVE,
|
||||
REALM_AFTER_REMOVE,
|
||||
RESOURCE_SERVER_BEFORE_REMOVE,
|
||||
RESOURCE_SERVER_AFTER_REMOVE,
|
||||
ROLE_BEFORE_REMOVE,
|
||||
ROLE_AFTER_REMOVE,
|
||||
USER_BEFORE_REMOVE,
|
||||
|
|
|
@ -144,6 +144,8 @@ public class MapFieldPredicates {
|
|||
put(AUTHENTICATION_SESSION_PREDICATES, RootAuthenticationSessionModel.SearchableFields.EXPIRATION, MapRootAuthenticationSessionEntity::getExpiration);
|
||||
|
||||
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.ID, predicateForKeyField(MapResourceServerEntity::getId));
|
||||
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.CLIENT_ID, MapResourceServerEntity::getClientId);
|
||||
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.REALM_ID, MapResourceServerEntity::getRealmId);
|
||||
|
||||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.ID, predicateForKeyField(MapResourceEntity::getId));
|
||||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.NAME, MapResourceEntity::getName);
|
||||
|
@ -153,10 +155,12 @@ public class MapFieldPredicates {
|
|||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.URI, MapFieldPredicates::checkResourceUri);
|
||||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.SCOPE_ID, MapFieldPredicates::checkResourceScopes);
|
||||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.OWNER_MANAGED_ACCESS, MapResourceEntity::isOwnerManagedAccess);
|
||||
put(AUTHZ_RESOURCE_PREDICATES, Resource.SearchableFields.REALM_ID, MapResourceEntity::getRealmId);
|
||||
|
||||
put(AUTHZ_SCOPE_PREDICATES, Scope.SearchableFields.ID, predicateForKeyField(MapScopeEntity::getId));
|
||||
put(AUTHZ_SCOPE_PREDICATES, Scope.SearchableFields.RESOURCE_SERVER_ID, MapScopeEntity::getResourceServerId);
|
||||
put(AUTHZ_SCOPE_PREDICATES, Scope.SearchableFields.NAME, MapScopeEntity::getName);
|
||||
put(AUTHZ_SCOPE_PREDICATES, Scope.SearchableFields.REALM_ID, MapScopeEntity::getRealmId);
|
||||
|
||||
put(AUTHZ_PERMISSION_TICKET_PREDICATES, PermissionTicket.SearchableFields.ID, predicateForKeyField(MapPermissionTicketEntity::getId));
|
||||
put(AUTHZ_PERMISSION_TICKET_PREDICATES, PermissionTicket.SearchableFields.OWNER, MapPermissionTicketEntity::getOwner);
|
||||
|
@ -166,12 +170,14 @@ public class MapFieldPredicates {
|
|||
put(AUTHZ_PERMISSION_TICKET_PREDICATES, PermissionTicket.SearchableFields.SCOPE_ID, predicateForKeyField(MapPermissionTicketEntity::getScopeId));
|
||||
put(AUTHZ_PERMISSION_TICKET_PREDICATES, PermissionTicket.SearchableFields.POLICY_ID, predicateForKeyField(MapPermissionTicketEntity::getPolicyId));
|
||||
put(AUTHZ_PERMISSION_TICKET_PREDICATES, PermissionTicket.SearchableFields.GRANTED_TIMESTAMP, MapPermissionTicketEntity::getGrantedTimestamp);
|
||||
put(AUTHZ_PERMISSION_TICKET_PREDICATES, PermissionTicket.SearchableFields.REALM_ID, MapPermissionTicketEntity::getRealmId);
|
||||
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.ID, predicateForKeyField(MapPolicyEntity::getId));
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.NAME, MapPolicyEntity::getName);
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.OWNER, MapPolicyEntity::getOwner);
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.TYPE, MapPolicyEntity::getType);
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.RESOURCE_SERVER_ID, MapPolicyEntity::getResourceServerId);
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.REALM_ID, MapPolicyEntity::getRealmId);
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.RESOURCE_ID, MapFieldPredicates::checkPolicyResources);
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.SCOPE_ID, MapFieldPredicates::checkPolicyScopes);
|
||||
put(AUTHZ_POLICY_PREDICATES, Policy.SearchableFields.CONFIG, MapFieldPredicates::checkPolicyConfig);
|
||||
|
|
|
@ -137,7 +137,6 @@ 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
|
||||
* @return a {@link PolicyProviderFactory} with the given <code>type</code>
|
||||
*/
|
||||
public PolicyProviderFactory getProviderFactory(String type) {
|
||||
|
|
|
@ -32,6 +32,7 @@ public interface PermissionTicket {
|
|||
public static final SearchableModelField<PermissionTicket> SCOPE_ID = new SearchableModelField<>("scopeId", String.class);
|
||||
public static final SearchableModelField<PermissionTicket> POLICY_ID = new SearchableModelField<>("policyId", String.class);
|
||||
public static final SearchableModelField<PermissionTicket> GRANTED_TIMESTAMP = new SearchableModelField<>("grantedTimestamp", String.class);
|
||||
public static final SearchableModelField<PermissionTicket> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
||||
}
|
||||
|
||||
public static enum FilterOption {
|
||||
|
|
|
@ -42,6 +42,7 @@ public interface Policy {
|
|||
public static final SearchableModelField<Policy> OWNER = new SearchableModelField<>("owner", String.class);
|
||||
public static final SearchableModelField<Policy> CONFIG = new SearchableModelField<>("config", String.class);
|
||||
public static final SearchableModelField<Policy> ASSOCIATED_POLICY_ID = new SearchableModelField<>("associatedPolicyId", String.class);
|
||||
public static final SearchableModelField<Policy> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
||||
}
|
||||
|
||||
public static enum FilterOption {
|
||||
|
@ -100,7 +101,7 @@ public interface Policy {
|
|||
/**
|
||||
* Sets the {DecisionStrategy} for this policy.
|
||||
*
|
||||
* @return the decision strategy for this policy
|
||||
* @param decisionStrategy for this policy
|
||||
*/
|
||||
void setDecisionStrategy(DecisionStrategy decisionStrategy);
|
||||
|
||||
|
@ -114,7 +115,7 @@ public interface Policy {
|
|||
/**
|
||||
* Sets the {Logic} for this policy.
|
||||
*
|
||||
* @return the decision strategy for this policy
|
||||
* @param logic for this policy
|
||||
*/
|
||||
void setLogic(Logic logic);
|
||||
|
||||
|
@ -129,7 +130,7 @@ public interface Policy {
|
|||
/**
|
||||
* Sets a {@link Map} with string-based key/value pairs representing any additional configuration for this policy.
|
||||
*
|
||||
* @return a map with any additional configuration for this policy.
|
||||
* @param config a map with any additional configuration for this policy.
|
||||
*/
|
||||
void setConfig(Map<String, String> config);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ public interface Resource {
|
|||
public static final SearchableModelField<Resource> RESOURCE_SERVER_ID = new SearchableModelField<>("resourceServerId", String.class);
|
||||
public static final SearchableModelField<Resource> OWNER = new SearchableModelField<>("owner", String.class);
|
||||
public static final SearchableModelField<Resource> TYPE = new SearchableModelField<>("type", String.class);
|
||||
public static final SearchableModelField<Resource> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
||||
|
||||
public static final SearchableModelField<Resource> URI = new SearchableModelField<>("uris", String.class);
|
||||
public static final SearchableModelField<Resource> SCOPE_ID = new SearchableModelField<>("scope", String.class);
|
||||
|
@ -133,7 +134,7 @@ public interface Resource {
|
|||
/**
|
||||
* Sets a string representing the type of this resource.
|
||||
*
|
||||
* @return the type of this resource or null if not defined
|
||||
* @param type the type of this resource or null if not defined
|
||||
*/
|
||||
void setType(String type);
|
||||
|
||||
|
@ -154,7 +155,7 @@ public interface Resource {
|
|||
/**
|
||||
* Sets an icon {@link java.net.URI} for this resource.
|
||||
*
|
||||
* @return a uri for an icon
|
||||
* @param iconUri an uri for an icon
|
||||
*/
|
||||
void setIconUri(String iconUri);
|
||||
|
||||
|
@ -203,6 +204,7 @@ public interface Resource {
|
|||
/**
|
||||
* Returns the first value of an attribute with the given <code>name</code>
|
||||
*
|
||||
* @param name of the attribute
|
||||
* @return the first value of an attribute
|
||||
*/
|
||||
String getSingleAttribute(String name);
|
||||
|
@ -210,6 +212,7 @@ public interface Resource {
|
|||
/**
|
||||
* Returns the values of an attribute with the given <code>name</code>
|
||||
*
|
||||
* @param name of the attribute
|
||||
* @return the values of an attribute
|
||||
*/
|
||||
List<String> getAttribute(String name);
|
||||
|
@ -218,8 +221,7 @@ public interface Resource {
|
|||
* Sets an attribute with the given <code>name</code> and <code>values</code>.
|
||||
*
|
||||
* @param name the attribute name
|
||||
* @param value the attribute values
|
||||
* @return a map holding the attributes associated with this resource
|
||||
* @param values the attribute values
|
||||
*/
|
||||
void setAttribute(String name, List<String> values);
|
||||
|
||||
|
|
|
@ -18,18 +18,11 @@
|
|||
|
||||
package org.keycloak.authorization.model;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Represents a resource server, whose resources are managed and protected. A resource server is basically an existing
|
||||
|
@ -40,7 +33,10 @@ import java.util.stream.Stream;
|
|||
public interface ResourceServer {
|
||||
|
||||
public static class SearchableFields {
|
||||
public static final SearchableModelField<ResourceServer> ID = new SearchableModelField<>("id", String.class);
|
||||
public static final SearchableModelField<ResourceServer> ID = new SearchableModelField<>("id", String.class);
|
||||
/** ID of the client (not the clientId) associated with resource server*/
|
||||
public static final SearchableModelField<ResourceServer> CLIENT_ID = new SearchableModelField<>("clientId", String.class);
|
||||
public static final SearchableModelField<ResourceServer> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,7 +49,7 @@ public interface ResourceServer {
|
|||
/**
|
||||
* Indicates if the resource server is allowed to manage its own resources remotely using the Protection API.
|
||||
*
|
||||
* {@code true} if the resource server is allowed to managed them remotely
|
||||
* @return {@code true} if the resource server is allowed to managed them remotely
|
||||
*/
|
||||
boolean isAllowRemoteResourceManagement();
|
||||
|
||||
|
@ -95,8 +91,14 @@ public interface ResourceServer {
|
|||
|
||||
/**
|
||||
* Returns id of a client that this {@link ResourceServer} is associated with
|
||||
* @return id of client
|
||||
*/
|
||||
default String getClientId() {
|
||||
return getId();
|
||||
}
|
||||
String getClientId();
|
||||
|
||||
/**
|
||||
* Returns reference of a realm that this {@link ResourceServer} belongs to.
|
||||
*
|
||||
* @return reference of a realm
|
||||
*/
|
||||
RealmModel getRealm();
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ public interface Scope {
|
|||
public static final SearchableModelField<Scope> ID = new SearchableModelField<>("id", String.class);
|
||||
public static final SearchableModelField<Scope> NAME = new SearchableModelField<>("name", String.class);
|
||||
public static final SearchableModelField<Scope> RESOURCE_SERVER_ID = new SearchableModelField<>("resourceServerId", String.class);
|
||||
public static final SearchableModelField<Scope> REALM_ID = new SearchableModelField<>("resourceServerId", String.class);
|
||||
}
|
||||
|
||||
public static enum FilterOption {
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.keycloak.authorization.model.PermissionTicket;
|
|||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.model.Scope;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
/**
|
||||
* A {@link PermissionTicketStore} is responsible to manage the persistence of {@link org.keycloak.authorization.model.PermissionTicket} instances.
|
||||
|
@ -145,21 +146,25 @@ public interface PermissionTicketStore {
|
|||
/**
|
||||
* Returns a list of {@link Resource} granted to the given {@code requester}
|
||||
*
|
||||
*
|
||||
* @param realm
|
||||
* @param requester the requester
|
||||
* @param name the keyword to query resources by name or null if any resource
|
||||
* @param firstResult first result to return. Ignored if negative or {@code null}.
|
||||
* @param maxResults maximum number of results to return. Ignored if negative or {@code null}.
|
||||
* @return a list of {@link Resource} granted to the given {@code requester}
|
||||
*/
|
||||
List<Resource> findGrantedResources(String requester, String name, Integer firstResult, Integer maxResults);
|
||||
List<Resource> findGrantedResources(RealmModel realm, String requester, String name, Integer firstResult, Integer maxResults);
|
||||
|
||||
/**
|
||||
* Returns a list of {@link Resource} granted by the owner to other users
|
||||
*
|
||||
*
|
||||
* @param realm
|
||||
* @param owner the owner
|
||||
* @param firstResult first result to return. Ignored if negative or {@code null}.
|
||||
* @param maxResults maximum number of results to return. Ignored if negative or {@code null}.
|
||||
* @return a list of {@link Resource} granted by the owner
|
||||
*/
|
||||
List<Resource> findGrantedOwnerResources(String owner, Integer firstResult, Integer maxResults);
|
||||
List<Resource> findGrantedOwnerResources(RealmModel realm, String owner, Integer firstResult, Integer maxResults);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.authorization.store;
|
|||
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
/**
|
||||
* A {@link ResourceServerStore} is responsible to manage the persistence of {@link ResourceServer} instances.
|
||||
|
@ -47,11 +48,13 @@ public interface ResourceServerStore {
|
|||
/**
|
||||
* Returns a {@link ResourceServer} instance based on its identifier.
|
||||
*
|
||||
*
|
||||
* @param realm
|
||||
* @param id the identifier of an existing resource server instance
|
||||
*
|
||||
* @return the resource server instance with the given identifier or null if no instance was found
|
||||
*/
|
||||
ResourceServer findById(String id);
|
||||
ResourceServer findById(RealmModel realm, String id);
|
||||
|
||||
/**
|
||||
* Returns a {@link ResourceServer} instance based on a client.
|
||||
|
|
|
@ -90,7 +90,7 @@ public class ResourcesService extends AbstractResourceService {
|
|||
public Response getSharedWithMe(@QueryParam("name") String name,
|
||||
@QueryParam("first") Integer first,
|
||||
@QueryParam("max") Integer max) {
|
||||
return queryResponse((f, m) -> toPermissions(ticketStore.findGrantedResources(auth.getUser().getId(), name, f, m), false)
|
||||
return queryResponse((f, m) -> toPermissions(ticketStore.findGrantedResources(auth.getRealm(), auth.getUser().getId(), name, f, m), false)
|
||||
.stream(), first, max);
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ public class ResourcesService extends AbstractResourceService {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getSharedWithOthers(@QueryParam("first") Integer first, @QueryParam("max") Integer max) {
|
||||
return queryResponse(
|
||||
(f, m) -> toPermissions(ticketStore.findGrantedOwnerResources(auth.getUser().getId(), f, m), true)
|
||||
(f, m) -> toPermissions(ticketStore.findGrantedOwnerResources(auth.getRealm(), auth.getUser().getId(), f, m), true)
|
||||
.stream(), first, max);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,22 +17,31 @@
|
|||
package org.keycloak.testsuite.model;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.aMapWithSize;
|
||||
import static org.hamcrest.Matchers.anEmptyMap;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
@RequireProvider(RealmProvider.class)
|
||||
public class RealmModelTest extends KeycloakModelTest {
|
||||
|
||||
private String realmId;
|
||||
private String realm1Id;
|
||||
private String realm2Id;
|
||||
|
||||
@Override
|
||||
public void createEnvironment(KeycloakSession s) {
|
||||
|
@ -44,6 +53,8 @@ public class RealmModelTest extends KeycloakModelTest {
|
|||
@Override
|
||||
public void cleanEnvironment(KeycloakSession s) {
|
||||
s.realms().removeRealm(realmId);
|
||||
if (realm1Id != null) s.realms().removeRealm(realm1Id);
|
||||
if (realm2Id != null) s.realms().removeRealm(realm2Id);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,6 +104,40 @@ public class RealmModelTest extends KeycloakModelTest {
|
|||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRealmPreRemoveDoesntRemoveEntitiesFromOtherRealms() {
|
||||
realm1Id = inComittedTransaction((Function<KeycloakSession, String>) session -> {
|
||||
RealmModel realm = session.realms().createRealm("realm1");
|
||||
realm.setDefaultRole(session.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
return realm.getId();
|
||||
});
|
||||
realm2Id = inComittedTransaction((Function<KeycloakSession, String>) session -> {
|
||||
RealmModel realm = session.realms().createRealm("realm2");
|
||||
realm.setDefaultRole(session.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||
return realm.getId();
|
||||
});
|
||||
|
||||
// Create client with resource server
|
||||
String clientRealm1 = withRealm(realm1Id, (keycloakSession, realmModel) -> {
|
||||
ClientModel clientRealm = realmModel.addClient("clientRealm1");
|
||||
AuthorizationProvider provider = keycloakSession.getProvider(AuthorizationProvider.class);
|
||||
provider.getStoreFactory().getResourceServerStore().create(clientRealm);
|
||||
|
||||
return clientRealm.getId();
|
||||
});
|
||||
|
||||
// Remove realm 2
|
||||
inComittedTransaction( (Consumer<KeycloakSession>) keycloakSession -> keycloakSession.realms().removeRealm(realm2Id));
|
||||
|
||||
|
||||
// ResourceServer in realm1 must still exist
|
||||
ResourceServer resourceServer = withRealm(realm1Id, (keycloakSession, realmModel) -> {
|
||||
ClientModel client1 = realmModel.getClientById(clientRealm1);
|
||||
return keycloakSession.getProvider(AuthorizationProvider.class).getStoreFactory().getResourceServerStore().findByClient(client1);
|
||||
});
|
||||
|
||||
assertThat(resourceServer, notNullValue());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue