I am trying to set server side cookies(sessions) in client side. But it is failing.
The process is as follows:
1) Inititate a call to an API which is residing in abc.com from blog.abc.com.
2) The API from abc.com is going to return a response object to blog.abc.com.
I am getting the set_cookie in response object from the API, but in the client side it is not setting!
The following are the request and response headers from abc.com when I called the API from blog.abc.com
Request Headers:
Host: abc.com
Connection: keep-alive
Accept: */*
Origin: http://blog.abc.com
Referer: http://blog.abc.com/
Response Headers:
Connection: keep-alive
Set-Cookie: session_token="2|1:0|10:1474371987|13:session_token|44:NDFjZjNiZjFiYjcwNDk4ZTk4NDllYmRhNmNkYzFjZTA=|f60c277db4f5f38ec31f55bc581ddcf997f38fa493276508156f983500de4b25"; expires=Wed, 21 Sep 2016 11:46:27 GMT; Path=/
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
X-Frame-Options: DENY
But in the client side (blog.abc.com), there is no cookie ("session-token").
Can anyone please help. Thanks in advance.
The cookie should still be getting set correctly on abc.com, but you can't see that cookie from javascript on blog.abc.com. This is part of the same-origin policy: you can't see cookies that are set for another domain (regardless of access-control-allow-*). If you need this information in the client, it needs to be in the body of the response.
Related
I'm using a fork of Django Simple SSO as an authentication mechanism on a Server.
It works great while we use the "standard" way to log in on the server. This means, we just access to the /login path, log in, and then navigate across the restricted paths, etc.
The problem comes when we want to connect to a 3rd server that also relays on SSO auth vía javascript/AJAX without direct access to /login path first.
I've tried to use django-cors-headers but didn't get the expected result.
I'm close to give up so any help is welcome.
The problem
Assume we are logged in on server 1 and auth server and we want a resource on server 2
When the browser is redirected to the Auth Server in order to verify that the browser is logged with a valid user, the cookie header is not transferred.
(See the diagram on button for further details on how Django Simple SSO works)
The headers set by the auth-server on the preflight request are the following:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept-encoding, accept, authorization, cookie, content-type, dnt, origin, user-agent, x-csrftoken, x-grafana-org-id, x-dashboard-id, x-panel-id, x-requested-with
Access-Control-Allow-Methods: DELETE, GET, OPTIONS, PATCH, POST, PUT
Access-Control-Allow-Origin: https://server1-domain
Access-Control-Max-Age: 86400
Connection: keep-alive
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Fri, 16 Jul 2021 12:14:54 GMT
Server: nginx
Vary: Origin
The headers on the GET request where the following:
Request/Client:
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: es-ES,es;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Host: auth-server-domain
Origin: https://server1-domain
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
sec-ch-ua-mobile: ?0
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/91.0.4472.114 Safari/537.36
x-grafana-org-id: 1
Response/Auth Server:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://server1-domain
Connection: keep-alive
Content-Language: es
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Fri, 16 Jul 2021 12:14:54 GMT
Location: /error_unauthorized_page
Referrer-Policy: same-origin
Server: nginx
Vary: Accept-Language, Cookie, Origin
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
I think all the headers are correct, but it's clearly there are some error.
On the cookie side, I have tried to play with the SingleSite property, setting it to None and Lax without any change.
The domain set on the cookie browser's memory is "correct" from my point of view as it is .auth-server-domain (note the dot).
I'm using DJango 3.2.5 and Google Chrome as a web browser.
If you have any idea of why cookie is not being send on the auth-server-domain cors requests, I will really appreciate your comments.
If do you think I have missed any piece of relevant information, feel free to ask!
Thank everyone to reach this point and help me!
Appendix:
A simplified schema of how Simple SSO works:
I have created a backend server in Django with Django Rest Framework, and a React frontend. My front retrieves data from the back through APIs. Each app is on a different subdomain of the same domain. I use
Cloudflare to manage DNS and for SSL / security.
I have had no problem with GET calls. For POST calls, I send the POST data to the server through a form, and I know it works as there is a change to the database (record created in this instance). However, I have implemented a 'retry until' function using axios and polly-js. This method waits until it receives a 201 CREATED response, otherwise retries.
My problem is that when I submit the form on React, the POST is indeed received and processed by my backend server, but the response is blocked. So after 10-15 seconds, I receive an error message through the console and my 'retry until' method sends another POST request. The response of this second one is not blocked by Chrome, and I receive the 201 status. But the overall effect is that I have now 2 identical records in the database because the first call did not 'receive' the response and retried.
The error in the console I get is:
Access to XMLHttpRequest at 'https://subdomain.domain.io/' from origin 'https://api.domain.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
What I have already done and has not worked:
I don' think it's a backend problem as the POST goes through and the record created. But I have whitelisted all CORS origins in Django
I have added the header 'Access-Control-Allow-Origin': '*' to my POST request through axios
I have manually added the same 'Access-Control-Allow-Origin': '*' header from my Django DRF response.
Both request that I send (first one through form submission, second one through automatic retry) are identical (seen through Chrome network tab):
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Origin: https://subdomain.domain.io
Referer: https://subdomain.domain.io/path
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
My POST and retry method:
const postData = (url, data, headers) => {
headers['Access-Control-Allow-Origin'] = "*"
return polly()
.waitAndRetry([100, 200, 400, 1000])
.executeForPromise(async () => {
const rsp = await axios.post(url, data, headers);
if (rsp.status < 210) {
return rsp.data;
}
return Promise.reject(rsp);
});
};
The response I get when the second try succeeds:
access-control-allow-origin: *
allow: GET, POST, HEAD, OPTIONS
cf-ray: 4dd7cbccce256948-CDG
content-length: 364
content-type: application/json
date: Mon, 27 May 2019 11:54:47 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
status: 201
strict-transport-security: max-age=2592000; includeSubDomains; preload
vary: Accept, Origin
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
For reference, the CORS settings in Django
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_HEADERS = (
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'access-control-allow-origin'
)
EDIT
Firefox shows me the response for the 504 GATEWAY TIMEOUT of the first POST request:
cf-ray: 4dd82ac15f42cd97-CDG
content-type: text/html; charset=UTF-8
date: Mon, 27 May 2019 13:00:36 GMT
expect-ct: max-age=604800, report-uri="ht….com/cdn-cgi/beacon/expect-ct"
expires: Thu, 01 Jan 1970 00:00:01 GMT
pragma: no-cache
server: cloudflare
set-cookie: __cfduid=d0a3a9ee872171ada14cb…n=.wisly.io; HttpOnly; Secure
set-cookie: cf_use_ob=0; path=/; expires=Mon, 27-May-19 13:01:06 GMT
strict-transport-security: max-age=2592000; includeSubDomains; preload
x-content-type-options: nosniff
X-Firefox-Spdy: h2
The Access-Control-Allow-Origin is missing, but it is part of my backend code. Could anything be happening with Cloudflare?
The expected result would be that, when I POST through the form, receive the 201 back (which would be accepted and read by Chrome) so that I can
Show the user the form has been correctly saved to the database
Not retry the POST, resulting in dual entry.
Thank you!
You don't need to put access-control-allow-origin in your CORS_ALLOW_HEADERS.
The Django CORS will add automatically on requests based on your configurations.
Some tips you could try:
Use default_headers instead of put all default headers (just to improve the code)
I already had problems with some basic headers that Chrome was sending and my app didn't allow them, so I had to add
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = default_headers + (
'Cache-Control', 'If-Modified-Since',
)
Try adding "trusted origins"
CSRF_TRUSTED_ORIGINS = (
'*.yourdomain.com',
)
Check out this lib. https://pypi.org/project/django-cors-headers. It helped me to solve the same problem with React.
I know about the SOAP -based webservices that SOAP messages, which are XML in turn, are transferred on the network, from client to the server. But what kind of data is transferred in case of RESTful webservice ?
from Wikipedia https://en.wikipedia.org/wiki/Representational_state_transfer
RESTful systems typically, but not always, communicate over the
Hypertext Transfer Protocol with the same HTTP verbs (GET, POST, PUT,
DELETE, etc.)
You can try yourself easily with curl or Fiddler. For example GitHub API is nice to experiment with.
Send this with Fiddler:
GET https://api.github.com/users/octocat HTTP/1.1
Host: api.github.com
User-Agent: Fiddler
and you will get this response:
HTTP/1.1 200 OK
Server: GitHub.com
Date: Fri, 10 Jul 2015 10:23:10 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 1155
Status: 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1436527371
Cache-Control: public, max-age=60, s-maxage=60
Last-Modified: Mon, 06 Jul 2015 23:59:25 GMT
ETag: "d811d5844be3eaf9ab1f60dd36198aa9"
Vary: Accept
X-GitHub-Media-Type: github.v3; format=json
X-XSS-Protection: 1; mode=block
X-Frame-Options: deny
Content-Security-Policy: default-src 'none'
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
Access-Control-Allow-Origin: *
X-GitHub-Request-Id: 3EAD7342:6BF1:E180441:559F9D0D
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Content-Type-Options: nosniff
Vary: Accept-Encoding
X-Served-By: bd82876e9bf04990f289ba22f246ee9b
{"login":"octocat","id":583231,"avatar_url":"https://avatars.githubusercontent.com/u/583231?v=3","gravatar_id":"","url":"https://api.github.com/users/octocat","html_url":"https://github.com/octocat","followers_url":"https://api.github.com/users/octocat/followers","following_url":"https://api.github.com/users/octocat/following{/other_user}","gists_url":"https://api.github.com/users/octocat/gists{/gist_id}","starred_url":"https://api.github.com/users/octocat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/octocat/subscriptions","organizations_url":"https://api.github.com/users/octocat/orgs","repos_url":"https://api.github.com/users/octocat/repos","events_url":"https://api.github.com/users/octocat/events{/privacy}","received_events_url":"https://api.github.com/users/octocat/received_events","type":"User","site_admin":false,"name":"The Octocat","company":"GitHub","blog":"http://www.github.com/blog","location":"San Francisco","email":"octocat#github.com","hireable":false,"bio":null,"public_repos":5,"public_gists":8,"followers":1054,"following":6,"created_at":"2011-01-25T18:44:36Z","updated_at":"2015-07-06T23:59:25Z"}
The following link answered my query. Now I know that the data sent in case of RESTful services is 'raw http' data.
http://rest.elkstein.org/2008/02/how-simple-is-rest.html
I'm trying to build a Ember app with PHP REST framework as my api locally. The Ember app is being served at http://localhost:4200 and the api is being served from just http://localhost. This is causing a CORS issue. I've tried everything that I can think of, but I keep getting an error back saying the request was blocked and that the preflight channel did not succeed. It doesn't succeed in Firefox or Chrome.
I've added the following to the .htaccess file for my api:
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Origin "http://localhost:4200"
Header set Access-Control-Allow-Credentials true
Header set Access-Control-Allow-Headers "accept, content-type"
Here's my request headers:
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:4200
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
And the response headers:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept, content-type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: http://localhost:4200
Connection: close
Content-Type: text/html; charset=utf-8
Date: Fri, 24 Jul 2015 17:10:49 GMT
Server: Apache/2.4.9 (Win64) PHP/5.5.12
Set-Cookie: 24fd751c8630b64fcf935a94e8bcef46=qih6pfnqo94d4cgi5b5d79h4i6; path=/
Transfer-Encoding: chunked
X-Powered-By: PHP/5.5.12
p3p: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Any ideas or solutions? Any help is appreciated. Thanks!
Is you your preflight OPTIONS request returning 200? You can try and return a 200 response with your .htaccess like this:
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header always set Access-Control-Allow-Origin "http://localhost:4200"
Header always set Access-Control-Allow-Credentials true
Header always set Access-Control-Allow-Headers "accept, content-type"
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
One possible issue may be that the browser isn't caching the server response to the browser's OPTIONS request. To fix this, try including an "Access-Control-Max-Age" header in your response and setting it to something like '86400' (1 day). Another issue, according to MDN's documentation on CORS, may be that since you are specifying a specific origin and not just using a wildcard response for the origin, you need to include a "vary" header in your response to specify that responses from the server will depend on the origin of the request. This can be done in the response like so:
Vary: Origin
If you get a CORS error with your main request following a successful OPTIONS request, I believe you also need to include the "Access-Control-Allow-Origin" header and "Vary" header in that response as well.
Hope this helps!
As this answer states, proper handling of the pre-flight OPTIONS request is necessary, but NOT SUFFICIENT for cross-site resource requests to work. All responses to any subsequent requests after prefligh must include Access-Control-Allow-Headers. Hope this helps.
In the server side servlet, add the headers and return 200 status. Example from RESTFul WCF service, where following code was added in Global.asax file
protected void Application_AuthenticateRequest(object sender, EventArgs e){
Response.AddHeader("Access-Control-Allow-Origin", "*");
if (Context.Request.HttpMethod.Equals("OPTIONS")) {
Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
Response.StatusCode = (int)System.Net.HttpStatusCode.OK;
Context.ApplicationInstance.CompleteRequest();
}
}
I'm trying to send an HTTP GET request in C++ using sockets, and I'm getting in response a 301 Moved permently, but to the same address I've asked for!
Here is my GET request :
GET /watch?v=1cQh1ccqu8M HTTP/1.1
Host: www.youtube.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Firefox/29.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language:en-US;q=0.6,en;q=0.4
Connection: keep-alive
All the \r\n are perfectly in place, because this GET request used to work for me not long ago, and I have not touched it since...
The response I'm getting from youtube :
HTTP/1.1 301 Moved Permanently
Date: Mon, 08 Dec 2014 11:04:10 GMT
Server: gwiseguy/2.0
Content-Type: text/html; charset=utf-8
Expires: Tue, 27 Apr 1971 19:44:06 EST
Location: https://www.youtube.com/watch?v=1cQh1ccqu8M
X-XSS-Protection: 1; mode=block; report=https://www.google.com/appserve/security-bugs/log/youtube
Cache-Control: no-cache
Content-Length: 0
P3P: CP="This is not a P3P policy! See http://support.google.com/accounts/bin/answer.py?answer=151657&hl=en for more info."
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic,p=0.002
According to the page they tell me to check http://support.google.com/accounts/bin/answer.py?answer=151657&hl=en, it says I need to add some kind of cookies now?
I've allways send this request without sending any cookies, so I am a bit confused...
me: Was your original request really done with https and not plain http...
#Amit: No, I was connecting to `www.youtube.com', then I've sent the GET request
Then you should look more closely at the redirect:
Location: https://www.youtube.com/watch?v=1cQh1ccqu8M
As you can see, this does redirect you to the same host, same page, but different protocol: you must use https instead of http.