From f6f70814835e75f8b81e6dfb0c1ea9a88872813e Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 16 Nov 2017 11:46:40 +0100 Subject: [PATCH] adjust headers for CORS - add `authorization` to default Access-Control-Allow-Headers - allow overriding `Access-Control-Allow-Headers` just like everything else in case default is inappropriate - ensure case-insensitive comparison for proper header checks --- jupyterhub/apihandlers/base.py | 11 +++++------ jupyterhub/handlers/base.py | 7 +++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index a5f7ed2d..ceff58b4 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -18,14 +18,14 @@ class APIHandler(BaseHandler): return '; '.join([super().content_security_policy, "default-src 'none'"]) def set_default_headers(self): - self.set_header('Content-Type', 'application/json') super().set_default_headers() + self.set_header('Content-Type', 'application/json') def check_referer(self): """Check Origin for cross-site API requests. - + Copied from WebSocket with changes: - + - allow unspecified host/referer (e.g. scripts) """ host = self.request.headers.get("Host") @@ -39,7 +39,7 @@ class APIHandler(BaseHandler): if not referer: self.log.warning("Blocking API request with no referer") return False - + host_path = url_path_join(host, self.hub.base_url) referer_path = referer.split('://', 1)[-1] if not (referer_path + '/').startswith(host_path): @@ -47,7 +47,7 @@ class APIHandler(BaseHandler): referer, host_path) return False return True - + def get_current_user_cookie(self): """Override get_user_cookie to check Referer header""" cookie_user = super().get_current_user_cookie() @@ -178,5 +178,4 @@ class APIHandler(BaseHandler): def options(self, *args, **kwargs): - self.set_header('Access-Control-Allow-Headers', 'accept, content-type') self.finish() diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 1d6638bc..fcc9a41e 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -12,7 +12,7 @@ from urllib.parse import urlparse, urlunparse, parse_qs, urlencode from jinja2 import TemplateNotFound from tornado.log import app_log -from tornado.httputil import url_concat +from tornado.httputil import url_concat, HTTPHeaders from tornado.ioloop import IOLoop from tornado.web import RequestHandler from tornado import gen, web @@ -131,12 +131,15 @@ class BaseHandler(RequestHandler): By default sets Content-Security-Policy of frame-ancestors 'self'. """ - headers = self.settings.get('headers', {}) + # wrap in HTTPHeaders for case-insensitivity + headers = HTTPHeaders(self.settings.get('headers', {})) headers.setdefault("X-JupyterHub-Version", __version__) for header_name, header_content in headers.items(): self.set_header(header_name, header_content) + if 'Access-Control-Allow-Headers' not in headers: + self.set_header('Access-Control-Allow-Headers', 'accept, content-type, authorization') if 'Content-Security-Policy' not in headers: self.set_header('Content-Security-Policy', self.content_security_policy)