diff --git a/etc/manila/api-paste.ini b/etc/manila/api-paste.ini index f3f07e4df3..41e739d0d0 100644 --- a/etc/manila/api-paste.ini +++ b/etc/manila/api-paste.ini @@ -10,9 +10,9 @@ use = call:manila.api:root_app_factory [composite:openstack_share_api] use = call:manila.api.middleware.auth:pipeline_factory -noauth = faultwrap ssl sizelimit noauth api -keystone = faultwrap ssl sizelimit authtoken keystonecontext api -keystone_nolimit = faultwrap ssl sizelimit authtoken keystonecontext api +noauth = cors faultwrap ssl sizelimit noauth api +keystone = cors faultwrap ssl sizelimit authtoken keystonecontext api +keystone_nolimit = cors faultwrap ssl sizelimit authtoken keystonecontext api [filter:faultwrap] paste.filter_factory = manila.api.middleware.fault:FaultWrapper.factory @@ -30,7 +30,7 @@ paste.filter_factory = oslo_middleware.ssl:SSLMiddleware.factory paste.app_factory = manila.api.v1.router:APIRouter.factory [pipeline:apiversions] -pipeline = faultwrap osshareversionapp +pipeline = cors faultwrap osshareversionapp [app:osshareversionapp] paste.app_factory = manila.api.versions:VersionsRouter.factory @@ -44,3 +44,7 @@ paste.filter_factory = manila.api.middleware.auth:ManilaKeystoneContext.factory [filter:authtoken] paste.filter_factory = keystonemiddleware.auth_token:filter_factory + +[filter:cors] +paste.filter_factory = oslo_middleware.cors:filter_factory +oslo_config_project = manila diff --git a/etc/oslo-config-generator/manila.conf b/etc/oslo-config-generator/manila.conf index 5ce7fd6399..676ccb894a 100644 --- a/etc/oslo-config-generator/manila.conf +++ b/etc/oslo-config-generator/manila.conf @@ -2,6 +2,7 @@ output_file = etc/manila/manila.conf.sample namespace = manila namespace = oslo.messaging +namespace = oslo.middleware.cors namespace = oslo.db namespace = oslo.db.concurrency namespace = keystonemiddleware.auth_token diff --git a/manila/tests/api/test_middleware.py b/manila/tests/api/test_middleware.py new file mode 100644 index 0000000000..960ce3e807 --- /dev/null +++ b/manila/tests/api/test_middleware.py @@ -0,0 +1,88 @@ +# Copyright (c) 2015 Hewlett Packard Enterprise Development LP +# +# 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. + +import ddt +from oslo_config import cfg + +from manila.tests.integrated import integrated_helpers + + +@ddt.ddt +class TestCORSMiddleware(integrated_helpers._IntegratedTestBase): + '''Provide a basic smoke test to ensure CORS middleware is active. + + The tests below provide minimal confirmation that the CORS middleware + is active, and may be configured. For comprehensive tests, please consult + the test suite in oslo_middleware. + ''' + + def setUp(self): + # Here we monkeypatch GroupAttr.__getattr__, necessary because the + # paste.ini method of initializing this middleware creates its own + # ConfigOpts instance, bypassing the regular config fixture. + # Mocking also does not work, as accessing an attribute on a mock + # object will return a MagicMock instance, which will fail + # configuration type checks. + def _mock_getattr(instance, key): + if key != 'allowed_origin': + return self._original_call_method(instance, key) + return "http://valid.example.com" + + self._original_call_method = cfg.ConfigOpts.GroupAttr.__getattr__ + cfg.ConfigOpts.GroupAttr.__getattr__ = _mock_getattr + + # Initialize the application after all the config overrides are in + # place. + super(TestCORSMiddleware, self).setUp() + + def tearDown(self): + super(TestCORSMiddleware, self).tearDown() + + # Reset the configuration overrides. + cfg.ConfigOpts.GroupAttr.__getattr__ = self._original_call_method + + @ddt.data( + ('http://valid.example.com', 'http://valid.example.com'), + ('http://invalid.example.com', None), + ) + @ddt.unpack + def test_options_request(self, origin_url, acao_header_expected): + response = self.api.api_request( + '', + method='OPTIONS', + headers={ + 'Origin': origin_url, + 'Access-Control-Request-Method': 'GET', + } + ) + self.assertEqual(200, response.status) + self.assertEqual(acao_header_expected, + response.getheader('Access-Control-Allow-Origin')) + + @ddt.data( + ('http://valid.example.com', 'http://valid.example.com'), + ('http://invalid.example.com', None), + ) + @ddt.unpack + def test_get_request(self, origin_url, acao_header_expected): + response = self.api.api_request( + '', + method='GET', + headers={ + 'Origin': origin_url + } + ) + self.assertEqual(404, response.status) + self.assertEqual(acao_header_expected, + response.getheader('Access-Control-Allow-Origin')) diff --git a/manila/tests/integrated/api/client.py b/manila/tests/integrated/api/client.py index 4393dbf528..9e41cec09c 100644 --- a/manila/tests/integrated/api/client.py +++ b/manila/tests/integrated/api/client.py @@ -172,6 +172,12 @@ class TestOpenStackClient(object): else: return "" + def api_options(self, relative_uri, **kwargs): + kwargs['method'] = 'OPTIONS' + kwargs.setdefault('check_response_status', [200]) + response = self.api_request(relative_uri, **kwargs) + return self._decode_json(response) + def api_get(self, relative_uri, **kwargs): kwargs.setdefault('check_response_status', [200]) response = self.api_request(relative_uri, **kwargs)