How to handle CORS using JAX-RS with Jersey - java

I'm developing a java script client application, in server-side I need to handle CORS, all the services I had written in JAX-RS with JERSEY.
My code:
#CrossOriginResourceSharing(allowAllOrigins = true)
#GET
#Path("/readOthersCalendar")
#Produces("application/json")
public Response readOthersCalendar(String dataJson) throws Exception {
//my code. Edited by gimbal2 to fix formatting
return Response.status(status).entity(jsonResponse).header("Access-Control-Allow-Origin", "*").build();
}
As of now, i'm getting error No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.”
Please assist me with this.
Thanks & Regards
Buddha Puneeth

Note: Make sure to read the UPDATE at the bottom. The original answer includes a "lazy" implementation of the CORS filter
With Jersey, to handle CORS, you can just use a ContainerResponseFilter. The ContainerResponseFilter for Jersey 1.x and 2.x are a bit different. Since you haven't mentioned which version you're using, I'll post both. Make sure you use the correct one.
Jersey 2.x
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers",
"CSRF-Token, X-Requested-By, Authorization, Content-Type");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
If you use package scanning to discover providers and resources, the #Provider annotation should take care of the configuration for you. If not, then you will need to explicitly register it with the ResourceConfig or the Application subclass.
Sample code to explicitly register filter with the ResourceConfig:
final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(new CORSFilter());
final final URI uri = ...;
final HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(uri, resourceConfig);
For Jersey 2.x, if you are having problems registering this filter, here are a couple resources that might help
Registering Resources and Providers in Jersey 2
What exactly is the ResourceConfig class in Jersey 2?
Jersey 1.x
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest request,
ContainerResponse response) {
response.getHttpHeaders().add("Access-Control-Allow-Origin", "*");
response.getHttpHeaders().add("Access-Control-Allow-Headers",
"CSRF-Token, X-Requested-By, Authorization, Content-Type");
response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHttpHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
return response;
}
}
web.xml configuration, you can use
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.CORSFilter</param-value>
</init-param>
Or ResourceConfig you can do
resourceConfig.getContainerResponseFilters().add(new CORSFilter());
Or package scanning with the #Provider annotation.
EDIT
Please note that the above example can be improved. You will need to know more about how CORS works. Please see here. For one, you will get the headers for all responses. This may not be desirable. You may just need to handle the preflight (or OPTIONS). If you want to see a better implemented CORS filter, you can check out the source code for the RESTeasy CorsFilter
UPDATE
So I decided to add a more correct implementation. The above implementation is lazy and adds all the CORS headers to all requests. The other mistake is that being that it is only a response filter, the request is still processes. This means that when the preflight request comes in, which is an OPTIONS request, there will be no OPTIONS method implemented, so we will get a 405 response, which is incorrect.
Here's how it should work. So there are two types of CORS requests: simple requests and preflight requests. For a simple request, the browser will send the actual request and add the Origin request header. The browser expects for the response to have the Access-Control-Allow-Origin header, saying that the origin from the Origin header is allowed. In order for it to be considered a "simple request", it must meet the following criteria:
Be one of the following method:
GET
HEAD
POST
Apart from headers automatically set by the browser, the request may only contain the following manually set headers:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Save-Data
Viewport-Width
Width
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
If the request doesn't meet all of these three criteria, a Preflight request is made. This is an OPTIONS request that is made to the server, prior to the actual request being made. It will contain different Access-Control-XX-XX headers, and the server should respond to those headers with its own CORS response headers. Here are the matching headers:
REQUEST HEADER
RESPONSE HEADER
Origin
Access-Control-Allow-Origin
Access-Control-Request-Headers
Access-Control-Allow-Headers
Access-Control-Request-Method
Access-Control-Allow-Methods
XHR.withCredentials
Access-Control-Allow-Credentials
With the Origin request header, the value will be the origin server domain, and the response Access-Control-Allow-Origin should be either this same address or * to specify that all origins are allowed.
If the client tries to manually set any headers not in the above list, then the browser will set the Access-Control-Request-Headers header, with the value being a list of all the headers the client is trying to set. The server should respond back with a Access-Control-Allow-Headers response header, with the value being a list of headers it allows.
The browser will also set the Access-Control-Request-Method request header, with the value being the HTTP method of the request. The server should respond with the Access-Control-Allow-Methods response header, with the value being a list of the methods it allows.
If the client uses the XHR.withCredentials, then the server should respond with the Access-Control-Allow-Credentials response header, with a value of true. Read more here.
So with all that said, here is a better implementation. Even though this is better than the above implementation, it is still inferior to the RESTEasy one I linked to, as this implementation still allows all origins. But this filter does a better job of adhering to the CORS spec than the above filter which just adds the CORS response headers to all request. Note that you may also need to modify the Access-Control-Allow-Headers to match the headers that your application will allow; you may want o either add or remove some headers from the list in this example.
#Provider
#PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
/**
* Method for ContainerRequestFilter.
*/
#Override
public void filter(ContainerRequestContext request) throws IOException {
// If it's a preflight request, we abort the request with
// a 200 status, and the CORS headers are added in the
// response filter method below.
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
/**
* A preflight request is an OPTIONS request
* with an Origin header.
*/
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
/**
* Method for ContainerResponseFilter.
*/
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
// if there is no Origin header, then it is not a
// cross origin request. We don't do anything.
if (request.getHeaderString("Origin") == null) {
return;
}
// If it is a preflight request, then we add all
// the CORS headers here.
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
// Whatever other non-standard/safe headers (see list above)
// you want the client to be able to send to the server,
// put it in this list. And remove the ones you don't want.
"X-Requested-With, Authorization, " +
"Accept-Version, Content-MD5, CSRF-Token, Content-Type");
}
// Cross origin requests can be either simple requests
// or preflight request. We need to add this header
// to both type of requests. Only preflight requests
// need the previously added headers.
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
To learn more about CORS, I suggest reading the MDN docs on Cross-Origin Resource Sharing (CORS)

Remove annotation "#CrossOriginResourceSharing(allowAllOrigins = true)"
Then Return Response like below:
return Response.ok()
.entity(jsonResponse)
.header("Access-Control-Allow-Origin", "*")
.build();
But the jsonResponse should replace with a POJO Object!

The other answer might be strictly correct, but misleading. The missing part is that you can mix filters from different sources together. Even thought Jersey might not provide CORS filter (not a fact I checked but I trust the other answer on that), you can use tomcat's own CORS filter.
I am using it successfully with Jersey. I have my own implementation of Basic Authentication filter, for example, together with CORS. Best of all, CORS filter is configured in web XML, not in code.

peeskillet's answer is correct. But I get this error when refresh the web page (it is working only on first load):
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.
So instead of using add method to add headers for response, I using put method. This is my class
public class MCORSFilter implements ContainerResponseFilter {
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS, HEAD";
public static final String[] ALL_HEADERs = {
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS
};
public static final String[] ALL_HEADER_VALUEs = {
ACCESS_CONTROL_ALLOW_ORIGIN_VALUE,
ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE,
ACCESS_CONTROL_ALLOW_HEADERS_VALUE,
ACCESS_CONTROL_ALLOW_METHODS_VALUE
};
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
for (int i = 0; i < ALL_HEADERs.length; i++) {
ArrayList<Object> value = new ArrayList<>();
value.add(ALL_HEADER_VALUEs[i]);
response.getHttpHeaders().put(ALL_HEADERs[i], value); //using put method
}
return response;
}
}
And add this class to init-param in web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.MCORSFilter</param-value>
</init-param>

To solve this for my project I used Micheal's answer and arrived at this:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>run-embedded</id>
<goals>
<goal>run</goal>
</goals>
<phase>pre-integration-test</phase>
<configuration>
<port>${maven.tomcat.port}</port>
<useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
<contextFile>${project.basedir}/tomcat/context.xml</contextFile>
<!--enable CORS for development purposes only. The web.xml file specified is a copy of
the auto generated web.xml with the additional CORS filter added -->
<tomcatWebXml>${maven.tomcat.web-xml.file}</tomcatWebXml>
</configuration>
</execution>
</executions>
</plugin>
The CORS filter being the basic example filter from the tomcat site.
Edit:
The maven.tomcat.web-xml.file variable is a pom defined property for the project and it contains the path to the web.xml file (located within my project)

Related

from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource [duplicate]

I'm developing a java script client application, in server-side I need to handle CORS, all the services I had written in JAX-RS with JERSEY.
My code:
#CrossOriginResourceSharing(allowAllOrigins = true)
#GET
#Path("/readOthersCalendar")
#Produces("application/json")
public Response readOthersCalendar(String dataJson) throws Exception {
//my code. Edited by gimbal2 to fix formatting
return Response.status(status).entity(jsonResponse).header("Access-Control-Allow-Origin", "*").build();
}
As of now, i'm getting error No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.”
Please assist me with this.
Thanks & Regards
Buddha Puneeth
Note: Make sure to read the UPDATE at the bottom. The original answer includes a "lazy" implementation of the CORS filter
With Jersey, to handle CORS, you can just use a ContainerResponseFilter. The ContainerResponseFilter for Jersey 1.x and 2.x are a bit different. Since you haven't mentioned which version you're using, I'll post both. Make sure you use the correct one.
Jersey 2.x
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers",
"CSRF-Token, X-Requested-By, Authorization, Content-Type");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
If you use package scanning to discover providers and resources, the #Provider annotation should take care of the configuration for you. If not, then you will need to explicitly register it with the ResourceConfig or the Application subclass.
Sample code to explicitly register filter with the ResourceConfig:
final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(new CORSFilter());
final final URI uri = ...;
final HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(uri, resourceConfig);
For Jersey 2.x, if you are having problems registering this filter, here are a couple resources that might help
Registering Resources and Providers in Jersey 2
What exactly is the ResourceConfig class in Jersey 2?
Jersey 1.x
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest request,
ContainerResponse response) {
response.getHttpHeaders().add("Access-Control-Allow-Origin", "*");
response.getHttpHeaders().add("Access-Control-Allow-Headers",
"CSRF-Token, X-Requested-By, Authorization, Content-Type");
response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHttpHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
return response;
}
}
web.xml configuration, you can use
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.CORSFilter</param-value>
</init-param>
Or ResourceConfig you can do
resourceConfig.getContainerResponseFilters().add(new CORSFilter());
Or package scanning with the #Provider annotation.
EDIT
Please note that the above example can be improved. You will need to know more about how CORS works. Please see here. For one, you will get the headers for all responses. This may not be desirable. You may just need to handle the preflight (or OPTIONS). If you want to see a better implemented CORS filter, you can check out the source code for the RESTeasy CorsFilter
UPDATE
So I decided to add a more correct implementation. The above implementation is lazy and adds all the CORS headers to all requests. The other mistake is that being that it is only a response filter, the request is still processes. This means that when the preflight request comes in, which is an OPTIONS request, there will be no OPTIONS method implemented, so we will get a 405 response, which is incorrect.
Here's how it should work. So there are two types of CORS requests: simple requests and preflight requests. For a simple request, the browser will send the actual request and add the Origin request header. The browser expects for the response to have the Access-Control-Allow-Origin header, saying that the origin from the Origin header is allowed. In order for it to be considered a "simple request", it must meet the following criteria:
Be one of the following method:
GET
HEAD
POST
Apart from headers automatically set by the browser, the request may only contain the following manually set headers:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Save-Data
Viewport-Width
Width
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
If the request doesn't meet all of these three criteria, a Preflight request is made. This is an OPTIONS request that is made to the server, prior to the actual request being made. It will contain different Access-Control-XX-XX headers, and the server should respond to those headers with its own CORS response headers. Here are the matching headers:
REQUEST HEADER
RESPONSE HEADER
Origin
Access-Control-Allow-Origin
Access-Control-Request-Headers
Access-Control-Allow-Headers
Access-Control-Request-Method
Access-Control-Allow-Methods
XHR.withCredentials
Access-Control-Allow-Credentials
With the Origin request header, the value will be the origin server domain, and the response Access-Control-Allow-Origin should be either this same address or * to specify that all origins are allowed.
If the client tries to manually set any headers not in the above list, then the browser will set the Access-Control-Request-Headers header, with the value being a list of all the headers the client is trying to set. The server should respond back with a Access-Control-Allow-Headers response header, with the value being a list of headers it allows.
The browser will also set the Access-Control-Request-Method request header, with the value being the HTTP method of the request. The server should respond with the Access-Control-Allow-Methods response header, with the value being a list of the methods it allows.
If the client uses the XHR.withCredentials, then the server should respond with the Access-Control-Allow-Credentials response header, with a value of true. Read more here.
So with all that said, here is a better implementation. Even though this is better than the above implementation, it is still inferior to the RESTEasy one I linked to, as this implementation still allows all origins. But this filter does a better job of adhering to the CORS spec than the above filter which just adds the CORS response headers to all request. Note that you may also need to modify the Access-Control-Allow-Headers to match the headers that your application will allow; you may want o either add or remove some headers from the list in this example.
#Provider
#PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
/**
* Method for ContainerRequestFilter.
*/
#Override
public void filter(ContainerRequestContext request) throws IOException {
// If it's a preflight request, we abort the request with
// a 200 status, and the CORS headers are added in the
// response filter method below.
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
/**
* A preflight request is an OPTIONS request
* with an Origin header.
*/
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
/**
* Method for ContainerResponseFilter.
*/
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
// if there is no Origin header, then it is not a
// cross origin request. We don't do anything.
if (request.getHeaderString("Origin") == null) {
return;
}
// If it is a preflight request, then we add all
// the CORS headers here.
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
// Whatever other non-standard/safe headers (see list above)
// you want the client to be able to send to the server,
// put it in this list. And remove the ones you don't want.
"X-Requested-With, Authorization, " +
"Accept-Version, Content-MD5, CSRF-Token, Content-Type");
}
// Cross origin requests can be either simple requests
// or preflight request. We need to add this header
// to both type of requests. Only preflight requests
// need the previously added headers.
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
To learn more about CORS, I suggest reading the MDN docs on Cross-Origin Resource Sharing (CORS)
Remove annotation "#CrossOriginResourceSharing(allowAllOrigins = true)"
Then Return Response like below:
return Response.ok()
.entity(jsonResponse)
.header("Access-Control-Allow-Origin", "*")
.build();
But the jsonResponse should replace with a POJO Object!
The other answer might be strictly correct, but misleading. The missing part is that you can mix filters from different sources together. Even thought Jersey might not provide CORS filter (not a fact I checked but I trust the other answer on that), you can use tomcat's own CORS filter.
I am using it successfully with Jersey. I have my own implementation of Basic Authentication filter, for example, together with CORS. Best of all, CORS filter is configured in web XML, not in code.
peeskillet's answer is correct. But I get this error when refresh the web page (it is working only on first load):
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.
So instead of using add method to add headers for response, I using put method. This is my class
public class MCORSFilter implements ContainerResponseFilter {
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS, HEAD";
public static final String[] ALL_HEADERs = {
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS
};
public static final String[] ALL_HEADER_VALUEs = {
ACCESS_CONTROL_ALLOW_ORIGIN_VALUE,
ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE,
ACCESS_CONTROL_ALLOW_HEADERS_VALUE,
ACCESS_CONTROL_ALLOW_METHODS_VALUE
};
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
for (int i = 0; i < ALL_HEADERs.length; i++) {
ArrayList<Object> value = new ArrayList<>();
value.add(ALL_HEADER_VALUEs[i]);
response.getHttpHeaders().put(ALL_HEADERs[i], value); //using put method
}
return response;
}
}
And add this class to init-param in web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.MCORSFilter</param-value>
</init-param>
To solve this for my project I used Micheal's answer and arrived at this:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>run-embedded</id>
<goals>
<goal>run</goal>
</goals>
<phase>pre-integration-test</phase>
<configuration>
<port>${maven.tomcat.port}</port>
<useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
<contextFile>${project.basedir}/tomcat/context.xml</contextFile>
<!--enable CORS for development purposes only. The web.xml file specified is a copy of
the auto generated web.xml with the additional CORS filter added -->
<tomcatWebXml>${maven.tomcat.web-xml.file}</tomcatWebXml>
</configuration>
</execution>
</executions>
</plugin>
The CORS filter being the basic example filter from the tomcat site.
Edit:
The maven.tomcat.web-xml.file variable is a pom defined property for the project and it contains the path to the web.xml file (located within my project)

Angular 5: Response for preflight has invalid HTTP status code 403

When I send a POST request to the server I get an error:
Failed to load http://localhost:8181/test: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.
The backend is written in Java Spring.
My method for creating a test:
createTest() {
const body = JSON.stringify({
'description': 'grtogjoritjhio',
'passingTime': 30,
'title': 'hoijyhoit'
});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json'
}
)
};
return this._http.post(`${this._config.API_URLS.test}`, body, httpOptions)
.subscribe(res => {
console.log(res );
}, error => {
console.log(error);
});
}
Get Method works, but Post doesn't. They both work in Swagger and Postman. I changed POST method many times. The headers in my code do not work, but I solved the problem with them expanding to Google Chrome. There was only an error:
Response for preflight has invalid HTTP status code 403.
It seems to me that this is not Angular problem. Please tell me how I or my friend (who wrote the backend) can solve this problem.
PROBLEM :
For any Cross-Origin POST request, the browser will first try to do a OPTIONS call and if and only if that call is successful, it will do the real POST call. But in your case, the OPTIONS call fails because there is no 'Access-Control-Allow-Origin' response header. And hence the actual call will not be done.
SLOUTION :
So for this to work you need to add CORS Configuration on the server side to set the appropriate headers needed for the Cross-Origin request like :
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "content-type, if-none-match");
response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Max-Age", "3600");
You need to ensure that the Spring accept CORS requests
Also if you have applied Spring security & require authorization headers for example for your API, then (only if you need to make your app support CORS) you should exclude the OPTIONS calls from authorization in your spring security configuration file.
It will be something like this:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
#Override
public void configure(WebSecurity web) throws Exception {
// Allow OPTIONS calls to be accessed without authentication
web.ignoring()
.antMatchers(HttpMethod.OPTIONS,"/**")
Note:
In production, probably it is better to use reverse proxy (like nginx) & not allow the browsers to call your API directly, in that case, you don't need to allow the OPTIONS calls as shown above.
I've had the exact same problem with Angular lately. It happens because some requests are triggering preflight requests eg. PATCH, DELETE, OPTIONS etc. This is a security feature in web browsers. It works from Swagger and Postman simply because they don't implement such a feature. To enable CORS requests in Spring you have to create a bean that returns WebMvcConfigurer object. Don't forget of #Configuration in case you made an extra class for this.
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}
Of course, you can tune this up to your needs.

CORS with basic HTTP Authentication

I'm having some problems using basic HTTP Authentication with CORS: We have a node express web server (UI), calling a HTTP API from a Java Dropwizard (Jersey) server, running on the same host.
The API is protected with HTTP basic authentication, and I''ve implemented the following filter on my Jersey server (taken from this post: How to handle CORS using JAX-RS with Jersey):
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "http://localhost:9000");
response.getHeaders().add("Access-Control-Allow-Headers",
"Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
However, when I try to load the web UI, my console gives me the following output:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:9000/intraday/parameters. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘http://localhost:9000’)
I'm unable to make sense of this error. Clearly the origin is the same (http://localhost:9000), so I don't get why it doesn't match.
I've also made sure that any preflighted OPTIONS requests are answered with HTTP code 200.
From the description in the question, it sounds like the Java Dropwizard (Jersey) server is running on http://localhost:9000 and the node express web server (UI) is running at another origin.
Regardless, you must set the value of the Access-Control-Allow-Origin response header in the CORSFilter code on the Jersey server to the origin of the frontend JavaScript code that’s making the request (apparently the node server). So if that’s, e.g., http://localhost:12345, then:
response.getHeaders().add("Access-Control-Allow-Origin", "http://localhost:12345");
It anyway must be something other than http://localhost:9000, because there’s no way your browser would emit that “disallows reading the remote resource at http://localhost:9000/…” error message if the frontend JavaScript code the request is getting sent from is being served from http://localhost:9000—since in that case it wouldn’t be a cross-origin request and your browser wouldn’t be blocking access to the response.

Cross-Origin Request Blocked Spring REST service + AJAX

Unable to call spring REST service
My spring service
#RequestMapping(value = "/MAS/authenticate", method = RequestMethod.POST)
public ResponseEntity<Map<String, String>> authenticate(#RequestBody Subject subject) {
Map<String, String> result = new HashMap<String, String>();
result.put("result_detail", "Invalid Password");
result.put("result", "failure");
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain
return new ResponseEntity<Map<String, String>>(result, responseHeaders, HttpStatus.OK);
}
My AJAX code
$.ajax(
{
crossDomain: true,
type: "POST",
contentType: "application/json; charset=utf-8",
async: false,
url: "http://localhost:8080/SpringMVC/rest/MAS/authenticate",
headers: {"Access-Control-Allow-Origin" : "*"},
data:{},
dataType: "json", //also tried "jsonp"
success: function(data, status, jqXHR)
{
alert('success');
},
error: function(jqXHR, status)
{
alert('error');
}
});
I am getting following error :(
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/SpringMVC/rest/MAS/authenticate. This can be fixed by moving the resource to the same domain or enabling CORS.
i have also tried dataType: "jsonp". its append my body object into URL which make different URL and cannot hit my service URL then and got 404 error.
My browser: firefox 36.0.4
How i can get rid from this error, any help?
My AJAX call and service were OK. After searching a lot on internet i have found that its server side problem not client side.
on server side with Spring we have to implement filter which will allow CORS requests.
filter will look like this.
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;
public class CORSFilter extends OncePerRequestFilter {
private static final Log LOG = LogFactory.getLog(CORSFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
LOG.trace("Sending Header....");
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
// response.addHeader("Access-Control-Allow-Headers", "Authorization");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1");
}
filterChain.doFilter(request, response);
}
}
and in web.xml apply this filter on your service requests like this
<filter>
<filter-name>cors</filter-name>
<filter-class>com.test.common.controller.CORSFilter</filter-class> <!-- your package name and filter class -->
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This may help someone else who went through this problem. :)
By default the only method allowed is a GET, and you don't allow the POST on your server side:
Access-Control-Allow-Origin: *
This header only enables CORS, but you need to add this:
Access-Control-Allow-Methods: POST, GET
More detailed how-to about the HTTP access control (CORS) on Mozilla project
So your code should be something like this:
responseHeaders.add("Access-Control-Allow-Methods", "POST, GET"); // also added header to allow POST, GET method to be available
responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain
Update:
I have re-read the article, and found out some details:
A simple cross-site request is one that:
Only uses GET, HEAD or POST. If POST is used to send data to the
server, the Content-Type of the data sent to the server with the HTTP
POST request is one of application/x-www-form-urlencoded,
multipart/form-data, or text/plain.
Does not set custom headers with
the HTTP Request (such as X-Modified, etc.)
As you can read in bold, you must set other Content-Type for your data (currently it is contentType: "application/json; charset=utf-8",) or use the preflight technique described later:
It uses methods other than GET, HEAD or POST. Also, if POST is used
to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as
X-PINGOTHER)
So I suggest you either change the contentType or try to work with this header into your request:
Access-Control-Request-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE
and this headers into your response:
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE
And after that you can try to call your method.
Following is the solution for cross platform spring boot web service call.
Application URL: http://localhost:8080
Webservice URL: http://localhost:9090
In your spring controller use following annotation
#CrossOrigin(origins = "http://localhost:8080")
#RequestMapping(value = "/uri", method = RequestMethod.GET)
public SomeObject someMethod(){
// your logic will come here
}

Java filter failing to set response headers

I am trying to create a Java "Filter" which detects a custom HTTP Request Header, and inserts response headers so that the file will download automatically. The response header that is most important for this is the "Content-Type = Attachment" response header. I have created an HTTP request object that inserts the custom Header:
function myHttpObject(filePath){
function makeHttpObject() {
return new XMLHttpRequest();
}
var request = makeHttpObject();
request.open("GET", filePath, false);
request.setRequestHeader("X-Wria-Download", "PDFdownload");
request.send(null);
window.open(filePath);
console.log(request.getAllResponseHeaders());
}
This will insert the X-Wria-Download header into the request.
Then I have a Java Filter which looks for that request header and should set the response header to "Content-Type=attachment"
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class Contenttypefilter implements Filter {
protected FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
//noop
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//get the headers we placed in the request
//based on those request headers, set some response headers
if(req.getHeader("X-Wria-Download") != null){
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", "attachment; filename=success.pdf");
}
chain.doFilter(req,res);
}
}
And then of course the web.xml has the code to include the Filter on all jsp files.
The thing that is baffling me, is that the header is being set on the response file, but it is not downloading as it should. If I put the res.setHeader("Content-Disposition", "attachment; filename=success.pdf"); line outside the "if" statement, then it will work, but it will apply the download behavior to all JSP's which I don't want.
Why is it applying the content-disposition but not working when I have the res.setHeader in the if statement; and then working when it is outside the if statement? Any ideas for how I can get the desired behavior (only applying content disposition to jsp's that I have applied a custom request header to)?
I think your issue is related to the Filter order of execution of your Web Context, i.e. some filters, in you web context, executes after your filter and override the header.
The Servlet Filter is an implementation of the Chain of Responsibility pattern
So you may try to:
Set the headers after the call to chain.doFilter:
.
...
chain.doFilter(req,res);
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//get the headers we placed in the request
//based on those request headers, set some response headers
if(req.getHeader("X-Wria-Download") != null){
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", "attachment; filename=success.pdf");
}
In this way your code will be executed after that the Servlet is called and, as explained below, if your filter is the first declared in web.xml, then the setHeader code will be the last executed (see image below).
make sure that your filter is the last to be executed after the Servlet is executed, i.e. it should be the first servlet Filter declared as explained here:
As you can see Filter1 (the first declared in web.xml) is the first one executed before the servlet is executed and the last one executed after the servlet is executed. So if you want to be sure to be the last Filter setting the header then declare it as Filter1.
The order of execution is determined by the order of declaration in your Deployment Descriptor (web.xml):
Servlet spec (section 6.2.4):
"The order the container uses in building the chain of filters to be
applied for a particular request URI is as follows:
"1. First, the matching filter mappings in the same
order that these elements appear in the deployment descriptor.
"2. Next, the matching filter mappings in the same
order that these elements appear in the deployment descriptor."
So to be sure simply declare it as the first filter in your web.xml. In this way it will be the very last filter setting the header. And, of course, set the header in your code after calling chain.doFilter, as already said.
Assuming you use a response wrapper as described here by others, the whole secret is when to call getWriter() on the original response! That's because the response object ignores all headers added AFTER you asked for a writer!
So, make sure you add all your headers Before you call getWriter().
Here is my recommended sequence for doFilter():
Create a response wrapper
chain.doFilter (origRequest, wrapper);
Assign all required headers to the original (!) Response
Get writer from original response
Copy the wrapper's content to this writer
Try this: set an attribute on the request if the request header is present. Then, check for the attribute after the chain.doFilter(...) and set the response headers then.
The problem is the header(X-Wria-Download) of your AjaxRequest (here XMLHttpRequest) is not being set in your HttpServletRequest object before the filter is being served.
I think better Idea will be to use a Dedicated Servlet to handle your ajax request.

Categories