mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Merge branch '3.5.x' into 4.0.x
Closes gh-50017
This commit is contained in:
+32
-3
@@ -162,15 +162,40 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
.jsonPath("_links.length()")
|
||||
.isEqualTo(3)
|
||||
.jsonPath("_links.self.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/endpoints"))
|
||||
.jsonPath("_links.self.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/endpoints/test"))
|
||||
.jsonPath("_links.test.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test-part.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/endpoints/test/{part}"))
|
||||
.jsonPath("_links.test-part.templated")
|
||||
.isEqualTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenRequestHasAQueryStringLinksToOtherEndpointsDoNotHaveAQueryString() {
|
||||
load(TestEndpointConfiguration.class,
|
||||
(client) -> client.get()
|
||||
.uri("?a=alpha")
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody()
|
||||
.jsonPath("_links.length()")
|
||||
.isEqualTo(3)
|
||||
.jsonPath("_links.self.href")
|
||||
.value(isLinkTo("/endpoints"))
|
||||
.jsonPath("_links.self.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test.href")
|
||||
.value(isLinkTo("/endpoints/test"))
|
||||
.jsonPath("_links.test.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test-part.href")
|
||||
.value(isLinkTo("/endpoints/test/{part}"))
|
||||
.jsonPath("_links.test-part.templated")
|
||||
.isEqualTo(true));
|
||||
}
|
||||
@@ -668,6 +693,10 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
||||
(client) -> client.get().uri("/customstatus").exchange().expectStatus().isEqualTo(234));
|
||||
}
|
||||
|
||||
private Consumer<Object> isLinkTo(String target) {
|
||||
return (href) -> assertThat(href).asString().doesNotContain("?").endsWith(target);
|
||||
}
|
||||
|
||||
protected abstract int getPort(T context);
|
||||
|
||||
protected void validateErrorBody(WebTestClient.BodyContentSpec body, HttpStatus status, String path,
|
||||
|
||||
+3
-1
@@ -50,6 +50,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* A custom {@link RequestMappingInfoHandlerMapping} that makes web endpoints available on
|
||||
@@ -111,8 +112,9 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH
|
||||
return new ResponseEntity<>(securityResponse.getStatus());
|
||||
}
|
||||
AccessLevel accessLevel = exchange.getAttribute(AccessLevel.REQUEST_ATTRIBUTE);
|
||||
String requestUri = UriComponentsBuilder.fromUri(request.getURI()).replaceQuery(null).toUriString();
|
||||
Map<String, Link> links = CloudFoundryWebFluxEndpointHandlerMapping.this.linksResolver
|
||||
.resolveLinks(request.getURI().toString());
|
||||
.resolveLinks(requestUri);
|
||||
return new ResponseEntity<>(
|
||||
Collections.singletonMap("_links", getAccessibleLinks(accessLevel, links)), HttpStatus.OK);
|
||||
});
|
||||
|
||||
+29
-7
@@ -147,23 +147,23 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
|
||||
.jsonPath("_links.length()")
|
||||
.isEqualTo(5)
|
||||
.jsonPath("_links.self.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication"))
|
||||
.jsonPath("_links.self.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.info.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/info"))
|
||||
.jsonPath("_links.info.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.env.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/env"))
|
||||
.jsonPath("_links.env.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/test"))
|
||||
.jsonPath("_links.test.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test-part.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/test/{part}"))
|
||||
.jsonPath("_links.test-part.templated")
|
||||
.isEqualTo(true)));
|
||||
}
|
||||
@@ -197,11 +197,11 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
|
||||
.jsonPath("_links.length()")
|
||||
.isEqualTo(2)
|
||||
.jsonPath("_links.self.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication"))
|
||||
.jsonPath("_links.self.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.info.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/info"))
|
||||
.jsonPath("_links.info.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.env")
|
||||
@@ -212,12 +212,34 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
|
||||
.doesNotExist()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenRequestHasAQueryStringLinksToOtherEndpointsDoNotHaveAQueryString() {
|
||||
given(this.tokenValidator.validate(any())).willReturn(Mono.empty());
|
||||
given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.RESTRICTED));
|
||||
this.contextRunner.run(withWebTestClient((client) -> client.get()
|
||||
.uri("/cfApplication?x=1")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken())
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody()
|
||||
.jsonPath("_links.self.href")
|
||||
.value(isLinkTo("/cfApplication"))
|
||||
.jsonPath("_links.info.href")
|
||||
.value(isLinkTo("/cfApplication/info"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void unknownEndpointsAreForbidden() {
|
||||
this.contextRunner.run(withWebTestClient(
|
||||
(client) -> client.get().uri("/cfApplication/unknown").exchange().expectStatus().isForbidden()));
|
||||
}
|
||||
|
||||
private Consumer<Object> isLinkTo(String target) {
|
||||
return (href) -> assertThat(href).asString().doesNotContain("?").endsWith(target);
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableReactiveWebApplicationContext> withWebTestClient(
|
||||
Consumer<WebTestClient> clientConsumer) {
|
||||
return (context) -> {
|
||||
|
||||
+29
-7
@@ -135,23 +135,23 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
.jsonPath("_links.length()")
|
||||
.isEqualTo(5)
|
||||
.jsonPath("_links.self.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication"))
|
||||
.jsonPath("_links.self.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.info.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/info"))
|
||||
.jsonPath("_links.info.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.env.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/env"))
|
||||
.jsonPath("_links.env.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/test"))
|
||||
.jsonPath("_links.test.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.test-part.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/test/{part}"))
|
||||
.jsonPath("_links.test-part.templated")
|
||||
.isEqualTo(true));
|
||||
}
|
||||
@@ -186,11 +186,11 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
.jsonPath("_links.length()")
|
||||
.isEqualTo(2)
|
||||
.jsonPath("_links.self.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication"))
|
||||
.jsonPath("_links.self.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.info.href")
|
||||
.isNotEmpty()
|
||||
.value(isLinkTo("/cfApplication/info"))
|
||||
.jsonPath("_links.info.templated")
|
||||
.isEqualTo(false)
|
||||
.jsonPath("_links.env")
|
||||
@@ -201,6 +201,24 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
.doesNotExist());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenRequestHasAQueryStringLinksToOtherEndpointsDoNotHaveAQueryString() {
|
||||
given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.RESTRICTED);
|
||||
load(TestEndpointConfiguration.class,
|
||||
(client) -> client.get()
|
||||
.uri("/cfApplication?x=1")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken())
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody()
|
||||
.jsonPath("_links.self.href")
|
||||
.value(isLinkTo("/cfApplication"))
|
||||
.jsonPath("_links.info.href")
|
||||
.value(isLinkTo("/cfApplication/info")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void unknownEndpointsAreForbidden() {
|
||||
load(TestEndpointConfiguration.class,
|
||||
@@ -212,6 +230,10 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
.isForbidden());
|
||||
}
|
||||
|
||||
private Consumer<Object> isLinkTo(String target) {
|
||||
return (href) -> assertThat(href).asString().doesNotContain("?").endsWith(target);
|
||||
}
|
||||
|
||||
private void load(Class<?> configuration, Consumer<WebTestClient> clientConsumer) {
|
||||
BiConsumer<ApplicationContext, WebTestClient> consumer = (context, client) -> clientConsumer.accept(client);
|
||||
new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
|
||||
Reference in New Issue
Block a user