[KEYCLOAK-14646] - Improving permission resolution and evaluation

This commit is contained in:
Pedro Igor 2020-07-02 22:17:43 -03:00 committed by Stian Thorgersen
parent 9204402514
commit 7501e42969
31 changed files with 542 additions and 318 deletions

View file

@ -40,7 +40,7 @@ public abstract class AbstractPermissionProvider implements PolicyProvider {
Policy policy = evaluation.getPolicy();
ResourcePermission permission = evaluation.getPermission();
policy.getAssociatedPolicies().forEach(associatedPolicy -> {
for (Policy associatedPolicy : policy.getAssociatedPolicies()) {
Map<Object, Decision.Effect> decisions = decisionCache.computeIfAbsent(associatedPolicy, p -> new HashMap<>());
Decision.Effect effect = decisions.get(permission);
@ -59,7 +59,7 @@ public abstract class AbstractPermissionProvider implements PolicyProvider {
} else {
defaultEvaluation.setEffect(effect);
}
});
}
}
@Override

View file

@ -133,8 +133,9 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
}
@Override
public ResourceServer getResourceServer() {
return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
public String getResourceServer() {
if (isUpdated()) return updated.getResourceServer();
return cached.getResourceServerId();
}
@Override
@ -203,7 +204,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
for (Scope scope : updated.getScopes()) {
if (!scopes.contains(scope)) {
PermissionTicketStore permissionStore = cacheSession.getPermissionTicketStore();
List<PermissionTicket> permissions = permissionStore.findByScope(scope.getId(), getResourceServer().getId());
List<PermissionTicket> permissions = permissionStore.findByScope(scope.getId(), getResourceServer());
for (PermissionTicket permission : permissions) {
permissionStore.delete(permission.getId());
@ -215,7 +216,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
for (Scope scope : updated.getScopes()) {
if (!scopes.contains(scope)) {
policyStore.findByResource(getId(), getResourceServer().getId(), policy -> policy.removeScope(scope));
policyStore.findByResource(getId(), getResourceServer(), policy -> policy.removeScope(scope));
}
}

View file

@ -601,8 +601,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
if (resource == null) return;
cache.invalidateObject(id);
invalidationEvents.add(ResourceRemovedEvent.create(id, resource.getName(), resource.getType(), resource.getUris(), resource.getOwner(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resource.getResourceServer().getId()));
cache.resourceRemoval(id, resource.getName(), resource.getType(), resource.getUris(), resource.getOwner(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resource.getResourceServer().getId(), invalidations);
invalidationEvents.add(ResourceRemovedEvent.create(id, resource.getName(), resource.getType(), resource.getUris(), resource.getOwner(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resource.getResourceServer()));
cache.resourceRemoval(id, resource.getName(), resource.getType(), resource.getUris(), resource.getOwner(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resource.getResourceServer(), invalidations);
getResourceStoreDelegate().delete(id);
}
@ -672,7 +672,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
@Override
public void findByOwner(String ownerId, String resourceServerId, Consumer<Resource> consumer) {
String cacheKey = getResourceByOwnerCacheKey(ownerId, resourceServerId);
cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByOwner(ownerId, resourceServerId),
cacheQuery(cacheKey, ResourceListQuery.class, () -> {
List<Resource> resources = new ArrayList<>();
getResourceStoreDelegate().findByOwner(ownerId, resourceServerId, new Consumer<Resource>() {
@Override
public void accept(Resource resource) {
resources.add(resource);
consumer.accept(resource);
}
});
return resources;
},
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
@ -718,7 +728,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
for (String id : ids) {
String cacheKey = getResourceByScopeCacheKey(id, resourceServerId);
cacheQuery(cacheKey, ResourceScopeListQuery.class, () -> getResourceStoreDelegate().findByScope(Arrays.asList(id), resourceServerId), (revision, resources) -> new ResourceScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
cacheQuery(cacheKey, ResourceScopeListQuery.class, () -> {
List<Resource> resources = new ArrayList<>();
getResourceStoreDelegate().findByScope(Arrays.asList(id), resourceServerId, new Consumer<Resource>() {
@Override
public void accept(Resource resource) {
resources.add(resource);
consumer.accept(resource);
}
});
return resources;
}, (revision, resources) -> new ResourceScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
}
@ -734,7 +754,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
public void findByType(String type, String resourceServerId, Consumer<Resource> consumer) {
if (type == null) return;
String cacheKey = getResourceByTypeCacheKey(type, resourceServerId);
cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByType(type, resourceServerId),
cacheQuery(cacheKey, ResourceListQuery.class, () -> {
List<Resource> resources = new ArrayList<>();
getResourceStoreDelegate().findByType(type, resourceServerId, new Consumer<Resource>() {
@Override
public void accept(Resource resource) {
resources.add(resource);
consumer.accept(resource);
}
});
return resources;
},
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
@ -754,7 +784,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
public void findByType(String type, String owner, String resourceServerId, Consumer<Resource> consumer) {
if (type == null) return;
String cacheKey = getResourceByTypeCacheKey(type, owner, resourceServerId);
cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByType(type, owner, resourceServerId),
cacheQuery(cacheKey, ResourceListQuery.class, () -> {
List<Resource> resources = new ArrayList<>();
getResourceStoreDelegate().findByType(type, owner, resourceServerId, new Consumer<Resource>() {
@Override
public void accept(Resource resource) {
resources.add(resource);
consumer.accept(resource);
}
});
return resources;
},
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
@ -770,7 +810,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
public void findByTypeInstance(String type, String resourceServerId, Consumer<Resource> consumer) {
if (type == null) return;
String cacheKey = getResourceByTypeInstanceCacheKey(type, resourceServerId);
cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByTypeInstance(type, resourceServerId),
cacheQuery(cacheKey, ResourceListQuery.class, () -> {
List<Resource> resources = new ArrayList<>();
getResourceStoreDelegate().findByTypeInstance(type, resourceServerId, new Consumer<Resource>() {
@Override
public void accept(Resource resource) {
resources.add(resource);
consumer.accept(resource);
}
});
return resources;
},
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
@ -788,20 +838,10 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
List<R> model = resultSupplier.get();
if (model == null) return null;
if (invalidations.contains(cacheKey)) {
if (consumer != null) {
for (R policy: model) {
consumer.accept(policy);
}
}
return model;
};
query = querySupplier.apply(loaded, model);
cache.addRevisioned(query, startupRevision);
if (consumer != null) {
for (R resource : model) {
consumer.andThen(r -> cacheResource(resource)).accept(resource);
}
}
return model;
} else if (query.isInvalid(invalidations)) {
List<R> result = resultSupplier.get();
@ -929,7 +969,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
@Override
public void findByResource(String resourceId, String resourceServerId, Consumer<Policy> consumer) {
String cacheKey = getPolicyByResource(resourceId, resourceServerId);
cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> getPolicyStoreDelegate().findByResource(resourceId, resourceServerId),
cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> {
List<Policy> policies = new ArrayList<>();
getPolicyStoreDelegate().findByResource(resourceId, resourceServerId, new Consumer<Policy>() {
@Override
public void accept(Policy policy) {
policies.add(policy);
consumer.accept(policy);
}
});
return policies;
},
(revision, policies) -> new PolicyResourceListQuery(revision, cacheKey, resourceId, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
@ -943,7 +993,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
@Override
public void findByResourceType(String resourceType, String resourceServerId, Consumer<Policy> consumer) {
String cacheKey = getPolicyByResourceType(resourceType, resourceServerId);
cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId),
cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> {
List<Policy> policies = new ArrayList<>();
getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId, new Consumer<Policy>() {
@Override
public void accept(Policy policy) {
policies.add(policy);
consumer.accept(policy);
}
});
return policies;
},
(revision, policies) -> new PolicyResourceListQuery(revision, cacheKey, resourceType, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
@ -977,7 +1037,15 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
public void findByScopeIds(List<String> scopeIds, String resourceId, String resourceServerId, Consumer<Policy> consumer) {
for (String id : scopeIds) {
String cacheKey = getPolicyByResourceScope(id, resourceId, resourceServerId);
cacheQuery(cacheKey, PolicyScopeListQuery.class, () -> getPolicyStoreDelegate().findByScopeIds(Arrays.asList(id), resourceId, resourceServerId), (revision, resources) -> new PolicyScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
cacheQuery(cacheKey, PolicyScopeListQuery.class, () -> {
List<Policy> policies = new ArrayList<>();
getPolicyStoreDelegate().findByScopeIds(Arrays.asList(id), resourceId, resourceServerId,
policy -> {
policies.add(policy);
consumer.accept(policy);
});
return policies;
}, (revision, resources) -> new PolicyScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId, consumer);
}
}
@ -1010,11 +1078,6 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
};
query = querySupplier.apply(loaded, model);
cache.addRevisioned(query, startupRevision);
if (consumer != null) {
for (R policy: model) {
consumer.andThen(r -> cachePolicy(policy)).accept(policy);
}
}
return model;
} else if (query.isInvalid(invalidations)) {
List<R> policies = resultSupplier.get();

View file

@ -56,7 +56,7 @@ public class CachedResource extends AbstractRevisioned implements InResourceServ
this.type = resource.getType();
this.owner = resource.getOwner();
this.iconUri = resource.getIconUri();
this.resourceServerId = resource.getResourceServer().getId();
this.resourceServerId = resource.getResourceServer();
ownerManagedAccess = resource.isOwnerManagedAccess();
if (resource.isFetched("uris")) {

View file

@ -39,7 +39,7 @@ import javax.persistence.UniqueConstraint;
})
@NamedQueries(
{
@NamedQuery(name="findPermissionIdByResource", query="select p.id from PermissionTicketEntity p inner join p.resource r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
@NamedQuery(name="findPermissionIdByResource", query="select p.id from PermissionTicketEntity p inner join p.resource r where p.resourceServer.id = :serverId and (r.resourceServer = :serverId and r.id = :resourceId)"),
@NamedQuery(name="findPermissionIdByScope", query="select p.id from PermissionTicketEntity p inner join p.scope s where p.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id = :scopeId)"),
@NamedQuery(name="findPermissionTicketIdByServerId", query="select p.id from PermissionTicketEntity p where p.resourceServer.id = :serverId "),
@NamedQuery(name="findGrantedResources", query="select distinct(r.id) from ResourceEntity r inner join PermissionTicketEntity p on r.id = p.resource.id where p.grantedTimestamp is not null and p.requester = :requester order by r.id"),

View file

@ -38,6 +38,9 @@ import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.Nationalized;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
@ -53,10 +56,10 @@ import org.keycloak.representations.idm.authorization.Logic;
{
@NamedQuery(name="findPolicyIdByServerId", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId "),
@NamedQuery(name="findPolicyIdByName", query="select p from PolicyEntity p left join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and p.name = :name"),
@NamedQuery(name="findPolicyIdByResource", query="select p from PolicyEntity p inner join p.resources r inner join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
@NamedQuery(name="findPolicyIdByResource", query="select p from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer = :serverId and r.id = :resourceId)"),
@NamedQuery(name="findPolicyIdByScope", query="select pe from PolicyEntity pe inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id))"),
@NamedQuery(name="findPolicyIdByResourceScope", query="select pe from PolicyEntity pe inner join pe.resources r inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id)) and exists (select p.id from ResourceEntity r inner join r.policies p where r.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and r.id in (:resourceId)))"),
@NamedQuery(name="findPolicyIdByNullResourceScope", query="select pe from PolicyEntity pe left join fetch pe.config c inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and s.id in (:scopeIds))) and pe.resources is empty and not exists (select pec from pe.config pec where KEY(pec) = 'defaultResourceType')"),
@NamedQuery(name="findPolicyIdByResourceScope", query="select pe from PolicyEntity pe inner join pe.resources r inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id)) and exists (select p.id from ResourceEntity r inner join r.policies p where r.resourceServer = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and r.id in (:resourceId)))"),
@NamedQuery(name="findPolicyIdByNullResourceScope", query="select pe from PolicyEntity pe left join fetch pe.config c inner join pe.scopes s inner join pe.associatedPolicies a where pe.resourceServer.id = :serverId and pe.type = 'scope' and pe.resources is empty and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and s.id in (:scopeIds))) and not exists (select pec from pe.config pec where KEY(pec) = 'defaultResourceType')"),
@NamedQuery(name="findPolicyIdByType", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type"),
@NamedQuery(name="findPolicyIdByResourceType", query="select p from PolicyEntity p inner join p.config c inner join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type"),
@NamedQuery(name="findPolicyIdByDependentPolices", query="select p.id from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)"),
@ -98,8 +101,10 @@ public class PolicyEntity {
@JoinColumn(name = "RESOURCE_SERVER_ID")
private ResourceServerEntity resourceServer;
@OneToMany(fetch = FetchType.LAZY, cascade = {})
@OneToMany(fetch = FetchType.EAGER, cascade = {})
@JoinTable(name = "ASSOCIATED_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "ASSOCIATED_POLICY_ID"))
@Fetch(FetchMode.SELECT)
@BatchSize(size = 20)
private Set<PolicyEntity> associatedPolicies;
@OneToMany(fetch = FetchType.LAZY, cascade = {})

View file

@ -57,18 +57,18 @@ import org.hibernate.annotations.FetchMode;
})
@NamedQueries(
{
@NamedQuery(name="findResourceIdByOwner", query="select distinct(r.id) from ResourceEntity r left join r.scopes s where r.resourceServer.id = :serverId and r.owner = :owner"),
@NamedQuery(name="findResourceIdByOwnerOrdered", query="select distinct(r.id) from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner order by r.id"),
@NamedQuery(name="findAnyResourceIdByOwner", query="select distinct(r.id) from ResourceEntity r where r.owner = :owner"),
@NamedQuery(name="findAnyResourceIdByOwnerOrdered", query="select distinct(r.id) from ResourceEntity r where r.owner = :owner order by r.id"),
@NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and :uri in elements(r.uris)"),
@NamedQuery(name="findResourceIdByName", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.owner = :ownerId and r.name = :name"),
@NamedQuery(name="findResourceIdByType", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.owner = :ownerId and r.type = :type"),
@NamedQuery(name="findResourceIdByTypeNoOwner", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.type = :type"),
@NamedQuery(name="findResourceIdByTypeInstance", query="select distinct(r) from ResourceEntity r left join fetch r.scopes s where r.resourceServer.id = :serverId and r.type = :type and r.owner <> :serverId"),
@NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId "),
@NamedQuery(name="findResourceIdByScope", query="select r from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
@NamedQuery(name="deleteResourceByResourceServer", query="delete from ResourceEntity r where r.resourceServer.id = :serverId")
@NamedQuery(name="findResourceIdByOwner", query="select r from ResourceEntity r where r.resourceServer = :serverId and r.owner = :owner"),
@NamedQuery(name="findResourceIdByOwnerOrdered", query="select r from ResourceEntity r where r.resourceServer = :serverId and r.owner = :owner order by r.id"),
@NamedQuery(name="findAnyResourceIdByOwner", query="select r from ResourceEntity r where r.owner = :owner"),
@NamedQuery(name="findAnyResourceIdByOwnerOrdered", query="select r.id from ResourceEntity r where r.owner = :owner order by r.id"),
@NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer = :serverId and :uri in elements(r.uris)"),
@NamedQuery(name="findResourceIdByName", query="select r from ResourceEntity r left join fetch r.scopes s where r.resourceServer = :serverId and r.owner = :ownerId and r.name = :name"),
@NamedQuery(name="findResourceIdByType", query="select r from ResourceEntity r left join fetch r.scopes s where r.resourceServer = :serverId and r.owner = :ownerId and r.type = :type"),
@NamedQuery(name="findResourceIdByTypeNoOwner", query="select r from ResourceEntity r left join fetch r.scopes s where r.resourceServer = :serverId and r.type = :type"),
@NamedQuery(name="findResourceIdByTypeInstance", query="select r from ResourceEntity r left join fetch r.scopes s where r.resourceServer = :serverId and r.type = :type and r.owner <> :serverId"),
@NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where r.resourceServer = :serverId "),
@NamedQuery(name="findResourceIdByScope", query="select r from ResourceEntity r inner join r.scopes s where r.resourceServer = :serverId and (s.resourceServer = :serverId and s.id in (:scopeIds))"),
@NamedQuery(name="deleteResourceByResourceServer", query="delete from ResourceEntity r where r.resourceServer = :serverId")
}
)
public class ResourceEntity {
@ -101,12 +101,13 @@ public class ResourceEntity {
@Column(name = "OWNER_MANAGED_ACCESS")
private boolean ownerManagedAccess;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "RESOURCE_SERVER_ID")
private ResourceServerEntity resourceServer;
@Column(name = "RESOURCE_SERVER_ID")
private String resourceServer;
@OneToMany(fetch = FetchType.LAZY, cascade = {})
@JoinTable(name = "RESOURCE_SCOPE", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
@Fetch(FetchMode.SELECT)
@BatchSize(size = 20)
private List<ScopeEntity> scopes;
@ManyToMany(fetch = FetchType.LAZY, cascade = {})
@ -176,11 +177,11 @@ public class ResourceEntity {
this.iconUri = iconUri;
}
public ResourceServerEntity getResourceServer() {
public String getResourceServer() {
return resourceServer;
}
public void setResourceServer(ResourceServerEntity resourceServer) {
public void setResourceServer(String resourceServer) {
this.resourceServer = resourceServer;
}

View file

@ -213,10 +213,11 @@ public class JPAPolicyStore implements PolicyStore {
query.setParameter("resourceId", resourceId);
query.setParameter("serverId", resourceServerId);
StoreFactory storeFactory = provider.getStoreFactory();
PolicyStore storeFactory = provider.getStoreFactory().getPolicyStore();
query.getResultList().stream()
.map(entity -> new PolicyAdapter(entity, entityManager, storeFactory))
query.getResultStream()
.map(entity -> storeFactory.findById(entity.getId(), resourceServerId))
.filter(Objects::nonNull)
.forEach(consumer::accept);
}
@ -237,8 +238,9 @@ public class JPAPolicyStore implements PolicyStore {
query.setParameter("type", resourceType);
query.setParameter("serverId", resourceServerId);
query.getResultList().stream()
query.getResultStream()
.map(id -> new PolicyAdapter(id, entityManager, provider.getStoreFactory()))
.filter(Objects::nonNull)
.forEach(consumer::accept);
}
@ -256,10 +258,10 @@ public class JPAPolicyStore implements PolicyStore {
query.setParameter("serverId", resourceServerId);
List<Policy> list = new LinkedList<>();
StoreFactory storeFactory = provider.getStoreFactory();
PolicyStore storeFactory = provider.getStoreFactory().getPolicyStore();
for (PolicyEntity entity : query.getResultList()) {
list.add(new PolicyAdapter(entity, entityManager, storeFactory));
list.add(storeFactory.findById(entity.getId(), resourceServerId));
}
return list;
@ -292,8 +294,9 @@ public class JPAPolicyStore implements PolicyStore {
StoreFactory storeFactory = provider.getStoreFactory();
query.getResultList().stream()
query.getResultStream()
.map(id -> new PolicyAdapter(id, entityManager, storeFactory))
.filter(Objects::nonNull)
.forEach(consumer::accept);
}

View file

@ -70,7 +70,7 @@ public class JPAResourceStore implements ResourceStore {
}
entity.setName(name);
entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer).getId());
entity.setOwner(owner);
this.entityManager.persist(entity);
@ -130,7 +130,7 @@ public class JPAResourceStore implements ResourceStore {
queryName = pagination ? "findAnyResourceIdByOwnerOrdered" : "findAnyResourceIdByOwner";
}
TypedQuery<String> query = entityManager.createNamedQuery(queryName, String.class);
TypedQuery<ResourceEntity> query = entityManager.createNamedQuery(queryName, ResourceEntity.class);
query.setFlushMode(FlushModeType.COMMIT);
query.setParameter("owner", ownerId);
@ -145,15 +145,7 @@ public class JPAResourceStore implements ResourceStore {
}
ResourceStore resourceStore = provider.getStoreFactory().getResourceStore();
List<String> result = query.getResultList();
for (String entity : result) {
Resource cached = resourceStore.findById(entity, resourceServerId);
if (cached != null) {
consumer.accept(cached);
}
}
query.getResultStream().map(id -> resourceStore.findById(id.getId(), resourceServerId)).forEach(consumer);
}
@Override
@ -209,7 +201,7 @@ public class JPAResourceStore implements ResourceStore {
List<Predicate> predicates = new ArrayList();
if (resourceServerId != null) {
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
predicates.add(builder.equal(root.get("resourceServer"), resourceServerId));
}
attributes.forEach((name, value) -> {

View file

@ -117,7 +117,7 @@ public class ResourceAdapter extends AbstractAuthorizationModel implements Resou
public List<Scope> getScopes() {
List<Scope> scopes = new LinkedList<>();
for (ScopeEntity scope : entity.getScopes()) {
scopes.add(storeFactory.getScopeStore().findById(scope.getId(), entity.getResourceServer().getId()));
scopes.add(storeFactory.getScopeStore().findById(scope.getId(), entity.getResourceServer()));
}
return Collections.unmodifiableList(scopes);
@ -136,9 +136,8 @@ public class ResourceAdapter extends AbstractAuthorizationModel implements Resou
}
@Override
public ResourceServer getResourceServer() {
ResourceServer temp = storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
return temp;
public String getResourceServer() {
return entity.getResourceServer();
}
@Override

View file

@ -455,14 +455,14 @@ public final class AuthorizationProvider implements Provider {
Resource resource = findById(id, null);
StoreFactory storeFactory = AuthorizationProvider.this.getStoreFactory();
PermissionTicketStore ticketStore = storeFactory.getPermissionTicketStore();
List<PermissionTicket> permissions = ticketStore.findByResource(id, resource.getResourceServer().getId());
List<PermissionTicket> permissions = ticketStore.findByResource(id, resource.getResourceServer());
for (PermissionTicket permission : permissions) {
ticketStore.delete(permission.getId());
}
PolicyStore policyStore = storeFactory.getPolicyStore();
List<Policy> policies = policyStore.findByResource(id, resource.getResourceServer().getId());
List<Policy> policies = policyStore.findByResource(id, resource.getResourceServer());
for (Policy policyModel : policies) {
if (policyModel.getResources().size() == 1) {

View file

@ -121,7 +121,7 @@ public interface Resource {
*
* @return the resource server associated with this resource
*/
ResourceServer getResourceServer();
String getResourceServer();
/**
* Returns the resource's owner, which is usually an identifier that uniquely identifies the resource's owner.

View file

@ -16,15 +16,18 @@
* limitations under the License.
*/
package org.keycloak.authorization.util;
package org.keycloak.authorization.permission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.keycloak.authorization.AuthorizationProvider;
@ -33,7 +36,6 @@ 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.authorization.permission.ResourcePermission;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
@ -58,8 +60,7 @@ public final class Permissions {
* @param authorization
* @return
*/
public static List<ResourcePermission> all(ResourceServer resourceServer, Identity identity, AuthorizationProvider authorization, AuthorizationRequest request) {
List<ResourcePermission> permissions = new ArrayList<>();
public static void all(ResourceServer resourceServer, Identity identity, AuthorizationProvider authorization, AuthorizationRequest request, Consumer<ResourcePermission> evaluator) {
StoreFactory storeFactory = authorization.getStoreFactory();
ResourceStore resourceStore = storeFactory.getResourceStore();
Metadata metadata = request.getMetadata();
@ -74,7 +75,7 @@ public final class Permissions {
// obtain all resources where owner is the resource server
resourceStore.findByOwner(resourceServer.getId(), resourceServer.getId(), resource -> {
if (limit.decrementAndGet() >= 0) {
permissions.add(createResourcePermissions(resource, authorization, request));
evaluator.accept(createResourcePermissions(resource, resourceServer, resource.getScopes(), authorization, request));
}
});
@ -83,7 +84,7 @@ public final class Permissions {
// obtain all resources where owner is the current user
resourceStore.findByOwner(identity.getId(), resourceServer.getId(), resource -> {
if (limit.decrementAndGet() >= 0) {
permissions.add(createResourcePermissions(resource, authorization, request));
evaluator.accept(createResourcePermissions(resource, resourceServer, resource.getScopes(), authorization, request));
}
});
}
@ -95,59 +96,56 @@ public final class Permissions {
Map<String, ResourcePermission> userManagedPermissions = new HashMap<>();
for (PermissionTicket ticket : tickets) {
ResourcePermission permission = userManagedPermissions.get(ticket.getResource().getId());
if (permission == null) {
userManagedPermissions.put(ticket.getResource().getId(), new ResourcePermission(ticket.getResource(), new ArrayList<>(), resourceServer, request.getClaims()));
limit.decrementAndGet();
}
if (limit.decrementAndGet() <= 0) {
if (limit.get() < 0) {
break;
}
ResourcePermission permission = userManagedPermissions.computeIfAbsent(ticket.getResource().getId(),
s -> {
limit.decrementAndGet();
ResourcePermission resourcePermission = new ResourcePermission(ticket.getResource(),
new ArrayList<>(), resourceServer,
request.getClaims());
resourcePermission.setGranted(true);
return resourcePermission;
});
permission.addScope(ticket.getScope());
}
permissions.addAll(userManagedPermissions.values());
for (ResourcePermission permission : userManagedPermissions.values()) {
evaluator.accept(permission);
}
}
}
return permissions;
public static ResourcePermission createResourcePermissions(Resource resource,
ResourceServer resourceServer, Collection<Scope> requestedScopes,
AuthorizationProvider authorization, AuthorizationRequest request) {
Set<Scope> scopes = resolveScopes(resource, resourceServer, requestedScopes, authorization);
return new ResourcePermission(resource, scopes, resourceServer, request.getClaims());
}
public static ResourcePermission createResourcePermissions(Resource resource, Collection<Scope> requestedScopes, AuthorizationProvider authorization, AuthorizationRequest request) {
List<Scope> scopes;
public static Set<Scope> resolveScopes(Resource resource, ResourceServer resourceServer,
Collection<Scope> requestedScopes, AuthorizationProvider authorization) {
if (requestedScopes.isEmpty()) {
scopes = populateTypedScopes(resource, authorization);
} else {
scopes = populateTypedScopes(resource, requestedScopes.stream().filter(scope -> resource.getScopes().contains(scope)).collect(Collectors.toList()), authorization);
return populateTypedScopes(resource, resourceServer, authorization);
}
return populateTypedScopes(resource, resourceServer, resource.getScopes(), authorization).stream()
.filter(scope -> requestedScopes.contains(scope)).collect(Collectors.toSet());
}
return new ResourcePermission(resource, scopes, resource.getResourceServer(), request.getClaims());
private static Set<Scope> populateTypedScopes(Resource resource,
ResourceServer resourceServer, AuthorizationProvider authorization) {
return populateTypedScopes(resource, resourceServer, resource.getScopes(), authorization);
}
public static ResourcePermission createResourcePermissions(Resource resource, AuthorizationProvider authorization, AuthorizationRequest request) {
List<Scope> requestedScopes = resource.getScopes();
if (requestedScopes.isEmpty()) {
return new ResourcePermission(resource, populateTypedScopes(resource, authorization), resource.getResourceServer(), request.getClaims());
}
return new ResourcePermission(resource, resource.getResourceServer(), request.getClaims());
}
private static List<Scope> populateTypedScopes(Resource resource, AuthorizationProvider authorization) {
return populateTypedScopes(resource, resource.getScopes(), authorization);
}
private static List<Scope> populateTypedScopes(Resource resource, List<Scope> defaultScopes, AuthorizationProvider authorization) {
private static Set<Scope> populateTypedScopes(Resource resource, ResourceServer resourceServer, List<Scope> defaultScopes, AuthorizationProvider authorization) {
String type = resource.getType();
ResourceServer resourceServer = resource.getResourceServer();
if (type == null || resource.getOwner().equals(resourceServer.getId())) {
return new ArrayList<>(defaultScopes);
return new LinkedHashSet<>(defaultScopes);
}
List<Scope> scopes = new ArrayList<>(defaultScopes);
Set<Scope> scopes = new LinkedHashSet<>(defaultScopes);
// check if there is a typed resource whose scopes are inherited by the resource being requested. In this case, we assume that parent resource
// is owned by the resource server itself

View file

@ -28,7 +28,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@ -41,19 +40,20 @@ import java.util.Set;
public class ResourcePermission {
private final Resource resource;
private final List<Scope> scopes;
private final Collection<Scope> scopes;
private ResourceServer resourceServer;
private Map<String, Set<String>> claims;
private boolean granted;
public ResourcePermission(Resource resource, List<Scope> scopes, ResourceServer resourceServer) {
public ResourcePermission(Resource resource, Collection<Scope> scopes, ResourceServer resourceServer) {
this(resource, scopes, resourceServer, null);
}
public ResourcePermission(Resource resource, ResourceServer resourceServer, Map<String, ? extends Collection<String>> claims) {
this(resource, new ArrayList<>(resource.getScopes()), resourceServer, claims);
this(resource, new LinkedHashSet<>(), resourceServer, claims);
}
public ResourcePermission(Resource resource, List<Scope> scopes, ResourceServer resourceServer, Map<String, ? extends Collection<String>> claims) {
public ResourcePermission(Resource resource, Collection<Scope> scopes, ResourceServer resourceServer, Map<String, ? extends Collection<String>> claims) {
this.resource = resource;
this.scopes = scopes;
this.resourceServer = resourceServer;
@ -79,7 +79,7 @@ public class ResourcePermission {
*
* @return a lit of permitted scopes
*/
public List<Scope> getScopes() {
public Collection<Scope> getScopes() {
return this.scopes;
}
@ -149,4 +149,12 @@ public class ResourcePermission {
}
this.claims.putAll(claims);
}
public void setGranted(boolean granted) {
this.granted = granted;
}
public boolean isGranted() {
return granted;
}
}

View file

@ -19,8 +19,10 @@
package org.keycloak.authorization.permission.evaluator;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
import java.util.Collection;
@ -40,4 +42,8 @@ public final class Evaluators {
public PermissionEvaluator from(Collection<ResourcePermission> permissions, EvaluationContext evaluationContext) {
return new IterablePermissionEvaluator(permissions.iterator(), evaluationContext, authorizationProvider);
}
public PermissionEvaluator from(EvaluationContext evaluationContext, ResourceServer resourceServer, AuthorizationRequest request) {
return new UnboundedPermissionEvaluator(evaluationContext, authorizationProvider, resourceServer, request);
}
}

View file

@ -60,8 +60,10 @@ class IterablePermissionEvaluator implements PermissionEvaluator {
storeFactory.setReadOnly(true);
while (this.permissions.hasNext()) {
this.policyEvaluator.evaluate(this.permissions.next(), authorizationProvider, executionContext, decision, decisionCache);
Iterator<ResourcePermission> permissions = getPermissions();
while (permissions.hasNext()) {
this.policyEvaluator.evaluate(permissions.next(), authorizationProvider, executionContext, decision, decisionCache);
}
decision.onComplete();
@ -74,6 +76,10 @@ class IterablePermissionEvaluator implements PermissionEvaluator {
return decision;
}
protected Iterator<ResourcePermission> getPermissions() {
return this.permissions;
}
@Override
public Collection<Permission> evaluate(ResourceServer resourceServer, AuthorizationRequest request) {
DecisionPermissionCollector decision = new DecisionPermissionCollector(authorizationProvider, resourceServer, request);

View file

@ -0,0 +1,69 @@
package org.keycloak.authorization.permission.evaluator;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.Decision;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.permission.Permissions;
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.policy.evaluation.DecisionPermissionCollector;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.policy.evaluation.PolicyEvaluator;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
import org.keycloak.representations.idm.authorization.Permission;
public class UnboundedPermissionEvaluator implements PermissionEvaluator {
private final EvaluationContext executionContext;
private final AuthorizationProvider authorizationProvider;
private final PolicyEvaluator policyEvaluator;
private final ResourceServer resourceServer;
private final AuthorizationRequest request;
UnboundedPermissionEvaluator(EvaluationContext executionContext,
AuthorizationProvider authorizationProvider, ResourceServer resourceServer,
AuthorizationRequest request) {
this.executionContext = executionContext;
this.authorizationProvider = authorizationProvider;
this.policyEvaluator = authorizationProvider.getPolicyEvaluator();
this.resourceServer = resourceServer;
this.request = request;
}
@Override
public Decision evaluate(Decision decision) {
StoreFactory storeFactory = authorizationProvider.getStoreFactory();
try {
Map<Policy, Map<Object, Decision.Effect>> decisionCache = new HashMap<>();
storeFactory.setReadOnly(true);
Permissions.all(resourceServer, executionContext.getIdentity(), authorizationProvider, request,
permission -> policyEvaluator.evaluate(permission, authorizationProvider, executionContext, decision, decisionCache));
decision.onComplete();
} catch (Throwable cause) {
decision.onError(cause);
} finally {
storeFactory.setReadOnly(false);
}
return decision;
}
@Override
public Collection<Permission> evaluate(ResourceServer resourceServer, AuthorizationRequest request) {
DecisionPermissionCollector decision = new DecisionPermissionCollector(authorizationProvider, resourceServer, request);
evaluate(decision);
return decision.results();
}
}

View file

@ -56,10 +56,13 @@ public class DecisionPermissionCollector extends AbstractDecisionCollector {
public void onComplete(Result result) {
ResourcePermission permission = result.getPermission();
Resource resource = permission.getResource();
List<Scope> requestedScopes = permission.getScopes();
Collection<Scope> requestedScopes = permission.getScopes();
if (Effect.PERMIT.equals(result.getEffect())) {
grantPermission(authorizationProvider, permissions, permission, resource != null ? resource.getScopes() : requestedScopes, resourceServer, request, result);
if (permission.getScopes().isEmpty() && !resource.getScopes().isEmpty()) {
return;
}
grantPermission(authorizationProvider, permissions, permission, requestedScopes, resourceServer, request, result);
} else {
Set<Scope> grantedScopes = new HashSet<>();
Set<Scope> deniedScopes = new HashSet<>();

View file

@ -18,7 +18,7 @@
package org.keycloak.authorization.policy.evaluation;
import java.util.List;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
@ -52,11 +52,13 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
PolicyEnforcementMode enforcementMode = resourceServer.getPolicyEnforcementMode();
if (PolicyEnforcementMode.DISABLED.equals(enforcementMode)) {
DefaultEvaluation evaluation = new DefaultEvaluation(permission, executionContext, decision, authorizationProvider);
grantAndComplete(permission, authorizationProvider, executionContext, decision);
return;
}
evaluation.grant();
decision.onComplete(permission);
// if marked as granted we just complete the evaluation
if (permission.isGranted()) {
grantAndComplete(permission, authorizationProvider, executionContext, decision);
return;
}
@ -78,7 +80,7 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
}
}
List<Scope> scopes = permission.getScopes();
Collection<Scope> scopes = permission.getScopes();
if (!scopes.isEmpty()) {
policyStore.findByScopeIds(scopes.stream().map(Scope::getId).collect(Collectors.toList()), null, resourceServer.getId(), policyConsumer);
@ -90,12 +92,19 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
}
if (PolicyEnforcementMode.PERMISSIVE.equals(enforcementMode)) {
DefaultEvaluation evaluation = new DefaultEvaluation(permission, executionContext, decision, authorizationProvider);
evaluation.grant();
decision.onComplete(permission);
grantAndComplete(permission, authorizationProvider, executionContext, decision);
}
}
private void grantAndComplete(ResourcePermission permission, AuthorizationProvider authorizationProvider,
EvaluationContext executionContext, Decision decision) {
DefaultEvaluation evaluation = new DefaultEvaluation(permission, executionContext, decision, authorizationProvider);
evaluation.grant();
decision.onComplete(permission);
}
private Consumer<Policy> createPolicyEvaluator(ResourcePermission permission, AuthorizationProvider authorizationProvider, EvaluationContext executionContext, Decision decision, AtomicBoolean verified, Map<Policy, Map<Object, Decision.Effect>> decisionCache) {
return parentPolicy -> {
PolicyProvider policyProvider = authorizationProvider.getProvider(parentPolicy.getType());

View file

@ -116,10 +116,10 @@ public class PermissionTicketAwareDecisionResultCollector extends DecisionPermis
filters.put(PermissionTicket.REQUESTER, identity.getId());
filters.put(PermissionTicket.SCOPE_IS_NULL, Boolean.TRUE.toString());
List<PermissionTicket> tickets = authorization.getStoreFactory().getPermissionTicketStore().find(filters, resource.getResourceServer().getId(), -1, -1);
List<PermissionTicket> tickets = authorization.getStoreFactory().getPermissionTicketStore().find(filters, resource.getResourceServer(), -1, -1);
if (tickets.isEmpty()) {
authorization.getStoreFactory().getPermissionTicketStore().create(resource.getId(), null, identity.getId(), resource.getResourceServer());
authorization.getStoreFactory().getPermissionTicketStore().create(resource.getId(), null, identity.getId(), resourceServer);
}
} else {
ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
@ -137,10 +137,10 @@ public class PermissionTicketAwareDecisionResultCollector extends DecisionPermis
filters.put(PermissionTicket.REQUESTER, identity.getId());
filters.put(PermissionTicket.SCOPE, scope.getId());
List<PermissionTicket> tickets = authorization.getStoreFactory().getPermissionTicketStore().find(filters, resource.getResourceServer().getId(), -1, -1);
List<PermissionTicket> tickets = authorization.getStoreFactory().getPermissionTicketStore().find(filters, resource.getResourceServer(), -1, -1);
if (tickets.isEmpty()) {
authorization.getStoreFactory().getPermissionTicketStore().create(resource.getId(), scope.getId(), identity.getId(), resource.getResourceServer());
authorization.getStoreFactory().getPermissionTicketStore().create(resource.getId(), scope.getId(), identity.getId(), resourceServer);
}
}
}

View file

@ -55,7 +55,14 @@ public class Result {
}
public PolicyResult policy(Policy policy) {
return results.computeIfAbsent(policy.getId(), id -> new PolicyResult(policy));
PolicyResult result = results.get(policy.getId());
if (result == null) {
result = new PolicyResult(policy);
results.put(policy.getId(), result);
}
return result;
}
public void setStatus(final Effect status) {

View file

@ -943,11 +943,11 @@ public class ModelToRepresentation {
return representation;
}
public static ResourceRepresentation toRepresentation(Resource model, ResourceServer resourceServer, AuthorizationProvider authorization) {
public static ResourceRepresentation toRepresentation(Resource model, String resourceServer, AuthorizationProvider authorization) {
return toRepresentation(model, resourceServer, authorization, true);
}
public static ResourceRepresentation toRepresentation(Resource model, ResourceServer resourceServer, AuthorizationProvider authorization, Boolean deep) {
public static ResourceRepresentation toRepresentation(Resource model, String resourceServer, AuthorizationProvider authorization, Boolean deep) {
ResourceRepresentation resource = new ResourceRepresentation();
resource.setId(model.getId());
@ -965,8 +965,8 @@ public class ModelToRepresentation {
KeycloakSession keycloakSession = authorization.getKeycloakSession();
RealmModel realm = authorization.getRealm();
if (owner.getId().equals(resourceServer.getId())) {
ClientModel clientModel = realm.getClientById(resourceServer.getId());
if (owner.getId().equals(resourceServer)) {
ClientModel clientModel = realm.getClientById(resourceServer);
owner.setName(clientModel.getClientId());
} else {
UserModel userModel = keycloakSession.users().getUserById(owner.getId(), realm);

View file

@ -47,13 +47,13 @@ import org.keycloak.authorization.common.KeycloakIdentity;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.permission.Permissions;
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.policy.evaluation.DecisionPermissionCollector;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.policy.evaluation.Result;
import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.authorization.util.Permissions;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionContext;
import org.keycloak.models.KeycloakSession;
@ -125,7 +125,13 @@ public class PolicyEvaluationService {
}
private EvaluationDecisionCollector evaluate(PolicyEvaluationRequest evaluationRequest, EvaluationContext evaluationContext, AuthorizationRequest request) {
return authorization.evaluators().from(createPermissions(evaluationRequest, evaluationContext, authorization, request), evaluationContext).evaluate(new EvaluationDecisionCollector(authorization, resourceServer, request));
List<ResourcePermission> permissions = createPermissions(evaluationRequest, evaluationContext, authorization, request);
if (permissions.isEmpty()) {
return authorization.evaluators().from(evaluationContext, resourceServer, request).evaluate(new EvaluationDecisionCollector(authorization, resourceServer, request));
}
return authorization.evaluators().from(permissions, evaluationContext).evaluate(new EvaluationDecisionCollector(authorization, resourceServer, request));
}
private EvaluationContext createEvaluationContext(PolicyEvaluationRequest representation, KeycloakIdentity identity) {
@ -170,12 +176,14 @@ public class PolicyEvaluationService {
if (resource.getId() != null) {
Resource resourceModel = storeFactory.getResourceStore().findById(resource.getId(), resourceServer.getId());
return new ArrayList<>(Arrays.asList(Permissions.createResourcePermissions(resourceModel, scopes, authorization, request))).stream();
return new ArrayList<>(Arrays.asList(
Permissions.createResourcePermissions(resourceModel, resourceServer, scopes, authorization, request))).stream();
} else if (resource.getType() != null) {
return storeFactory.getResourceStore().findByType(resource.getType(), resourceServer.getId()).stream().map(resource1 -> Permissions.createResourcePermissions(resource1, scopes, authorization, request));
return storeFactory.getResourceStore().findByType(resource.getType(), resourceServer.getId()).stream().map(resource1 -> Permissions.createResourcePermissions(resource1,
resourceServer, scopes, authorization, request));
} else {
if (scopes.isEmpty()) {
return Permissions.all(resourceServer, evaluationContext.getIdentity(), authorization, request).stream();
return Stream.empty();
}
List<Resource> resources = storeFactory.getResourceStore().findByScope(scopes.stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId());
@ -185,7 +193,8 @@ public class PolicyEvaluationService {
}
return resources.stream().map(resource12 -> Permissions.createResourcePermissions(resource12, scopes, authorization, request));
return resources.stream().map(resource12 -> Permissions.createResourcePermissions(resource12, resourceServer,
scopes, authorization, request));
}
}).collect(Collectors.toList());
}

View file

@ -128,7 +128,7 @@ public class ResourceSetService {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Resource with name [" + resource.getName() + "] already exists.", Status.CONFLICT);
}
return toRepresentation(toModel(resource, this.resourceServer, authorization), resourceServer, authorization);
return toRepresentation(toModel(resource, this.resourceServer, authorization), resourceServer.getId(), authorization);
}
@Path("{id}")
@ -166,7 +166,7 @@ public class ResourceSetService {
storeFactory.getResourceStore().delete(id);
audit(toRepresentation(resource, resourceServer, authorization), OperationType.DELETE);
audit(toRepresentation(resource, resourceServer.getId(), authorization), OperationType.DELETE);
return Response.noContent().build();
}
@ -176,7 +176,7 @@ public class ResourceSetService {
@NoCache
@Produces("application/json")
public Response findById(@PathParam("id") String id) {
return findById(id, resource -> toRepresentation(resource, resourceServer, authorization, true));
return findById(id, resource -> toRepresentation(resource, resourceServer.getId(), authorization, true));
}
public Response findById(String id, Function<Resource, ? extends ResourceRepresentation> toRepresentation) {
@ -322,7 +322,7 @@ public class ResourceSetService {
return Response.status(Status.NO_CONTENT).build();
}
return Response.ok(toRepresentation(model, this.resourceServer, authorization)).build();
return Response.ok(toRepresentation(model, this.resourceServer.getId(), authorization)).build();
}
@GET
@ -339,7 +339,7 @@ public class ResourceSetService {
@QueryParam("deep") Boolean deep,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult) {
return find(id, name, uri, owner, type, scope, matchingUri, exactName, deep, firstResult, maxResult, (BiFunction<Resource, Boolean, ResourceRepresentation>) (resource, deep1) -> toRepresentation(resource, resourceServer, authorization, deep1));
return find(id, name, uri, owner, type, scope, matchingUri, exactName, deep, firstResult, maxResult, (BiFunction<Resource, Boolean, ResourceRepresentation>) (resource, deep1) -> toRepresentation(resource, resourceServer.getId(), authorization, deep1));
}
public Response find(@QueryParam("_id") String id,

View file

@ -19,7 +19,6 @@ package org.keycloak.authorization.authorization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@ -48,6 +47,7 @@ import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.model.PermissionTicket;
import org.keycloak.authorization.permission.Permissions;
import org.keycloak.authorization.permission.ResourcePermission;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.policy.evaluation.PermissionTicketAwareDecisionResultCollector;
@ -55,7 +55,6 @@ 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.authorization.util.Permissions;
import org.keycloak.authorization.util.Tokens;
import org.keycloak.common.util.Base64Url;
import org.keycloak.events.Details;
@ -197,9 +196,9 @@ public class AuthorizationTokenService {
Collection<Permission> permissions;
if (request.getTicket() != null) {
permissions = evaluateUserManagedPermissions(request, ticket, resourceServer, evaluationContext, identity);
permissions = evaluateUserManagedPermissions(request, ticket, resourceServer, evaluationContext);
} else if (ticket.getPermissions().isEmpty() && request.getRpt() == null) {
permissions = evaluateAllPermissions(request, resourceServer, evaluationContext, identity);
permissions = evaluateAllPermissions(request, resourceServer, evaluationContext);
} else {
permissions = evaluatePermissions(request, ticket, resourceServer, evaluationContext, identity);
}
@ -257,21 +256,21 @@ public class AuthorizationTokenService {
private Collection<Permission> evaluatePermissions(KeycloakAuthorizationRequest request, PermissionTicketToken ticket, ResourceServer resourceServer, EvaluationContext evaluationContext, KeycloakIdentity identity) {
AuthorizationProvider authorization = request.getAuthorization();
return authorization.evaluators()
.from(createPermissions(ticket, request, resourceServer, identity, authorization), evaluationContext)
.from(createPermissions(ticket, request, resourceServer, authorization, evaluationContext), evaluationContext)
.evaluate(resourceServer, request);
}
private Collection<Permission> evaluateUserManagedPermissions(KeycloakAuthorizationRequest request, PermissionTicketToken ticket, ResourceServer resourceServer, EvaluationContext evaluationContext, KeycloakIdentity identity) {
private Collection<Permission> evaluateUserManagedPermissions(KeycloakAuthorizationRequest request, PermissionTicketToken ticket, ResourceServer resourceServer, EvaluationContext evaluationContext) {
AuthorizationProvider authorization = request.getAuthorization();
return authorization.evaluators()
.from(createPermissions(ticket, request, resourceServer, identity, authorization), evaluationContext)
.evaluate(new PermissionTicketAwareDecisionResultCollector(request, ticket, identity, resourceServer, authorization)).results();
.from(createPermissions(ticket, request, resourceServer, authorization, evaluationContext), evaluationContext)
.evaluate(new PermissionTicketAwareDecisionResultCollector(request, ticket, evaluationContext.getIdentity(), resourceServer, authorization)).results();
}
private Collection<Permission> evaluateAllPermissions(KeycloakAuthorizationRequest request, ResourceServer resourceServer, EvaluationContext evaluationContext, KeycloakIdentity identity) {
private Collection<Permission> evaluateAllPermissions(KeycloakAuthorizationRequest request, ResourceServer resourceServer, EvaluationContext evaluationContext) {
AuthorizationProvider authorization = request.getAuthorization();
return authorization.evaluators()
.from(Permissions.all(resourceServer, identity, authorization, request), evaluationContext)
.from(evaluationContext, resourceServer, request)
.evaluate(resourceServer, request);
}
@ -419,7 +418,8 @@ public class AuthorizationTokenService {
return evaluationContextProvider.apply(request, request.getAuthorization());
}
private Collection<ResourcePermission> createPermissions(PermissionTicketToken ticket, KeycloakAuthorizationRequest request, ResourceServer resourceServer, KeycloakIdentity identity, AuthorizationProvider authorization) {
private Collection<ResourcePermission> createPermissions(PermissionTicketToken ticket, KeycloakAuthorizationRequest request, ResourceServer resourceServer, AuthorizationProvider authorization, EvaluationContext context) {
KeycloakIdentity identity = (KeycloakIdentity) context.getIdentity();
StoreFactory storeFactory = authorization.getStoreFactory();
Map<String, ResourcePermission> permissionsToEvaluate = new LinkedHashMap<>();
ResourceStore resourceStore = storeFactory.getResourceStore();
@ -432,145 +432,32 @@ public class AuthorizationTokenService {
break;
}
Set<String> requestedScopes = permission.getScopes();
if (permission.getScopes() == null) {
requestedScopes = new HashSet<>();
}
List<Resource> requestedResources = new ArrayList<>();
Set<Scope> requestedScopesModel = resolveRequestedScopes(request, resourceServer, scopeStore, permission);
String resourceId = permission.getResourceId();
if (resourceId != null) {
Resource resource = null;
if (resourceId.indexOf('-') != -1) {
resource = resourceStore.findById(resourceId, resourceServer.getId());
}
if (resource != null) {
requestedResources.add(resource);
} else if (resourceId.startsWith("resource-type:")) {
// only resource types, no resource instances. resource types are owned by the resource server
String resourceType = resourceId.substring("resource-type:".length());
resourceStore.findByType(resourceType, resourceServer.getId(), resourceServer.getId(), requestedResources::add);
} else if (resourceId.startsWith("resource-type-any:")) {
// any resource with a given type
String resourceType = resourceId.substring("resource-type-any:".length());
resourceStore.findByType(resourceType, null, resourceServer.getId(), requestedResources::add);
} else if (resourceId.startsWith("resource-type-instance:")) {
// only resource instances with a given type
String resourceType = resourceId.substring("resource-type-instance:".length());
resourceStore.findByTypeInstance(resourceType, resourceServer.getId(), requestedResources::add);
} else if (resourceId.startsWith("resource-type-owner:")) {
// only resources where the current identity is the owner
String resourceType = resourceId.substring("resource-type-owner:".length());
resourceStore.findByType(resourceType, identity.getId(), resourceServer.getId(), requestedResources::add);
resolveResourcePermission(request, resourceServer, identity, authorization, storeFactory, permissionsToEvaluate,
resourceStore,
limit, permission, requestedScopesModel, resourceId);
} else {
String resourceName = resourceId;
Resource ownerResource = resourceStore.findByName(resourceName, identity.getId(), resourceServer.getId());
if (ownerResource != null) {
permission.setResourceId(ownerResource.getId());
requestedResources.add(ownerResource);
}
if (!identity.isResourceServer() || !identity.getId().equals(resourceServer.getId())) {
List<PermissionTicket> tickets = storeFactory.getPermissionTicketStore().findGranted(resourceName, identity.getId(), resourceServer.getId());
for (PermissionTicket permissionTicket : tickets) {
requestedResources.add(permissionTicket.getResource());
}
Resource serverResource = resourceStore.findByName(resourceName, resourceServer.getId());
if (serverResource != null) {
permission.setResourceId(serverResource.getId());
requestedResources.add(serverResource);
}
}
resolveScopePermissions(request, resourceServer, authorization, permissionsToEvaluate, resourceStore, limit,
requestedScopesModel);
}
}
String clientAdditionalScopes = request.getScope();
resolvePreviousGrantedPermissions(ticket, request, resourceServer, permissionsToEvaluate, resourceStore, scopeStore, limit);
if (clientAdditionalScopes != null) {
requestedScopes.addAll(Arrays.asList(clientAdditionalScopes.split(" ")));
}
Set<Scope> requestedScopesModel = requestedScopes.stream().map(s -> scopeStore.findByName(s, resourceServer.getId())).filter(Objects::nonNull).collect(Collectors.toSet());
if (resourceId != null && requestedResources.isEmpty()) {
throw new CorsErrorResponseException(request.getCors(), "invalid_resource", "Resource with id [" + resourceId + "] does not exist.", Status.BAD_REQUEST);
}
if (!requestedScopes.isEmpty() && requestedScopesModel.isEmpty()) {
throw new CorsErrorResponseException(request.getCors(), "invalid_scope", "One of the given scopes " + permission.getScopes() + " is invalid", Status.BAD_REQUEST);
}
if (!requestedResources.isEmpty()) {
for (Resource resource : requestedResources) {
if (limit != null && limit.get() <= 0) {
break;
}
ResourcePermission perm = permissionsToEvaluate.get(resource.getId());
if (perm == null) {
perm = Permissions.createResourcePermissions(resource, requestedScopesModel, authorization, request);
//if scopes were requested, check if the permission to evaluate resolves to any of the requested scopes.
// if it is not the case, then the requested scope is invalid and we don't need to evaluate
if (!requestedScopesModel.isEmpty() && perm.getScopes().isEmpty()) {
continue;
}
permissionsToEvaluate.put(resource.getId(), perm);
if (limit != null) {
limit.decrementAndGet();
}
} else {
for (Scope scope : requestedScopesModel) {
perm.addScope(scope);
}
}
}
} else {
AtomicBoolean processed = new AtomicBoolean();
resourceStore.findByScope(requestedScopesModel.stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId(), resource -> {
if (limit != null && limit.get() <= 0) {
return;
}
ResourcePermission perm = permissionsToEvaluate.get(resource.getId());
if (perm == null) {
perm = Permissions.createResourcePermissions(resource, requestedScopesModel, authorization, request);
permissionsToEvaluate.put(resource.getId(), perm);
if (limit != null) {
limit.decrementAndGet();
}
} else {
for (Scope scope : requestedScopesModel) {
perm.addScope(scope);
}
}
processed.compareAndSet(false, true);
});
if (!processed.get()) {
for (Scope scope : requestedScopesModel) {
if (limit != null && limit.getAndDecrement() <= 0) {
break;
}
permissionsToEvaluate.computeIfAbsent(scope.getId(), s -> new ResourcePermission(null, new ArrayList<>(Arrays.asList(scope)), resourceServer, request.getClaims()));
}
}
}
return permissionsToEvaluate.values();
}
private void resolvePreviousGrantedPermissions(PermissionTicketToken ticket,
KeycloakAuthorizationRequest request, ResourceServer resourceServer,
Map<String, ResourcePermission> permissionsToEvaluate, ResourceStore resourceStore, ScopeStore scopeStore,
AtomicInteger limit) {
AccessToken rpt = request.getRpt();
if (rpt != null && rpt.isActive()) {
AccessToken.Authorization authorizationData = rpt.getAuthorization();
Authorization authorizationData = rpt.getAuthorization();
if (authorizationData != null) {
Collection<Permission> permissions = authorizationData.getPermissions();
@ -618,8 +505,166 @@ public class AuthorizationTokenService {
}
}
}
}
return permissionsToEvaluate.values();
private void resolveScopePermissions(KeycloakAuthorizationRequest request,
ResourceServer resourceServer, AuthorizationProvider authorization,
Map<String, ResourcePermission> permissionsToEvaluate, ResourceStore resourceStore, AtomicInteger limit,
Set<Scope> requestedScopesModel) {
AtomicBoolean processed = new AtomicBoolean();
resourceStore.findByScope(requestedScopesModel.stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId(), resource -> {
if (limit != null && limit.get() <= 0) {
return;
}
ResourcePermission perm = permissionsToEvaluate.get(resource.getId());
if (perm == null) {
perm = Permissions.createResourcePermissions(resource, resourceServer, requestedScopesModel, authorization, request);
permissionsToEvaluate.put(resource.getId(), perm);
if (limit != null) {
limit.decrementAndGet();
}
} else {
for (Scope scope : requestedScopesModel) {
perm.addScope(scope);
}
}
processed.compareAndSet(false, true);
});
if (!processed.get()) {
for (Scope scope : requestedScopesModel) {
if (limit != null && limit.getAndDecrement() <= 0) {
break;
}
permissionsToEvaluate.computeIfAbsent(scope.getId(), s -> new ResourcePermission(null, new ArrayList<>(Arrays.asList(scope)), resourceServer, request.getClaims()));
}
}
}
private void resolveResourcePermission(KeycloakAuthorizationRequest request,
ResourceServer resourceServer, KeycloakIdentity identity, AuthorizationProvider authorization,
StoreFactory storeFactory, Map<String, ResourcePermission> permissionsToEvaluate, ResourceStore resourceStore,
AtomicInteger limit, Permission permission, Set<Scope> requestedScopesModel, String resourceId) {
Resource resource;
if (resourceId.indexOf('-') != -1) {
resource = resourceStore.findById(resourceId, resourceServer.getId());
} else {
resource = null;
}
if (resource != null) {
addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, resource);
} else if (resourceId.startsWith("resource-type:")) {
// only resource types, no resource instances. resource types are owned by the resource server
String resourceType = resourceId.substring("resource-type:".length());
resourceStore.findByType(resourceType, resourceServer.getId(), resourceServer.getId(),
resource1 -> addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, resource1));
} else if (resourceId.startsWith("resource-type-any:")) {
// any resource with a given type
String resourceType = resourceId.substring("resource-type-any:".length());
resourceStore.findByType(resourceType, null, resourceServer.getId(),
resource12 -> addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, resource12));
} else if (resourceId.startsWith("resource-type-instance:")) {
// only resource instances with a given type
String resourceType = resourceId.substring("resource-type-instance:".length());
resourceStore.findByTypeInstance(resourceType, resourceServer.getId(),
resource13 -> addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, resource13));
} else if (resourceId.startsWith("resource-type-owner:")) {
// only resources where the current identity is the owner
String resourceType = resourceId.substring("resource-type-owner:".length());
resourceStore.findByType(resourceType, identity.getId(), resourceServer.getId(),
resource14 -> addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, resource14));
} else {
Resource ownerResource = resourceStore.findByName(resourceId, identity.getId(), resourceServer.getId());
if (ownerResource != null) {
permission.setResourceId(ownerResource.getId());
addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, ownerResource);
}
if (!identity.isResourceServer() || !identity.getId().equals(resourceServer.getId())) {
List<PermissionTicket> tickets = storeFactory.getPermissionTicketStore().findGranted(resourceId, identity.getId(), resourceServer.getId());
if (!tickets.isEmpty()) {
List<Scope> scopes = new ArrayList<>();
Resource grantedResource = null;
for (PermissionTicket permissionTicket : tickets) {
if (grantedResource == null) {
grantedResource = permissionTicket.getResource();
}
scopes.add(permissionTicket.getScope());
}
requestedScopesModel.retainAll(scopes);
ResourcePermission resourcePermission = addPermission(request, resourceServer, authorization,
permissionsToEvaluate, limit,
requestedScopesModel, grantedResource);
// the permission is explicitly granted by the owner, mark this permission as granted so that we don't run the evaluation engine on it
resourcePermission.setGranted(true);
}
Resource serverResource = resourceStore.findByName(resourceId, resourceServer.getId());
if (serverResource != null) {
permission.setResourceId(serverResource.getId());
addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, serverResource);
}
}
}
if (permissionsToEvaluate.isEmpty()) {
throw new CorsErrorResponseException(request.getCors(), "invalid_resource", "Resource with id [" + resourceId + "] does not exist.", Status.BAD_REQUEST);
}
}
private Set<Scope> resolveRequestedScopes(KeycloakAuthorizationRequest request,
ResourceServer resourceServer, ScopeStore scopeStore, Permission permission) {
String clientAdditionalScopes = request.getScope();
Set<String> requestedScopes = permission.getScopes();
if (permission.getScopes() == null) {
requestedScopes = new HashSet<>();
}
if (clientAdditionalScopes != null) {
requestedScopes.addAll(Arrays.asList(clientAdditionalScopes.split(" ")));
}
Set<Scope> requestedScopesModel = requestedScopes.stream().map(s -> scopeStore.findByName(s, resourceServer.getId())).filter(
Objects::nonNull).collect(Collectors.toSet());
if (!requestedScopes.isEmpty() && requestedScopesModel.isEmpty()) {
throw new CorsErrorResponseException(request.getCors(), "invalid_scope", "One of the given scopes " + permission.getScopes() + " is invalid", Status.BAD_REQUEST);
}
return requestedScopesModel;
}
private ResourcePermission addPermission(KeycloakAuthorizationRequest request, ResourceServer resourceServer,
AuthorizationProvider authorization, Map<String, ResourcePermission> permissionsToEvaluate, AtomicInteger limit,
Set<Scope> requestedScopesModel, Resource resource) {
ResourcePermission permission = permissionsToEvaluate.get(resource.getId());
if (permission == null) {
permission = new ResourcePermission(resource,
Permissions.resolveScopes(resource, resourceServer, requestedScopesModel, authorization), resourceServer,
request.getClaims());
//if scopes were requested, check if the permission to evaluate resolves to any of the requested scopes.
// if it is not the case, then the requested scope is invalid and we don't need to evaluate
if (!requestedScopesModel.isEmpty() && permission.getScopes().isEmpty()) {
return null;
}
permissionsToEvaluate.put(resource.getId(), permission);
if (limit != null) {
limit.decrementAndGet();
}
}
return permission;
}
private PermissionTicketToken verifyPermissionTicket(KeycloakAuthorizationRequest request) {

View file

@ -128,7 +128,7 @@ public class AbstractPermissionService {
if (scope == null && resource.getType() != null) {
scope = resourceStore.findByType(resource.getType(), resourceServer.getId()).stream()
.filter(baseResource -> baseResource.getOwner().equals(resource.getResourceServer().getId()))
.filter(baseResource -> baseResource.getOwner().equals(resource.getResourceServer()))
.flatMap(resource1 -> resource1.getScopes().stream())
.filter(baseScope -> baseScope.getName().equals(scopeName)).findFirst().orElse(null);
}

View file

@ -334,7 +334,7 @@ public class ExportUtils {
List<ResourceRepresentation> resources = storeFactory.getResourceStore().findByResourceServer(settingsModel.getId())
.stream().map(resource -> {
ResourceRepresentation rep = toRepresentation(resource, settingsModel, authorization);
ResourceRepresentation rep = toRepresentation(resource, settingsModel.getId(), authorization);
if (rep.getOwner().getId().equals(settingsModel.getId())) {
rep.setOwner((ResourceOwnerRepresentation) null);

View file

@ -234,7 +234,7 @@ public class AuthorizationBean {
public ResourceBean(Resource resource) {
RealmModel realm = authorization.getRealm();
resourceServer = new ResourceServerBean(realm.getClientById(resource.getResourceServer().getId()));
resourceServer = new ResourceServerBean(realm.getClientById(resource.getResourceServer()));
this.resource = resource;
userOwner = authorization.getKeycloakSession().users().getUserById(resource.getOwner(), realm);
if (userOwner == null) {

View file

@ -21,6 +21,7 @@ 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;
@ -822,7 +823,7 @@ public class AccountFormService extends AbstractSecuredLocalService {
filters.put(PermissionTicket.GRANTED, Boolean.FALSE.toString());
}
List<PermissionTicket> tickets = ticketStore.find(filters, resource.getResourceServer().getId(), -1, -1);
List<PermissionTicket> tickets = ticketStore.find(filters, resource.getResourceServer(), -1, -1);
Iterator<PermissionTicket> iterator = tickets.iterator();
while (iterator.hasNext()) {
@ -876,6 +877,7 @@ public class AccountFormService extends AbstractSecuredLocalService {
AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
PermissionTicketStore ticketStore = authorization.getStoreFactory().getPermissionTicketStore();
Resource resource = authorization.getStoreFactory().getResourceStore().findById(resourceId, null);
ResourceServer resourceServer = authorization.getStoreFactory().getResourceServerStore().findById(resource.getResourceServer());
if (resource == null) {
return ErrorResponse.error("Invalid resource", Response.Status.BAD_REQUEST);
@ -908,21 +910,21 @@ public class AccountFormService extends AbstractSecuredLocalService {
filters.put(PermissionTicket.OWNER, auth.getUser().getId());
filters.put(PermissionTicket.REQUESTER, user.getId());
List<PermissionTicket> tickets = ticketStore.find(filters, resource.getResourceServer().getId(), -1, -1);
List<PermissionTicket> tickets = ticketStore.find(filters, resource.getResourceServer(), -1, -1);
if (tickets.isEmpty()) {
if (scopes != null && scopes.length > 0) {
for (String scope : scopes) {
PermissionTicket ticket = ticketStore.create(resourceId, scope, user.getId(), resource.getResourceServer());
PermissionTicket ticket = ticketStore.create(resourceId, scope, user.getId(), resourceServer);
ticket.setGrantedTimestamp(System.currentTimeMillis());
}
} else {
if (resource.getScopes().isEmpty()) {
PermissionTicket ticket = ticketStore.create(resourceId, null, user.getId(), resource.getResourceServer());
PermissionTicket ticket = ticketStore.create(resourceId, null, user.getId(), resourceServer);
ticket.setGrantedTimestamp(System.currentTimeMillis());
} else {
for (Scope scope : resource.getScopes()) {
PermissionTicket ticket = ticketStore.create(resourceId, scope.getId(), user.getId(), resource.getResourceServer());
PermissionTicket ticket = ticketStore.create(resourceId, scope.getId(), user.getId(), resourceServer);
ticket.setGrantedTimestamp(System.currentTimeMillis());
}
}
@ -939,7 +941,7 @@ public class AccountFormService extends AbstractSecuredLocalService {
}
for (String grantScope : grantScopes) {
PermissionTicket ticket = ticketStore.create(resourceId, grantScope, user.getId(), resource.getResourceServer());
PermissionTicket ticket = ticketStore.create(resourceId, grantScope, user.getId(), resourceServer);
ticket.setGrantedTimestamp(System.currentTimeMillis());
}
}
@ -983,7 +985,7 @@ public class AccountFormService extends AbstractSecuredLocalService {
filters.put(PermissionTicket.GRANTED, Boolean.FALSE.toString());
}
for (PermissionTicket ticket : ticketStore.find(filters, resource.getResourceServer().getId(), -1, -1)) {
for (PermissionTicket ticket : ticketStore.find(filters, resource.getResourceServer(), -1, -1)) {
ticketStore.delete(ticket.getId());
}
}

View file

@ -89,8 +89,7 @@ public abstract class AbstractResourceService {
setScopes(resource.getScopes().stream().map(Scope::new).collect(Collectors.toSet()));
ResourceServer resourceServer = resource.getResourceServer();
this.client = new Client(provider.getRealm().getClientById(resourceServer.getId()));
this.client = new Client(provider.getRealm().getClientById(resource.getResourceServer()));
}
Resource(org.keycloak.authorization.model.Resource resource, AuthorizationProvider provider) {

View file

@ -56,7 +56,7 @@ public class ResourceService extends AbstractResourceService {
Auth auth, HttpRequest request) {
super(session, user, auth, request);
this.resource = resource;
this.resourceServer = resource.getResourceServer();
this.resourceServer = provider.getStoreFactory().getResourceServerStore().findById(resource.getResourceServer());
}
/**
@ -122,7 +122,6 @@ public class ResourceService extends AbstractResourceService {
throw new BadRequestException("invalid_permissions");
}
ResourceServer resourceServer = resource.getResourceServer();
Map<String, String> filters = new HashMap<>();
filters.put(PermissionTicket.RESOURCE, resource.getId());
@ -132,7 +131,7 @@ public class ResourceService extends AbstractResourceService {
filters.put(PermissionTicket.REQUESTER, user.getId());
List<PermissionTicket> tickets = ticketStore.find(filters, resource.getResourceServer().getId(), -1, -1);
List<PermissionTicket> tickets = ticketStore.find(filters, resource.getResourceServer(), -1, -1);
// grants all requested permissions
if (tickets.isEmpty()) {