[KEYCLOAK-6787] - Wrong validation of resources with same name and different owners
This commit is contained in:
parent
9b1275f182
commit
1e1de85685
30 changed files with 535 additions and 217 deletions
|
@ -97,7 +97,7 @@ public class AuthzClient {
|
||||||
* @return a {@link ProtectionResource}
|
* @return a {@link ProtectionResource}
|
||||||
*/
|
*/
|
||||||
public ProtectionResource protection() {
|
public ProtectionResource protection() {
|
||||||
return new ProtectionResource(this.http, this.serverConfiguration, createPatSupplier());
|
return new ProtectionResource(this.http, this.serverConfiguration, configuration, createPatSupplier());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,7 +107,7 @@ public class AuthzClient {
|
||||||
* @return a {@link ProtectionResource}
|
* @return a {@link ProtectionResource}
|
||||||
*/
|
*/
|
||||||
public ProtectionResource protection(final String accessToken) {
|
public ProtectionResource protection(final String accessToken) {
|
||||||
return new ProtectionResource(this.http, this.serverConfiguration, new TokenCallable(http, configuration, serverConfiguration) {
|
return new ProtectionResource(this.http, this.serverConfiguration, configuration, new TokenCallable(http, configuration, serverConfiguration) {
|
||||||
@Override
|
@Override
|
||||||
public String call() {
|
public String call() {
|
||||||
return accessToken;
|
return accessToken;
|
||||||
|
@ -128,7 +128,7 @@ public class AuthzClient {
|
||||||
* @return a {@link ProtectionResource}
|
* @return a {@link ProtectionResource}
|
||||||
*/
|
*/
|
||||||
public ProtectionResource protection(String userName, String password) {
|
public ProtectionResource protection(String userName, String password) {
|
||||||
return new ProtectionResource(this.http, this.serverConfiguration, createPatSupplier(userName, password));
|
return new ProtectionResource(this.http, this.serverConfiguration, configuration, createPatSupplier(userName, password));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import org.keycloak.authorization.client.Configuration;
|
||||||
import org.keycloak.authorization.client.representation.ResourceRepresentation;
|
import org.keycloak.authorization.client.representation.ResourceRepresentation;
|
||||||
import org.keycloak.authorization.client.representation.ServerConfiguration;
|
import org.keycloak.authorization.client.representation.ServerConfiguration;
|
||||||
import org.keycloak.authorization.client.util.Http;
|
import org.keycloak.authorization.client.util.Http;
|
||||||
|
@ -38,11 +39,13 @@ public class ProtectedResource {
|
||||||
|
|
||||||
private final Http http;
|
private final Http http;
|
||||||
private ServerConfiguration serverConfiguration;
|
private ServerConfiguration serverConfiguration;
|
||||||
|
private final Configuration configuration;
|
||||||
private final TokenCallable pat;
|
private final TokenCallable pat;
|
||||||
|
|
||||||
ProtectedResource(Http http, ServerConfiguration serverConfiguration, TokenCallable pat) {
|
ProtectedResource(Http http, ServerConfiguration serverConfiguration, Configuration configuration, TokenCallable pat) {
|
||||||
this.http = http;
|
this.http = http;
|
||||||
this.serverConfiguration = serverConfiguration;
|
this.serverConfiguration = serverConfiguration;
|
||||||
|
this.configuration = configuration;
|
||||||
this.pat = pat;
|
this.pat = pat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,13 +122,30 @@ public class ProtectedResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query the server for a resource given its <code>name</code>.
|
* Query the server for a resource given its <code>name</code> where the owner is the resource server itself.
|
||||||
*
|
*
|
||||||
* @param id the resource name
|
* @param id the resource name
|
||||||
* @return a {@link ResourceRepresentation}
|
* @return a {@link ResourceRepresentation}
|
||||||
*/
|
*/
|
||||||
public ResourceRepresentation findByName(String name) {
|
public ResourceRepresentation findByName(String name) {
|
||||||
String[] representations = find(null, name, null, null, null, null, null, null);
|
String[] representations = find(null, name, null, configuration.getResource(), null, null, null, null);
|
||||||
|
|
||||||
|
if (representations.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return findById(representations[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query the server for a resource given its <code>name</code> and a given <code>ownerId</code>.
|
||||||
|
*
|
||||||
|
* @param name the resource name
|
||||||
|
* @param ownerId the owner id
|
||||||
|
* @return a {@link ResourceRepresentation}
|
||||||
|
*/
|
||||||
|
public ResourceRepresentation findByName(String name, String ownerId) {
|
||||||
|
String[] representations = find(null, name, null, ownerId, null, null, null, null);
|
||||||
|
|
||||||
if (representations.length == 0) {
|
if (representations.length == 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.authorization.client.resource;
|
package org.keycloak.authorization.client.resource;
|
||||||
|
|
||||||
|
import org.keycloak.authorization.client.Configuration;
|
||||||
import org.keycloak.authorization.client.representation.ServerConfiguration;
|
import org.keycloak.authorization.client.representation.ServerConfiguration;
|
||||||
import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
|
import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
|
||||||
import org.keycloak.authorization.client.util.Http;
|
import org.keycloak.authorization.client.util.Http;
|
||||||
|
@ -31,15 +32,17 @@ public class ProtectionResource {
|
||||||
|
|
||||||
private final TokenCallable pat;
|
private final TokenCallable pat;
|
||||||
private final Http http;
|
private final Http http;
|
||||||
|
private final Configuration configuration;
|
||||||
private ServerConfiguration serverConfiguration;
|
private ServerConfiguration serverConfiguration;
|
||||||
|
|
||||||
public ProtectionResource(Http http, ServerConfiguration serverConfiguration, TokenCallable pat) {
|
public ProtectionResource(Http http, ServerConfiguration serverConfiguration, Configuration configuration, TokenCallable pat) {
|
||||||
if (pat == null) {
|
if (pat == null) {
|
||||||
throw new RuntimeException("No access token was provided when creating client for Protection API.");
|
throw new RuntimeException("No access token was provided when creating client for Protection API.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.http = http;
|
this.http = http;
|
||||||
this.serverConfiguration = serverConfiguration;
|
this.serverConfiguration = serverConfiguration;
|
||||||
|
this.configuration = configuration;
|
||||||
this.pat = pat;
|
this.pat = pat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +52,7 @@ public class ProtectionResource {
|
||||||
* @return a {@link ProtectedResource}
|
* @return a {@link ProtectedResource}
|
||||||
*/
|
*/
|
||||||
public ProtectedResource resource() {
|
public ProtectedResource resource() {
|
||||||
return new ProtectedResource(http, serverConfiguration, pat);
|
return new ProtectedResource(http, serverConfiguration, configuration, pat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -44,4 +44,12 @@ public class HttpResponseException extends RuntimeException {
|
||||||
public byte[] getBytes() {
|
public byte[] getBytes() {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (bytes != null) {
|
||||||
|
return new StringBuilder(super.toString()).append(" / Response from server: ").append(new String(bytes)).toString();
|
||||||
|
}
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public final class Throwables {
|
||||||
*/
|
*/
|
||||||
public static RuntimeException handleWrapException(String message, Throwable cause) {
|
public static RuntimeException handleWrapException(String message, Throwable cause) {
|
||||||
if (cause instanceof HttpResponseException) {
|
if (cause instanceof HttpResponseException) {
|
||||||
throw handleAndWrapHttpResponseException(message, HttpResponseException.class.cast(cause));
|
throw handleAndWrapHttpResponseException(HttpResponseException.class.cast(cause));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RuntimeException(message, cause);
|
return new RuntimeException(message, cause);
|
||||||
|
@ -91,19 +91,11 @@ public final class Throwables {
|
||||||
throw new RuntimeException(message, cause);
|
throw new RuntimeException(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RuntimeException handleAndWrapHttpResponseException(String message, HttpResponseException exception) {
|
private static RuntimeException handleAndWrapHttpResponseException(HttpResponseException exception) {
|
||||||
HttpResponseException hre = HttpResponseException.class.cast(exception);
|
|
||||||
StringBuilder detail = new StringBuilder(message);
|
|
||||||
byte[] bytes = hre.getBytes();
|
|
||||||
|
|
||||||
if (bytes != null) {
|
|
||||||
detail.append(". Server message: ").append(new String(bytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (403 == exception.getStatusCode()) {
|
if (403 == exception.getStatusCode()) {
|
||||||
throw new AuthorizationDeniedException(detail.toString(), exception);
|
throw new AuthorizationDeniedException(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RuntimeException(detail.toString(), exception);
|
return new RuntimeException(exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,11 @@ public interface ResourcesResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
List<ResourceRepresentation> findByName(@QueryParam("name") String name);
|
List<ResourceRepresentation> findByName(@QueryParam("name") String name);
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
List<ResourceRepresentation> findByName(@QueryParam("name") String name, @QueryParam("owner") String owner);
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
|
|
@ -79,7 +79,7 @@ public class StoreFactoryCacheManager extends CacheManager {
|
||||||
|
|
||||||
public void resourceUpdated(String id, String name, String type, String uri, Set<String> scopes, String serverId, String owner, Set<String> invalidations) {
|
public void resourceUpdated(String id, String name, String type, String uri, Set<String> scopes, String serverId, String owner, Set<String> invalidations) {
|
||||||
invalidations.add(id);
|
invalidations.add(id);
|
||||||
invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
|
invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, owner, serverId));
|
||||||
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));
|
||||||
|
|
|
@ -336,8 +336,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
return "scope.name." + name + "." + serverId;
|
return "scope.name." + name + "." + serverId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getResourceByNameCacheKey(String name, String serverId) {
|
public static String getResourceByNameCacheKey(String name, String ownerId, String serverId) {
|
||||||
return "resource.name." + name + "." + serverId;
|
return "resource.name." + name + "." + ownerId + "." + serverId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getResourceByOwnerCacheKey(String owner, String serverId) {
|
public static String getResourceByOwnerCacheKey(String owner, String serverId) {
|
||||||
|
@ -580,10 +580,15 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource findByName(String name, String resourceServerId) {
|
public Resource findByName(String name, String resourceServerId) {
|
||||||
|
return findByName(name, resourceServerId, resourceServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource findByName(String name, String ownerId, String resourceServerId) {
|
||||||
if (name == null) return null;
|
if (name == null) return null;
|
||||||
String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
|
String cacheKey = getResourceByNameCacheKey(name, ownerId, resourceServerId);
|
||||||
List<Resource> result = cacheQuery(cacheKey, ResourceListQuery.class, () -> {
|
List<Resource> result = cacheQuery(cacheKey, ResourceListQuery.class, () -> {
|
||||||
Resource resource = getResourceStoreDelegate().findByName(name, resourceServerId);
|
Resource resource = getResourceStoreDelegate().findByName(name, ownerId, resourceServerId);
|
||||||
|
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
|
@ -47,7 +47,7 @@ import java.util.List;
|
||||||
@NamedQuery(name="findResourceIdByOwner", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner"),
|
@NamedQuery(name="findResourceIdByOwner", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner"),
|
||||||
@NamedQuery(name="findAnyResourceIdByOwner", query="select r.id from ResourceEntity r where r.owner = :owner"),
|
@NamedQuery(name="findAnyResourceIdByOwner", query="select r.id from ResourceEntity r where r.owner = :owner"),
|
||||||
@NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.uri = :uri"),
|
@NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.uri = :uri"),
|
||||||
@NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.name = :name"),
|
@NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :ownerId and r.name = :name"),
|
||||||
@NamedQuery(name="findResourceIdByType", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.type = :type"),
|
@NamedQuery(name="findResourceIdByType", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.type = :type"),
|
||||||
@NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId "),
|
@NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId "),
|
||||||
@NamedQuery(name="findResourceIdByScope", query="select r.id from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
|
@NamedQuery(name="findResourceIdByScope", query="select r.id from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
|
||||||
|
|
|
@ -237,11 +237,17 @@ public class JPAResourceStore implements ResourceStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource findByName(String name, String resourceServerId) {
|
public Resource findByName(String name, String resourceServerId) {
|
||||||
|
return findByName(name, resourceServerId, resourceServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource findByName(String name, String ownerId, String resourceServerId) {
|
||||||
TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByName", String.class);
|
TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByName", String.class);
|
||||||
|
|
||||||
query.setFlushMode(FlushModeType.COMMIT);
|
query.setFlushMode(FlushModeType.COMMIT);
|
||||||
query.setParameter("serverId", resourceServerId);
|
query.setParameter("serverId", resourceServerId);
|
||||||
query.setParameter("name", name);
|
query.setParameter("name", name);
|
||||||
|
query.setParameter("ownerId", ownerId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String id = query.getSingleResult();
|
String id = query.getSingleResult();
|
||||||
|
|
|
@ -285,7 +285,7 @@ public final class AuthorizationProvider implements Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
throw new RuntimeException("Resource [" + id + "] does not exist");
|
throw new RuntimeException("Resource [" + id + "] does not exist or is not owned by the resource server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return resource.getId();
|
return resource.getId();
|
||||||
|
@ -459,6 +459,11 @@ public final class AuthorizationProvider implements Provider {
|
||||||
return delegate.findByName(name, resourceServerId);
|
return delegate.findByName(name, resourceServerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource findByName(String name, String ownerId, String resourceServerId) {
|
||||||
|
return delegate.findByName(name, ownerId, resourceServerId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Resource> findByType(String type, String resourceServerId) {
|
public List<Resource> findByType(String type, String resourceServerId) {
|
||||||
return delegate.findByType(type, resourceServerId);
|
return delegate.findByType(type, resourceServerId);
|
||||||
|
|
|
@ -117,7 +117,7 @@ public class PermissionTicketAwareDecisionResultCollector extends DecisionResult
|
||||||
Resource resource = resourceStore.findById(permission.getResourceId(), resourceServer.getId());
|
Resource resource = resourceStore.findById(permission.getResourceId(), resourceServer.getId());
|
||||||
|
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
resource = resourceStore.findByName(permission.getResourceId(), resourceServer.getId());
|
resource = resourceStore.findByName(permission.getResourceId(), identity.getId(), resourceServer.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resource.isOwnerManagedAccess() || resource.getOwner().equals(identity.getId()) || resource.getOwner().equals(resourceServer.getId())) {
|
if (!resource.isOwnerManagedAccess() || resource.getOwner().equals(identity.getId()) || resource.getOwner().equals(resourceServer.getId())) {
|
||||||
|
|
|
@ -97,7 +97,7 @@ public interface ResourceStore {
|
||||||
List<Resource> findByScope(List<String> id, String resourceServerId);
|
List<Resource> findByScope(List<String> id, String resourceServerId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a {@link Resource} by its name.
|
* Find a {@link Resource} by its name where the owner is the resource server itself.
|
||||||
*
|
*
|
||||||
* @param name the name of the resource
|
* @param name the name of the resource
|
||||||
* @param resourceServerId the identifier of the resource server
|
* @param resourceServerId the identifier of the resource server
|
||||||
|
@ -105,6 +105,16 @@ public interface ResourceStore {
|
||||||
*/
|
*/
|
||||||
Resource findByName(String name, String resourceServerId);
|
Resource findByName(String name, String resourceServerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a {@link Resource} by its name where the owner is the given <code>ownerId</code>.
|
||||||
|
*
|
||||||
|
* @param name the name of the resource
|
||||||
|
* @param ownerId the owner id
|
||||||
|
* @param resourceServerId the identifier of the resource server
|
||||||
|
* @return a resource with the given name
|
||||||
|
*/
|
||||||
|
Resource findByName(String name, String ownerId, String resourceServerId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all {@link Resource} with the given type.
|
* Finds all {@link Resource} with the given type.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2275,7 +2275,7 @@ public class RepresentationToModel {
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
resource = storeFactory.getResourceStore().findByName(resourceId, policy.getResourceServer().getId());
|
resource = storeFactory.getResourceStore().findByName(resourceId, policy.getResourceServer().getId());
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist");
|
throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist or is not owned by the resource server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2303,28 +2303,6 @@ public class RepresentationToModel {
|
||||||
|
|
||||||
public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||||
ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
|
ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
|
||||||
Resource existing;
|
|
||||||
|
|
||||||
if (resource.getId() != null) {
|
|
||||||
existing = resourceStore.findById(resource.getId(), resourceServer.getId());
|
|
||||||
} else {
|
|
||||||
existing = resourceStore.findByName(resource.getName(), resourceServer.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existing != null) {
|
|
||||||
existing.setName(resource.getName());
|
|
||||||
existing.setDisplayName(resource.getDisplayName());
|
|
||||||
existing.setType(resource.getType());
|
|
||||||
existing.setUri(resource.getUri());
|
|
||||||
existing.setIconUri(resource.getIconUri());
|
|
||||||
existing.setOwnerManagedAccess(Boolean.TRUE.equals(resource.getOwnerManagedAccess()));
|
|
||||||
existing.updateScopes(resource.getScopes().stream()
|
|
||||||
.map((ScopeRepresentation scope) -> toModel(scope, resourceServer, authorization))
|
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
|
|
||||||
return existing;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceOwnerRepresentation owner = resource.getOwner();
|
ResourceOwnerRepresentation owner = resource.getOwner();
|
||||||
|
|
||||||
if (owner == null) {
|
if (owner == null) {
|
||||||
|
@ -2338,12 +2316,6 @@ public class RepresentationToModel {
|
||||||
throw new RuntimeException("No owner specified for resource [" + resource.getName() + "].");
|
throw new RuntimeException("No owner specified for resource [" + resource.getName() + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientModel clientModel = authorization.getRealm().getClientById(resourceServer.getId());
|
|
||||||
|
|
||||||
if (ownerId.equals(clientModel.getClientId())) {
|
|
||||||
ownerId = resourceServer.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resourceServer.getId().equals(ownerId)) {
|
if (!resourceServer.getId().equals(ownerId)) {
|
||||||
RealmModel realm = authorization.getRealm();
|
RealmModel realm = authorization.getRealm();
|
||||||
KeycloakSession keycloakSession = authorization.getKeycloakSession();
|
KeycloakSession keycloakSession = authorization.getKeycloakSession();
|
||||||
|
@ -2361,6 +2333,28 @@ public class RepresentationToModel {
|
||||||
ownerId = ownerModel.getId();
|
ownerId = ownerModel.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Resource existing;
|
||||||
|
|
||||||
|
if (resource.getId() != null) {
|
||||||
|
existing = resourceStore.findById(resource.getId(), resourceServer.getId());
|
||||||
|
} else {
|
||||||
|
existing = resourceStore.findByName(resource.getName(), ownerId, resourceServer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
existing.setName(resource.getName());
|
||||||
|
existing.setDisplayName(resource.getDisplayName());
|
||||||
|
existing.setType(resource.getType());
|
||||||
|
existing.setUri(resource.getUri());
|
||||||
|
existing.setIconUri(resource.getIconUri());
|
||||||
|
existing.setOwnerManagedAccess(Boolean.TRUE.equals(resource.getOwnerManagedAccess()));
|
||||||
|
existing.updateScopes(resource.getScopes().stream()
|
||||||
|
.map((ScopeRepresentation scope) -> toModel(scope, resourceServer, authorization))
|
||||||
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
Resource model = resourceStore.create(resource.getName(), resourceServer, ownerId);
|
Resource model = resourceStore.create(resource.getName(), resourceServer, ownerId);
|
||||||
|
|
||||||
model.setDisplayName(resource.getDisplayName());
|
model.setDisplayName(resource.getDisplayName());
|
||||||
|
|
|
@ -118,7 +118,6 @@ public class ResourceSetService {
|
||||||
public Response create(ResourceRepresentation resource, Function<Resource, ?> toRepresentation) {
|
public Response create(ResourceRepresentation resource, Function<Resource, ?> toRepresentation) {
|
||||||
requireManage();
|
requireManage();
|
||||||
StoreFactory storeFactory = this.authorization.getStoreFactory();
|
StoreFactory storeFactory = this.authorization.getStoreFactory();
|
||||||
Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), this.resourceServer.getId());
|
|
||||||
ResourceOwnerRepresentation owner = resource.getOwner();
|
ResourceOwnerRepresentation owner = resource.getOwner();
|
||||||
|
|
||||||
if (owner == null) {
|
if (owner == null) {
|
||||||
|
@ -132,7 +131,9 @@ public class ResourceSetService {
|
||||||
return ErrorResponse.error("You must specify the resource owner.", Status.BAD_REQUEST);
|
return ErrorResponse.error("You must specify the resource owner.", Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingResource != null && existingResource.getOwner().equals(ownerId)) {
|
Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), ownerId, this.resourceServer.getId());
|
||||||
|
|
||||||
|
if (existingResource != null) {
|
||||||
return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists.");
|
return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,13 +172,13 @@ public class AuthorizationTokenService {
|
||||||
|
|
||||||
private List<Result> evaluatePermissions(AuthorizationRequest authorizationRequest, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
|
private List<Result> evaluatePermissions(AuthorizationRequest authorizationRequest, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
|
||||||
return authorization.evaluators()
|
return authorization.evaluators()
|
||||||
.from(createPermissions(ticket, authorizationRequest, resourceServer, authorization), evaluationContext)
|
.from(createPermissions(ticket, authorizationRequest, resourceServer, identity, authorization), evaluationContext)
|
||||||
.evaluate();
|
.evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Result> evaluateUserManagedPermissions(AuthorizationRequest request, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
|
private List<Result> evaluateUserManagedPermissions(AuthorizationRequest request, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
|
||||||
return authorization.evaluators()
|
return authorization.evaluators()
|
||||||
.from(createPermissions(ticket, request, resourceServer, authorization), evaluationContext)
|
.from(createPermissions(ticket, request, resourceServer, identity, authorization), evaluationContext)
|
||||||
.evaluate(new PermissionTicketAwareDecisionResultCollector(request, ticket, identity, resourceServer, authorization)).results();
|
.evaluate(new PermissionTicketAwareDecisionResultCollector(request, ticket, identity, resourceServer, authorization)).results();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ public class AuthorizationTokenService {
|
||||||
return evaluationContextProvider.apply(authorizationRequest, authorization);
|
return evaluationContextProvider.apply(authorizationRequest, authorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ResourcePermission> createPermissions(PermissionTicketToken ticket, AuthorizationRequest request, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
private List<ResourcePermission> createPermissions(PermissionTicketToken ticket, AuthorizationRequest request, ResourceServer resourceServer, KeycloakIdentity identity, AuthorizationProvider authorization) {
|
||||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||||
Map<String, Set<String>> permissionsToEvaluate = new LinkedHashMap<>();
|
Map<String, Set<String>> permissionsToEvaluate = new LinkedHashMap<>();
|
||||||
ResourceStore resourceStore = storeFactory.getResourceStore();
|
ResourceStore resourceStore = storeFactory.getResourceStore();
|
||||||
|
@ -294,17 +294,31 @@ public class AuthorizationTokenService {
|
||||||
requestedScopes = new HashSet<>();
|
requestedScopes = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Resource existingResource = null;
|
List<Resource> existingResources = new ArrayList<>();
|
||||||
|
|
||||||
if (requestedResource.getResourceId() != null) {
|
if (requestedResource.getResourceId() != null) {
|
||||||
existingResource = resourceStore.findById(requestedResource.getResourceId(), resourceServer.getId());
|
Resource resource = resourceStore.findById(requestedResource.getResourceId(), resourceServer.getId());
|
||||||
|
|
||||||
if (existingResource == null) {
|
if (resource != null) {
|
||||||
existingResource = resourceStore.findByName(requestedResource.getResourceId(), resourceServer.getId());
|
existingResources.add(resource);
|
||||||
|
} else {
|
||||||
|
Resource ownerResource = resourceStore.findByName(requestedResource.getResourceId(), identity.getId(), resourceServer.getId());
|
||||||
|
|
||||||
|
if (ownerResource != null) {
|
||||||
|
existingResources.add(ownerResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!identity.isResourceServer()) {
|
||||||
|
Resource serverResource = resourceStore.findByName(requestedResource.getResourceId(), resourceServer.getId());
|
||||||
|
|
||||||
|
if (serverResource != null) {
|
||||||
|
existingResources.add(serverResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingResource == null && (requestedScopes == null || requestedScopes.isEmpty())) {
|
if (existingResources.isEmpty() && (requestedScopes == null || requestedScopes.isEmpty())) {
|
||||||
throw new CorsErrorResponseException(cors, "invalid_resource", "Resource with id [" + requestedResource.getResourceId() + "] does not exist.", Status.FORBIDDEN);
|
throw new CorsErrorResponseException(cors, "invalid_resource", "Resource with id [" + requestedResource.getResourceId() + "] does not exist.", Status.FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,18 +328,20 @@ public class AuthorizationTokenService {
|
||||||
requestedScopes.addAll(Arrays.asList(clientAdditionalScopes.split(" ")));
|
requestedScopes.addAll(Arrays.asList(clientAdditionalScopes.split(" ")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingResource != null) {
|
if (!existingResources.isEmpty()) {
|
||||||
Set<String> scopes = permissionsToEvaluate.get(existingResource.getId());
|
for (Resource resource : existingResources) {
|
||||||
|
Set<String> scopes = permissionsToEvaluate.get(resource.getId());
|
||||||
|
|
||||||
if (scopes == null) {
|
if (scopes == null) {
|
||||||
scopes = new HashSet<>();
|
scopes = new HashSet<>();
|
||||||
permissionsToEvaluate.put(existingResource.getId(), scopes);
|
permissionsToEvaluate.put(resource.getId(), scopes);
|
||||||
if (limit != null) {
|
if (limit != null) {
|
||||||
limit--;
|
limit--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scopes.addAll(requestedScopes);
|
scopes.addAll(requestedScopes);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
List<Resource> resources = resourceStore.findByScope(new ArrayList<>(requestedScopes), ticket.getAudience()[0]);
|
List<Resource> resources = resourceStore.findByScope(new ArrayList<>(requestedScopes), ticket.getAudience()[0]);
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ public class KeycloakIdentity implements Identity {
|
||||||
return this.accessToken;
|
return this.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isResourceServer() {
|
public boolean isResourceServer() {
|
||||||
UserModel clientUser = null;
|
UserModel clientUser = null;
|
||||||
|
|
||||||
ClientModel clientModel = getTargetClient();
|
ClientModel clientModel = getTargetClient();
|
||||||
|
|
|
@ -67,41 +67,61 @@ public class AbstractPermissionService {
|
||||||
|
|
||||||
private List<ResourceRepresentation> verifyRequestedResource(List<PermissionRequest> request) {
|
private List<ResourceRepresentation> verifyRequestedResource(List<PermissionRequest> request) {
|
||||||
ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
|
ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
|
||||||
|
List<ResourceRepresentation> requestedResources = new ArrayList<>();
|
||||||
|
|
||||||
return request.stream().map(permissionRequest -> {
|
for (PermissionRequest permissionRequest : request) {
|
||||||
String resourceSetId = permissionRequest.getResourceId();
|
String resourceSetId = permissionRequest.getResourceId();
|
||||||
Resource resource = null;
|
List<Resource> resources = new ArrayList<>();
|
||||||
|
|
||||||
if (resourceSetId == null) {
|
if (resourceSetId == null) {
|
||||||
if (permissionRequest.getScopes() == null || permissionRequest.getScopes().isEmpty()) {
|
if (permissionRequest.getScopes() == null || permissionRequest.getScopes().isEmpty()) {
|
||||||
throw new ErrorResponseException("invalid_resource_id", "Resource id or name not provided.", Response.Status.BAD_REQUEST);
|
throw new ErrorResponseException("invalid_resource_id", "Resource id or name not provided.", Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resource = resourceStore.findById(resourceSetId, resourceServer.getId());
|
Resource resource = resourceStore.findById(resourceSetId, resourceServer.getId());
|
||||||
|
|
||||||
if (resource == null) {
|
if (resource != null) {
|
||||||
resource = resourceStore.findByName(resourceSetId, this.resourceServer.getId());
|
resources.add(resource);
|
||||||
|
} else {
|
||||||
|
Resource userResource = resourceStore.findByName(resourceSetId, identity.getId(), this.resourceServer.getId());
|
||||||
|
|
||||||
|
if (userResource != null) {
|
||||||
|
resources.add(userResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource == null) {
|
if (!identity.isResourceServer()) {
|
||||||
|
Resource serverResource = resourceStore.findByName(resourceSetId, this.resourceServer.getId());
|
||||||
|
|
||||||
|
if (serverResource != null) {
|
||||||
|
resources.add(serverResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resources.isEmpty()) {
|
||||||
throw new ErrorResponseException("invalid_resource_id", "Resource set with id [" + resourceSetId + "] does not exists in this server.", Response.Status.BAD_REQUEST);
|
throw new ErrorResponseException("invalid_resource_id", "Resource set with id [" + resourceSetId + "] does not exists in this server.", Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resources.isEmpty()) {
|
||||||
|
requestedResources.add(new ResourceRepresentation(null, verifyRequestedScopes(permissionRequest, null)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (Resource resource : resources) {
|
||||||
Set<ScopeRepresentation> scopes = verifyRequestedScopes(permissionRequest, resource);
|
Set<ScopeRepresentation> scopes = verifyRequestedScopes(permissionRequest, resource);
|
||||||
|
|
||||||
if (resource != null) {
|
|
||||||
ResourceRepresentation representation = new ResourceRepresentation(resource.getName(), scopes);
|
ResourceRepresentation representation = new ResourceRepresentation(resource.getName(), scopes);
|
||||||
|
|
||||||
representation.setId(resource.getId());
|
representation.setId(resource.getId());
|
||||||
representation.setOwnerManagedAccess(resource.isOwnerManagedAccess());
|
representation.setOwnerManagedAccess(resource.isOwnerManagedAccess());
|
||||||
representation.setOwner(new ResourceOwnerRepresentation(resource.getOwner()));
|
representation.setOwner(new ResourceOwnerRepresentation(resource.getOwner()));
|
||||||
|
|
||||||
return representation;
|
requestedResources.add(representation);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ResourceRepresentation(null, scopes);
|
return requestedResources;
|
||||||
}).collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<ScopeRepresentation> verifyRequestedScopes(PermissionRequest request, Resource resource) {
|
private Set<ScopeRepresentation> verifyRequestedScopes(PermissionRequest request, Resource resource) {
|
||||||
|
|
|
@ -18,22 +18,26 @@
|
||||||
package org.keycloak.testsuite.admin.client.authorization;
|
package org.keycloak.testsuite.admin.client.authorization;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.admin.client.resource.ResourceScopeResource;
|
import org.keycloak.admin.client.resource.ResourceScopeResource;
|
||||||
import org.keycloak.admin.client.resource.ResourceScopesResource;
|
import org.keycloak.admin.client.resource.ResourceScopesResource;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||||
import org.keycloak.testsuite.ProfileAssume;
|
import org.keycloak.testsuite.ProfileAssume;
|
||||||
import org.keycloak.testsuite.admin.client.AbstractClientTest;
|
import org.keycloak.testsuite.admin.client.AbstractClientTest;
|
||||||
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
|
import org.keycloak.testsuite.util.UserBuilder;
|
||||||
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
@ -42,24 +46,32 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
|
||||||
|
|
||||||
protected static final String RESOURCE_SERVER_CLIENT_ID = "resource-server-test";
|
protected static final String RESOURCE_SERVER_CLIENT_ID = "resource-server-test";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultPageUriParameters() {
|
||||||
|
super.setDefaultPageUriParameters();
|
||||||
|
testRealmPage.setAuthRealm("authz-test");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getRealmId() {
|
||||||
|
return "authz-test";
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void enabled() {
|
public static void enabled() {
|
||||||
ProfileAssume.assumePreview();
|
ProfileAssume.assumePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Override
|
||||||
public void onBeforeAuthzTests() {
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
createOidcClient(RESOURCE_SERVER_CLIENT_ID);
|
testRealms.add(createTestRealm().build());
|
||||||
|
super.addTestRealms(testRealms);
|
||||||
ClientRepresentation resourceServer = getResourceServer();
|
|
||||||
|
|
||||||
assertEquals(RESOURCE_SERVER_CLIENT_ID, resourceServer.getName());
|
|
||||||
assertFalse(resourceServer.getAuthorizationServicesEnabled());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void onAfterAuthzTests() {
|
public void onAfterReenableAuthorization() {
|
||||||
getClientResource().remove();
|
enableAuthorizationServices(false);
|
||||||
|
enableAuthorizationServices(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ClientResource getClientResource() {
|
protected ClientResource getClientResource() {
|
||||||
|
@ -70,23 +82,23 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
|
||||||
return findClientRepresentation(RESOURCE_SERVER_CLIENT_ID);
|
return findClientRepresentation(RESOURCE_SERVER_CLIENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void enableAuthorizationServices() {
|
protected void enableAuthorizationServices(boolean enable) {
|
||||||
ClientRepresentation resourceServer = getResourceServer();
|
ClientRepresentation resourceServer = getResourceServer();
|
||||||
|
|
||||||
resourceServer.setAuthorizationServicesEnabled(true);
|
resourceServer.setAuthorizationServicesEnabled(enable);
|
||||||
resourceServer.setServiceAccountsEnabled(true);
|
resourceServer.setServiceAccountsEnabled(true);
|
||||||
resourceServer.setPublicClient(false);
|
resourceServer.setPublicClient(false);
|
||||||
resourceServer.setSecret("secret");
|
resourceServer.setSecret("secret");
|
||||||
|
|
||||||
getClientResource().update(resourceServer);
|
getClientResource().update(resourceServer);
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
AuthorizationResource authorization = getClientResource().authorization();
|
AuthorizationResource authorization = getClientResource().authorization();
|
||||||
ResourceServerRepresentation settings = authorization.exportSettings();
|
ResourceServerRepresentation settings = authorization.exportSettings();
|
||||||
|
|
||||||
settings.setAllowRemoteResourceManagement(true);
|
settings.setAllowRemoteResourceManagement(true);
|
||||||
|
|
||||||
authorization.update(settings);
|
authorization.update(settings);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected ResourceScopeResource createDefaultScope() {
|
protected ResourceScopeResource createDefaultScope() {
|
||||||
return createScope("Test Scope", "Scope Icon");
|
return createScope("Test Scope", "Scope Icon");
|
||||||
|
@ -108,4 +120,17 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
|
||||||
|
|
||||||
return resources.scope(stored.getId());
|
return resources.scope(stored.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RealmBuilder createTestRealm() {
|
||||||
|
return RealmBuilder.create().name("authz-test")
|
||||||
|
.user(UserBuilder.create().username("marta").password("password"))
|
||||||
|
.user(UserBuilder.create().username("kolo").password("password"))
|
||||||
|
.client(ClientBuilder.create().clientId(RESOURCE_SERVER_CLIENT_ID)
|
||||||
|
.name(RESOURCE_SERVER_CLIENT_ID)
|
||||||
|
.secret("secret")
|
||||||
|
.authorizationServicesEnabled(true)
|
||||||
|
.redirectUris("http://localhost/" + RESOURCE_SERVER_CLIENT_ID)
|
||||||
|
.defaultRoles("uma_protection")
|
||||||
|
.directAccessGrants());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||||
|
@ -44,17 +45,38 @@ public class AuthorizationTest extends AbstractAuthorizationTest {
|
||||||
ClientResource clientResource = getClientResource();
|
ClientResource clientResource = getClientResource();
|
||||||
ClientRepresentation resourceServer = getResourceServer();
|
ClientRepresentation resourceServer = getResourceServer();
|
||||||
|
|
||||||
enableAuthorizationServices();
|
enableAuthorizationServices(false);
|
||||||
|
enableAuthorizationServices(true);
|
||||||
|
|
||||||
|
clientResource.authorization().resources().create(new ResourceRepresentation("Should be removed"));
|
||||||
|
|
||||||
|
JSPolicyRepresentation policy = new JSPolicyRepresentation();
|
||||||
|
|
||||||
|
policy.setName("should be removed");
|
||||||
|
policy.setCode("");
|
||||||
|
|
||||||
|
clientResource.authorization().policies().js().create(policy);
|
||||||
|
|
||||||
|
List<ResourceRepresentation> defaultResources = clientResource.authorization().resources().resources();
|
||||||
|
|
||||||
|
assertEquals(2, defaultResources.size());
|
||||||
|
|
||||||
|
List<PolicyRepresentation> defaultPolicies = clientResource.authorization().policies().policies();
|
||||||
|
|
||||||
|
assertEquals(3, defaultPolicies.size());
|
||||||
|
|
||||||
|
enableAuthorizationServices(false);
|
||||||
|
enableAuthorizationServices(true);
|
||||||
|
|
||||||
ResourceServerRepresentation settings = clientResource.authorization().getSettings();
|
ResourceServerRepresentation settings = clientResource.authorization().getSettings();
|
||||||
|
|
||||||
assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
|
assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
|
||||||
assertEquals(resourceServer.getId(), settings.getClientId());
|
assertEquals(resourceServer.getId(), settings.getClientId());
|
||||||
List<ResourceRepresentation> defaultResources = clientResource.authorization().resources().resources();
|
defaultResources = clientResource.authorization().resources().resources();
|
||||||
|
|
||||||
assertEquals(1, defaultResources.size());
|
assertEquals(1, defaultResources.size());
|
||||||
|
|
||||||
List<PolicyRepresentation> defaultPolicies = clientResource.authorization().policies().policies();
|
defaultPolicies = clientResource.authorization().policies().policies();
|
||||||
|
|
||||||
assertEquals(2, defaultPolicies.size());
|
assertEquals(2, defaultPolicies.size());
|
||||||
}
|
}
|
||||||
|
@ -72,8 +94,6 @@ public class AuthorizationTest extends AbstractAuthorizationTest {
|
||||||
ClientResource clientResource = getClientResource();
|
ClientResource clientResource = getClientResource();
|
||||||
ClientRepresentation resourceServer = getResourceServer();
|
ClientRepresentation resourceServer = getResourceServer();
|
||||||
|
|
||||||
enableAuthorizationServices();
|
|
||||||
|
|
||||||
ResourceServerRepresentation settings = clientResource.authorization().getSettings();
|
ResourceServerRepresentation settings = clientResource.authorization().getSettings();
|
||||||
|
|
||||||
assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
|
assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
|
||||||
|
|
|
@ -46,8 +46,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
|
||||||
String permissionName = "resource-based-permission";
|
String permissionName = "resource-based-permission";
|
||||||
|
|
||||||
ClientResource clientResource = getClientResource();
|
ClientResource clientResource = getClientResource();
|
||||||
|
|
||||||
enableAuthorizationServices();
|
|
||||||
AuthorizationResource authorizationResource = clientResource.authorization();
|
AuthorizationResource authorizationResource = clientResource.authorization();
|
||||||
|
|
||||||
//get Default Resource
|
//get Default Resource
|
||||||
|
@ -89,8 +87,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRoleBasedPolicy() {
|
public void testRoleBasedPolicy() {
|
||||||
ClientResource clientResource = getClientResource();
|
ClientResource clientResource = getClientResource();
|
||||||
|
|
||||||
enableAuthorizationServices();
|
|
||||||
AuthorizationResource authorizationResource = clientResource.authorization();
|
AuthorizationResource authorizationResource = clientResource.authorization();
|
||||||
|
|
||||||
ClientRepresentation account = testRealmResource().clients().findByClientId("account").get(0);
|
ClientRepresentation account = testRealmResource().clients().findByClientId("account").get(0);
|
||||||
|
@ -121,8 +117,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRoleBasedPolicyWithMultipleRoles() {
|
public void testRoleBasedPolicyWithMultipleRoles() {
|
||||||
ClientResource clientResource = getClientResource();
|
ClientResource clientResource = getClientResource();
|
||||||
|
|
||||||
enableAuthorizationServices();
|
|
||||||
AuthorizationResource authorizationResource = clientResource.authorization();
|
AuthorizationResource authorizationResource = clientResource.authorization();
|
||||||
|
|
||||||
testRealmResource().clients().create(ClientBuilder.create().clientId("test-client-1").defaultRoles("client-role").build()).close();
|
testRealmResource().clients().create(ClientBuilder.create().clientId("test-client-1").defaultRoles("client-role").build()).close();
|
||||||
|
|
|
@ -54,19 +54,6 @@ public class GenericPolicyManagementTest extends AbstractAuthorizationTest {
|
||||||
|
|
||||||
private static final String[] EXPECTED_BUILTIN_POLICY_PROVIDERS = {"test", "user", "role", "rules", "js", "time", "aggregate", "scope", "resource"};
|
private static final String[] EXPECTED_BUILTIN_POLICY_PROVIDERS = {"test", "user", "role", "rules", "js", "time", "aggregate", "scope", "resource"};
|
||||||
|
|
||||||
@Before
|
|
||||||
@Override
|
|
||||||
public void onBeforeAuthzTests() {
|
|
||||||
super.onBeforeAuthzTests();
|
|
||||||
enableAuthorizationServices();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
@Override
|
|
||||||
public void onAfterAuthzTests() {
|
|
||||||
super.onAfterAuthzTests();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() {
|
public void testCreate() {
|
||||||
PolicyRepresentation newPolicy = createTestingPolicy().toRepresentation();
|
PolicyRepresentation newPolicy = createTestingPolicy().toRepresentation();
|
||||||
|
|
|
@ -48,24 +48,9 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
|
||||||
testRealmResource().users().create(UserBuilder.create().username("alice").build());
|
testRealmResource().users().create(UserBuilder.create().username("alice").build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
public void onAfterAuthzTests() {
|
|
||||||
ClientResource clientResource = getClientResource();
|
|
||||||
|
|
||||||
// Needed to disable authz first. TODO: Looks like a bug. Check later...
|
|
||||||
ClientRepresentation client = clientResource.toRepresentation();
|
|
||||||
client.setAuthorizationServicesEnabled(false);
|
|
||||||
clientResource.update(client);
|
|
||||||
|
|
||||||
getClientResource().remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testImportUnorderedSettings() throws Exception {
|
public void testImportUnorderedSettings() throws Exception {
|
||||||
ClientResource clientResource = getClientResource();
|
ClientResource clientResource = getClientResource();
|
||||||
|
|
||||||
enableAuthorizationServices();
|
|
||||||
|
|
||||||
ResourceServerRepresentation toImport = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/import-authorization-unordered-settings.json"), ResourceServerRepresentation.class);
|
ResourceServerRepresentation toImport = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/import-authorization-unordered-settings.json"), ResourceServerRepresentation.class);
|
||||||
|
|
||||||
realmsResouce().realm(getRealmId()).roles().create(new RoleRepresentation("user", null, false));
|
realmsResouce().realm(getRealmId()).roles().create(new RoleRepresentation("user", null, false));
|
||||||
|
@ -75,6 +60,6 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
|
||||||
|
|
||||||
authorizationResource.importSettings(toImport);
|
authorizationResource.importSettings(toImport);
|
||||||
|
|
||||||
assertEquals(15, authorizationResource.policies().policies().size());
|
assertEquals(13, authorizationResource.policies().policies().size());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,12 +18,11 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.admin.client.authorization;
|
package org.keycloak.testsuite.admin.client.authorization;
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.ResourceResource;
|
import org.keycloak.admin.client.resource.ResourceResource;
|
||||||
import org.keycloak.admin.client.resource.ResourcesResource;
|
import org.keycloak.admin.client.resource.ResourcesResource;
|
||||||
import org.keycloak.authorization.client.util.HttpResponseException;
|
import org.keycloak.authorization.client.util.HttpResponseException;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||||
|
|
||||||
|
@ -35,6 +34,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
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;
|
||||||
|
@ -45,33 +45,6 @@ import static org.junit.Assert.fail;
|
||||||
*/
|
*/
|
||||||
public class ResourceManagementTest extends AbstractAuthorizationTest {
|
public class ResourceManagementTest extends AbstractAuthorizationTest {
|
||||||
|
|
||||||
@Before
|
|
||||||
@Override
|
|
||||||
public void onBeforeAuthzTests() {
|
|
||||||
super.onBeforeAuthzTests();
|
|
||||||
enableAuthorizationServices();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
|
||||||
RealmRepresentation testRealmRep = new RealmRepresentation();
|
|
||||||
testRealmRep.setId("authz-test");
|
|
||||||
testRealmRep.setRealm("authz-test");
|
|
||||||
testRealmRep.setEnabled(true);
|
|
||||||
testRealms.add(testRealmRep);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDefaultPageUriParameters() {
|
|
||||||
super.setDefaultPageUriParameters();
|
|
||||||
testRealmPage.setAuthRealm("authz-test");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getRealmId() {
|
|
||||||
return "authz-test";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() {
|
public void testCreate() {
|
||||||
ResourceRepresentation newResource = createResource();
|
ResourceRepresentation newResource = createResource();
|
||||||
|
@ -102,6 +75,28 @@ public class ResourceManagementTest extends AbstractAuthorizationTest {
|
||||||
assertEquals("Test Resource Another", newResource.getName());
|
assertEquals("Test Resource Another", newResource.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void failCreateWithSameNameDifferentOwner() {
|
||||||
|
ResourceRepresentation martaResource = createResource("Resource A", "marta", null, null, null);
|
||||||
|
ResourceRepresentation koloResource = createResource("Resource A", "kolo", null, null, null);
|
||||||
|
|
||||||
|
assertNotNull(martaResource.getId());
|
||||||
|
assertNotNull(koloResource.getId());
|
||||||
|
assertNotEquals(martaResource.getId(), koloResource.getId());
|
||||||
|
|
||||||
|
assertEquals(2, getClientResource().authorization().resources().findByName(martaResource.getName()).size());
|
||||||
|
|
||||||
|
List<ResourceRepresentation> martaResources = getClientResource().authorization().resources().findByName(martaResource.getName(), "marta");
|
||||||
|
|
||||||
|
assertEquals(1, martaResources.size());
|
||||||
|
assertEquals(martaResource.getId(), martaResources.get(0).getId());
|
||||||
|
|
||||||
|
List<ResourceRepresentation> koloResources = getClientResource().authorization().resources().findByName(martaResource.getName(), "kolo");
|
||||||
|
|
||||||
|
assertEquals(1, koloResources.size());
|
||||||
|
assertEquals(koloResource.getId(), koloResources.get(0).getId());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdate() {
|
public void testUpdate() {
|
||||||
ResourceRepresentation resource = createResource();
|
ResourceRepresentation resource = createResource();
|
||||||
|
@ -198,12 +193,17 @@ public class ResourceManagementTest extends AbstractAuthorizationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceRepresentation createResource() {
|
private ResourceRepresentation createResource() {
|
||||||
|
return createResource("Test Resource", null, "/test/*", "test-resource", "icon-test-resource");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResourceRepresentation createResource(String name, String owner, String uri, String type, String iconUri) {
|
||||||
ResourceRepresentation newResource = new ResourceRepresentation();
|
ResourceRepresentation newResource = new ResourceRepresentation();
|
||||||
|
|
||||||
newResource.setName("Test Resource");
|
newResource.setName(name);
|
||||||
newResource.setUri("/test/*");
|
newResource.setUri(uri);
|
||||||
newResource.setType("test-resource");
|
newResource.setType(type);
|
||||||
newResource.setIconUri("icon-test-resource");
|
newResource.setIconUri(iconUri);
|
||||||
|
newResource.setOwner(owner != null ? new ResourceOwnerRepresentation(owner) : null);
|
||||||
|
|
||||||
return doCreateResource(newResource);
|
return doCreateResource(newResource);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,6 @@ import static org.junit.Assert.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class ScopeManagementTest extends AbstractAuthorizationTest {
|
public class ScopeManagementTest extends AbstractAuthorizationTest {
|
||||||
|
|
||||||
@Before
|
|
||||||
@Override
|
|
||||||
public void onBeforeAuthzTests() {
|
|
||||||
super.onBeforeAuthzTests();
|
|
||||||
enableAuthorizationServices();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() {
|
public void testCreate() {
|
||||||
ScopeRepresentation newScope = createDefaultScope().toRepresentation();
|
ScopeRepresentation newScope = createDefaultScope().toRepresentation();
|
||||||
|
|
|
@ -127,7 +127,7 @@ public class AuthorizationAPITest extends AbstractAuthzTest {
|
||||||
assertEquals("resource-server-test", rpt.getAudience()[0]);
|
assertEquals("resource-server-test", rpt.getAudience()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RealmResource getRealm() throws Exception {
|
private RealmResource getRealm() {
|
||||||
return adminClient.realm("authz-test");
|
return adminClient.realm("authz-test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.testsuite.authz;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientsResource;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
|
import org.keycloak.admin.client.resource.ResourcesResource;
|
||||||
|
import org.keycloak.authorization.client.AuthzClient;
|
||||||
|
import org.keycloak.authorization.client.Configuration;
|
||||||
|
import org.keycloak.jose.jws.JWSInputException;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.AccessToken.Authorization;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
|
||||||
|
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
|
||||||
|
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.Permission;
|
||||||
|
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
|
import org.keycloak.testsuite.util.RoleBuilder;
|
||||||
|
import org.keycloak.testsuite.util.RolesBuilder;
|
||||||
|
import org.keycloak.testsuite.util.UserBuilder;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class AuthorizationTest extends AbstractAuthzTest {
|
||||||
|
|
||||||
|
private AuthzClient authzClient;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
|
testRealms.add(RealmBuilder.create().name("authz-test")
|
||||||
|
.roles(RolesBuilder.create().realmRole(RoleBuilder.create().name("uma_authorization").build()))
|
||||||
|
.user(UserBuilder.create().username("marta").password("password").addRoles("uma_authorization"))
|
||||||
|
.user(UserBuilder.create().username("kolo").password("password"))
|
||||||
|
.client(ClientBuilder.create().clientId("resource-server-test")
|
||||||
|
.secret("secret")
|
||||||
|
.authorizationServicesEnabled(true)
|
||||||
|
.redirectUris("http://localhost/resource-server-test")
|
||||||
|
.defaultRoles("uma_protection")
|
||||||
|
.directAccessGrants())
|
||||||
|
.client(ClientBuilder.create().clientId("test-client")
|
||||||
|
.secret("secret")
|
||||||
|
.authorizationServicesEnabled(true)
|
||||||
|
.redirectUris("http://localhost/test-client")
|
||||||
|
.directAccessGrants())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void configureAuthorization() throws Exception {
|
||||||
|
ClientResource client = getClient();
|
||||||
|
AuthorizationResource authorization = client.authorization();
|
||||||
|
|
||||||
|
JSPolicyRepresentation policy = new JSPolicyRepresentation();
|
||||||
|
|
||||||
|
policy.setName("Grant Policy");
|
||||||
|
policy.setCode("$evaluation.grant();");
|
||||||
|
|
||||||
|
authorization.policies().js().create(policy).close();
|
||||||
|
|
||||||
|
policy = new JSPolicyRepresentation();
|
||||||
|
|
||||||
|
policy.setName("Deny Policy");
|
||||||
|
policy.setCode("$evaluation.deny();");
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void onAfter() {
|
||||||
|
ResourcesResource resources = getClient().authorization().resources();
|
||||||
|
List<ResourceRepresentation> existingResources = resources.resources();
|
||||||
|
|
||||||
|
for (ResourceRepresentation resource : existingResources) {
|
||||||
|
resources.resource(resource.getId()).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResourceWithSameNameDifferentOwner() throws JWSInputException {
|
||||||
|
ResourceRepresentation koloResource = createResource("Resource A", "kolo", "Scope A", "Scope B");
|
||||||
|
|
||||||
|
createResourcePermission(koloResource, "Grant Policy");
|
||||||
|
|
||||||
|
ResourceRepresentation martaResource = createResource("Resource A", "marta", "Scope A", "Scope B");
|
||||||
|
|
||||||
|
createResourcePermission(martaResource, "Grant Policy");
|
||||||
|
|
||||||
|
assertNotEquals(koloResource.getId(), martaResource.getId());
|
||||||
|
|
||||||
|
AuthorizationRequest request = new AuthorizationRequest();
|
||||||
|
|
||||||
|
request.addPermission("Resource A");
|
||||||
|
|
||||||
|
List<Permission> permissions = authorize("kolo", "password", request);
|
||||||
|
|
||||||
|
assertEquals(1, permissions.size());
|
||||||
|
|
||||||
|
Permission permission = permissions.get(0);
|
||||||
|
assertTrue(permission.getScopes().containsAll(Arrays.asList("Scope A", "Scope B")));
|
||||||
|
|
||||||
|
assertEquals(koloResource.getId(), permission.getResourceId());
|
||||||
|
|
||||||
|
permissions = authorize("marta", "password", request);
|
||||||
|
|
||||||
|
assertEquals(1, permissions.size());
|
||||||
|
|
||||||
|
permission = permissions.get(0);
|
||||||
|
|
||||||
|
assertEquals(martaResource.getId(), permission.getResourceId());
|
||||||
|
assertTrue(permission.getScopes().containsAll(Arrays.asList("Scope A", "Scope B")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResourceServerWithSameNameDifferentOwner() {
|
||||||
|
ResourceRepresentation koloResource = createResource("Resource A", "kolo", "Scope A", "Scope B");
|
||||||
|
|
||||||
|
createResourcePermission(koloResource, "Grant Policy");
|
||||||
|
|
||||||
|
ResourceRepresentation serverResource = createResource("Resource A", null, "Scope A", "Scope B");
|
||||||
|
|
||||||
|
createResourcePermission(serverResource, "Grant Policy");
|
||||||
|
|
||||||
|
AuthorizationRequest request = new AuthorizationRequest();
|
||||||
|
|
||||||
|
request.addPermission("Resource A");
|
||||||
|
|
||||||
|
List<Permission> permissions = authorize("kolo", "password", request);
|
||||||
|
|
||||||
|
assertEquals(2, permissions.size());
|
||||||
|
|
||||||
|
for (Permission permission : permissions) {
|
||||||
|
assertTrue(permission.getResourceId().equals(koloResource.getId()) || permission.getResourceId().equals(serverResource.getId()));
|
||||||
|
assertEquals("Resource A", permission.getResourceName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Permission> authorize(String userName, String password, AuthorizationRequest request) {
|
||||||
|
AuthorizationResponse response = getAuthzClient().authorization(userName, password).authorize(request);
|
||||||
|
AccessToken token = toAccessToken(response.getToken());
|
||||||
|
Authorization authorization = token.getAuthorization();
|
||||||
|
return authorization.getPermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createResourcePermission(ResourceRepresentation resource, String... policies) {
|
||||||
|
ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
|
||||||
|
|
||||||
|
permission.setName(resource.getName() + UUID.randomUUID().toString());
|
||||||
|
permission.addResource(resource.getId());
|
||||||
|
permission.addPolicy(policies);
|
||||||
|
|
||||||
|
Response response = getClient().authorization().permissions().resource().create(permission);
|
||||||
|
|
||||||
|
assertEquals(201, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private ResourceRepresentation createResource(String name, String owner, String... scopes) {
|
||||||
|
ResourceRepresentation resource = new ResourceRepresentation();
|
||||||
|
|
||||||
|
resource.setName(name);
|
||||||
|
resource.setOwner(owner != null ? new ResourceOwnerRepresentation(owner) : null);
|
||||||
|
resource.addScope(scopes);
|
||||||
|
|
||||||
|
Response response = getClient().authorization().resources().create(resource);
|
||||||
|
ResourceRepresentation stored = response.readEntity(ResourceRepresentation.class);
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
resource.setId(stored.getId());
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RealmResource getRealm() {
|
||||||
|
return adminClient.realm("authz-test");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientResource getClient() {
|
||||||
|
ClientsResource clients = getRealm().clients();
|
||||||
|
return clients.findByClientId("resource-server-test").stream().map(representation -> clients.get(representation.getId())).findFirst().orElseThrow(() -> new RuntimeException("Expected client [resource-server-test]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthzClient getAuthzClient() {
|
||||||
|
if (authzClient == null) {
|
||||||
|
try {
|
||||||
|
authzClient = AuthzClient.create(JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/default-keycloak.json"), Configuration.class));
|
||||||
|
} catch (IOException cause) {
|
||||||
|
throw new RuntimeException("Failed to create authz client", cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return authzClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,7 +52,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
|
||||||
public void testCreatePermissionTicketWithResourceName() throws Exception {
|
public void testCreatePermissionTicketWithResourceName() throws Exception {
|
||||||
ResourceRepresentation resource = addResource("Resource A", "kolo", true);
|
ResourceRepresentation resource = addResource("Resource A", "kolo", true);
|
||||||
AuthzClient authzClient = getAuthzClient();
|
AuthzClient authzClient = getAuthzClient();
|
||||||
PermissionResponse response = authzClient.protection("marta", "password").permission().create(new PermissionRequest(resource.getName()));
|
PermissionResponse response = authzClient.protection("marta", "password").permission().create(new PermissionRequest(resource.getId()));
|
||||||
AuthorizationRequest request = new AuthorizationRequest();
|
AuthorizationRequest request = new AuthorizationRequest();
|
||||||
request.setTicket(response.getTicket());
|
request.setTicket(response.getTicket());
|
||||||
request.setClaimToken(authzClient.obtainAccessToken("marta", "password").getToken());
|
request.setClaimToken(authzClient.obtainAccessToken("marta", "password").getToken());
|
||||||
|
@ -125,7 +125,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteScopeAndPermissionTicket() throws Exception {
|
public void testDeleteScopeAndPermissionTicket() throws Exception {
|
||||||
ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB", "ScopeC");
|
ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB", "ScopeC");
|
||||||
PermissionRequest permissionRequest = new PermissionRequest(resource.getName());
|
PermissionRequest permissionRequest = new PermissionRequest(resource.getId());
|
||||||
|
|
||||||
permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeB", "ScopeC")));
|
permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeB", "ScopeC")));
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveScopeFromResource() throws Exception {
|
public void testRemoveScopeFromResource() throws Exception {
|
||||||
ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB");
|
ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB");
|
||||||
PermissionRequest permissionRequest = new PermissionRequest(resource.getName(), "ScopeA", "ScopeB");
|
PermissionRequest permissionRequest = new PermissionRequest(resource.getId(), "ScopeA", "ScopeB");
|
||||||
AuthzClient authzClient = getAuthzClient();
|
AuthzClient authzClient = getAuthzClient();
|
||||||
PermissionResponse response = authzClient.protection("marta", "password").permission().create(permissionRequest);
|
PermissionResponse response = authzClient.protection("marta", "password").permission().create(permissionRequest);
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
|
||||||
|
|
||||||
getClient(getRealm()).authorization().resources().resource(resourceA.getId()).update(resourceA);
|
getClient(getRealm()).authorization().resources().resource(resourceA.getId()).update(resourceA);
|
||||||
|
|
||||||
PermissionRequest permissionRequest = new PermissionRequest("Resource A");
|
PermissionRequest permissionRequest = new PermissionRequest(resourceA.getId());
|
||||||
|
|
||||||
permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeC")));
|
permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeC")));
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ public class UmaGrantTypeTest extends AbstractResourceServerTest {
|
||||||
ResourceRepresentation resourceA = addResource("Resource Marta", "marta", true, "ScopeA", "ScopeB", "ScopeC");
|
ResourceRepresentation resourceA = addResource("Resource Marta", "marta", true, "ScopeA", "ScopeB", "ScopeC");
|
||||||
|
|
||||||
permission.setName(resourceA.getName() + " Permission");
|
permission.setName(resourceA.getName() + " Permission");
|
||||||
permission.addResource(resourceA.getName());
|
permission.addResource(resourceA.getId());
|
||||||
permission.addPolicy("Default Policy");
|
permission.addPolicy("Default Policy");
|
||||||
|
|
||||||
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
||||||
|
@ -131,7 +131,7 @@ public class UmaGrantTypeTest extends AbstractResourceServerTest {
|
||||||
ResourceRepresentation resourceB = addResource("Resource B", "marta", "ScopeA", "ScopeB", "ScopeC");
|
ResourceRepresentation resourceB = addResource("Resource B", "marta", "ScopeA", "ScopeB", "ScopeC");
|
||||||
|
|
||||||
permission.setName(resourceB.getName() + " Permission");
|
permission.setName(resourceB.getName() + " Permission");
|
||||||
permission.addResource(resourceB.getName());
|
permission.addResource(resourceB.getId());
|
||||||
permission.addPolicy("Default Policy");
|
permission.addPolicy("Default Policy");
|
||||||
|
|
||||||
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
|
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
|
||||||
|
|
||||||
permission.setName(resource.getName() + " Permission");
|
permission.setName(resource.getName() + " Permission");
|
||||||
permission.addResource(resource.getName());
|
permission.addResource(resource.getId());
|
||||||
permission.addPolicy("Only Owner Policy");
|
permission.addPolicy("Only Owner Policy");
|
||||||
|
|
||||||
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
||||||
|
@ -91,7 +91,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertTrue(permissions.isEmpty());
|
assertTrue(permissions.isEmpty());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
|
response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
|
||||||
fail("User should have access to resource from another user");
|
fail("User should have access to resource from another user");
|
||||||
} catch (AuthorizationDeniedException ade) {
|
} catch (AuthorizationDeniedException ade) {
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
|
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
|
||||||
|
|
||||||
permission.setName(resource.getName() + " Permission");
|
permission.setName(resource.getName() + " Permission");
|
||||||
permission.addResource(resource.getName());
|
permission.addResource(resource.getId());
|
||||||
permission.addPolicy("Only Owner Policy");
|
permission.addPolicy("Only Owner Policy");
|
||||||
|
|
||||||
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
||||||
|
@ -127,7 +127,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertTrue(permissions.isEmpty());
|
assertTrue(permissions.isEmpty());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = authorize("kolo", "password", "Resource A", new String[] {});
|
response = authorize("kolo", "password", resource.getId(), new String[] {});
|
||||||
fail("User should have access to resource from another user");
|
fail("User should have access to resource from another user");
|
||||||
} catch (AuthorizationDeniedException ade) {
|
} catch (AuthorizationDeniedException ade) {
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertTrue(ticket.isGranted());
|
assertTrue(ticket.isGranted());
|
||||||
}
|
}
|
||||||
|
|
||||||
response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
|
response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
|
||||||
rpt = response.getToken();
|
rpt = response.getToken();
|
||||||
|
|
||||||
assertNotNull(rpt);
|
assertNotNull(rpt);
|
||||||
|
@ -180,7 +180,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
resource = addResource("Resource A", "marta", true);
|
resource = addResource("Resource A", "marta", true);
|
||||||
|
|
||||||
permission.setName(resource.getName() + " Permission");
|
permission.setName(resource.getName() + " Permission");
|
||||||
permission.addResource(resource.getName());
|
permission.addResource(resource.getId());
|
||||||
permission.addPolicy("Only Owner Policy");
|
permission.addPolicy("Only Owner Policy");
|
||||||
|
|
||||||
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
||||||
|
@ -203,7 +203,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertTrue(permissions.isEmpty());
|
assertTrue(permissions.isEmpty());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = authorize("kolo", "password", "Resource A", new String[] {});
|
response = authorize("kolo", "password", resource.getId(), new String[] {});
|
||||||
fail("User should have access to resource from another user");
|
fail("User should have access to resource from another user");
|
||||||
} catch (AuthorizationDeniedException ade) {
|
} catch (AuthorizationDeniedException ade) {
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertTrue(ticket.isGranted());
|
assertTrue(ticket.isGranted());
|
||||||
}
|
}
|
||||||
|
|
||||||
response = authorize("kolo", "password", resource.getName(), new String[] {});
|
response = authorize("kolo", "password", resource.getId(), new String[] {});
|
||||||
rpt = response.getToken();
|
rpt = response.getToken();
|
||||||
|
|
||||||
assertNotNull(rpt);
|
assertNotNull(rpt);
|
||||||
|
@ -249,7 +249,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertPermissions(permissions, resource.getName());
|
assertPermissions(permissions, resource.getName());
|
||||||
assertTrue(permissions.isEmpty());
|
assertTrue(permissions.isEmpty());
|
||||||
|
|
||||||
response = authorize("kolo", "password", resource.getName(), new String[] {});
|
response = authorize("kolo", "password", resource.getId(), new String[] {});
|
||||||
rpt = response.getToken();
|
rpt = response.getToken();
|
||||||
|
|
||||||
assertNotNull(rpt);
|
assertNotNull(rpt);
|
||||||
|
@ -282,7 +282,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
|
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
|
||||||
|
|
||||||
permission.setName(resource.getName() + " Permission");
|
permission.setName(resource.getName() + " Permission");
|
||||||
permission.addResource(resource.getName());
|
permission.addResource(resource.getId());
|
||||||
permission.addPolicy("Only Owner Policy");
|
permission.addPolicy("Only Owner Policy");
|
||||||
|
|
||||||
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
|
||||||
|
@ -305,7 +305,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
assertTrue(permissions.isEmpty());
|
assertTrue(permissions.isEmpty());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = authorize("kolo", "password", "Resource A", new String[] {"ScopeA"});
|
response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA"});
|
||||||
fail("User should have access to resource from another user");
|
fail("User should have access to resource from another user");
|
||||||
} catch (AuthorizationDeniedException ade) {
|
} catch (AuthorizationDeniedException ade) {
|
||||||
|
|
||||||
|
@ -324,7 +324,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
|
||||||
|
|
||||||
permissionResource.update(ticket);
|
permissionResource.update(ticket);
|
||||||
|
|
||||||
response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
|
response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
|
||||||
rpt = response.getToken();
|
rpt = response.getToken();
|
||||||
|
|
||||||
assertNotNull(rpt);
|
assertNotNull(rpt);
|
||||||
|
|
Loading…
Reference in a new issue