Reject non-scalar endpoint parameter with Jersey
Actuator endpoints should only declare simple type in the signature of an operation. In particular, nested types are not supported. While this is enforced in Spring MVC and Spring Webflux, the Jersey implementation leniently allowed to bind such types prior to this commit. This commit adapts the expectation in the Jersey implementation so that it rejects such request as well. Closes gh-43209
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,6 +55,7 @@ import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -189,8 +190,10 @@ public class JerseyEndpointResourceFactory {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> extractBodyArguments(ContainerRequestContext data) {
|
||||
Map<String, Object> entity = ((ContainerRequest) data).readEntity(Map.class);
|
||||
private Map<String, String> extractBodyArguments(ContainerRequestContext data) {
|
||||
Map<String, String> entity = ((ContainerRequest) data).readEntity(Map.class,
|
||||
new ParameterizedTypeReference<Map<String, String>>() {
|
||||
}.getType());
|
||||
return (entity != null) ? entity : Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
@@ -314,6 +314,24 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeOperationWithListOfValuesIsRejected() {
|
||||
load(TestEndpointConfiguration.class, (client) -> {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("generic", List.of("one", "two"));
|
||||
client.post().uri("/test/one").bodyValue(body).exchange().expectStatus().isBadRequest();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeOperationWithNestedValueIsRejected() {
|
||||
load(TestEndpointConfiguration.class, (client) -> {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("generic", Map.of("nested", "one"));
|
||||
client.post().uri("/test/one").bodyValue(body).exchange().expectStatus().isBadRequest();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeOperationWithVoidResponse() {
|
||||
load(VoidWriteResponseEndpointConfiguration.class, (context, client) -> {
|
||||
@@ -968,6 +986,11 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
this.endpointDelegate.write(foo, bar);
|
||||
}
|
||||
|
||||
@WriteOperation
|
||||
void writeGeneric(@Selector String part, Object generic) {
|
||||
this.endpointDelegate.write(generic.toString(), generic.toString());
|
||||
}
|
||||
|
||||
@DeleteOperation
|
||||
Map<String, Object> deletePart(@Selector String part) {
|
||||
return Collections.singletonMap("part", part);
|
||||
|
||||
Reference in New Issue
Block a user