diff --git a/mistral/api/app.py b/mistral/api/app.py index 9643bb9e3..0e02f3576 100644 --- a/mistral/api/app.py +++ b/mistral/api/app.py @@ -15,6 +15,7 @@ from oslo_config import cfg import oslo_middleware.cors as cors_middleware +import oslo_middleware.http_proxy_to_wsgi as http_proxy_to_wsgi_middleware import osprofiler.web import pecan @@ -82,6 +83,9 @@ def setup_app(config=None): enabled=cfg.CONF.profiler.enabled ) + # Create HTTPProxyToWSGI wrapper + app = http_proxy_to_wsgi_middleware.HTTPProxyToWSGI(app, cfg.CONF) + # Create a CORS wrapper, and attach mistral-specific defaults that must be # included in all CORS responses. return cors_middleware.CORS(app, cfg.CONF) diff --git a/mistral/api/controllers/root.py b/mistral/api/controllers/root.py index 9183b9359..355c3b1ba 100644 --- a/mistral/api/controllers/root.py +++ b/mistral/api/controllers/root.py @@ -67,7 +67,7 @@ class RootController(object): def index(self): LOG.debug("Fetching API versions.") - host_url_v2 = '%s/%s' % (pecan.request.host_url, 'v2') + host_url_v2 = '%s/%s' % (pecan.request.application_url, 'v2') api_v2 = APIVersion( id='v2.0', status='CURRENT', diff --git a/mistral/api/controllers/v2/root.py b/mistral/api/controllers/v2/root.py index 1c5b1f74d..156659f1a 100644 --- a/mistral/api/controllers/v2/root.py +++ b/mistral/api/controllers/v2/root.py @@ -59,4 +59,5 @@ class Controller(object): @wsme_pecan.wsexpose(RootResource) def index(self): - return RootResource(uri='%s/%s' % (pecan.request.host_url, 'v2')) + return RootResource(uri='%s/%s' % (pecan.request.application_url, + 'v2')) diff --git a/mistral/context.py b/mistral/context.py index 567a8e582..bf48a6f62 100644 --- a/mistral/context.py +++ b/mistral/context.py @@ -31,7 +31,7 @@ from mistral import utils CONF = cfg.CONF _CTX_THREAD_LOCAL_NAME = "MISTRAL_APP_CTX_THREAD_LOCAL" -ALLOWED_WITHOUT_AUTH = ['/', '/v2/'] +ALLOWED_WITHOUT_AUTH = ['/', '/v2/', '/workflowv2/', '/workflowv2/v2/'] class MistralContext(oslo_context.RequestContext): diff --git a/mistral/tests/unit/api/test_oslo_middleware.py b/mistral/tests/unit/api/test_oslo_middleware.py new file mode 100644 index 000000000..ab7038dcf --- /dev/null +++ b/mistral/tests/unit/api/test_oslo_middleware.py @@ -0,0 +1,42 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Tests http_proxy_to_wsgi middleware.""" + +from mistral.tests.unit.api import base +from oslo_config import cfg +from oslo_middleware import http_proxy_to_wsgi as http_proxy_to_wsgi_middleware + + +class TestHTTPProxyToWSGIMiddleware(base.APITest): + """Test oslo_middleware HTTPProxyToWSGI. + + It checks that oslo_middleware middleware HTTPProxyToWSGI is executed + when enabled. + """ + + def setUp(self): + # Make sure the HTTPProxyToWSGI options are registered + cfg.CONF.register_opts(http_proxy_to_wsgi_middleware.OPTS, + 'oslo_middleware') + + # Enable proxy headers parsing in HTTPProxyToWSGI middleware. + self.override_config( + "enable_proxy_headers_parsing", + "True", + group='oslo_middleware' + ) + + # Create the application. + super(TestHTTPProxyToWSGIMiddleware, self).setUp() diff --git a/mistral/tests/unit/api/v2/test_root.py b/mistral/tests/unit/api/v2/test_root.py index f09807fc2..334581393 100644 --- a/mistral/tests/unit/api/v2/test_root.py +++ b/mistral/tests/unit/api/v2/test_root.py @@ -15,6 +15,7 @@ from oslo_serialization import jsonutils from mistral.tests.unit.api import base from mistral.tests.unit.api import test_auth +from mistral.tests.unit.api import test_oslo_middleware class TestRootController(base.APITest): @@ -71,3 +72,69 @@ class TestRootControllerWithAuth(test_auth.TestKeystoneMiddleware): 'http://localhost/v2', data['uri'] ) + + +class TestRootControllerWithHTTPProxyToWSGI(test_oslo_middleware. + TestHTTPProxyToWSGIMiddleware): + def test_index(self): + resp = self.app.get('/', headers={'Accept': 'application/json', + 'Host': 'localhost'}) + + self.assertEqual(200, resp.status_int) + + data = jsonutils.loads(resp.body.decode()) + data = data['versions'] + self.assertEqual('v2.0', data[0]['id']) + self.assertEqual('CURRENT', data[0]['status']) + self.assertEqual( + [{'href': 'http://localhost/v2', 'rel': 'self', 'target': 'v2'}], + data[0]['links'] + ) + + def test_v2_root(self): + resp = self.app.get('/v2/', headers={'Accept': 'application/json', + 'Host': 'localhost'}) + + self.assertEqual(200, resp.status_int) + + data = jsonutils.loads(resp.body.decode()) + + self.assertEqual( + 'http://localhost/v2', + data['uri'] + ) + + def test_index_with_prefix(self): + resp = self.app.get('/', + headers={'Accept': 'application/json', + 'Host': 'openstack', + 'X-Forwarded-Proto': 'https', + 'X-Forwarded-Prefix': '/workflowv2'}) + + self.assertEqual(200, resp.status_int) + + data = jsonutils.loads(resp.body.decode()) + data = data['versions'] + self.assertEqual('v2.0', data[0]['id']) + self.assertEqual('CURRENT', data[0]['status']) + self.assertEqual( + [{'href': 'https://openstack/workflowv2/v2', 'rel': 'self', + 'target': 'v2'}], + data[0]['links'] + ) + + def test_v2_root_with_prefix(self): + resp = self.app.get('/v2/', + headers={'Accept': 'application/json', + 'Host': 'openstack', + 'X-Forwarded-Proto': 'https', + 'X-Forwarded-Prefix': '/workflowv2'}) + + self.assertEqual(200, resp.status_int) + + data = jsonutils.loads(resp.body.decode()) + + self.assertEqual( + 'https://openstack/workflowv2/v2', + data['uri'] + ) diff --git a/mistral/utils/rest_utils.py b/mistral/utils/rest_utils.py index e941b40aa..70a146d64 100644 --- a/mistral/utils/rest_utils.py +++ b/mistral/utils/rest_utils.py @@ -235,7 +235,7 @@ def get_all(list_cls, cls, get_all_function, get_function, return list_cls.convert_with_links( rest_resources, limit, - pecan.request.host_url, + pecan.request.application_url, sort_keys=','.join(sort_keys), sort_dirs=','.join(sort_dirs), fields=','.join(fields) if fields else '', diff --git a/tools/config/config-generator.mistral.conf b/tools/config/config-generator.mistral.conf index 677a2301a..a6c9ac28d 100644 --- a/tools/config/config-generator.mistral.conf +++ b/tools/config/config-generator.mistral.conf @@ -3,6 +3,7 @@ namespace = mistral.config namespace = oslo.db namespace = oslo.messaging namespace = oslo.middleware.cors +namespace = oslo.middleware.http_proxy_to_wsgi namespace = keystonemiddleware.auth_token namespace = periodic.config namespace = oslo.log