Search code examples
springspring-bootspring-mvcspring-securitycors

Spring Boot Security CORS


I have a problem with CORS filter on spring security URL's. It doesn't set Access-Control-Allow-Origin and other exposed header on URL's belonging to spring sec (login/logout) or filtered by Spring Security.

Here are the configurations.

CORS:

@Configuration
@EnableWebMvc
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
********some irrelevant configs************
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/*").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS", "PUT")
                .allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
                        "Access-Control-Request-Headers")
                .exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
                .allowCredentials(true).maxAge(3600);
    }
}

Security:

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                .formLogin()
                    .successHandler(ajaxSuccessHandler)
                    .failureHandler(ajaxFailureHandler)
                    .loginProcessingUrl("/authentication")
                    .passwordParameter("password")
                    .usernameParameter("username")
                .and()
                .logout()
                    .deleteCookies("JSESSIONID")
                    .invalidateHttpSession(true)
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/")
                .and()
                .csrf().disable()
                .anonymous().disable()
                .authorizeRequests()
                .antMatchers("/authentication").permitAll()
                .antMatchers("/oauth/token").permitAll()
                .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
                .antMatchers("/user/*").access("hasRole('ROLE_USER')");
    }
}

So, if I make a request to the url's which are not listened by security - CORS headers are set. Spring security URL's - not set.

Spring boot 1.4.1


Solution

  • Instead of using the CorsRegistry you can write your own CorsFilter and add it to your security configuration.

    Custom CorsFilter class:

    public class CorsFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            HttpServletRequest request= (HttpServletRequest) servletRequest;
    
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "*");
            response.setHeader("Access-Control-Allow-Credentials", true);
            response.setHeader("Access-Control-Max-Age", 180);
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    Security config class:

    @Configuration
    @EnableWebSecurity
    public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Bean
        CorsFilter corsFilter() {
            CorsFilter filter = new CorsFilter();
            return filter;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter
                    .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                    .formLogin()
                        .successHandler(ajaxSuccessHandler)
                        .failureHandler(ajaxFailureHandler)
                        .loginProcessingUrl("/authentication")
                        .passwordParameter("password")
                        .usernameParameter("username")
                    .and()
                    .logout()
                        .deleteCookies("JSESSIONID")
                        .invalidateHttpSession(true)
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/")
                    .and()
                    .csrf().disable()
                    .anonymous().disable()
                    .authorizeRequests()
                    .antMatchers("/authentication").permitAll()
                    .antMatchers("/oauth/token").permitAll()
                    .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
                    .antMatchers("/user/*").access("hasRole('ROLE_USER')");
        }
    }