From 6a623dbb64785b882a864b4c80e0f8e052062848 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Sep 10 2020 10:59:02 +0000 Subject: Set Access-Control-Allow-Origin header to allow CORS for GET requests. This is needed to enable Cross-Origin Resource Sharing for ODCS. It is needed if you want to parse the ODCS API results using javascript to produce some reports on external sites. --- diff --git a/server/odcs/server/api_utils.py b/server/odcs/server/api_utils.py index 5d6e7bc..5ae5467 100644 --- a/server/odcs/server/api_utils.py +++ b/server/odcs/server/api_utils.py @@ -22,7 +22,8 @@ import copy import six import flask -from flask import request, url_for +from flask import request, url_for, Response +from functools import wraps from odcs.server.models import Compose from odcs.server import conf from odcs.server.errors import Forbidden @@ -357,3 +358,30 @@ def filter_composes(flask_request): page = flask_request.args.get("page", 1, type=int) per_page = flask_request.args.get("per_page", 10, type=int) return query.paginate(page, per_page, False) + + +def cors_header(allow="*"): + """ + A decorator that sets the Access-Control-Allow-Origin header to + the desired value on a Flask route. + :param allow: a string of the domain to allow. This defaults to '*'. + """ + + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + rv = func(*args, **kwargs) + if rv: + # If a tuple was provided, then the Flask Response should be the first object + if isinstance(rv, tuple): + response = rv[0] + else: + response = rv + # Make sure we are dealing with a Flask Response object + if isinstance(response, Response): + response.headers.add("Access-Control-Allow-Origin", allow) + return rv + + return wrapper + + return decorator diff --git a/server/odcs/server/views.py b/server/odcs/server/views.py index 180bfcc..88e110f 100644 --- a/server/odcs/server/views.py +++ b/server/odcs/server/views.py @@ -44,6 +44,7 @@ from odcs.server.api_utils import ( filter_composes, validate_json_data, raise_if_input_not_allowed, + cors_header, ) from odcs.server.auth import requires_role, login_required, has_role from odcs.server.auth import require_scopes @@ -104,6 +105,7 @@ class ODCSAPI(MethodView): else: return conf.seconds_to_live + @cors_header() def get(self, id): """Returns ODCS composes. @@ -592,6 +594,7 @@ class ODCSAPI(MethodView): class AboutAPI(MethodView): + @cors_header() def get(self): """Returns information about this ODCS instance in JSON format. @@ -632,6 +635,7 @@ class Index(View): class MetricsAPI(MethodView): + @cors_header() def get(self): """ Returns the Prometheus metrics. diff --git a/server/tests/test_views.py b/server/tests/test_views.py index a1aaa57..73692b7 100644 --- a/server/tests/test_views.py +++ b/server/tests/test_views.py @@ -1361,6 +1361,7 @@ class TestViews(ViewBaseTest): self.assertEqual(data["id"], 1) self.assertEqual(data["source"], "testmodule:master") self.assertEqual(data["pungi_config_dump"], None) + self.assertEqual(resp.headers["Access-Control-Allow-Origin"], "*") def test_query_composes(self): resp = self.client.get("/api/1/composes/")