[KEYCLOAK-9600] - Find by name in authz client returning wrong resource

This commit is contained in:
Pedro Igor 2019-12-19 18:25:49 -03:00 committed by Stian Thorgersen
parent 00a36e5f7b
commit 658a083a0c
6 changed files with 70 additions and 16 deletions

View file

@ -128,7 +128,7 @@ public class ProtectedResource {
* @return a {@link ResourceRepresentation}
*/
public ResourceRepresentation findByName(String name) {
List<ResourceRepresentation> representations = find(null, name, null, configuration.getResource(), null, null, false, true, null, null);
List<ResourceRepresentation> representations = find(null, name, null, configuration.getResource(), null, null, false, true, true, null, null);
if (representations.isEmpty()) {
return null;
@ -145,7 +145,7 @@ public class ProtectedResource {
* @return a {@link ResourceRepresentation}
*/
public ResourceRepresentation findByName(String name, String ownerId) {
List<ResourceRepresentation> representations = find(null, name, null, ownerId, null, null, false, true,null, null);
List<ResourceRepresentation> representations = find(null, name, null, ownerId, null, null, false, true, true, null, null);
if (representations.isEmpty()) {
return null;
@ -172,7 +172,7 @@ public class ProtectedResource {
Callable<String[]> callable = new Callable<String[]>() {
@Override
public String[] call() throws Exception {
return (String[]) createFindRequest(id, name, uri, owner, type, scope, matchingUri, false, firstResult, maxResult).response().json(String[].class).execute();
return (String[]) createFindRequest(id, name, uri, owner, type, scope, matchingUri, false, false, firstResult, maxResult).response().json(String[].class).execute();
}
};
try {
@ -183,8 +183,8 @@ public class ProtectedResource {
}
/**
* Query the server for any resource with the matching arguments.
*
* <p>Query the server for any resource with the matching arguments, where queries by name are partial.
*
* @param id the resource id
* @param name the resource name
* @param uri the resource uri
@ -198,11 +198,31 @@ public class ProtectedResource {
* @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) {
return find(id, name, uri, owner, type, scope, matchingUri, false, deep, firstResult, maxResult);
}
/**
* 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 exactName if the the {@code name} provided should have a exact match
* @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 exactName, 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>>() {
return (List<ResourceRepresentation>) createFindRequest(id, name, uri, owner, type, scope, matchingUri, exactName, deep, firstResult, maxResult).response().json(new TypeReference<List<ResourceRepresentation>>() {
}).execute();
}
};
@ -257,7 +277,7 @@ public class ProtectedResource {
* @param uri the resource uri
*/
public List<ResourceRepresentation> findByUri(String uri) {
return find(null, null, uri, null, null, null, false, true, null, null);
return find(null, null, uri, null, null, null, false, false, true, null, null);
}
/**
@ -268,10 +288,10 @@ public class ProtectedResource {
* @return a list of resources
*/
public List<ResourceRepresentation> findByMatchingUri(String uri) {
return find(null, null, uri, null, null, null, true, true,null, null);
return find(null, null, uri, null, null, null, true, false, true,null, null);
}
private HttpMethod createFindRequest(String id, String name, String uri, String owner, String type, String scope, boolean matchingUri, boolean deep, Integer firstResult, Integer maxResult) {
private HttpMethod createFindRequest(String id, String name, String uri, String owner, String type, String scope, boolean matchingUri, boolean exactName, boolean deep, Integer firstResult, Integer maxResult) {
return http.get(serverConfiguration.getResourceRegistrationEndpoint())
.authorizationBearer(pat.call())
.param("_id", id)
@ -281,6 +301,7 @@ public class ProtectedResource {
.param("type", type)
.param("scope", scope)
.param("matchingUri", Boolean.valueOf(matchingUri).toString())
.param("exactName", Boolean.valueOf(exactName).toString())
.param("deep", Boolean.toString(deep))
.param("first", firstResult != null ? firstResult.toString() : null)
.param("max", maxResult != null ? maxResult.toString() : Integer.toString(-1));

View file

@ -217,9 +217,9 @@ public class JPAResourceStore implements ResourceStore {
predicates.add(root.get(name).in(value));
} else if ("scope".equals(name)) {
predicates.add(root.join("scopes").get("id").in(value));
} else if ("ownerManagedAccess".equals(name)) {
} else if ("ownerManagedAccess".equals(name) && value.length > 0) {
predicates.add(builder.equal(root.get(name), Boolean.valueOf(value[0])));
} else if ("uri".equals(name)) {
} else if ("uri".equals(name) && value.length > 0 && value[0] != null) {
predicates.add(builder.lower(root.join("uris")).in(value[0].toLowerCase()));
} else if ("uri_not_null".equals(name)) {
// predicates.add(builder.isNotEmpty(root.get("uris"))); looks like there is a bug in hibernate and this line doesn't work: https://hibernate.atlassian.net/browse/HHH-6686
@ -228,8 +228,13 @@ public class JPAResourceStore implements ResourceStore {
predicates.add(builder.notEqual(urisSize, 0));
} else if ("owner".equals(name)) {
predicates.add(root.get(name).in(value));
} else {
predicates.add(builder.like(builder.lower(root.get(name)), "%" + value[0].toLowerCase() + "%"));
} else if (!Resource.EXACT_NAME.equals(name)) {
if ("name".equals(name) && attributes.containsKey(Resource.EXACT_NAME) && Boolean.valueOf(attributes.get(Resource.EXACT_NAME)[0])
&& value.length > 0 && value[0] != null) {
predicates.add(builder.equal(builder.lower(root.get(name)), value[0].toLowerCase()));
} else if (value.length > 0 && value[0] != null) {
predicates.add(builder.like(builder.lower(root.get(name)), "%" + value[0].toLowerCase() + "%"));
}
}
});

View file

@ -29,6 +29,8 @@ import java.util.Set;
*/
public interface Resource {
String EXACT_NAME = "EXACT_NAME";
/**
* Returns the unique identifier for this instance.
*

View file

@ -335,10 +335,11 @@ public class ResourceSetService {
@QueryParam("type") String type,
@QueryParam("scope") String scope,
@QueryParam("matchingUri") Boolean matchingUri,
@QueryParam("exactName") Boolean exactName,
@QueryParam("deep") Boolean deep,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult) {
return find(id, name, uri, owner, type, scope, matchingUri, deep, firstResult, maxResult, (BiFunction<Resource, Boolean, ResourceRepresentation>) (resource, deep1) -> toRepresentation(resource, resourceServer, authorization, deep1));
return find(id, name, uri, owner, type, scope, matchingUri, exactName, deep, firstResult, maxResult, (BiFunction<Resource, Boolean, ResourceRepresentation>) (resource, deep1) -> toRepresentation(resource, resourceServer, authorization, deep1));
}
public Response find(@QueryParam("_id") String id,
@ -348,6 +349,7 @@ public class ResourceSetService {
@QueryParam("type") String type,
@QueryParam("scope") String scope,
@QueryParam("matchingUri") Boolean matchingUri,
@QueryParam("exactName") Boolean exactName,
@QueryParam("deep") Boolean deep,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult,
@ -368,6 +370,10 @@ public class ResourceSetService {
if (name != null && !"".equals(name.trim())) {
search.put("name", new String[] {name});
if (exactName != null && exactName) {
search.put(Resource.EXACT_NAME, new String[] {Boolean.TRUE.toString()});
}
}
if (uri != null && !"".equals(uri.trim())) {

View file

@ -123,14 +123,15 @@ public class ResourceService {
@QueryParam("type") String type,
@QueryParam("scope") String scope,
@QueryParam("matchingUri") Boolean matchingUri,
@QueryParam("exactName") Boolean exactName,
@QueryParam("deep") Boolean deep,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResult) {
if(deep != null && deep) {
return resourceManager.find(id, name, uri, owner, type, scope, matchingUri, deep, firstResult, maxResult);
return resourceManager.find(id, name, uri, owner, type, scope, matchingUri, exactName, 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());
return resourceManager.find(id, name, uri, owner, type, scope, matchingUri, exactName, deep, firstResult, maxResult, (BiFunction<Resource, Boolean, String>) (resource, deep1) -> resource.getId());
}
}

View file

@ -18,6 +18,7 @@ package org.keycloak.testsuite.authz;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@ -229,6 +230,24 @@ public class AuthzClientCredentialsTest extends AbstractAuthzTest {
assertEquals(1, userSessions.size());
}
@Test
public void testFindByName() {
AuthzClient authzClient = getAuthzClient("default-session-keycloak.json");
ProtectionResource protection = authzClient.protection();
protection.resource().create(new ResourceRepresentation("Admin Resources"));
protection.resource().create(new ResourceRepresentation("Resource"));
ResourceRepresentation resource = authzClient.protection().resource().findByName("Resource");
assertEquals("Resource", resource.getName());
ResourceRepresentation adminResource = authzClient.protection().resource().findByName("Admin Resources");
assertEquals("Admin Resources", adminResource.getName());
assertNotEquals(resource.getId(), adminResource.getId());
}
private RealmBuilder configureRealm(RealmBuilder builder, ClientBuilder clientBuilder) {
return builder
.roles(RolesBuilder.create().realmRole(new RoleRepresentation("uma_authorization", "", false)))