Properly encode id in URL

Closes: #19816
This commit is contained in:
Hynek Mlnarik 2023-04-03 17:33:49 +02:00 committed by Pedro Igor
parent 687c3868c1
commit 0ddc71d987
3 changed files with 28 additions and 24 deletions

View file

@ -26,6 +26,7 @@ import org.keycloak.authorization.client.util.Throwables;
import org.keycloak.authorization.client.util.TokenCallable; import org.keycloak.authorization.client.util.TokenCallable;
import org.keycloak.representations.idm.authorization.UmaPermissionRepresentation; import org.keycloak.representations.idm.authorization.UmaPermissionRepresentation;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import static org.keycloak.common.util.Encode.encodePathAsIs;
/** /**
* An entry point for managing user-managed permissions for a particular resource * An entry point for managing user-managed permissions for a particular resource
@ -60,7 +61,7 @@ public class PolicyResource {
Callable<UmaPermissionRepresentation> callable = new Callable<UmaPermissionRepresentation>() { Callable<UmaPermissionRepresentation> callable = new Callable<UmaPermissionRepresentation>() {
@Override @Override
public UmaPermissionRepresentation call() throws Exception { public UmaPermissionRepresentation call() throws Exception {
return http.<UmaPermissionRepresentation>post(serverConfiguration.getPolicyEndpoint() + "/" + resourceId) return http.<UmaPermissionRepresentation>post(serverConfiguration.getPolicyEndpoint() + "/" + encodePathAsIs(resourceId))
.authorizationBearer(pat.call()) .authorizationBearer(pat.call())
.json(JsonSerialization.writeValueAsBytes(permission)) .json(JsonSerialization.writeValueAsBytes(permission))
.response().json(UmaPermissionRepresentation.class).execute(); .response().json(UmaPermissionRepresentation.class).execute();
@ -90,7 +91,7 @@ public class PolicyResource {
Callable<Void> callable = new Callable<Void>() { Callable<Void> callable = new Callable<Void>() {
@Override @Override
public Void call() throws Exception { public Void call() throws Exception {
http.<Void>put(serverConfiguration.getPolicyEndpoint() + "/"+ permission.getId()) http.<Void>put(serverConfiguration.getPolicyEndpoint() + "/"+ encodePathAsIs(permission.getId()))
.authorizationBearer(pat.call()) .authorizationBearer(pat.call())
.json(JsonSerialization.writeValueAsBytes(permission)).execute(); .json(JsonSerialization.writeValueAsBytes(permission)).execute();
return null; return null;
@ -112,7 +113,7 @@ public class PolicyResource {
Callable<Void> callable = new Callable<Void>() { Callable<Void> callable = new Callable<Void>() {
@Override @Override
public Void call() { public Void call() {
http.<UmaPermissionRepresentation>delete(serverConfiguration.getPolicyEndpoint() + "/" + id) http.<UmaPermissionRepresentation>delete(serverConfiguration.getPolicyEndpoint() + "/" + encodePathAsIs(id))
.authorizationBearer(pat.call()) .authorizationBearer(pat.call())
.response().execute(); .response().execute();
return null; return null;
@ -173,7 +174,7 @@ public class PolicyResource {
Callable<UmaPermissionRepresentation> callable = new Callable<UmaPermissionRepresentation>() { Callable<UmaPermissionRepresentation> callable = new Callable<UmaPermissionRepresentation>() {
@Override @Override
public UmaPermissionRepresentation call() { public UmaPermissionRepresentation call() {
return http.<UmaPermissionRepresentation>get(serverConfiguration.getPolicyEndpoint() + "/" + id) return http.<UmaPermissionRepresentation>get(serverConfiguration.getPolicyEndpoint() + "/" + encodePathAsIs(id))
.authorizationBearer(pat.call()) .authorizationBearer(pat.call())
.response().json(UmaPermissionRepresentation.class).execute(); .response().json(UmaPermissionRepresentation.class).execute();
} }

View file

@ -29,6 +29,7 @@ import org.keycloak.authorization.client.util.Throwables;
import org.keycloak.authorization.client.util.TokenCallable; import org.keycloak.authorization.client.util.TokenCallable;
import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import static org.keycloak.common.util.Encode.encodePathAsIs;
/** /**
* An entry point for managing resources using the Protection API. * An entry point for managing resources using the Protection API.
@ -86,7 +87,7 @@ public class ProtectedResource {
Callable callable = new Callable() { Callable callable = new Callable() {
@Override @Override
public Object call() throws Exception { public Object call() throws Exception {
http.<ResourceRepresentation>put(serverConfiguration.getResourceRegistrationEndpoint() + "/" + resource.getId()) http.<ResourceRepresentation>put(serverConfiguration.getResourceRegistrationEndpoint() + "/" + encodePathAsIs(resource.getId()))
.authorizationBearer(pat.call()) .authorizationBearer(pat.call())
.json(JsonSerialization.writeValueAsBytes(resource)).execute(); .json(JsonSerialization.writeValueAsBytes(resource)).execute();
return null; return null;
@ -109,7 +110,7 @@ public class ProtectedResource {
Callable<ResourceRepresentation> callable = new Callable<ResourceRepresentation>() { Callable<ResourceRepresentation> callable = new Callable<ResourceRepresentation>() {
@Override @Override
public ResourceRepresentation call() throws Exception { public ResourceRepresentation call() throws Exception {
return http.<ResourceRepresentation>get(serverConfiguration.getResourceRegistrationEndpoint() + "/" + id) return http.<ResourceRepresentation>get(serverConfiguration.getResourceRegistrationEndpoint() + "/" + encodePathAsIs(id))
.authorizationBearer(pat.call()) .authorizationBearer(pat.call())
.response().json(ResourceRepresentation.class).execute(); .response().json(ResourceRepresentation.class).execute();
} }
@ -258,7 +259,7 @@ public class ProtectedResource {
Callable callable = new Callable() { Callable callable = new Callable() {
@Override @Override
public Object call() throws Exception { public Object call() throws Exception {
http.delete(serverConfiguration.getResourceRegistrationEndpoint() + "/" + id) http.delete(serverConfiguration.getResourceRegistrationEndpoint() + "/" + encodePathAsIs(id))
.authorizationBearer(pat.call()) .authorizationBearer(pat.call())
.execute(); .execute();
return null; return null;

View file

@ -59,12 +59,14 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.keycloak.common.util.Encode.encodePathAsIs;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -302,7 +304,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
@Test @Test
public void testGetResource() { public void testGetResource() {
Resource resource = doGet("/" + getMyResources().get(0).getId(), Resource.class); Resource resource = doGet("/" + encodePathAsIs(getMyResources().get(0).getId()), Resource.class);
String uri = resource.getUri(); String uri = resource.getUri();
int id = Integer.parseInt(uri.substring(uri.lastIndexOf('/') + 1)); int id = Integer.parseInt(uri.substring(uri.lastIndexOf('/') + 1));
@ -318,14 +320,14 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
OAuth2ErrorRepresentation response = doGet("/invalid_resource", OAuth2ErrorRepresentation.class); OAuth2ErrorRepresentation response = doGet("/invalid_resource", OAuth2ErrorRepresentation.class);
assertEquals("resource_not_found", response.getError()); assertEquals("resource_not_found", response.getError());
response = doGet("/" + getMyResources().get(0).getId(), authzClient.obtainAccessToken("jdoe", "password").getToken(), OAuth2ErrorRepresentation.class); response = doGet("/" + encodePathAsIs(getMyResources().get(0).getId()), authzClient.obtainAccessToken("jdoe", "password").getToken(), OAuth2ErrorRepresentation.class);
assertEquals("invalid_resource", response.getError()); assertEquals("invalid_resource", response.getError());
} }
@Test @Test
public void testGetPermissions() throws Exception { public void testGetPermissions() throws Exception {
Resource resource = getMyResources().get(0); Resource resource = getMyResources().get(0);
List<Permission> shares = doGet("/" + resource.getId() + "/permissions", new TypeReference<List<Permission>>() {}); List<Permission> shares = doGet("/" + encodePathAsIs(resource.getId()) + "/permissions", new TypeReference<List<Permission>>() {});
assertEquals(1, shares.size()); assertEquals(1, shares.size());
@ -348,11 +350,11 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
permissions.add(permission); permissions.add(permission);
} }
SimpleHttp.doPut(getAccountUrl("resources/" + resource.getId() + "/permissions"), httpClient) SimpleHttp.doPut(getAccountUrl("resources/" + encodePathAsIs(resource.getId()) + "/permissions"), httpClient)
.auth(tokenUtil.getToken()) .auth(tokenUtil.getToken())
.json(permissions).asResponse(); .json(permissions).asResponse();
shares = doGet("/" + resource.getId() + "/permissions", new TypeReference<List<Permission>>() {}); shares = doGet("/" + encodePathAsIs(resource.getId()) + "/permissions", new TypeReference<List<Permission>>() {});
assertEquals(3, shares.size()); assertEquals(3, shares.size());
@ -384,7 +386,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
permissions.add(new Permission(users.get(users.size() - 1), "Scope A", "Scope B", "Scope C", "Scope D")); permissions.add(new Permission(users.get(users.size() - 1), "Scope A", "Scope B", "Scope C", "Scope D"));
String resourceId = sharedResource.getId(); String resourceId = sharedResource.getId();
SimpleHttp.Response response = SimpleHttp.doPut(getAccountUrl("resources/" + resourceId + "/permissions"), httpClient) SimpleHttp.Response response = SimpleHttp.doPut(getAccountUrl("resources/" + encodePathAsIs(resourceId) + "/permissions"), httpClient)
.auth(tokenUtil.getToken()) .auth(tokenUtil.getToken())
.json(permissions).asResponse(); .json(permissions).asResponse();
@ -408,7 +410,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
public void failShareResourceInvalidPermissions() throws Exception { public void failShareResourceInvalidPermissions() throws Exception {
List<Permission> permissions = new ArrayList<>(); List<Permission> permissions = new ArrayList<>();
SimpleHttp.Response response = SimpleHttp.doPut(getAccountUrl("resources/" + getMyResources().get(0).getId() + "/permissions"), httpClient) SimpleHttp.Response response = SimpleHttp.doPut(getAccountUrl("resources/" + encodePathAsIs(getMyResources().get(0).getId()) + "/permissions"), httpClient)
.auth(tokenUtil.getToken()) .auth(tokenUtil.getToken())
.json(permissions).asResponse(); .json(permissions).asResponse();
@ -434,7 +436,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
final String resourcesUrl = getAccountUrl("resources"); final String resourcesUrl = getAccountUrl("resources");
final String sharedWithOthersUrl = resourcesUrl + "/shared-with-others"; final String sharedWithOthersUrl = resourcesUrl + "/shared-with-others";
final String sharedWithMeUrl = resourcesUrl + "/shared-with-me"; final String sharedWithMeUrl = resourcesUrl + "/shared-with-me";
final String resourceUrl = resourcesUrl + "/" + resourceId; final String resourceUrl = resourcesUrl + "/" + encodePathAsIs(resourceId);
final String permissionsUrl = resourceUrl + "/permissions"; final String permissionsUrl = resourceUrl + "/permissions";
final String requestsUrl = resourceUrl + "/permissions/requests"; final String requestsUrl = resourceUrl + "/permissions/requests";
@ -473,7 +475,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
permissions.add(new Permission(users.get(users.size() - 1), "Scope B", "Scope D")); permissions.add(new Permission(users.get(users.size() - 1), "Scope B", "Scope D"));
String resourceId = sharedResource.getId(); String resourceId = sharedResource.getId();
SimpleHttp.Response response = SimpleHttp.doPut(getAccountUrl("resources/" + resourceId + "/permissions"), httpClient) SimpleHttp.Response response = SimpleHttp.doPut(getAccountUrl("resources/" + encodePathAsIs(resourceId) + "/permissions"), httpClient)
.auth(tokenUtil.getToken()) .auth(tokenUtil.getToken())
.json(permissions).asResponse(); .json(permissions).asResponse();
@ -496,7 +498,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
@Test @Test
public void testGetPermissionRequests() { public void testGetPermissionRequests() {
Resource resource = getMyResources().get(0); Resource resource = getMyResources().get(0);
List<Permission> requests = doGet("/" + resource.getId() + "/permissions/requests", List<Permission> requests = doGet("/" + encodePathAsIs(resource.getId()) + "/permissions/requests",
new TypeReference<List<Permission>>() {}); new TypeReference<List<Permission>>() {});
assertTrue(requests.isEmpty()); assertTrue(requests.isEmpty());
@ -526,7 +528,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
} }
} }
requests = doGet("/" + resource.getId() + "/permissions/requests", requests = doGet("/" + encodePathAsIs(resource.getId()) + "/permissions/requests",
new TypeReference<List<Permission>>() {}); new TypeReference<List<Permission>>() {});
assertEquals(3, requests.size()); assertEquals(3, requests.size());
@ -560,7 +562,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
@Test @Test
public void testApprovePermissionRequest() throws IOException { public void testApprovePermissionRequest() throws IOException {
Resource resource = getMyResources().get(0); Resource resource = getMyResources().get(0);
List<Permission> requests = doGet("/" + resource.getId() + "/permissions/requests", List<Permission> requests = doGet("/" + encodePathAsIs(resource.getId()) + "/permissions/requests",
new TypeReference<List<Permission>>() {}); new TypeReference<List<Permission>>() {});
assertTrue(requests.isEmpty()); assertTrue(requests.isEmpty());
@ -590,7 +592,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
} }
} }
requests = doGet("/" + resource.getId() + "/permissions/requests", requests = doGet("/" + encodePathAsIs(resource.getId()) + "/permissions/requests",
new TypeReference<List<Permission>>() {}); new TypeReference<List<Permission>>() {});
assertEquals(3, requests.size()); assertEquals(3, requests.size());
@ -609,14 +611,14 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest {
} }
} }
SimpleHttp.doPut(getAccountUrl("resources/" + resource.getId() + "/permissions"), httpClient) SimpleHttp.doPut(getAccountUrl("resources/" + encodePathAsIs(resource.getId()) + "/permissions"), httpClient)
.auth(tokenUtil.getToken()) .auth(tokenUtil.getToken())
.json(requests).asResponse(); .json(requests).asResponse();
requests = doGet("/" + resource.getId() + "/permissions/requests", requests = doGet("/" + encodePathAsIs(resource.getId()) + "/permissions/requests",
new TypeReference<List<Permission>>() {}); new TypeReference<List<Permission>>() {});
assertTrue(requests.isEmpty()); assertThat(requests, empty());
for (String user : Arrays.asList("alice", "jdoe")) { for (String user : Arrays.asList("alice", "jdoe")) {
AbstractResourceService.ResourcePermission sharedResource = getSharedWithMe(user).stream() AbstractResourceService.ResourcePermission sharedResource = getSharedWithMe(user).stream()