From 1a3657572e8824bb91ba07c84838a15413ce4c82 Mon Sep 17 00:00:00 2001 From: Eran Sandler Date: Mon, 13 Jul 2015 09:42:23 +0300 Subject: [PATCH 1/2] Added fine grind control of CORS header for QueryResultAPI and possibly future APIs. --- redash/controllers.py | 24 +++++++++++++++--------- redash/settings.py | 8 +++++++- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/redash/controllers.py b/redash/controllers.py index 73fc066cfe..6b9025947f 100644 --- a/redash/controllers.py +++ b/redash/controllers.py @@ -489,20 +489,26 @@ def csv_response(query_result): return make_response(s.getvalue(), 200, headers) @staticmethod - def add_access_control_allow_origin_header(headers): + def add_cors_headers(headers): if 'Origin' in request.headers: origin = request.headers['Origin'] - if origin in settings.QUERIES_RESULT_CORS: + if origin in settings.ACCESS_CONTROL_ALLOW_ORIGIN: headers['Access-Control-Allow-Origin'] = origin - headers['Access-Control-Allow-Credentials'] = 'true' - if request.method == 'OPTIONS': - headers['Access-Control-Request-Method'] = 'GET, POST, PUT' - headers['Access-Control-Allow-Headers'] = 'Content-Type' + headers['Access-Control-Allow-Credentials'] = str(settings.ACCESS_CONTROL_ALLOW_CREDENTIALS).lower() @require_permission('view_query') def options(self, query_id=None, query_result_id=None, filetype='json'): - self.add_access_control_allow_origin_header(request.headers) + headers = {} + self.add_cors_headers(headers) + + if settings.ACCESS_CONTROL_REQUEST_METHOD: + headers['Access-Control-Request-Method'] = settings.ACCESS_CONTROL_REQUEST_METHOD + + if settings.ACCESS_CONTROL_ALLOW_HEADERS: + headers['Access-Control-Allow-Headers'] = settings.ACCESS_CONTROL_ALLOW_HEADERS + + return make_response(null, 200, headers) @require_permission('view_query') def get(self, query_id=None, query_result_id=None, filetype='json'): @@ -535,8 +541,8 @@ def get(self, query_id=None, query_result_id=None, filetype='json'): headers = {} - if len(settings.QUERIES_RESULT_CORS) > 0: - self.add_access_control_allow_origin_header(headers) + if len(settings.ACCESS_CONTROL_ALLOW_ORIGIN) > 0: + self.add_cors_headers(headers) if filetype == 'json': data = json.dumps({'query_result': query_result.to_dict()}, cls=utils.JSONEncoder) diff --git a/redash/settings.py b/redash/settings.py index 1f3cf8c485..8e7691f90f 100644 --- a/redash/settings.py +++ b/redash/settings.py @@ -81,7 +81,13 @@ def parse_boolean(str): CLIENT_SIDE_METRICS = parse_boolean(os.environ.get("REDASH_CLIENT_SIDE_METRICS", "false")) ANALYTICS = os.environ.get("REDASH_ANALYTICS", "") -QUERIES_RESULT_CORS = set_from_string(os.environ.get("REDASH_QUERIES_RESULT_CORS", "")) +# CORS settings for the Query Result API (and possbily future external APIs). +# In most cases all you need to do is set REDASH_CORS_ACCESS_CONTROL_ALLOW_ORIGIN +# to the calling domain (or domains in a comma separated list). +ACCESS_CONTROL_ALLOW_ORIGIN = set_from_string(os.environ.get("REDASH_CORS_ACCESS_CONTROL_ALLOW_ORIGIN", "")) +ACCESS_CONTROL_ALLOW_CREDENTIALS = parse_boolean(os.environ.get("REDASH_CORS_ACCESS_CONTROL_ALLOW_CREDENTIALS", "false")) +ACCESS_CONTROL_REQUEST_METHOD = os.environ.get("REDASH_CORS_ACCESS_CONTROL_REQUEST_METHOD", "GET, POST, PUT") +ACCESS_CONTROL_ALLOW_HEADERS = os.environ.get("REDASH_CORS_ACCESS_CONTROL_ALLOW_HEADERS", "Content-Type") # Query Runners QUERY_RUNNERS = array_from_string(os.environ.get("REDASH_ENABLED_QUERY_RUNNERS", ",".join([ From 4a7c066bf0e08bf7e52f06a5c11dfd69b5467ec6 Mon Sep 17 00:00:00 2001 From: Eran Sandler Date: Mon, 13 Jul 2015 10:05:07 +0300 Subject: [PATCH 2/2] Too many languages... :-( --- redash/controllers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redash/controllers.py b/redash/controllers.py index 6b9025947f..b0c8ac084d 100644 --- a/redash/controllers.py +++ b/redash/controllers.py @@ -508,7 +508,7 @@ def options(self, query_id=None, query_result_id=None, filetype='json'): if settings.ACCESS_CONTROL_ALLOW_HEADERS: headers['Access-Control-Allow-Headers'] = settings.ACCESS_CONTROL_ALLOW_HEADERS - return make_response(null, 200, headers) + return make_response("", 200, headers) @require_permission('view_query') def get(self, query_id=None, query_result_id=None, filetype='json'):