Spring Boot swallowing Access-Control-Request-Headers on OPTIONS preflight - spring

I have a Spring Boot REST application that has a very simple CORS filter on it. What I want to do is dynamically respond to the values in the Access-Control-Request-Headers header, rather than provide a specific list. The common wisdom seems to be the explicitly set the values returned in the "Access-Control-Allow-Headers", however we will be white-listing a set of origins and want to allow any headers they send. I cannot find a way to parrot back the value of Access-Control-Allow-Headers in Access-Control-Request-Headers.
Here's the code
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS"); // will need to enable other methods when/as implemented
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
((HttpServletRequest) servletRequest).getHeader("Access-Control-Request-Headers"));
filterChain.doFilter(servletRequest, servletResponse);
}
With this request & response from Chrome (when we were hard-coding the value of Access-Control-Allow-Headers)
Remote Address:10.199.240.16:443
Request URL:https://myapp.com/gradebooks/5566669e-e4b0-d05e-0150-98d7ffffffff/assignments/3ad7f1e7-679b-4d8b-856e-d2e3589eaad6
Request Method:OPTIONS
Status Code:200 OK
Response Headers
view source
Access-Control-Allow-Methods → POST, PUT, GET, DELETE, OPTIONS
Access-Control-Max-Age → 3600
Content-Type → application/hal+json; charset=UTF-8
Date → Tue, 21 Jul 2015 20:42:29 GMT
Server → Jetty(9.2.9.v20150224)
Transfer-Encoding → chunked
X-Application-Context → application
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:PUT
Connection:keep-alive
Host:gbservices-api.dev-prsn.com
Origin:http://localhost:3000
Referer:http://localhost:3000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36
This is the error
XMLHttpRequest cannot load
https://myapp.com/gradebooks/5566669e-e4b0-d05e-0150-98d7ffffffff/assignments/3ad7f1e7-679b-4d8b-856e-d2e3589eaad6.
Request header field Content-Type is not allowed by
Access-Control-Allow-Headers.
What I've found debugging into the filter is that the Access-Control-Request-Headers, and only that header, is missing by the time it gets to the filter. Misspell the header and it arrives, so it seems that something is intercepting the header and discarding it before it gets to my filter...

Related

Cannot send POST request to Spring Resource server

I have a Spring Boot ResourceServer, and a React client application. I am trying to send a POST request to one of the server endpoints (which has the #CrossOrigin annotation btw.), however, I am getting this error in the console:
Access to XMLHttpRequest at 'http://localhost:8080/api/search' from
origin 'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: It
does not have HTTP ok status.
The preflight request returns a 401 Http status, and I don't know why.
The response headers for the preflight request look like this:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: http://localhost:3000
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Sun, 20 Oct 2019 17:23:54 GMT
Expires: 0
Pragma: no-cache
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
WWW-Authenticate: Basic realm="Realm"
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
My preflight request headers look like this:
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Origin: http://localhost:3000
Referer: http://localhost:3000/movie-search
Sec-Fetch-Mode: no-cors
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36
I am using Axios to send the request (if that matters). Anyone knows what's going on here?
Whoops...my HTTPSecurity config looked like this:
http
.authorizeRequests()
.antMatchers(HTTPMethod.POST, "/api/search").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
instead of this:
http
.authorizeRequests()
.antMatchers("/api/search").permitAll()
.anyRequest().authenticated()
.and().httpBasic()

Angular + Spring mvc : Getting Invalid CORS request error when making server call

when i tried to login from my angular login page. I am getting following. and response saying 'Invalid CORS request'.
Request URL:http://127.0.0.1:8088/myproduct/login
Request Method:OPTIONS
Status Code:403 Forbidden
Remote Address:127.0.0.1:8088
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Cache-Control:no-cache, no-store, must-revalidate
Connection:keep-alive
Content-Length:20
Date:Tue, 16 Jan 2018 09:59:47 GMT
Expires:Thu, 01 Jan 1970 00:00:00 GMT
Pragma:no-cache
Server:WildFly/9
X-Powered-By:Undertow/1
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:127.0.0.1:8088
Origin:http://localhost:4200
Pragma:no-cache
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36`enter code here`
Not getting what is the problem (where is the problem)? Please suggest.
You can avoid this by adding an annotation in your service side. Something like this -
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Methods", "POST, GET");
response.setHeader("Access-Control-Allow-Origin", "localhost:4200");
Place #CrossOrigin annotation at the top of the #RequestMapping annotation
like this:
#CrossOrigin(origins = "*")
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "postanswer", headers = "Accept=application/json;charset=UTF-8", method = RequestMethod.POST)
public ResponseEntity<AnswerResult> PostAnswer(HttpServletRequest request) throws Exception {
}

Ajax Request header field Key is not allowed by Access-Control-Allow-Headers

Trying to build a DNN Service Framework WebAPI but I'm having trouble consuming it with CORS. I have all of the appropriate headers (I think) but it still doesn't seem to be working.
Error:
XMLHttpRequest cannot load http://www.dnndev.me/mysite/builder/API/echo?message=Hello+World&_=1412707749275. Request header field Key is not allowed by Access-Control-Allow-Headers.
Request Headers:
Remote Address: 127.0.0.1:80
URL: http://www.dnndev.me/mysite/builder/API/echo?message=Hello
Request Method: OPTIONS
Status Code: 200 OK
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Access-Control-Request-Headers: accept, key
Access-Control-Request-Method: GET
Connection: keep-alive
Host: www.dnndev.me
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
Response Headers:
Access-Control-All-Headers: Origin, X-Requested-With, Content-Type, Accept, Key
Access-Control-Allow-Methods: *
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Content-Length: 13
Content-Type: application/json; charset=utf-8
Date: Tue, 07 Oct 2014 18:49:10 GMT
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/7.5
Generally, this error would be caused by not having the appropriate header in 'Access-Control-All-Headers'. However, I am sending the correct response to allow ajax to continue with its request. It simply refuses to.
Here is my ajax call to the method:
$.ajax({
type: 'GET',
url: 'http://www.dnndev.me/mysite/builder/API/echo',
dataType: 'json',
data: { message: 'Hello' },
crossDomain: true,
headers: { 'Key': 'Bearer 7680ff6e-1362-4236-a9cd-c6bc8b6f13ea' },
success: function (result) { console.log(result); }
});
Probably obvious, but this only happens on cross domain requests and only when I include the custom header (therefore procing ajax to do an OPTIONS).
Your server responds with the following custom header to the preflight request:
Access-Control-All-Headers: Origin, X-Requested-With, Content-Type, Accept, Key
whereas if you (or the person who wrote this server) read carefully about CORS he should have responded with:
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Key
Now the client client could go ahead and use the Key custom header.
This being said, Bearer is quite specific to OAuth 2 which is sent throughout the Authorization header. Using Key seems like a terrible violation of RFCs and stuff and a wheel reinvention kinda.
Please note the typo in Nyx's question and Darin's answer ('ow' missing). So it's
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Key
and it resolves the error message 'Request header field some-header-field is not allowed by Access-Control-Allow-Headers in preflight mode', if sent as an answer to the browser's OPTION request.
Add this to your server response headers :
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');

Spring MVC does not handle RequestMethod.OPTIONS

I am in the context of a Rest API. As I am performing cross domain request, I need to send back the header "Access-Control-Allow-Origin".
I have a controller such:
#Controller
#RequestMapping("/api")
public class PackageManagerRestController {
#RequestMapping(method = RequestMethod.OPTIONS, value = "/test")
public void commonOptions(HttpServletResponse theHttpServletResponse) throws IOException {
theHttpServletResponse.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");
theHttpServletResponse.addHeader("Access-Control-Max-Age", "60"); // seconds to cache preflight request --> less OPTIONS traffic
theHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
theHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
}
#RequestMapping(method = RequestMethod.GET, value = "/test")
public void getPtions(HttpServletResponse theHttpServletResponse) throws IOException {
theHttpServletResponse.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");
theHttpServletResponse.addHeader("Access-Control-Max-Age", "60"); // seconds to cache preflight request --> less OPTIONS traffic
theHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
theHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
}
}
If I run a test with GET, the result is as expected:
$ curl -i -X GET http://localhost:8081/api/test
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with
Access-Control-Max-Age: 60
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Content-Length: 0
Date: Wed, 16 Apr 2014 08:18:38 GMT
However, if I send the request with OPTIONS, the controller never handles the request:
$ curl -i -X OPTIONS http://localhost:8081/api/test
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Wed, 16 Apr 2014 08:19:56 GMT
Anyone has any clue of why I am receiving this "default response" and why I cannot customize it ?
For default Spring DispatcherServlet supports GET, HEAD, POST, PUT, PATCH and DELETE only; if you want to support TRACE and OPTIONS you have to put "dispatchOptionsRequest" and "dispatchTraceRequest" properties to "true"; check here docs.spring.io/spring/docs/4.0.3.RELEASE/javadoc-api
In order to support OPTIONS too in your web.xml you have to put this:
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
By adding it I can handle OPTIONS:
~$ curl -i -X OPTIONS http://localhost:8180/sample/api/test
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with
Access-Control-Max-Age: 60
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Wed, 16 Apr 2014 08:44:55 GMT
Angelo
according to the last answer
I resolve my problem
#RequestMapping(value = "/**",method = RequestMethod.OPTIONS)
public String getOption(HttpServletResponse response,Model model)
{
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
return "";
}
and we need to add something to the dispacherservlet
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
and this is over

Please help me understand Ajax request versus Backbone fetch()

My app can currently hit our API with a standard JQuery Ajax GET request and get good data back. CORS has been properly implemented on the remote server as far as I can see. Here are the response headers:
company_client_envelope_id: 88764736-6654-22e4-br344-a1w2239a892d
access-control-allow-headers: X-Requested-With, Cookie, Set-Cookie, Accept, Access-Control
Allow-Credentials, Origin, Content-Type, Request-Id , X-Api-Version, X-Request-Id,Authorization, COMPANY_AUTH_WEB
access-control-expose-headers: Location
response-time: 55
request-id: 88764736-6654-22e4-br344-a1w2239a892d
company_api_version: 0.01.09
server: localhost
transfer-encoding: chunked
connection: close
access-control-allow-credentials: true
date: Sun, 09 Feb 2014 14:44:05 GMT
access-control-allow-origin: *
access-control-allow-methods: GET, POST
content-type: application/json
However, using Backbone and calling the same GET request by using fetch() causes the following CORS error:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
I cannot figure out what the difference is. Both requests are running from localhost.
In the case of the AJAX query, the following is being sent as requested by the API guys:
headers: {
"accept":"application/json"
}
And in the case of the model and collection declaration I am sending the headers like so:
MyApp.someCollection = Backbone.Collection.extend(
{
model:MyApp.someModel,
headers: {
'Accept':'application/json',
'withCredentials': 'true'
},
url: MYCOMPANY_GLOBALS.API + '/endpoint'
});
and my fetch is simply:
someCollection.fetch();
===============================
Added in response to: #ddewaele
These are the headers from the network tab:
Request URL:http://api-blah.com:3000/
Request Headers CAUTION: Provisional headers are shown.
Accept:application/json
Cache-Control:no-cache
Origin:http://localhost
Pragma:no-cache
Referer:http://localhost/blah/blah/main.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107Safari/537.36
There is no pre-flight or remote headers from the API server:
many thanks,
Wittner
I've recommended to you rewrite Backbone.sync method, because in your app you have some security field for example and other reason.
var oldBackboneSync = Backbone.sync;
// Override Backbone.Sync
Backbone.sync = function (method, model, options) {
if (method) {
if (options.data) {
// properly formats data for back-end to parse
options.data = JSON.stringify(options.data);
}
// transform all delete requests to application/json
options.contentType = 'application/json';
}
return oldBackboneSync.apply(this, [method, model, options]);
}
You can add different headers as you want.

Resources