Merge branch '3.0.x' into 3.1.x

Closes gh-38365
This commit is contained in:
Andy Wilkinson 2023-11-15 16:00:05 +00:00
commit 37b2567aeb
2 changed files with 36 additions and 35 deletions

View File

@ -75,22 +75,23 @@ import static org.mockito.Mockito.mock;
*/ */
class CloudFoundryWebFluxEndpointIntegrationTests { class CloudFoundryWebFluxEndpointIntegrationTests {
private static final ReactiveTokenValidator tokenValidator = mock(ReactiveTokenValidator.class); private final ReactiveTokenValidator tokenValidator = mock(ReactiveTokenValidator.class);
private static final ReactiveCloudFoundrySecurityService securityService = mock( private final ReactiveCloudFoundrySecurityService securityService = mock(ReactiveCloudFoundrySecurityService.class);
ReactiveCloudFoundrySecurityService.class);
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner( private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(
AnnotationConfigReactiveWebServerApplicationContext::new) AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class,
ReactiveWebServerFactoryAutoConfiguration.class)) ReactiveWebServerFactoryAutoConfiguration.class))
.withUserConfiguration(TestEndpointConfiguration.class) .withUserConfiguration(TestEndpointConfiguration.class)
.withBean(ReactiveTokenValidator.class, () -> this.tokenValidator)
.withBean(ReactiveCloudFoundrySecurityService.class, () -> this.securityService)
.withPropertyValues("server.port=0"); .withPropertyValues("server.port=0");
@Test @Test
void operationWithSecurityInterceptorForbidden() { void operationWithSecurityInterceptorForbidden() {
given(tokenValidator.validate(any())).willReturn(Mono.empty()); given(this.tokenValidator.validate(any())).willReturn(Mono.empty());
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.RESTRICTED)); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.RESTRICTED));
this.contextRunner.run(withWebTestClient((client) -> client.get() this.contextRunner.run(withWebTestClient((client) -> client.get()
.uri("/cfApplication/test") .uri("/cfApplication/test")
.accept(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)
@ -102,8 +103,8 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
@Test @Test
void operationWithSecurityInterceptorSuccess() { void operationWithSecurityInterceptorSuccess() {
given(tokenValidator.validate(any())).willReturn(Mono.empty()); given(this.tokenValidator.validate(any())).willReturn(Mono.empty());
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.FULL)); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.FULL));
this.contextRunner.run(withWebTestClient((client) -> client.get() this.contextRunner.run(withWebTestClient((client) -> client.get()
.uri("/cfApplication/test") .uri("/cfApplication/test")
.accept(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)
@ -131,8 +132,8 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
@Test @Test
void linksToOtherEndpointsWithFullAccess() { void linksToOtherEndpointsWithFullAccess() {
given(tokenValidator.validate(any())).willReturn(Mono.empty()); given(this.tokenValidator.validate(any())).willReturn(Mono.empty());
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.FULL)); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.FULL));
this.contextRunner.run(withWebTestClient((client) -> client.get() this.contextRunner.run(withWebTestClient((client) -> client.get()
.uri("/cfApplication") .uri("/cfApplication")
.accept(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)
@ -169,7 +170,7 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
void linksToOtherEndpointsForbidden() { void linksToOtherEndpointsForbidden() {
CloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, CloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,
"invalid-token"); "invalid-token");
willThrow(exception).given(tokenValidator).validate(any()); willThrow(exception).given(this.tokenValidator).validate(any());
this.contextRunner.run(withWebTestClient((client) -> client.get() this.contextRunner.run(withWebTestClient((client) -> client.get()
.uri("/cfApplication") .uri("/cfApplication")
.accept(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)
@ -181,8 +182,8 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
@Test @Test
void linksToOtherEndpointsWithRestrictedAccess() { void linksToOtherEndpointsWithRestrictedAccess() {
given(tokenValidator.validate(any())).willReturn(Mono.empty()); given(this.tokenValidator.validate(any())).willReturn(Mono.empty());
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.RESTRICTED)); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(Mono.just(AccessLevel.RESTRICTED));
this.contextRunner.run(withWebTestClient((client) -> client.get() this.contextRunner.run(withWebTestClient((client) -> client.get()
.uri("/cfApplication") .uri("/cfApplication")
.accept(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)
@ -232,7 +233,8 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
static class CloudFoundryReactiveConfiguration { static class CloudFoundryReactiveConfiguration {
@Bean @Bean
CloudFoundrySecurityInterceptor interceptor() { CloudFoundrySecurityInterceptor interceptor(ReactiveTokenValidator tokenValidator,
ReactiveCloudFoundrySecurityService securityService) {
return new CloudFoundrySecurityInterceptor(tokenValidator, securityService, "app-id"); return new CloudFoundrySecurityInterceptor(tokenValidator, securityService, "app-id");
} }

View File

@ -43,6 +43,7 @@ import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer; import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -70,13 +71,13 @@ import static org.mockito.Mockito.mock;
*/ */
class CloudFoundryMvcWebEndpointIntegrationTests { class CloudFoundryMvcWebEndpointIntegrationTests {
private static final TokenValidator tokenValidator = mock(TokenValidator.class); private final TokenValidator tokenValidator = mock(TokenValidator.class);
private static final CloudFoundrySecurityService securityService = mock(CloudFoundrySecurityService.class); private final CloudFoundrySecurityService securityService = mock(CloudFoundrySecurityService.class);
@Test @Test
void operationWithSecurityInterceptorForbidden() { void operationWithSecurityInterceptorForbidden() {
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.RESTRICTED); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.RESTRICTED);
load(TestEndpointConfiguration.class, load(TestEndpointConfiguration.class,
(client) -> client.get() (client) -> client.get()
.uri("/cfApplication/test") .uri("/cfApplication/test")
@ -89,7 +90,7 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
@Test @Test
void operationWithSecurityInterceptorSuccess() { void operationWithSecurityInterceptorSuccess() {
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.FULL); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.FULL);
load(TestEndpointConfiguration.class, load(TestEndpointConfiguration.class,
(client) -> client.get() (client) -> client.get()
.uri("/cfApplication/test") .uri("/cfApplication/test")
@ -119,7 +120,7 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
@Test @Test
void linksToOtherEndpointsWithFullAccess() { void linksToOtherEndpointsWithFullAccess() {
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.FULL); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.FULL);
load(TestEndpointConfiguration.class, load(TestEndpointConfiguration.class,
(client) -> client.get() (client) -> client.get()
.uri("/cfApplication") .uri("/cfApplication")
@ -157,7 +158,7 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
void linksToOtherEndpointsForbidden() { void linksToOtherEndpointsForbidden() {
CloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, CloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,
"invalid-token"); "invalid-token");
willThrow(exception).given(tokenValidator).validate(any()); willThrow(exception).given(this.tokenValidator).validate(any());
load(TestEndpointConfiguration.class, load(TestEndpointConfiguration.class,
(client) -> client.get() (client) -> client.get()
.uri("/cfApplication") .uri("/cfApplication")
@ -170,7 +171,7 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
@Test @Test
void linksToOtherEndpointsWithRestrictedAccess() { void linksToOtherEndpointsWithRestrictedAccess() {
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.RESTRICTED); given(this.securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.RESTRICTED);
load(TestEndpointConfiguration.class, load(TestEndpointConfiguration.class,
(client) -> client.get() (client) -> client.get()
.uri("/cfApplication") .uri("/cfApplication")
@ -198,26 +199,23 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
.doesNotExist()); .doesNotExist());
} }
private AnnotationConfigServletWebServerApplicationContext createApplicationContext(Class<?>... config) { private void load(Class<?> configuration, Consumer<WebTestClient> clientConsumer) {
return new AnnotationConfigServletWebServerApplicationContext(config); BiConsumer<ApplicationContext, WebTestClient> consumer = (context, client) -> clientConsumer.accept(client);
new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withUserConfiguration(configuration, CloudFoundryMvcConfiguration.class)
.withBean(TokenValidator.class, () -> this.tokenValidator)
.withBean(CloudFoundrySecurityService.class, () -> this.securityService)
.run((context) -> consumer.accept(context, WebTestClient.bindToServer()
.baseUrl("http://localhost:" + getPort(
(AnnotationConfigServletWebServerApplicationContext) context.getSourceApplicationContext()))
.responseTimeout(Duration.ofMinutes(5))
.build()));
} }
private int getPort(AnnotationConfigServletWebServerApplicationContext context) { private int getPort(AnnotationConfigServletWebServerApplicationContext context) {
return context.getWebServer().getPort(); return context.getWebServer().getPort();
} }
private void load(Class<?> configuration, Consumer<WebTestClient> clientConsumer) {
BiConsumer<ApplicationContext, WebTestClient> consumer = (context, client) -> clientConsumer.accept(client);
try (AnnotationConfigServletWebServerApplicationContext context = createApplicationContext(configuration,
CloudFoundryMvcConfiguration.class)) {
consumer.accept(context,
WebTestClient.bindToServer()
.baseUrl("http://localhost:" + getPort(context))
.responseTimeout(Duration.ofMinutes(5))
.build());
}
}
private String mockAccessToken() { private String mockAccessToken() {
return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwu" return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwu"
+ "Y29tIiwiZXhwIjoxNDI2NDIwODAwLCJhd2Vzb21lIjp0cnVlfQ." + "Y29tIiwiZXhwIjoxNDI2NDIwODAwLCJhd2Vzb21lIjp0cnVlfQ."
@ -229,7 +227,8 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
static class CloudFoundryMvcConfiguration { static class CloudFoundryMvcConfiguration {
@Bean @Bean
CloudFoundrySecurityInterceptor interceptor() { CloudFoundrySecurityInterceptor interceptor(TokenValidator tokenValidator,
CloudFoundrySecurityService securityService) {
return new CloudFoundrySecurityInterceptor(tokenValidator, securityService, "app-id"); return new CloudFoundrySecurityInterceptor(tokenValidator, securityService, "app-id");
} }