Before I was using Spring 4.1.x release and had my own Cors Filter and Interceptor. I was also using Tomcat 8.0.8 all was good.
As I had moved the same application to Tomcat 8.0.23 CORS stopped working.
Therefore, I had the application updated to the following versions of Spring dependencies as of my POM:
org.springframework: 4.2.0.RC2
org.springframework.security: 4.0.1.RELEASE
org.springframework.security.oauth2: 2.0.7.RELEASE
org.springframework.ws.version: 2.2.0.RELEASE
spring.data.commons.core.version: 1.4.1.RELEASE
Now, I had also updated my securityConfiguration.xml to have the proper schemas for security 4.0.1.RELEASE.
The application works fine, all changes perfectly except for CORS.
So I had followed the instructions and added to my WebMvcConfigurerAdapter implementation class the following:
@Override
public void addCorsMappings(CorsRegistry registry) {
Properties prop = null;
try {
InputStream in = getClass().getResourceAsStream(
"/com/nando/config/cors.properties");
prop = new Properties();
prop.load(in);
in.close();
} catch (IOException e) {
prop = null;
}
if (prop != null) {
String domains = prop.getProperty("allowed.origins");
List<String> allowedOrigins = new ArrayList<String>(
Arrays.asList(domains.split(",")));
if (allowedOrigins.size() > 0) {
String[] arrayOrigins = null;
arrayOrigins = new String[allowedOrigins.size()];
arrayOrigins = allowedOrigins.toArray(arrayOrigins);
registry.addMapping("/**")
.allowedOrigins(arrayOrigins)
.allowedMethods("PUT, POST, GET, OPTIONS, DELETE")
.allowedHeaders("*")
.exposedHeaders("Authorization", "Content-Type")
.allowCredentials(false).maxAge(3600);
}
} else {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("PUT, POST, GET, OPTIONS, DELETE")
.allowedHeaders("*")
.exposedHeaders("Authorization", "Content-Type")
.allowCredentials(false).maxAge(3600);
}
}
Just doing that alone does not fix the problem, although using a debugger to Tomcat I can see that being properly executed and added. I have a properties file so that I can change allowed domains without recompiling the application as I had done before with my own implementation on 4.1.x Spring.
Because I had this application as an OAuth2 application I had implemented an interceptor too.
On my WebMvcConfigurerAdapter implementation I had an interceptor before, so I had tried to add it to it as so:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CORSInterceptor());
super.addInterceptors(registry);
}
Which loads my CORSInterceptor implemention as follows:
package com.nando.api.filters;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
*
* @author Nando
*
*/
@Component
public class CORSInterceptor extends HandlerInterceptorAdapter {
private Properties prop = new Properties();
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
InputStream in = getClass().getResourceAsStream("/com/nando/config/cors.properties");
prop.load(in);
in.close();
String domains = prop.getProperty("allowed.origins");
Set<String> allowedOrigins = new HashSet<String>(Arrays.asList(domains
.split(",")));
String originHeader = "";
originHeader = request.getHeader("Origin");
if (null != originHeader) {
for (String s : allowedOrigins) {
if (originHeader.contains(s)) {
if (!response.getHeaderNames().contains("Access-Control-Allow-Origin")) {
response.addHeader("Access-Control-Allow-Origin",
originHeader);
}
if (!response.getHeaderNames().contains("Access-Control-Allow-Methods")) {
response.addHeader("Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, DELETE, HEAD");
}
if (!response.getHeaderNames().contains("Access-Control-Allow-Credentials")) {
response.addHeader("Access-Control-Allow-Credentials", "true");
}
if (!response.getHeaderNames().contains("Access-Control-Allow-Headers")) {
response.addHeader("Access-Control-Allow-Headers",
"Authorization, Origin, Content-Type, x-Requested-with, Accept, Accept-Enconding, X-CSRF-Token");
}
if (!response.getHeaderNames().contains("Access-Control-Max-Age")) {
response.addHeader("Access-Control-Max-Age", "1800");
}
return true;
}
}
}
return true;
}
}
And still will not make a difference.
I do not want to add the CORS filter to Tomcat as it will not allow me to set the domains on a properties file, forcing me to edit the Tomcat instances configuration every time a domain is added or removed.
Looks like I have a conundrum here.
Also I thought that by following Spring 4.2 directions on setting up CORS would make it easier which is not the case.
Can anyone help?
Thanks,
Carlos.
If you want to use Spring CORS support, I think you should :
allowedMethods("PUT, POST, GET, OPTIONS, DELETE")
to allowedMethods("PUT", "POST", "GET", "OPTIONS", "DELETE")
(it is a varargs parameter)allowedHeaders("*")
, it is already the defaultsCORSInterceptor
As an alternative, be aware that Spring Framework 4.2 GA also provides a CorsFilter
implementation that could be used in combinaison with UrlBasedCorsConfigurationSource
to provide global CORS support.
If you are using Spring Boot (which supports Filter
beans), it could be something like this in one of your @Configuration
annotated classes:
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addExposedHeader("Authorization");
config.addExposedHeader("Content-Type");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With