I'm running a Jenkins server behind an Apache Proxy.
I'm using Chrome as my browser
Now in a couple of places I have javascript code that looks like this.
console.log("Looking for " + log_url)
$.ajax({
url: log_url,
dataType: "xml"
})
.done(function(xml) {
console.log("FOUND " + log_url);
})
(with something more interesting going on in the "done" section of course)
Now, in one place it works fine, that's when it's in a javascript file in jenkins userContent (a folder where you can put files you want jenkins to serve up via HTML) which is loaded from HTML on a jenkins generated page.
Looking at the headers I see
Request URL:http://myserver.com/jenkins/job/WPF-TryBuild/1190/artifact/Win32_Debug_build_log.xml
Request Method:GET
Status Code:200 OK
Remote Address:82.39.249.244:80
Response Headers
view parsed
HTTP/1.1 200 OK
Date: Mon, 31 Oct 2016 12:35:58 GMT
Server: Jetty(9.2.z-SNAPSHOT)
X-Content-Type-Options: nosniff
Content-Security-Policy: sandbox allow-scripts; default-src 'self'; script-src 'self' https://ajax.googleapis.com;
X-WebKit-CSP: sandbox allow-scripts; default-src 'self'; script-src 'self' https://ajax.googleapis.com;
X-Content-Security-Policy: sandbox allow-scripts; default-src 'self'; script-src 'self' https://ajax.googleapis.com;
Last-Modified: Mon, 31 Oct 2016 10:40:11 GMT
Expires: Mon, 31 Oct 2016 10:40:11 GMT
Accept-Ranges: bytes
Content-Type: application/xml
Content-Encoding: gzip
Access-Control-Allow-Origin: null
Access-Control-Allow-Methods: GET, PUT, OPTIONS
Access-Control-Allow-Headers: X-Requested-With
Keep-Alive: timeout=5, max=93
Connection: Keep-Alive
Transfer-Encoding: chunked
Request Headers
view parsed
GET /jenkins/job/WPF-TryBuild/1190/artifact/Win32_Debug_build_log.xml HTTP/1.1
Host: myserver.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: application/xml, text/xml, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
Referer: http://myserver.com/jenkins/job/WPF-TryBuild/1190/?auto_refresh=false
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cookie: ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE=Sm9uOjE0Nzg4NjU1MTIyODg6ZjNlNmM5NDIwZDQwYWU0YzdiOTc2MWJjN2NjNzUxNDE5NDdhNmI3OGI0M2E1OGIxMzM4NjEwYmEyZjRmOGUwZA==; JSESSIONID.e269d02c=1nyxka737w02s1v7tq8opej8fu; JSESSIONID.61f82bd1=5qgyu4eegvkozmo5u1axqc6t; screenResolution=1440x900; JSESSIONID.61f82bd1=238or6iqc0se7r2lo4cyyco4; hudson_auto_refresh=false
So it's sending a GET request, headers are being served up as I have set them in the Apache proxy, and the page works, lovely.
However, if I do the same thing in a javascript file loaded by an HTML page which is in userContent, I see the following headers
Request URL:http://myserver.com/jenkins/job/WPF-TryBuild/1190/artifact/Win32_Debug_build_log.xml
Request Method:OPTIONS
Status Code:403 Forbidden
Remote Address:82.39.249.244:80
Response Headers
view parsed
HTTP/1.1 403 Forbidden
Date: Mon, 31 Oct 2016 13:18:45 GMT
Server: Jetty(9.2.z-SNAPSHOT)
X-Content-Type-Options: nosniff
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/html;charset=UTF-8
X-Hudson: 1.395
X-Jenkins: 2.27
X-Jenkins-Session: f3999f25
X-Hudson-CLI-Port: 8081
X-Jenkins-CLI-Port: 8081
X-Jenkins-CLI2-Port: 8081
X-You-Are-Authenticated-As: anonymous
X-You-Are-In-Group:
X-Required-Permission: hudson.model.Hudson.Read
X-Permission-Implied-By: hudson.security.Permission.GenericRead
X-Permission-Implied-By: hudson.model.Hudson.Administer
Set-Cookie: JSESSIONID.61f82bd1=tts6a6zkw60r1rfiu36q4l7b8;Path=/jenkins;HttpOnly
Access-Control-Allow-Origin: null
Access-Control-Allow-Methods: GET, PUT, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: x-requested-with
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 383
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Request Headers
view parsed
OPTIONS /jenkins/job/WPF-TryBuild/1190/artifact/Win32_Debug_build_log.xml HTTP/1.1
Host: myserver.com
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
Access-Control-Request-Headers: x-requested-with
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
So it is sending an OPTIONS request, which is failing, so the code fails there and the page doesn't work (incidentally it works fine when I don't
So I have two questions.
1) Why do I see an OPTIONS request in one case, but not the other?
2) How can I make it work?
Now I know that an OPTIONS request is sent when the jquery is cross-domain, but I don't see how this would qualify as cross domain.
Everything is served up by the same server, the only difference is that in one case the parent page is generated by jenkins at the url /jenkins/job/WPF-TryBuild/[job_number]
whereas in the failing case the parent page is an html page served up by jenkins at
/jenkins/userContent/WpfReports/msbuild/MSBuildLog.html
(Incidentally, changing Access-Control-Allow-Origin from null to * makes no difference in either case)
Related
I'm working on a React App which needs to fetch data from an Api.
I made it work with fake data.
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => {
console.log(response);
return response.json();
})
.then((json) => {
return json;
})
Now i wanted to get data from our local Api with Apigility.
fetch('http://localserver:8081/news')
.then((response) => {
console.log(response);
return response.json();
})
.then((json) => {
return json;
})
But i get net::ERR_ABORTED 403 (The origin "http://localho.st:5000" is not authorized). The app was created with create-react-app and gets served by its run script.
Now the thing is it works, when i enter http://localserver:8081/news in Firefox and Edge. I receive the json data. The same when trying it with my phone, curl or an api tester.
This is the answer when trying to fetch from the app:
HTTP/1.1 403 The origin "http://localhost:3000" is not authorized
Content-Type: text/html; charset=UTF-8
Server: Microsoft-IIS/10.0
X-Powered-By: PHP/7.0.30
Access-Control-Allow-Origin: *
Date: Thu, 07 Oct 2021 12:59:08 GMT
Content-Length: 0
And when calling from browser:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Vary: Origin
Server: Microsoft-IIS/10.0
X-Powered-By: PHP/7.0.30
WWW-Authenticate: Bearer realm="Service"
Access-Control-Allow-Origin: *
Date: Thu, 07 Oct 2021 13:03:08 GMT
Content-Length: 133933
I've read about setting up a proxy to get CORS calls, but i wondered if there are other solutions to this problem.
EDIT:
localserver:
GET /news HTTP/1.1
Host: 10.254.2.10:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
Accept: */*
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Origin: http://localhost:3000
Referer: http://localhost:3000/
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
HTTP/1.1 403 The origin "http://localhost:3000" is not authorized
Content-Type: text/html; charset=UTF-8
Server: Microsoft-IIS/10.0
X-Powered-By: PHP/7.0.30
Access-Control-Allow-Origin: *
Date: Thu, 07 Oct 2021 14:15:22 GMT
Content-Length: 0
https://jsonplaceholder.typicode.com/posts
Host: jsonplaceholder.typicode.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
Accept: */*
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Origin: http://localhost:3000
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Referer: http://localhost:3000/
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
HTTP/3 200 OK
date: Thu, 07 Oct 2021 14:17:37 GMT
content-type: application/json; charset=utf-8
x-powered-by: Express
x-ratelimit-limit: 1000
x-ratelimit-remaining: 999
x-ratelimit-reset: 1633547463
access-control-allow-origin: http://localhost:3000
vary: Origin, Accept-Encoding
access-control-allow-credentials: true
cache-control: max-age=43200
pragma: no-cache
expires: -1
x-content-type-options: nosniff
etag: W/"6b80-Ybsq/K6GwwqrYkAsFxqDXGC7DoM"
via: 1.1 vegur
cf-cache-status: HIT
age: 4307
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=qYfd07Dc%2BG9NUgzVp1DHMPuBcDx8UOvlbWfDD51OGSN8s74yaJFooN99m7nG4NSHV%2BeqY78Qw%2Bb7ozFdWCmF8ngPRnQPc3tlVdrSwGy8TKWYLwWSEYI4YE88GU5yyErQ8P5jLa5tUkPnB4FA6mg7"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
cf-ray: 69a7c10bdbf66d8f-MUC
content-encoding: br
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400
Create-React-App comes with a simple way to handle this: add a proxy field to your package.json file as shown below. In this case, a request is made from server A to server B
"proxy": "http://localserver:8081/",
You can run a local reverse proxy to get the API calls from the same origin (say mapping localhost:3000/api/news to localhost:8081/news) but then it'd probably be easier to set up a CORS proxy.
You could try to make the API JSONP and circumvent the same origin policy that way, but this is likely also more hairy than setting up a CORS proxy.
Long story short: Whenever you make requests across origins, CORS needs to be set up.
For some reason cookies set by server are not being saved, can't access them from within my js code, in devtools in Application tab in cookies section it's all empty, but somehow when I make a request to the server after the initial one, those cookies that apparently didn't save are being included in the header.
I have set withCredentials to true in axios config, as well as CORS_ALLOW_CREDENTIALS to true on my backend.
Here are the headers from the request that should save cookies:
Response Header:
access-control-allow-credentials: true
access-control-allow-origin: <frontend url>
content-length: 22
content-type: text/html; charset=utf-8
date: Mon, 01 Feb 2021 12:04:09 GMT
server: nginx/1.19.2
set-cookie: csrftoken=<token>; expires=Mon, 31 Jan 2022 12:04:09 GMT; Max-Age=31449600; Path=/; SameSite=Lax
set-cookie: sessionid=<sessionid>; expires=Mon, 01 Feb 2021 13:04:09 GMT; HttpOnly; Max-Age=3600; Path=/
strict-transport-security: max-age=31536000
vary: Cookie, Origin
x-frame-options: SAMEORIGIN
Request Headers:
:authority: <backend url>
:method: POST
:path: /login/
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
cache-control: no-cache
content-length: 66
content-type: application/json;charset=UTF-8
dnt: 1
origin: <frontend url>
pragma: no-cache
referer: <current frontend url query>
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
As you can see in the response I'm getting two cookies to be set, sessionid and csrftoken, those are not being saved.
What's weird those cookies are present in the following request:
Request Headers:
:authority: <backend url>
:method: GET
:path: /numbers/
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
cache-control: no-cache
cookie: csrftoken=<token>; sessionid=<sessionid>
dnt: 1
origin: <frontend url>
pragma: no-cache
referer: <current frontend url query>
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
How is it possible for the cookies to not be set but still included in the request? And what can cause this behavior? I really need them to be saved.
My backend and frontend are located at different urls, my backend is running on Django with a rest-framework.
UPDATE
I've also tried to set samesite on the cookies to none, as well as changing request content-type to application/x-www-form-urlencoded. Still no luck.
After hours spent troubleshooting this problem I found out a solution, somewhat. My frontend app and backend app are hosted from different urls, but under the same domain, like that: <frontend>.<mydomain>.com and <backend>.<mydomain>.com
When frontend application was making a request to the backend, backend was sending set-cookie headers that would save the cookies under <backend>.<mydomain>.com (I was able to confirm this in here: chrome://settings/siteData), which made them inaccessible from within <frontend>.<mydomain>.com, I were able to fix that by adding a domain property to the set-cookie header that would point to .<mydomain>.com. To do that I had to create a middleware in Django that would add my predefined domain name to the cookies before being send back to the client.
I'm not really 100% happy with this because if my applications were served from different domains, I'm not sure if I could make the cookies work at all, since setting set-cookie to a different domain is not allowed by the browser.
I need some more eyes on this. My preflight request is failing with 405 Method Not Allowed.
As far as I can tell it should be working. Here's my request:
OPTIONS http://diffDomain/spf/v1/user/user#example.com/password/change
HTTP/1.1
Host: diffDomain.com
Connection: keep-alive
Access-Control-Request-Method: PUT
Origin: http://www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Accept: */*
Referer: http://www.example.com/appName/index.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,es-US;q=0.8,es;q=0.6,en;q=0.4
Response:
HTTP/1.1 405 Method Not Allowed
Date: Thu, 14 Sep 2017 02:06:30 GMT
Server: Apache/2.4.7 (Ubuntu)
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS, DELETE
X-Powered-By: PHP/5.5.9-1ubuntu4.20
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type, api_key, Authorization, Accept
Content-Length: 0
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json
I'm waiting for access to the server so that I can add Access-Control-Request-Method to the Access-Control-Allow-Headers line. Would that help?
I just need some eyes, because I've been debugging this for a few hours today and I don't have access to the server yet.
When I do as #sideshowbarker suggested below i get:
> curl -i -X OPTIONS http://diffDomain.com/spf/v1/user/user#example.com/password/change
HTTP/1.1 500 Internal Server Error
Date: Thu, 14 Sep 2017 21:25:39 GMT
Server: Apache/2.4.7 (Ubuntu)
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS, DELETE
X-Powered-By: PHP/5.5.9-1ubuntu4.20
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type, api_key, Authorization, Accept, Content-Type, api_key, Authorization, Accept, Access-Control-Request-Method, Origin
Content-Length: 0
Connection: close
Content-Type: application/json
I don't know how your backend looks like, but what I would suggest you is to add a middleware that intercepts every OPTIONS and return a 200 response and moving to the next request.
To clarify here is a post about this issue with Laravel based APIs.
I hope it helps.
The setup uses a Backbone Model, Nginx server. The users enter their username and password which is then passed via a post. The server authenticates and returns a session cookie.
When the backend and front-end are on the same server (e.g. connect via localhost) the cookie is stored. However when the connection is remote, it is not stored in Chrome; however, it is stored in Safari and FireFox.
Ajax is setup via
$.ajaxSetup({
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
The request headers are
POST /login HTTP/1.1
Host: localhost:8102
Connection: keep-alive
Content-Length: 59
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://127.0.0.1:9102
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36
Content-Type: application/json
DNT: 1
Referer: http://127.0.0.1:9102/somefolder
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
The response headers are
HTTP/1.1 200 OK
access-control-allow-origin: http://127.0.0.1:9102
access-control-allow-credentials: true
vary: origin,accept-encoding
access-control-expose-headers: WWW-Authenticate,Server-Authorization
content-type: text/html; charset=utf-8
set-cookie: na-auth-token=encrypted-string; Max-Age=86400; Expires=Thu, 27 Apr 2017 13:32:44 GMT; HttpOnly; SameSite=Strict; Path=/
cache-control: no-cache
content-encoding: gzip
Date: Wed, 26 Apr 2017 13:32:44 GMT
Connection: keep-alive
Transfer-Encoding: chunked
In FireFox and Safari the cookie is stored just fine, but in Chrome it gets the response and tosses the cookie without any notification.
Update
The cookie is actually being saved under the localhost domain, however when you navigate back to the page (e.g. via a window.location.reload) the cookie disappears.
So the answer to my question lied in a library we were using
hapi-auth-cookie
The package updated and a flag was introduced isSameSite. Changed this value to false to allow the cors cookie to persist between pages loads.
I have a page served by HTTP. Client code sends AJAX-requests for authorization to the same domain, but on HTTPS. (so it is CORS).
FireFox generates this request: // domains and cookies are changed
OPTIONS /auth/registration/json/info/ HTTP/1.1
Host: my-site.dev
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-ru,pl;q=0.8,ru;q=0.6,en-us;q=0.4,en;q=0.2
Accept-Encoding: gzip, deflate
Origin: http://my-site.dev
Access-Control-Request-Method: GET
Access-Control-Request-Headers: x-requested-with
Connection: keep-alive
And my server responds:
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Thu, 07 Nov 2013 09:55:55 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: https://my-site.dev
Vary: Cookie
Access-Control-Allow-Origin: http://my-site.dev
Access-Control-Allow-Methods: OPTIONS, GET
Set-Cookie: csrftoken=foobar; expires=Thu, 06-Nov-2014 09:55:55 GMT; Max-Age=31449600; Path=/
0
FireBug shows that OPTIONS request succeeded, but does not fire GET request after it:
What is wrong in my response?
Qantas 94 Heavy, you're right. There should be only one Access-Control-Allow-Origin header with only one domain: domain, that specified in Origin request header.
This is right answer that firefox accepts:
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Thu, 07 Nov 2013 09:55:55 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Cookie
Access-Control-Allow-Origin: http://my-site.dev // The same as `Origin`
Access-Control-Allow-Methods: OPTIONS, GET
Set-Cookie: csrftoken=foobar; expires=Thu, 06-Nov-2014 09:55:55 GMT; Max-Age=31449600; Path=/
0