spring-mvcspring-boottestingcors

Testing CORs in SpringBootTest


Im trying to write a test to verify our CORS settings. I configure CORS like this.

@Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
//        super.configure(httpSecurity);
        httpSecurity.csrf().disable();
        httpSecurity.authorizeRequests().antMatchers("/**").permitAll();
        httpSecurity.cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        List<String> allowedMethods = CORS_ALLOWED_METHODS;
        configuration.setAllowedMethods(allowedMethods);
        configuration.setAllowedOrigins(CORS_ALLOWED_ORIGINS);
        configuration.setAllowedHeaders(CORS_ALLOWED_HEADERS);
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

I have verified with the debugger that CORS_ALLOWED_METHODS has values when my test runs.

Here is my test. It fails when I assert on the headers.

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("dev")
public class ControllerTests {

    @Autowired
    private WebApplicationContext wac;

    public MockMvc mockMvc;

    @Before
    public void setup() {
        DefaultMockMvcBuilder builder = MockMvcBuilders
                .webAppContextSetup(this.wac)
                .apply(SecurityMockMvcConfigurers.springSecurity())
                .dispatchOptions(true);
        this.mockMvc = builder.build();
    }

    @Test
    public void testCors() throws Exception {
        this.mockMvc
                .perform(get("/test-cors"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(header().string("Access-Control-Allow-Methods", "OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,CONNECT"))
                .andExpect(content().string("whatever"));
    }

    @SpringBootApplication(scanBasePackages = {"the.packages"})
    @Controller
    static class TestApplication {

        public static void main(String[] args) throws Exception {
            SpringApplication.run(TestApplication.class, args);
        }

        @RequestMapping(value = {"test-cors"},  method = RequestMethod.GET)
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody String testCors() {
            return "whatever";
        }
    }
}

As a note, when I actually run a SpringBoot app with this configuration we do get CORS headers.

Any help appreciated.


Solution

  • The CORS request needs to include an Origin header for the server to process it. The mock GET request is not having this header. The API does allow us to include headers in the mock requests.

    public MockHttpServletRequestBuilder header(String name, Object... values)

    Add a header to the request. Values are always added. Parameters: name - the header name values - one or more header values

    Here is the code that works

    .perform(options("/test-cors")
        .header("Access-Control-Request-Method", "GET")
        .header("Origin", "http://www.someurl.com"))
    

    Both headers are required, and the configuration requires that allowed origins and methods align with the values passed in the test.