From 6a623dbb64785b882a864b4c80e0f8e052062848 Mon Sep 17 00:00:00 2001
From: Jan Kaluza <jkaluza@redhat.com>
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/")