Reputation: 4072
I'm trying to configure Spring Security to make it support CORS. Thanks to this post, Spring security CORS Filter, I've made it work on my localhost with Spring Boot with this configuration code :
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.antMatcher("/api/**")
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/login").permitAll()
.antMatchers(HttpMethod.GET, "/api/websocket/**").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.addFilterBefore(new JWTLoginFilter("/api/login", HttpMethod.POST, authenticationManager(), tokenAuthenticationService, myUserService), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class)
.csrf().disable();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH"));
// setAllowCredentials(true) is important, otherwise:
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
configuration.setAllowCredentials(true);
// setAllowedHeaders is important! Without it, OPTIONS preflight request
// will fail with 403 Invalid CORS request
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
But when I deploy my apps on remote Tomcat servers, it doesn't work :
Access to XMLHttpRequest at 'http://xxx:9080/yyy/api/user/findByLogin/?login=zzz' from origin 'http://xxx:10080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here's a screenshot of the failing OPTIONS request :
And the working request on my localhost :
Is my configuration class enough or do I need to set something in Tomcat settings ? Thank you
Upvotes: 5
Views: 3876
Reputation: 75984
The response 403 reflects an authorization failure. It could be that your server is set up to ask authorization for options request. You have to make sure the options is configured to send successful response (2xx status code) to allow the browser to send the actual request. 2xx response notifies the browser the server handles CORS requests.
The reason your request worked locally could be that you are authorized when you made the request. So check your authentication to make sure its correct. As such pre flight requests don't send any authorization headers so you shouldn't be expecting on the server side.
Upvotes: 0
Reputation: 3682
Just configure CorsFilter in order to add the relevant CORS response headers (like Access-Control-Allow-Origin) using the provided CorsConfigurationSource. Read its documentation for more. Since you already have UrlBasedCorsConfigurationSource, you can have the filter configured like below:
@Bean
public FilterRegistrationBean corsFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource()));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
Just have the bean mentioned above in your config and hopefully it works.
Here is the full config I've of which you only need some part as mentioned above:
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addExposedHeader("Content-Disposition");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
Upvotes: 0
Reputation: 591
Upvotes: 0
Reputation: 4088
Try putting a debug point in the corsConfigurationSource()
method in your local and check if it is being executed. If it is not getting executed, investigate the reason - probably by enabling debug logs of Spring and/or rechecking Spring configuration.
Also, try adding OPTIONS to setAllowedMethods
configuration.setAllowedMethods(ImmutableList.of("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
Upvotes: 0
Reputation: 238
Check to see if the tomcat server has a conflicting CORS filter configured in $CATALINA_BASE/conf/web.xml
Upvotes: 0
Reputation: 1644
Tomcat has its own cors filter too and if you using an other server before tomcat ( like nodejs, apache server vs ) check its cors filters too.
Upvotes: 0
Reputation: 66
Spring security provides a way to configure CORS in http configurer, there's a much cleaner approach to add CORS filter to the application-
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCORSFilterClass implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
Ordering the filter with the highest precedence makes sure that MyCORSFilterClassimplementation of javax.servlet.Filter is the first one in the chain.
Upvotes: 1