Merge branch '4.0.x'

Closes gh-50258
This commit is contained in:
Andy Wilkinson
2026-04-30 12:38:09 +01:00
2 changed files with 22 additions and 1 deletions
@@ -148,7 +148,7 @@ public final class CloudFoundryActuatorAutoConfiguration {
? new SecurityService(restClientBuilder, cloudControllerUrl, skipSslValidation) : null;
}
private CorsConfiguration getCorsConfiguration() {
private static CorsConfiguration getCorsConfiguration() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
corsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));
@@ -173,6 +173,8 @@ public final class CloudFoundryActuatorAutoConfiguration {
SecurityFilterChain cloudFoundrySecurityFilterChain(HttpSecurity http) throws Exception {
RequestMatcher cloudFoundryRequest = getRequestMatcher();
http.csrf((csrf) -> csrf.ignoringRequestMatchers(cloudFoundryRequest));
CorsConfiguration corsConfiguration = getCorsConfiguration();
http.cors((cors) -> cors.configurationSource((request) -> corsConfiguration));
http.securityMatchers((matches) -> matches.requestMatchers(cloudFoundryRequest))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll());
return http.build();
@@ -50,6 +50,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -61,11 +62,13 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CompositeFilter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -212,6 +215,22 @@ class CloudFoundryActuatorAutoConfigurationTests {
});
}
@Test
void crossOriginRequestToCloudFoundryPathsPermittedBySpringSecurity() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration());
this.contextRunner.withBean(TestEndpoint.class, TestEndpoint::new)
.withBean("corsConfigurationSource", UrlBasedCorsConfigurationSource.class, () -> source)
.withPropertyValues("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id")
.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
mvc.perform(get(BASE_PATH + "/test").header(HttpHeaders.ORIGIN, "elsewhere.example.com")
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isServiceUnavailable());
// If CORS fails we'll get a 403, if it works we get service unavailable
// because of "Cloud controller URL is not available"
});
}
private SecurityFilterChain getSecurityFilterChain(AssertableWebApplicationContext context) {
Filter springSecurityFilterChain = context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN, Filter.class);
FilterChainProxy filterChainProxy = getFilterChainProxy(springSecurityFilterChain);