[KEYCLOAK-10020] - Add ability to request user-managed (ticket) permissions by name
This commit is contained in:
parent
e7deb77725
commit
ebcfeb20a3
11 changed files with 155 additions and 18 deletions
|
@ -42,9 +42,9 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
|
||||||
@Override
|
@Override
|
||||||
public PermissionTicket getDelegateForUpdate() {
|
public PermissionTicket getDelegateForUpdate() {
|
||||||
if (updated == null) {
|
if (updated == null) {
|
||||||
cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
|
|
||||||
updated = cacheSession.getPermissionTicketStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
|
updated = cacheSession.getPermissionTicketStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
|
||||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
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());
|
||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
|
||||||
@Override
|
@Override
|
||||||
public void setGrantedTimestamp(Long millis) {
|
public void setGrantedTimestamp(Long millis) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
|
cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), updated.getResource().getName(), cached.getScopeId(), cached.getResourceServerId());
|
||||||
updated.setGrantedTimestamp(millis);
|
updated.setGrantedTimestamp(millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ public class PermissionTicketAdapter implements PermissionTicket, CachedModel<Pe
|
||||||
@Override
|
@Override
|
||||||
public void setPolicy(Policy policy) {
|
public void setPolicy(Policy policy) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), cached.getScopeId(), cached.getResourceServerId());
|
cacheSession.registerPermissionTicketInvalidation(cached.getId(), cached.getOwner(), cached.getRequester(), cached.getResourceId(), updated.getResource().getName(), cached.getScopeId(), cached.getResourceServerId());
|
||||||
updated.setPolicy(policy);
|
updated.setPolicy(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
|
||||||
@Override
|
@Override
|
||||||
public void setDisplayName(String name) {
|
public void setDisplayName(String name) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
cacheSession.registerResourceInvalidation(cached.getId(), name, cached.getType(), cached.getUris(modelSupplier), cached.getScopesIds(modelSupplier), cached.getResourceServerId(), cached.getOwner());
|
cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), cached.getUris(modelSupplier), cached.getScopesIds(modelSupplier), cached.getResourceServerId(), cached.getOwner());
|
||||||
updated.setDisplayName(name);
|
updated.setDisplayName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
|
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
|
||||||
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, null));
|
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, null));
|
||||||
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(id, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(id, serverId));
|
||||||
|
addInvalidations(InResourcePredicate.create().resource(name), invalidations);
|
||||||
|
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
|
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
|
||||||
|
@ -137,11 +138,12 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void permissionTicketUpdated(String id, String owner, String requester, String resource, String scope, String serverId, Set<String> invalidations) {
|
public void permissionTicketUpdated(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId, Set<String> invalidations) {
|
||||||
invalidations.add(id);
|
invalidations.add(id);
|
||||||
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByOwner(owner, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByOwner(owner, serverId));
|
||||||
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(resource, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(resource, serverId));
|
||||||
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByGranted(requester, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByGranted(requester, serverId));
|
||||||
|
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResourceNameAndGranted(resourceName, requester, serverId));
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByScope(scope, serverId));
|
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByScope(scope, serverId));
|
||||||
}
|
}
|
||||||
|
@ -151,8 +153,8 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
|
policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void permissionTicketRemoval(String id, String owner, String requester, String resource, String scope, String serverId, Set<String> invalidations) {
|
public void permissionTicketRemoval(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId, Set<String> invalidations) {
|
||||||
permissionTicketUpdated(id, owner, requester, resource, scope, serverId, invalidations);
|
permissionTicketUpdated(id, owner, requester, resource, resourceName, scope, serverId, invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,12 +295,12 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
invalidationEvents.add(PolicyUpdatedEvent.create(id, name, resources, resourceTypes, scopes, serverId));
|
invalidationEvents.add(PolicyUpdatedEvent.create(id, name, resources, resourceTypes, scopes, serverId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPermissionTicketInvalidation(String id, String owner, String requester, String resource, String scope, String serverId) {
|
public void registerPermissionTicketInvalidation(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) {
|
||||||
cache.permissionTicketUpdated(id, owner, requester, resource, scope, serverId, invalidations);
|
cache.permissionTicketUpdated(id, owner, requester, resource, resourceName, scope, serverId, invalidations);
|
||||||
PermissionTicketAdapter adapter = managedPermissionTickets.get(id);
|
PermissionTicketAdapter adapter = managedPermissionTickets.get(id);
|
||||||
if (adapter != null) adapter.invalidateFlag();
|
if (adapter != null) adapter.invalidateFlag();
|
||||||
|
|
||||||
invalidationEvents.add(PermissionTicketUpdatedEvent.create(id, owner, requester, resource, scope, serverId));
|
invalidationEvents.add(PermissionTicketUpdatedEvent.create(id, owner, requester, resource, resourceName, scope, serverId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> getResourceTypes(Set<String> resources, String serverId) {
|
private Set<String> getResourceTypes(Set<String> resources, String serverId) {
|
||||||
|
@ -400,6 +400,10 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
return "permission.ticket.granted." + userId + "." + serverId;
|
return "permission.ticket.granted." + userId + "." + serverId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPermissionTicketByResourceNameAndGranted(String resourceName, String userId, String serverId) {
|
||||||
|
return "permission.ticket.granted." + resourceName + "." + userId + "." + serverId;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getPermissionTicketByOwner(String owner, String serverId) {
|
public static String getPermissionTicketByOwner(String owner, String serverId) {
|
||||||
return "permission.ticket.owner." + owner + "." + serverId;
|
return "permission.ticket.owner." + owner + "." + serverId;
|
||||||
}
|
}
|
||||||
|
@ -993,7 +997,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
@Override
|
@Override
|
||||||
public PermissionTicket create(String resourceId, String scopeId, String requester, ResourceServer resourceServer) {
|
public PermissionTicket create(String resourceId, String scopeId, String requester, ResourceServer resourceServer) {
|
||||||
PermissionTicket created = getPermissionTicketStoreDelegate().create(resourceId, scopeId, requester, resourceServer);
|
PermissionTicket created = getPermissionTicketStoreDelegate().create(resourceId, scopeId, requester, resourceServer);
|
||||||
registerPermissionTicketInvalidation(created.getId(), created.getOwner(), created.getRequester(), created.getResource().getId(), scopeId, created.getResourceServer().getId());
|
registerPermissionTicketInvalidation(created.getId(), created.getOwner(), created.getRequester(), created.getResource().getId(), created.getResource().getName(), scopeId, created.getResourceServer().getId());
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,8 +1012,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
if (permission.getScope() != null) {
|
if (permission.getScope() != null) {
|
||||||
scopeId = permission.getScope().getId();
|
scopeId = permission.getScope().getId();
|
||||||
}
|
}
|
||||||
invalidationEvents.add(PermissionTicketRemovedEvent.create(id, permission.getOwner(), permission.getRequester(), permission.getResource().getId(), scopeId, permission.getResourceServer().getId()));
|
invalidationEvents.add(PermissionTicketRemovedEvent.create(id, permission.getOwner(), permission.getRequester(), permission.getResource().getId(), permission.getResource().getName(), scopeId, permission.getResourceServer().getId()));
|
||||||
cache.permissionTicketRemoval(id, permission.getOwner(), permission.getRequester(), permission.getResource().getId(), scopeId, permission.getResourceServer().getId(), invalidations);
|
cache.permissionTicketRemoval(id, permission.getOwner(), permission.getRequester(), permission.getResource().getId(), permission.getResource().getName(),scopeId, permission.getResourceServer().getId(), invalidations);
|
||||||
getPermissionTicketStoreDelegate().delete(id);
|
getPermissionTicketStoreDelegate().delete(id);
|
||||||
UserManagedPermissionUtil.removePolicy(permission, StoreFactoryCacheSession.this);
|
UserManagedPermissionUtil.removePolicy(permission, StoreFactoryCacheSession.this);
|
||||||
|
|
||||||
|
@ -1075,6 +1079,13 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
(revision, permissions) -> new PermissionTicketListQuery(revision, cacheKey, permissions.stream().map(permission -> permission.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
(revision, permissions) -> new PermissionTicketListQuery(revision, cacheKey, permissions.stream().map(permission -> permission.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PermissionTicket> findGranted(String resourceName, String userId, String resourceServerId) {
|
||||||
|
String cacheKey = getPermissionTicketByResourceNameAndGranted(resourceName, userId, resourceServerId);
|
||||||
|
return cacheQuery(cacheKey, PermissionTicketListQuery.class, () -> getPermissionTicketStoreDelegate().findGranted(resourceName, userId, resourceServerId),
|
||||||
|
(revision, permissions) -> new PermissionTicketResourceListQuery(revision, cacheKey, resourceName, permissions.stream().map(permission -> permission.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PermissionTicket> findByOwner(String owner, String resourceServerId) {
|
public List<PermissionTicket> findByOwner(String owner, String resourceServerId) {
|
||||||
String cacheKey = getPermissionTicketByOwner(owner, resourceServerId);
|
String cacheKey = getPermissionTicketByOwner(owner, resourceServerId);
|
||||||
|
|
|
@ -33,13 +33,15 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
|
||||||
private String scope;
|
private String scope;
|
||||||
private String serverId;
|
private String serverId;
|
||||||
private String requester;
|
private String requester;
|
||||||
|
private String resourceName;
|
||||||
|
|
||||||
public static PermissionTicketRemovedEvent create(String id, String owner, String requester, String resource, String scope, String serverId) {
|
public static PermissionTicketRemovedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) {
|
||||||
PermissionTicketRemovedEvent event = new PermissionTicketRemovedEvent();
|
PermissionTicketRemovedEvent event = new PermissionTicketRemovedEvent();
|
||||||
event.id = id;
|
event.id = id;
|
||||||
event.owner = owner;
|
event.owner = owner;
|
||||||
event.requester = requester;
|
event.requester = requester;
|
||||||
event.resource = resource;
|
event.resource = resource;
|
||||||
|
event.resourceName = resourceName;
|
||||||
event.scope = scope;
|
event.scope = scope;
|
||||||
event.serverId = serverId;
|
event.serverId = serverId;
|
||||||
return event;
|
return event;
|
||||||
|
@ -57,6 +59,6 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
||||||
cache.permissionTicketRemoval(id, owner, requester, resource, scope, serverId, invalidations);
|
cache.permissionTicketRemoval(id, owner, requester, resource, resourceName, scope, serverId, invalidations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,15 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
|
||||||
private String scope;
|
private String scope;
|
||||||
private String serverId;
|
private String serverId;
|
||||||
private String requester;
|
private String requester;
|
||||||
|
private String resourceName;
|
||||||
|
|
||||||
public static PermissionTicketUpdatedEvent create(String id, String owner, String requester, String resource, String scope, String serverId) {
|
public static PermissionTicketUpdatedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) {
|
||||||
PermissionTicketUpdatedEvent event = new PermissionTicketUpdatedEvent();
|
PermissionTicketUpdatedEvent event = new PermissionTicketUpdatedEvent();
|
||||||
event.id = id;
|
event.id = id;
|
||||||
event.owner = owner;
|
event.owner = owner;
|
||||||
event.requester = requester;
|
event.requester = requester;
|
||||||
event.resource = resource;
|
event.resource = resource;
|
||||||
|
event.resourceName = resourceName;
|
||||||
event.scope = scope;
|
event.scope = scope;
|
||||||
event.serverId = serverId;
|
event.serverId = serverId;
|
||||||
return event;
|
return event;
|
||||||
|
@ -57,6 +59,6 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
|
||||||
cache.permissionTicketUpdated(id, owner, requester, resource, scope, serverId, invalidations);
|
cache.permissionTicketUpdated(id, owner, requester, resource, resourceName, scope, serverId, invalidations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,8 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
|
||||||
}
|
}
|
||||||
} else if (PermissionTicket.RESOURCE.equals(name)) {
|
} else if (PermissionTicket.RESOURCE.equals(name)) {
|
||||||
predicates.add(root.join("resource").get("id").in(value));
|
predicates.add(root.join("resource").get("id").in(value));
|
||||||
|
} else if (PermissionTicket.RESOURCE_NAME.equals(name)) {
|
||||||
|
predicates.add(root.join("resource").get("name").in(value));
|
||||||
} else if (PermissionTicket.OWNER.equals(name)) {
|
} else if (PermissionTicket.OWNER.equals(name)) {
|
||||||
predicates.add(builder.equal(root.get("owner"), value));
|
predicates.add(builder.equal(root.get("owner"), value));
|
||||||
} else if (PermissionTicket.REQUESTER.equals(name)) {
|
} else if (PermissionTicket.REQUESTER.equals(name)) {
|
||||||
|
@ -249,6 +251,17 @@ public class JPAPermissionTicketStore implements PermissionTicketStore {
|
||||||
return find(filters, resourceServerId, -1, -1);
|
return find(filters, resourceServerId, -1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PermissionTicket> findGranted(String resourceName, String userId, String resourceServerId) {
|
||||||
|
HashMap<String, String> filters = new HashMap<>();
|
||||||
|
|
||||||
|
filters.put(PermissionTicket.RESOURCE_NAME, resourceName);
|
||||||
|
filters.put(PermissionTicket.GRANTED, Boolean.TRUE.toString());
|
||||||
|
filters.put(PermissionTicket.REQUESTER, userId);
|
||||||
|
|
||||||
|
return find(filters, resourceServerId, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PermissionTicket> findByOwner(String owner, String resourceServerId) {
|
public List<PermissionTicket> findByOwner(String owner, String resourceServerId) {
|
||||||
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByType", String.class);
|
TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByType", String.class);
|
||||||
|
|
|
@ -23,6 +23,7 @@ public interface PermissionTicket {
|
||||||
|
|
||||||
String ID = "id";
|
String ID = "id";
|
||||||
String RESOURCE = "resource.id";
|
String RESOURCE = "resource.id";
|
||||||
|
String RESOURCE_NAME = "resource.name";
|
||||||
String SCOPE = "scope.id";
|
String SCOPE = "scope.id";
|
||||||
String SCOPE_IS_NULL = "scope_is_null";
|
String SCOPE_IS_NULL = "scope_is_null";
|
||||||
String OWNER = "owner";
|
String OWNER = "owner";
|
||||||
|
|
|
@ -99,4 +99,14 @@ public interface PermissionTicketStore {
|
||||||
* @return a list of permissions granted for a particular user
|
* @return a list of permissions granted for a particular user
|
||||||
*/
|
*/
|
||||||
List<PermissionTicket> findGranted(String userId, String resourceServerId);
|
List<PermissionTicket> findGranted(String userId, String resourceServerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of {@link PermissionTicket} with name equal to {@code resourceName} granted to the given {@code userId}.
|
||||||
|
*
|
||||||
|
* @param resourceName the name of a resource
|
||||||
|
* @param userId the user id
|
||||||
|
* @param resourceServerId the resource server id
|
||||||
|
* @return a list of permissions granted for a particular user
|
||||||
|
*/
|
||||||
|
List<PermissionTicket> findGranted(String resourceName, String userId, String resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.keycloak.authorization.common.KeycloakIdentity;
|
||||||
import org.keycloak.authorization.model.Resource;
|
import org.keycloak.authorization.model.Resource;
|
||||||
import org.keycloak.authorization.model.ResourceServer;
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
import org.keycloak.authorization.model.Scope;
|
import org.keycloak.authorization.model.Scope;
|
||||||
|
import org.keycloak.authorization.model.PermissionTicket;
|
||||||
import org.keycloak.authorization.permission.ResourcePermission;
|
import org.keycloak.authorization.permission.ResourcePermission;
|
||||||
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
import org.keycloak.authorization.policy.evaluation.PermissionTicketAwareDecisionResultCollector;
|
import org.keycloak.authorization.policy.evaluation.PermissionTicketAwareDecisionResultCollector;
|
||||||
|
@ -419,6 +420,11 @@ public class AuthorizationTokenService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!identity.isResourceServer()) {
|
if (!identity.isResourceServer()) {
|
||||||
|
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());
|
Resource serverResource = resourceStore.findByName(resourceName, resourceServer.getId());
|
||||||
|
|
||||||
if (serverResource != null) {
|
if (serverResource != null) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -34,7 +35,9 @@ import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.authorization.client.AuthorizationDeniedException;
|
import org.keycloak.authorization.client.AuthorizationDeniedException;
|
||||||
import org.keycloak.authorization.client.resource.PermissionResource;
|
import org.keycloak.authorization.client.resource.PermissionResource;
|
||||||
|
import org.keycloak.authorization.client.util.HttpResponseException;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
|
||||||
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
|
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
|
||||||
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.Permission;
|
import org.keycloak.representations.idm.authorization.Permission;
|
||||||
|
@ -284,7 +287,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = authorize("kolo", "password", resource.getId(), new String[] {});
|
response = authorize("kolo", "password", resource.getId(), new String[] {});
|
||||||
fail("User should have access to resource from another user");
|
fail("User should not have access to resource from another user");
|
||||||
} catch (AuthorizationDeniedException ade) {
|
} catch (AuthorizationDeniedException ade) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -330,6 +333,86 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertTrue(permissions.isEmpty());
|
assertTrue(permissions.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUserGrantedAccessConsideredWhenRequestingAuthorizationByResourceName() throws Exception {
|
||||||
|
ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
|
||||||
|
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
|
||||||
|
|
||||||
|
permission.setName(resource.getName() + " Permission");
|
||||||
|
permission.addResource(resource.getId());
|
||||||
|
permission.addPolicy("Only Owner Policy");
|
||||||
|
|
||||||
|
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
||||||
|
|
||||||
|
try {
|
||||||
|
AuthorizationResponse response = authorize("kolo", "password", resource.getId(), new String[] {});
|
||||||
|
fail("User should not have access to resource from another user");
|
||||||
|
} catch (AuthorizationDeniedException ade) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PermissionResource permissionResource = getAuthzClient().protection().permission();
|
||||||
|
List<PermissionTicketRepresentation> permissionTickets = permissionResource.findByResource(resource.getId());
|
||||||
|
|
||||||
|
assertFalse(permissionTickets.isEmpty());
|
||||||
|
assertEquals(2, permissionTickets.size());
|
||||||
|
|
||||||
|
for (PermissionTicketRepresentation ticket : permissionTickets) {
|
||||||
|
assertFalse(ticket.isGranted());
|
||||||
|
|
||||||
|
ticket.setGranted(true);
|
||||||
|
|
||||||
|
permissionResource.update(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionTickets = permissionResource.findByResource(resource.getId());
|
||||||
|
|
||||||
|
assertFalse(permissionTickets.isEmpty());
|
||||||
|
assertEquals(2, permissionTickets.size());
|
||||||
|
|
||||||
|
for (PermissionTicketRepresentation ticket : permissionTickets) {
|
||||||
|
assertTrue(ticket.isGranted());
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthorizationRequest request = new AuthorizationRequest();
|
||||||
|
// No resource id used in request, only name
|
||||||
|
request.addPermission("Resource A", "ScopeA", "ScopeB");
|
||||||
|
|
||||||
|
List<Permission> permissions = authorize("kolo", "password", request);
|
||||||
|
|
||||||
|
assertEquals(1, permissions.size());
|
||||||
|
Permission koloPermission = permissions.get(0);
|
||||||
|
assertEquals("Resource A", koloPermission.getResourceName());
|
||||||
|
assertTrue(koloPermission.getScopes().containsAll(Arrays.asList("ScopeA", "ScopeB")));
|
||||||
|
|
||||||
|
ResourceRepresentation resourceRep = getAuthzClient().protection().resource().findById(resource.getId());
|
||||||
|
|
||||||
|
resourceRep.setName("Resource A Changed");
|
||||||
|
|
||||||
|
getAuthzClient().protection().resource().update(resourceRep);
|
||||||
|
|
||||||
|
request = new AuthorizationRequest();
|
||||||
|
// Try to use the old name
|
||||||
|
request.addPermission("Resource A", "ScopeA", "ScopeB");
|
||||||
|
|
||||||
|
try {
|
||||||
|
authorize("kolo", "password", request);
|
||||||
|
fail("User should not have access to resource from another user");
|
||||||
|
} catch (RuntimeException ade) {
|
||||||
|
assertTrue(ade.getCause().toString().contains("invalid_resource"));
|
||||||
|
}
|
||||||
|
|
||||||
|
request = new AuthorizationRequest();
|
||||||
|
request.addPermission(resourceRep.getName(), "ScopeA", "ScopeB");
|
||||||
|
|
||||||
|
permissions = authorize("kolo", "password", request);
|
||||||
|
|
||||||
|
assertEquals(1, permissions.size());
|
||||||
|
koloPermission = permissions.get(0);
|
||||||
|
assertEquals(resourceRep.getName(), koloPermission.getResourceName());
|
||||||
|
assertTrue(koloPermission.getScopes().containsAll(Arrays.asList("ScopeA", "ScopeB")));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserGrantsAccessToResourceWithoutScopes() throws Exception {
|
public void testUserGrantsAccessToResourceWithoutScopes() throws Exception {
|
||||||
ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
|
ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
|
||||||
|
@ -547,4 +630,11 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertPermissions(permissions, "Resource A");
|
assertPermissions(permissions, "Resource A");
|
||||||
assertTrue(permissions.isEmpty());
|
assertTrue(permissions.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Permission> authorize(String userName, String password, AuthorizationRequest request) {
|
||||||
|
AuthorizationResponse response = getAuthzClient().authorization(userName, password).authorize(request);
|
||||||
|
AccessToken token = toAccessToken(response.getToken());
|
||||||
|
AccessToken.Authorization authorization = token.getAuthorization();
|
||||||
|
return new ArrayList<>(authorization.getPermissions());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue