From 9acf6a80f4753c1b22c049eb57ea6c3fd5cac965 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 10 Oct 2017 17:01:48 +0200 Subject: [PATCH 1/2] allow token-authenticated requests cross-origin by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit we already apply this logic in our server-side checks, but browsers check `Access-Control-Allow-Origin` headers themselves as well, meaning that token-authenticated requests can’t be made cross-origin without CORS headers from browsers, only scripts. This makes default browser and server-side origin checks consistent --- notebook/base/handlers.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/notebook/base/handlers.py b/notebook/base/handlers.py index d5a738251..a33005eaf 100755 --- a/notebook/base/handlers.py +++ b/notebook/base/handlers.py @@ -281,6 +281,16 @@ class IPythonHandler(AuthenticatedHandler): origin = self.get_origin() if origin and self.allow_origin_pat.match(origin): self.set_header("Access-Control-Allow-Origin", origin) + elif ( + self.token_authenticated + and "Access-Control-Allow-Origin" not in + self.settings.get('headers', {}) + ): + # allow token-authenticated requests cross-origin by default. + # only apply this exception if allow-origin has not been specified. + self.set_header('Access-Control-Allow-Origin', + self.request.headers.get('Origin', '')) + if self.allow_credentials: self.set_header("Access-Control-Allow-Credentials", 'true') @@ -517,6 +527,22 @@ class APIHandler(IPythonHandler): self.set_header('Access-Control-Allow-Methods', 'GET, PUT, POST, PATCH, DELETE, OPTIONS') + # if authorization header is requested, + # that means the request is token-authenticated. + # avoid browser-side rejection of the preflight request. + # only allow this exception if allow_origin has not been specified. + requested_headers = self.request.headers.get('Access-Control-Request-Headers', '').split(',') + if requested_headers and any( + h.strip().lower() == 'authorization' + for h in requested_headers + ) and ( + self.allow_origin + or self.allow_origin_pat + or 'Access-Control-Allow-Origin' in self.settings.get('headers', {}) + ): + self.set_header('Access-Control-Allow-Origin', + self.request.headers.get('Origin', '')) + class Template404(IPythonHandler): """Render our 404 template""" From 08f7189cbaeea7e4a4f83bfa69c9420b124ad633 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 11 Oct 2017 10:51:12 +0200 Subject: [PATCH 2/2] only allow CORS exception when auth is enabled --- notebook/base/handlers.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/notebook/base/handlers.py b/notebook/base/handlers.py index a33005eaf..3423e3675 100755 --- a/notebook/base/handlers.py +++ b/notebook/base/handlers.py @@ -530,11 +530,17 @@ class APIHandler(IPythonHandler): # if authorization header is requested, # that means the request is token-authenticated. # avoid browser-side rejection of the preflight request. - # only allow this exception if allow_origin has not been specified. + # only allow this exception if allow_origin has not been specified + # and notebook authentication is enabled. + # If the token is not valid, the 'real' request will still be rejected. requested_headers = self.request.headers.get('Access-Control-Request-Headers', '').split(',') if requested_headers and any( h.strip().lower() == 'authorization' for h in requested_headers + ) and ( + # FIXME: it would be even better to check specifically for token-auth, + # but there is currently no API for this. + self.login_available ) and ( self.allow_origin or self.allow_origin_pat