nodeSolidServer / node-solid-server

Solid server on top of the file-system in NodeJS
https://solidproject.org/for-developers/pod-server
Other
1.77k stars 297 forks source link

CORS Issue with Google Chrome #1255

Open Leoudayan opened 5 years ago

Leoudayan commented 5 years ago

Single Sign On to a profile is blocked by CORS in Google Chrome as https://solid.example.com/jwks is cached by the browser with a particular Access-Control-Allow-Origin header. Tested using Google Chrome Version 75.0.3770.100 and Solid 5.1.6.

Please describe what you did in reproducible steps

Browse to https://solid.example.com Click Log in Click the solid.example.com identity provider and login with test1 Visit the test1 profile at https://test1.solid.example.com Click Log in Click the test1.solid.example.com identity provider Click logout Browse to https://solid.example.com Click logout

Browse to https://solid.example.com Click Log in Click the solid.example.com identity provider and login with test2 Visit the test2 profile at https://test2.solid.example.com Click Log in Click the test2.solid.example.com identity provider

Expected behaviour:

Automatic login as test2.

Actual behaviour:

Nothing happens when you click the identity provider.

Any material that will help, logs, error messages, etc.

Details:

The console in Chrome developer tools says:

“Access to fetch at 'https://solid.example.com/jwks' from origin 'https://test2.solid.example.com' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'https://test1.solid.example.com' that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Cross-Origin Read Blocking (CORB) blocked cross-origin response https://solid.example.com/jwks with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.

The following HTTP request is made for test1:

GET /jwks HTTP/1.1 Host: solid.mydomain.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Accept: / Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: https://test1.solid.mydomain.com/common/popup.html Origin: https://test1.solid.mydomain.com DNT: 1 Connection: keep-alive

The following HTTP response is seen from the server for test1:

HTTP/1.1 200 OK Date: Wed, 03 Jul 2019 12:00:00 GMT Server: Apache X-Frame-Options: SAMEORIGIN X-Powered-By: solid-server/5.1.6 Access-Control-Allow-Origin: https://test1.solid.mydomain.com Vary: Accept,Authorization,Origin Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate Allow: OPTIONS, HEAD, GET, PATCH, POST, PUT, DELETE Content-Type: application/json; charset=utf-8 Content-Length: 3090 ETag: W/"c12-rnReKfRAdIl+RoAH4i8+uD1Huqg" Keep-Alive: timeout=5, max=100 Connection: Keep-Alive

{"keys":[{"kid"………………….]}

The following HTTP request is made for test2:

GET /jwks HTTP/1.1 Host: solid.mydomain.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Accept: / Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: https://test2.solid.mydomain.com/common/popup.html Origin: https://test2.solid.mydomain.com DNT: 1 Connection: keep-alive If-None-Match: W/"c12-rnReKfRAdIl+RoAH4i8+uD1Huqg"

The following HTTP response is seen from the server for test2:

HTTP/1.1 304 Not Modified Date: Wed, 03 Jul 2019 12:01:00 GMT Server: Apache Connection: Keep-Alive Keep-Alive: timeout=5, max=100 ETag: W/"c12-rnReKfRAdIl+RoAH4i8+uD1Huqg" Vary: Accept,Authorization,Origin

Since the request to /jwks for test2 uses the If-None-Match header the server responds with a HTTP 304 and the browser uses the cached response. Unfortunately the cached response has the “Access-Control-Allow-Origin: https://test1.solid.mydomain.com” header which does not match the origin on https://test2.solid.mydomain.com and the browser blocks the request.

@RubenVerborgh thoughts?

RubenVerborgh commented 5 years ago

@RubenVerborgh thoughts?

CORS is a pain.

The Vary header is set incorrectly.

Leoudayan commented 5 years ago

Thanks for the reply Ruben. What should the Vary header be set to instead? @RubenVerborgh

RubenVerborgh commented 5 years ago

/jwks should Vary: Origin

Leoudayan commented 5 years ago

So, since node solid server returns this header it’s a bug that will be fixed in the next version? @RubenVerborgh

Leoudayan commented 5 years ago

@RubenVerborgh @kjetilk

We believe we’ve managed to find a workaround to this issue for our setup. In the end, we’ve noticed that Chrome seems to prioritise the ‘ETag’ header over ‘Vary: Origin’, so even with Origin set in Vary, it would send a conditional request to the server (Using the ‘If-None-Match’ header) and the Node Solid server would always return a HTTP 304 (Non Modified) response. The removal of the ETag prevents Chrome utilising ETag for caching purposes and the Vary Origin header applies.

As our Solid instance is setup with Apache on the frontend running through a reverse proxy, we’ve applied the code below to the Apache Virtual Host:

<Location /jwks>
Header unset ETag
</Location>

@Otto-AA We do also have an explicit use case with a remote file manager that logs into a Solid POD from another URL, which then causes an ETag to override Vary on openid-configuration (Located in /.well-known). Unsetting the ETag as above to .well-known has solved this problem for us also. (This issue was Opera specific, Current Version:62.0.3331.43)

<Location /.well-known>
Header unset ETag
</Location>
RubenVerborgh commented 5 years ago

The NSS 304 is wrong.

michielbdejong commented 5 years ago

@jaxoncreed probably the easiest solution is to always add Origin to the Vary header in the http response.

Another fix would probably be to always return Access-Control-Allow-Origin: * on GET and HEAD, and only do the echoing of the Origin request header on verbs that require a preflight, like POST, PATCH, etc., and on OPTIONS so that the preflight works. But the first option is probably simpler. :)

michielbdejong commented 5 years ago

This may also be relevant: https://github.com/solid/web-access-control-spec/blob/master/Background.md#epilog-a-second-cors-twist

michielbdejong commented 5 years ago

indeed, looks like curl -i https://inrupt.net/jwks already returns Vary: Accept, Authorization, Origin

michielbdejong commented 5 years ago

@Leoudayan we have been looking at this with three people just now, and cannot reproduce the problem. Would you be available for a screen sharing session so we can debug this with you?

michielbdejong commented 5 years ago

maybe weak/strong etag is of influence here as well.

dmitrizagidulin commented 5 years ago

+1, could not reproduce the CORS issue either (while looking at it with Michiel). However, this is a really important issue, and we should definitely get to the bottom of it (since it affects whether we need to suppress ETags on the server side or not).

The one thing I noticed, while trying to reproduce, is that my Chrome requests were NOT sending a If-None-Match: header, whereas @Leoudayan's example was sending that header. I'm not sure if this is an issue with the way I was trying to reproduce (using fetch() on the console), or a slight difference in OS/Chrome version, or what.

michielbdejong commented 5 years ago

@Leoudayan can you try to visit https://site-one.5apps.com/ and then visit https://site-two.5apps.com/ with your browser, and let us know if the second one is or is not able to retrieve https://inrupt.net/jwks?

michielbdejong commented 4 years ago

@csarven can you reproduce this bug? may be related to what you and Tim described in https://github.com/solid/web-access-control-spec/blob/master/Background.md#epilog-a-second-cors-twist

michielbdejong commented 3 years ago

I think this is because you're running NSS behind Apache. I just reproduced this on solidweb.org:


curl 'https://solidweb.org/jwks' \
  -H 'Connection: keep-alive' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36' \
  -H 'Accept: */*' \
  -H 'Origin: https://ewingson.solidweb.org' \
  -H 'Sec-Fetch-Site: same-site' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Referer: https://ewingson.solidweb.org/common/popup.html' \
  -H 'Accept-Language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7,fr-FR;q=0.6,fr;q=0.5,de-DE;q=0.4,de;q=0.3,es-ES;q=0.2,es;q=0.1,id-ID;q=0.1,id;q=0.1' \
  -H 'If-None-Match: W/"c12-hLnJBRlUy3d5pfVbi7+DfxyeKLU"' \
  --compressed
michielbdejong commented 3 years ago

cc @ewingson

michielbdejong commented 3 years ago

See https://serverfault.com/questions/748684/304-with-cors-on-apache. I'll see if I can reproduce and fix it because it will also affect the Solid-Nextcloud project we're working on through NLNet. I also created a companion issue for it to track it there: https://github.com/pdsinterop/solid-nextcloud/issues/1

michielbdejong commented 3 years ago

Looks like running NSS behind Apache will not work properly until https://bz.apache.org/bugzilla/attachment.cgi?id=37345&action=edit is merged. Mark Nottingham and Roy Fielding themselves are participating in that bugfix. :)