diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
index 80c9e42..72cd7aa 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
@@ -17,14 +17,14 @@
*/
package org.keycloak.authorization.client.resource;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
+import com.fasterxml.jackson.core.type.TypeReference;
import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.util.Http;
+import org.keycloak.authorization.client.util.HttpMethod;
import org.keycloak.authorization.client.util.Throwables;
import org.keycloak.authorization.client.util.TokenCallable;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
@@ -128,13 +128,13 @@ public class ProtectedResource {
* @return a {@link ResourceRepresentation}
*/
public ResourceRepresentation findByName(String name) {
- String[] representations = find(null, name, null, configuration.getResource(), null, null, false, null, null);
+ List<ResourceRepresentation> representations = find(null, name, null, configuration.getResource(), null, null, false, true, null, null);
- if (representations.length == 0) {
+ if (representations.isEmpty()) {
return null;
}
- return findById(representations[0]);
+ return representations.get(0);
}
/**
@@ -145,13 +145,13 @@ public class ProtectedResource {
* @return a {@link ResourceRepresentation}
*/
public ResourceRepresentation findByName(String name, String ownerId) {
- String[] representations = find(null, name, null, ownerId, null, null, false, null, null);
+ List<ResourceRepresentation> representations = find(null, name, null, ownerId, null, null, false, true,null, null);
- if (representations.length == 0) {
+ if (representations.isEmpty()) {
return null;
}
- return findById(representations[0]);
+ return representations.get(0);
}
/**
@@ -172,19 +172,7 @@ public class ProtectedResource {
Callable<String[]> callable = new Callable<String[]>() {
@Override
public String[] call() throws Exception {
- return http.<String[]>get(serverConfiguration.getResourceRegistrationEndpoint())
- .authorizationBearer(pat.call())
- .param("_id", id)
- .param("name", name)
- .param("uri", uri)
- .param("owner", owner)
- .param("type", type)
- .param("scope", scope)
- .param("matchingUri", Boolean.valueOf(matchingUri).toString())
- .param("deep", Boolean.FALSE.toString())
- .param("first", firstResult != null ? firstResult.toString() : null)
- .param("max", maxResult != null ? maxResult.toString() : null)
- .response().json(String[].class).execute();
+ return (String[]) createFindRequest(id, name, uri, owner, type, scope, matchingUri, false, firstResult, maxResult).response().json(String[].class).execute();
}
};
try {
@@ -195,6 +183,40 @@ public class ProtectedResource {
}
/**
+ * Query the server for any resource with the matching arguments.
+ *
+ * @param id the resource id
+ * @param name the resource name
+ * @param uri the resource uri
+ * @param owner the resource owner
+ * @param type the resource type
+ * @param scope the resource scope
+ * @param matchingUri the resource uri. Use this parameter to lookup a resource that best match the given uri
+ * @param deep if the result should be a list of resource representations with details about the resource. If false, only ids are returned
+ * @param firstResult the position of the first resource to retrieve
+ * @param maxResult the maximum number of resources to retrieve
+ * @return a list of resource representations or an array of strings representing resource ids, depending on the generic type
+ */
+ public <R> R find(final String id, final String name, final String uri, final String owner, final String type, final String scope, final boolean matchingUri, final boolean deep, final Integer firstResult, final Integer maxResult) {
+ if (deep) {
+ Callable<List<ResourceRepresentation>> callable = new Callable<List<ResourceRepresentation>>() {
+ @Override
+ public List<ResourceRepresentation> call() {
+ return (List<ResourceRepresentation>) createFindRequest(id, name, uri, owner, type, scope, matchingUri, deep, firstResult, maxResult).response().json(new TypeReference<List<ResourceRepresentation>>() {
+ }).execute();
+ }
+ };
+ try {
+ return (R) callable.call();
+ } catch (Exception cause) {
+ return (R) Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Could not find resource", cause);
+ }
+ }
+
+ return (R) find(id, name, uri, owner, type, scope, matchingUri, firstResult, maxResult);
+ }
+
+ /**
* Query the server for all resources.
*
* @return @return an array of strings with the resource ids
@@ -235,19 +257,7 @@ public class ProtectedResource {
* @param uri the resource uri
*/
public List<ResourceRepresentation> findByUri(String uri) {
- String[] ids = find(null, null, uri, null, null, null, false, null, null);
-
- if (ids.length == 0) {
- return Collections.emptyList();
- }
-
- List<ResourceRepresentation> representations = new ArrayList<>();
-
- for (String id : ids) {
- representations.add(findById(id));
- }
-
- return representations;
+ return find(null, null, uri, null, null, null, false, true, null, null);
}
/**
@@ -258,18 +268,21 @@ public class ProtectedResource {
* @return a list of resources
*/
public List<ResourceRepresentation> findByMatchingUri(String uri) {
- String[] ids = find(null, null, uri, null, null, null, true, null, null);
-
- if (ids.length == 0) {
- return Collections.emptyList();
- }
-
- List<ResourceRepresentation> representations = new ArrayList<>();
-
- for (String id : ids) {
- representations.add(findById(id));
- }
+ return find(null, null, uri, null, null, null, true, true,null, null);
+ }
- return representations;
+ private HttpMethod createFindRequest(String id, String name, String uri, String owner, String type, String scope, boolean matchingUri, boolean deep, Integer firstResult, Integer maxResult) {
+ return http.get(serverConfiguration.getResourceRegistrationEndpoint())
+ .authorizationBearer(pat.call())
+ .param("_id", id)
+ .param("name", name)
+ .param("uri", uri)
+ .param("owner", owner)
+ .param("type", type)
+ .param("scope", scope)
+ .param("matchingUri", Boolean.valueOf(matchingUri).toString())
+ .param("deep", Boolean.toString(deep))
+ .param("first", firstResult != null ? firstResult.toString() : null)
+ .param("max", maxResult != null ? maxResult.toString() : null);
}
}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java b/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
index 4368a9a..de83a61 100644
--- a/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
+++ b/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
@@ -128,7 +128,12 @@ public class ResourceService {
@QueryParam("deep") Boolean deep,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult) {
- return resourceManager.find(id, name, uri, owner, type, scope, matchingUri, deep, firstResult, maxResult, (BiFunction<Resource, Boolean, String>) (resource, deep1) -> resource.getId());
+
+ if(deep != null && deep) {
+ return resourceManager.find(id, name, uri, owner, type, scope, matchingUri, deep, firstResult, maxResult);
+ } else {
+ return resourceManager.find(id, name, uri, owner, type, scope, matchingUri, deep, firstResult, maxResult, (BiFunction<Resource, Boolean, String>) (resource, deep1) -> resource.getId());
+ }
}
private void checkResourceServerSettings() {
@@ -136,4 +141,4 @@ public class ResourceService {
throw new ErrorResponseException("not_supported", "Remote management is disabled.", Status.BAD_REQUEST);
}
}
-}
\ No newline at end of file
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementWithAuthzClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementWithAuthzClientTest.java
index 5800071..1855f9e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementWithAuthzClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementWithAuthzClientTest.java
@@ -19,12 +19,22 @@ package org.keycloak.testsuite.admin.client.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.hamcrest.collection.IsMapContaining;
import org.junit.Test;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.Configuration;
@@ -96,6 +106,36 @@ public class ResourceManagementWithAuthzClientTest extends ResourceManagementTes
assertEquals("/resources/{pattern}/sub-resources/{pattern}/*", resources.get(0).getUri());
}
+ @Test
+ public void testFindDeep() {
+ ResourceRepresentation resource1 = new ResourceRepresentation("/*", new HashSet<>());
+
+ resource1.addScope("a", "b", "c");
+ resource1.setType("type");
+
+ Map<String, List<String>> attributes = new HashMap<>();
+
+ attributes.put("a", Arrays.asList("a"));
+ attributes.put("b", Arrays.asList("b"));
+ attributes.put("c", Arrays.asList("c"));
+
+ resource1.setAttributes(attributes);
+
+ resource1.setIconUri("icon");
+ resource1.setUris(new HashSet<>(Arrays.asList("/a", "/b", "/c")));
+
+ ResourceRepresentation resource = doCreateResource(resource1);
+ AuthzClient authzClient = getAuthzClient();
+ List<ResourceRepresentation> representations = authzClient.protection().resource().find(resource.getId(), null, null, null, null, null, false, true,null, null);
+
+ assertEquals(1, representations.size());
+ assertEquals(resource.getId(), representations.get(0).getId());
+ assertEquals(resource.getName(), representations.get(0).getName());
+ assertEquals(resource.getIconUri(), representations.get(0).getIconUri());
+ assertThat(resource.getUris(), Matchers.containsInAnyOrder(representations.get(0).getUris().toArray()));
+ assertThat(resource.getAttributes().entrySet(), Matchers.containsInAnyOrder(representations.get(0).getAttributes().entrySet().toArray()));
+ }
+
@Override
protected ResourceRepresentation doCreateResource(ResourceRepresentation newResource) {
ResourceRepresentation resource = toResourceRepresentation(newResource);
@@ -127,7 +167,7 @@ public class ResourceManagementWithAuthzClientTest extends ResourceManagementTes
resourceRepresentation.setId(created.getId());
resourceRepresentation.setName(created.getName());
resourceRepresentation.setIconUri(created.getIconUri());
- resourceRepresentation.setUri(created.getUri());
+ resourceRepresentation.setUris(created.getUris());
resourceRepresentation.setType(created.getType());
resourceRepresentation.setOwner(created.getOwner());
resourceRepresentation.setScopes(created.getScopes().stream().map(scopeRepresentation -> {
@@ -151,7 +191,13 @@ public class ResourceManagementWithAuthzClientTest extends ResourceManagementTes
resource.setId(newResource.getId());
resource.setName(newResource.getName());
resource.setIconUri(newResource.getIconUri());
- resource.setUri(newResource.getUri());
+
+ if (newResource.getUris() != null && !newResource.getUris().isEmpty()) {
+ resource.setUris(newResource.getUris());
+ } else {
+ resource.setUri(newResource.getUri());
+ }
+
resource.setType(newResource.getType());
if (newResource.getOwner() != null) {
@@ -169,6 +215,7 @@ public class ResourceManagementWithAuthzClientTest extends ResourceManagementTes
resource.setAttributes(newResource.getAttributes());
+
return resource;
}