Skip to content

Commit 145ed26

Browse files
committed
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
1 parent 9f6b25e commit 145ed26

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/jersey/JerseyEndpointResourceFactory.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -55,6 +55,7 @@
5555
import org.springframework.boot.actuate.endpoint.web.WebOperation;
5656
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
5757
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
58+
import org.springframework.core.ParameterizedTypeReference;
5859
import org.springframework.util.AntPathMatcher;
5960
import org.springframework.util.ClassUtils;
6061
import org.springframework.util.CollectionUtils;
@@ -189,8 +190,10 @@ public Response apply(ContainerRequestContext data) {
189190
}
190191

191192
@SuppressWarnings("unchecked")
192-
private Map<String, Object> extractBodyArguments(ContainerRequestContext data) {
193-
Map<String, Object> entity = ((ContainerRequest) data).readEntity(Map.class);
193+
private Map<String, String> extractBodyArguments(ContainerRequestContext data) {
194+
Map<String, String> entity = ((ContainerRequest) data).readEntity(Map.class,
195+
new ParameterizedTypeReference<Map<String, String>>() {
196+
}.getType());
194197
return (entity != null) ? entity : Collections.emptyMap();
195198
}
196199

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,24 @@ void writeOperation() {
314314
});
315315
}
316316

317+
@Test
318+
void writeOperationWithListOfValuesIsRejected() {
319+
load(TestEndpointConfiguration.class, (client) -> {
320+
Map<String, Object> body = new HashMap<>();
321+
body.put("generic", List.of("one", "two"));
322+
client.post().uri("/test/one").bodyValue(body).exchange().expectStatus().isBadRequest();
323+
});
324+
}
325+
326+
@Test
327+
void writeOperationWithNestedValueIsRejected() {
328+
load(TestEndpointConfiguration.class, (client) -> {
329+
Map<String, Object> body = new HashMap<>();
330+
body.put("generic", Map.of("nested", "one"));
331+
client.post().uri("/test/one").bodyValue(body).exchange().expectStatus().isBadRequest();
332+
});
333+
}
334+
317335
@Test
318336
void writeOperationWithVoidResponse() {
319337
load(VoidWriteResponseEndpointConfiguration.class, (context, client) -> {
@@ -968,6 +986,11 @@ void write(@Nullable String foo, @Nullable String bar) {
968986
this.endpointDelegate.write(foo, bar);
969987
}
970988

989+
@WriteOperation
990+
void writeGeneric(@Selector String part, Object generic) {
991+
this.endpointDelegate.write(generic.toString(), generic.toString());
992+
}
993+
971994
@DeleteOperation
972995
Map<String, Object> deletePart(@Selector String part) {
973996
return Collections.singletonMap("part", part);

0 commit comments

Comments
 (0)