diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
index 4c0fae24e0..53af9b6e1e 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
@@ -448,6 +448,36 @@ public final class HttpSecurity extends
return getOrApply(new CorsConfigurer<>());
}
+ /**
+ * Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is
+ * provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is
+ * defined, then that {@link CorsConfiguration} is used. Otherwise, if Spring MVC is
+ * on the classpath a {@link HandlerMappingIntrospector} is used.
+ * You can enable CORS using:
+ *
+ *
+ * @Configuration
+ * @EnableWebSecurity
+ * public class CorsSecurityConfig extends WebSecurityConfigurerAdapter {
+ *
+ * @Override
+ * protected void configure(HttpSecurity http) throws Exception {
+ * http
+ * .cors(withDefaults());
+ * }
+ * }
+ *
+ *
+ * @param corsCustomizer the {@link Customizer} to provide more options for
+ * the {@link CorsConfigurer}
+ * @return the {@link HttpSecurity} for further customizations
+ * @throws Exception
+ */
+ public HttpSecurity cors(Customizer> corsCustomizer) throws Exception {
+ corsCustomizer.customize(getOrApply(new CorsConfigurer<>()));
+ return HttpSecurity.this;
+ }
+
/**
* Allows configuring of Session Management.
*
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
index 8122817caf..b6bb33e58f 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
@@ -42,6 +42,7 @@ import java.util.Arrays;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -131,6 +132,55 @@ public class CorsConfigurerTests {
}
}
+ @Test
+ public void getWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(MvcCorsInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @Test
+ public void optionsWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(MvcCorsInLambdaConfig.class).autowire();
+
+ this.mvc.perform(options("/")
+ .header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @EnableWebMvc
+ @EnableWebSecurity
+ static class MvcCorsInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .cors(withDefaults());
+ // @formatter:on
+ }
+
+ @RestController
+ @CrossOrigin(methods = {
+ RequestMethod.GET, RequestMethod.POST
+ })
+ static class CorsController {
+ @RequestMapping("/")
+ String hello() {
+ return "Hello";
+ }
+ }
+ }
+
@Test
public void getWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(ConfigSourceConfig.class).autowire();
@@ -180,6 +230,57 @@ public class CorsConfigurerTests {
}
}
+ @Test
+ public void getWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
+ throws Exception {
+ this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @Test
+ public void optionsWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
+ throws Exception {
+ this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
+
+ this.mvc.perform(options("/")
+ .header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @EnableWebSecurity
+ static class ConfigSourceInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .cors(withDefaults());
+ // @formatter:on
+ }
+
+ @Bean
+ CorsConfigurationSource corsConfigurationSource() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
+ corsConfiguration.setAllowedMethods(Arrays.asList(
+ RequestMethod.GET.name(),
+ RequestMethod.POST.name()));
+ source.registerCorsConfiguration("/**", corsConfiguration);
+ return source;
+ }
+ }
+
@Test
public void getWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterConfig.class).autowire();
@@ -228,4 +329,53 @@ public class CorsConfigurerTests {
return new CorsFilter(source);
}
}
+
+ @Test
+ public void getWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(CorsFilterInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @Test
+ public void optionsWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(CorsFilterInLambdaConfig.class).autowire();
+
+ this.mvc.perform(options("/")
+ .header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @EnableWebSecurity
+ static class CorsFilterInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .cors(withDefaults());
+ // @formatter:on
+ }
+
+ @Bean
+ CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
+ corsConfiguration.setAllowedMethods(Arrays.asList(
+ RequestMethod.GET.name(),
+ RequestMethod.POST.name()));
+ source.registerCorsConfiguration("/**", corsConfiguration);
+ return new CorsFilter(source);
+ }
+ }
}