I am building a prototype application that does an Ajax GET call via javascript in an html page. The configuration I am using is:
Windows/Apache Web Server (XAMPP)
MongoDB
Chrome Browser
All running on the same Windows7(32) machine. The mongodb server and data are installed in the C:\ path; the Apache server is in the C:\XAMPP path. I can access the MongoDB server directly through the browser; for example a call to:
localhost:28017/ database/ collection
will return the collection's data in json format.
However, if I try running the same Ajax call in javascript via an html page, I get the error:
XMLHttpRequest cannot load http:// localhost:28017/ database/ collection. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http:// localhost' is therefore not allowed access.
I modified/inspected my httpd.conf file and have the following set for :
<Directory />
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type,
Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
AllowOverride none
Require all denied
</Directory>
I also confirmed that the headers_module is being loaded:
LoadModule headers_module modules/mod_headers.so
However, this does not work. The port number is changing between the html and the ajax call (80 vs. 28017), therefore a new domain.
Here is the script code:
var xhr = new XMLHttpRequest();
console.log("xhr open")
xhr.open("GET", "http://localhost:28017/ database/ collection/", false);
xhr.send();
Here are the response headers from the html call:
Accept-Ranges:bytes
Access-Control-Allow-Headers:X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding
Access-Control-Allow-Methods:POST, GET, OPTIONS, DELETE, PUT
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1000
Connection:Keep-Alive
Content-Length:564
Content-Type:text/html
Date:Mon, 09 Jan 2017 23:47:06 GMT
ETag:"234-545b12ed82b40"
Keep-Alive:timeout=5, max=100
Last-Modified:Mon, 09 Jan 2017 22:49:41 GMT
Server:Apache/2.4.23 (Win32) OpenSSL/1.0.2h PHP/5.5.38
And all the headers from the xhr call:
General
Request URL:http://localhost:28017/ database/ collection/
Request Method:GET
Status Code:200 OK
Response Headers
Connection:close
Content-Length:369
Content-Type:text/plain;charset=utf-8
x-action:
x-ns:database.collection
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Host:localhost:28017
Origin:http:// localhost
Referer:http://localhost/ load_mongodb_data.html
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Any assistance appreciated.
CORS is a mechanism where restricted Resources can be requested from (Shared to) another domain - i.e. "Cross Origin" ... the domain owning the resource controls who can have it - this is the important part of CORS, the owner of the resource permits or denies access to the resource
In your case, the page making the request is served on port 80, the resource is requested on port 28017
Think of port 80 as being your domain with your resources
Think of port 28017 being someone elses domain, and they have some resources you want to use
You can't "enable CORS" on your domain and expect the other domain to then grant you access to it's resources - if that's how CORS worked, there'd be no need for CORS to begin with
What you'll need to do is set those Access-Control-* headers on the server running on port 28017
Related
I have a JavaScript application let's say that it is deployed on portal.example.com.
That includes a <script> tag that loads source that is served from assets.example.com.
That JavaScript file makes an HTTP request to an API on admin.example.com
This API request is erroring due to CORS pre-flight failing.
Failed to load http://admin.example.com/v0/user/navigation: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://portal.example.com' is therefore not allowed access.
The actual OPTIONS request is as below
OPTIONS /v0/user/navigation HTTP/1.1
Host: admin.example.com
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://portal.example.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
Access-Control-Request-Headers: authorization,x-correlation-id,x-user-domain
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,en-GB;q=0.8
The actual OPTIONS response is as below
HTTP/1.1 200
Allow: GET
Access-Control-Allow-Headers: authorization,x-correlation-id,x-user-domain
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: http://portal.example.com
Vary: Origin
Content-Length: 0
Date: Tue, 20 Feb 2018 12:12:19 GMT
Set-Cookie: 97d2c19dadc3933a73dce9bec0748df1=5a15895c5e0f5b526c177132cb4aa666; path=/; HttpOnly
Cache-control: private
X-RBT-SCAR: 10.127.48.7:777511903:1000
I think the issue is because the request is actually coming from a script served from assets.example.com is making the request. So I should be returning Access-Control-Allow-Origin: http://assets.example.com in the OPTIONS response. However, I have followed the advice of W3C.
The Access-Control-Allow-Origin header indicates whether a resource can be shared based by returning the value of the Origin request header, "*", or "null" in the response.
So am I misunderstanding CORS, or is the browser sending the Origin of the main executing URL and not the URL of the script making the request?
UPDATED
GET response
HTTP/1.1 200
X-Correlation-Id: 8978b245-081a-4c4a-b4c9-73f2920ab55c
Content-Type: application/vnd.example+json
Transfer-Encoding: chunked
Date: Tue, 20 Feb 2018 13:22:39 GMT
Set-Cookie: 97d2c19dadc3933a73dce9bec0748df1=dc4e3543c3071d752959e7176c5e4d29; path=/; HttpOnly
Cache-control: private
X-RBT-SCAR: 10.127.48.7:778160108:2000
No 'Access-Control-Allow-Origin' header is present on the requested resource.
That means that 'Access-Control-Allow-Origin' header is missing, not that your domain is not allowed.
If you didn't have permission, you would see something like
The 'Access-Control-Allow-Origin' header has a value 'http://www.example.com' that is not equal to the supplied origin.
So, to solve your problem you need to configure your GET response to provide the necessary CORS headers as well as the OPTIONS response.
In your edited question the GET response headers doesn't provide anything for the Access-Control-* so that's why you get the error!
Your CORS preflight is not failing - you're getting a 200 response and all the required CORS response headers...
However, you're not returning any of the CORS response headers in the GET response - that is what's failing. At a minimum, you need to return a Access-Control-Allow-Origin response header which matches the one returned in the OPTIONS response.
So just include this in your GET response and you'll be fine:
Access-Control-Allow-Origin: http://portal.example.com
Finally, the Origin request header is added by the browser, and trust me - it's correct. But it really doesn't matter what value is sent, since all that is required is that the Access-Control-Allow-Origin response header matches the Origin request header (either by having a value of '*' or exactly matching the Origin value).
I ham trying to make a request to a REST api. It is a CORS request.
My frontend : Angular 1.5 (localhost:3000)
My Backend : Django (*****.ddns.net)
So I am using a service ( made by someone who doesn't want to share the code :( ), that is doing a OPTIONS request before the real request (preflight). To be precise, the call is made through the resolve option of UI-router state definition.
Django has CORS to allow *.
This is the error that i get in google chrome :
XMLHttpRequest cannot load https://****.net/api/myprofile. The request was redirected to 'https://*****.net/punchclock/api/myprofile/', which is disallowed for cross-origin requests that require preflight.
If I do a classic $http request in a controller, it is working.
This is the request recieved my django :
+6655:5740d0f9:10|
OPTIONS /punchclock/api//myprofile HTTP/1.0|
Host:*****.net|
Connection:close|
Pragma:no-cache|
Cache-Control:no-cache|
Access-Control-Request-Method:GET|
Origin:http%3a//localhost%3a3000|
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36|
Access-Control-Request-Headers:accept, authorization|
Accept:*/*|
Referer:http%3a//localhost%3a3000/dashboard|
Accept-Encoding:gzip, deflate, sdch|
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,es;q=0.2
-6655:5740d0f9:10
And this is the response i get if I do it with postman (it is working with postman when i do an OPTIONS request)
Access-Control-Allow-Headers →x-requested-with, content-type, accept, origin, authorization, x-csrftoken
Access-Control-Allow-Methods →GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Origin →*
Access-Control-Max-Age →86400
Allow →GET, HEAD, OPTIONS
Connection →keep-alive
Content-Type →application/json
Date →Sat, 21 May 2016 21:15:02 GMT
Server →nginx/1.6.2
Transfer-Encoding →chunked
Vary →Accept
X-Frame-Options →SAMEORIGIN
I think it is an issue on Django's side, I don't know. If you have any idea... (I need to learn a lot about CORS...)
Make sure the URL you are targeting is correctly constructed and that there is a trailing slash at the end of the route you are calling. As mentioned here. So instead of this
'http://localhost:5000/auth'
you would call this
'http://localhost:5000/auth/'
Hope this helps.
It is probably because some of the headers you are sending are not allowed. To make sure, just go to google chrome debugger and copy the request headers and send them using postman. If it fails eliminate the headers until you find out which one is not allowed.
There is a similar answer here that may help. Specifically where it says
According to the W3 CORS Spec Section 6.2 Preflight Requests, the preflight must reject the request if any header submitted does not match the allowed headers.
I have a trouble with CORS.
I use an API which has
Access-Control-Allow-Origin: http://www.example.com
Because of that, I can't access the informations I need to continue my website.
But, strangely, I can see it if I put the API url into the Firefox address bar.
This is my header request :
Host: carto.strasmap.eu
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: application/json, text/plain
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.49:9000/
Origin: http://192.168.1.49:9000
Connection: keep-alive
And the Header Answer
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Origin: http://www.example.com/
Access-Control-Max-Age: 0
Cache-Control: max-age=31536000
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 781
Content-Type: text/javascript; charset=utf-8
Date: Sat, 25 Jul 2015 01:23:50 GMT
Expires: Sun, 24 Jul 2016 01:23:50 GMT
Keep-Alive: timeout=5, max=100
Server: Apache
Vary: Accept-Encoding
X-Powered-By: PHP/5.6.8
Of course, I can't modify the API.
I use AngularJS for my website.
Is there anything I can do to get the data hidden behind this ?
Thank you for your help
Lothigo
No.
If the Access-Control-Allow-Origin header is example.com and you're attempting to access it from any other origin, you won't be able to.
Is there anything I can do to get the data hidden behind this ?
No, not with pure client code, but Yes if you can involve a custom server. See possible work-arounds discussed below.
Same origin security in a browser prevents an Ajax request to a page at origin Y when that request is made from a web page that is not also origin Y. This can only be changed by having the server that is serving the request enable CORS from the origin who's page you are making the request from or from all origins. The only way to change that is by changing the CORS support on the API server. There is nothing you can do purely on the client side to override the same origin protections. And, if there was a pure client thing that could override it, it would be quickly closed as a security hole.
Same origin protections do not apply to a URL typed into the URL bar since there is no "origin" that is different than the URL entered into the URL bar. That explains why you can access the API server by typing URLs directly into the URL bar. The same origin protections for Ajax calls made from a web page are additional security measures implemented by the browser that do not apply when entering a URL directly into the URL bar. But, there is no way to use this capability from Javascript to skirt the same origin protections because Javascript cannot freely reach across windows of different origins.
There are some possible work-arounds.
If the API server supports JSONP, then you could use that. But, since JSONP is specifically for cross origin requests, if the API server isn't allowing cross origin requests with a regular Ajax request, then they probably wouldn't be allowing them via JSONP.
You can implement your own server proxy. From your existing web page, you would make a request of your own server proxy. That proxy would either already be on the same origin as your web page or would support CORS from at least the origin on your web page so that the Ajax call to your own server proxy would be permitted. Your server proxy would then call the API server to get the results you want and return them via the Ajax call made to the server proxy. Since same origin protections are implemented and enforced only in the browser for Ajax calls made from the browser, the server proxy is not limited by them and it can freely access the API server.
if you are accessing the other origin(host) from your origin then you will not access the api in ajax call because other origin will have been disallow the access of another host. So to access the api you need to allow the particular path pattern on server side which you want to access.
web.xml file in java project.
<web-app>
<filter>
<filter-name>myFilter</filter-name>
<filter-class>CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>myRestPath</servlet-name>
<servlet-class>com.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<url-pattern>/rest/*</url-pattern>
<servlet-name>myRestPath</servlet-name>
</servlet-mapping>
</web-app>
You can edit your login in MyFilter.java file or you can also add the init parameter in web.xml file.
MyFilter.java
public class CorsFilter implements Filter{
#Override
public void init(FilterConfig fConfig) throws ServletException {
// do something
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) request;
HttpServletResponse response = (HttpServletResponse) response;
//here * is used to allow all the origin i.e. anyone can access the api
response.addHeader("Access-Control-Allow-Origin", "*");
// methods which is allowable from the filter
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS,PUT, DELETE, HEAD");
//custom header entry
response.addHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");
filterChain.doFilter(request, response);
}
#Override
public void destroy() {
//do something
}
}
I think it will be right solution for your query.
I'm trying to send a file to rackspace via AJAX. This is my first time looking at CORS. I see in the documentation the option to send a preflight request, however since I personally set the header and know that my origin is valid I'm trying to forgo, these are the headers from my upload endpoint:
HTTP/1.1 204 No Content
Content-Length: 0
X-Container-Object-Count: 2
Accept-Ranges: bytes
X-Container-Meta-Access-Log-Delivery: false
X-Container-Meta-Access-Control-Expose-Headers: etag location x-timestamp x-trans-id
X-Timestamp: 1401852621.29287
X-Container-Meta-Access-Control-Allow-Origin: h ttp://localhost:8080**<-- (manually added the space after "h" so stackoverflow would let me submit)
X-Container-Bytes-Used: 5572910
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txfc64055cb1114b6fb0ef6-0053a77a46ord1
Date: Mon, 23 Jun 2014 00:52:22 GMT
However, whenever I try to send the request it immediate fails in chrome with the following message:
XMLHttpRequest cannot load [**I'm redacting my actual endpoint**]. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'h ttp://localhost:8080' is therefore not allowed access.
Here are my request headers:
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryZSg4nEq8EDaXQQBu
Origin:h ttp://localhost:8080
Referer:h ttp://localhost:8080/tools/artwork
<-- (manually added the space after "h" so stackoverflow would let me submit)
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
What am I missing? Is preflight request required even if you know origin is permitted? I never see a packet come back to seems like Chrome isn't sending?
Yes, preflight is required any time your CORS request is not of the "simple" variety--meaning, you have a method other than GET, HEAD, or POST, a content type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, or your request sets a custom header.
Regardless of this, however, the response you've pasted does not contain Access-Control-Allow-Origin (it has X-Container-Meta-Access-Control-Allow-Origin) in the first place, which is why your request was rejected.
In your server,add Access-Control-Allow-Origin: http://foo.example header.
For example in Spring Controller, response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080");
Additional things,
Access-Control-Allow-Origin: http://foo.example // you can add as many urls separated by commas or '*' to allow all urs
Access-Control-Allow-Methods: POST, GET, OPTIONS // Request method options separated by commas
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000 // expiration in milliseconds
Refer this MDN site.
What I am trying to do is to have a page on the HTTP protocol sending an AJAX call to the same Web server but using HTTPS. Both the requesting page and the AJAX handler are on the same server, having the same domain and port. (I.e., only difference is the protocol.) To illustrate,
From
http://www.example.com/index.php
Triggers a jQuery AJAX call to
https://www.example.com/authenticate.php?user=123&password=456
(I am hoping to pass the password through HTTPS to make it encrypted over the Internet. Due to some design constraints I must use AJAX call instead of redirecting the page.)
I understand that there is a CORS issue here and thus I researched a bit and found that I could actually make use of the Access-Control-Allow-Origin header to help. I then set the following in my Apache's configuration file,
Header set Access-Control-Allow-Origin *
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "content-type, accept"
Header set Access-Control-Max-Age 1000
I can see that when the browser requests the resources from the server, the headers can be seen. Request:
Accept */*
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Authorization Basic Y2FzZXRhZ3JhbWRldjpwYXNzd29yZGRldiE=
Cache-Control no-cache
Connection keep-alive
Cookie __utma=99230732.2019724749.1337107099.1337849971.1337856946.9; __utmz=99230732.1337107099.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=217650581.954519005.1337107174.1337772401.1337777327.5; __utmz=217650581.1337107174.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=99230732; PHPSESSID=m8lnqhqv2qa6f884a8um413n81
Host www.example.com
Pragma no-cache
Referer http://www.example.com/index.php
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0
The response is like,
Accept-Ranges bytes
Access-Control-Allow-Head... content-type, accept
Access-Control-Allow-Meth... GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Orig... *
Access-Control-Max-Age 1000
Connection close
Content-Length 16599
Content-Type application/x-javascript
Date Thu, 24 May 2012 14:48:17 GMT
Etag "48157-40d7-4c0c938b220c0"
Last-Modified Thu, 24 May 2012 14:39:39 GMT
Server Apache/2.2.3 (CentOS)
So it looks like the header part is fulfilled. (Am I right?)
Then when I tried to call the follow jQuery AJAX code in JavaScript,
$.ajax({
// Use HTTPS as there is password transferred
url : "https://www.example.com/authentication.php",
type : 'POST',
dataType : 'json',
async : false,
data : ajaxData,
beforeSend : function(xhr, opt) {},
error : function(error) {
console.log("Ajax error: unable to login user: ");
console.log(error);
},
success : function(status) {
if(status==USER_AUTH_AUTHENTICATE_USER_SUCCESS) {
console.log("User login succeeded!");
} else {
console.log("User login failed.");
}
}
});
The browser (FireFox 12) will just return an object,
readyState 0
status 0
statusText "[Exception... "Access to restricted URI denied" code: "1012" nsresult: "0x805303f4 (NS_ERROR_DOM_BAD_URI)" location: "http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js Line: 8240"]"
Is there something that I missed out?
In fact I had already tried a lot of suggestions from forums and blogs trying to get this done but still I am unsuccessful. I also tried using JSONP and it works fine on FireFox but failed on Chrome/Safari with no readable error message but just throwing an error from jQuery code "head.insertBefore( script, head.firstChild );".
Appreciate much if someone can give me a clue on what is wrong with my code/settings.
Thanks!
Edited on 2012-05-25 20:29 (UTC +08:00)
As suggested I read this reference case (http://stackoverflow.com/questions/5750696/how-to-get-a-cross-origin-resource-sharing-cors-post-request-working) and I found that it linked to this case (http://stackoverflow.com/questions/5584923/a-cors-post-request-works-from-plain-javascript-but-why-not-with-jquery) as well which is related. I tried the sample XHR code there,
var request = new XMLHttpRequest();
var params = "action=something";
request.open('POST', 'https://www.example.com/controllers/Authentication.php', true);
request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);
The code is called from a page with HTTP protocol. Once the code is executed, the error below is thrown right away,
Access to restricted URI denied...test_xhr.php Line 11
(If I change the HTTPS in JavaScript HTTP, the script works right away and so there should not be any syntax problem or so.)
The request and response headers of the page itself are as follows. Request is,
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Authorization Basic Y2FzZXRhZ3JhbWRldjpwYXNzd29yZGRldiE=
Cache-Control no-cache
Connection keep-alive
Cookie __utma=99230732.2019724749.1337107099.1337856946.1337921578.10; __utmz=99230732.1337107099.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=217650581.954519005.1337107174.1337772401.1337777327.5; __utmz=217650581.1337107174.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=99230732; PHPSESSID=ktd6anojfi40ohemlujosdmhi4
Host www.example.com
Pragma no-cache
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0
The response is,
Access-Control-Allow-Head... content-type, accept
Access-Control-Allow-Meth... GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Orig... *
Access-Control-Max-Age 1000
Connection close
Content-Length 590
Content-Type text/html; charset=UTF-8
Date Fri, 25 May 2012 12:24:44 GMT
Server Apache/2.2.3 (CentOS)
X-Powered-By PHP/5.1.6
So I am just thinking something is fundamentally wrong with my setup but not jQuery as native XHR does not work as well. :(
You have two issues:
1) Access-Control-Allow-Origin "*" is not working with authenticated calls, instead of * reflect the calls Access-Control-Request-Origin or Origin header fields.
2) You'll need Access-Control-Allow-Credentials: true in the response.
Other things that might help: setting authorization header manually, assembling name and password with base64. This is the surest way to have working. Its advantage is its drawback: setting authorization header manually activates the OPTIONS header based CORS handshake. (All your requests are preceded with an OPTIONS request that you have to also handle) This one seems to have a coherent implementation across all modern browsers (IE9 of course is an exception, IE10 however works allegedly).
HTH