Merge "Added CORS support to Nova"
This commit is contained in:
commit
af17939764
@ -6,7 +6,7 @@ use = egg:Paste#urlmap
|
||||
/: meta
|
||||
|
||||
[pipeline:meta]
|
||||
pipeline = ec2faultwrap logrequest metaapp
|
||||
pipeline = cors ec2faultwrap logrequest metaapp
|
||||
|
||||
[app:metaapp]
|
||||
paste.app_factory = nova.api.metadata.handler:MetadataRequestHandler.factory
|
||||
@ -22,8 +22,8 @@ use = egg:Paste#urlmap
|
||||
|
||||
[composite:ec2cloud]
|
||||
use = call:nova.api.auth:pipeline_factory
|
||||
noauth2 = ec2faultwrap logrequest ec2noauth cloudrequest validator ec2executor
|
||||
keystone = ec2faultwrap logrequest ec2keystoneauth cloudrequest validator ec2executor
|
||||
noauth2 = cors ec2faultwrap logrequest ec2noauth cloudrequest validator ec2executor
|
||||
keystone = cors ec2faultwrap logrequest ec2keystoneauth cloudrequest validator ec2executor
|
||||
|
||||
[filter:ec2faultwrap]
|
||||
paste.filter_factory = nova.api.ec2:FaultWrapper.factory
|
||||
@ -82,19 +82,19 @@ use = call:nova.api.openstack.urlmap:urlmap_factory
|
||||
# NOTE: this is deprecated in favor of openstack_compute_api_v21_legacy_v2_compatible
|
||||
[composite:openstack_compute_api_legacy_v2]
|
||||
use = call:nova.api.auth:pipeline_factory
|
||||
noauth2 = compute_req_id faultwrap sizelimit noauth2 legacy_ratelimit osapi_compute_app_legacy_v2
|
||||
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_ratelimit osapi_compute_app_legacy_v2
|
||||
keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_legacy_v2
|
||||
noauth2 = cors compute_req_id faultwrap sizelimit noauth2 legacy_ratelimit osapi_compute_app_legacy_v2
|
||||
keystone = cors compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_ratelimit osapi_compute_app_legacy_v2
|
||||
keystone_nolimit = cors compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_legacy_v2
|
||||
|
||||
[composite:openstack_compute_api_v21]
|
||||
use = call:nova.api.auth:pipeline_factory_v21
|
||||
noauth2 = compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21
|
||||
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21
|
||||
noauth2 = cors compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21
|
||||
keystone = cors compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21
|
||||
|
||||
[composite:openstack_compute_api_v21_legacy_v2_compatible]
|
||||
use = call:nova.api.auth:pipeline_factory_v21
|
||||
noauth2 = compute_req_id faultwrap sizelimit noauth2 legacy_v2_compatible osapi_compute_app_v21
|
||||
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_v2_compatible osapi_compute_app_v21
|
||||
noauth2 = cors compute_req_id faultwrap sizelimit noauth2 legacy_v2_compatible osapi_compute_app_v21
|
||||
keystone = cors compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_v2_compatible osapi_compute_app_v21
|
||||
|
||||
[filter:request_id]
|
||||
paste.filter_factory = oslo_middleware:RequestId.factory
|
||||
@ -133,6 +133,10 @@ paste.app_factory = nova.api.openstack.compute.versions:Versions.factory
|
||||
# Shared #
|
||||
##########
|
||||
|
||||
[filter:cors]
|
||||
paste.filter_factory = oslo_middleware.cors:filter_factory
|
||||
oslo_config_project = nova
|
||||
|
||||
[filter:keystonecontext]
|
||||
paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory
|
||||
|
||||
|
@ -314,8 +314,8 @@ class ApiSampleTestBase(integrated_helpers._IntegratedTestBase):
|
||||
}
|
||||
|
||||
def _get_response(self, url, method, body=None, strip_version=False,
|
||||
api_version=None):
|
||||
headers = {}
|
||||
api_version=None, headers=None):
|
||||
headers = headers or {}
|
||||
headers['Content-Type'] = 'application/' + self.ctype
|
||||
headers['Accept'] = 'application/' + self.ctype
|
||||
if api_version:
|
||||
@ -323,26 +323,39 @@ class ApiSampleTestBase(integrated_helpers._IntegratedTestBase):
|
||||
return self.api.api_request(url, body=body, method=method,
|
||||
headers=headers, strip_version=strip_version)
|
||||
|
||||
def _do_get(self, url, strip_version=False, api_version=None):
|
||||
def _do_options(self, url, strip_version=False, api_version=None,
|
||||
headers=None):
|
||||
return self._get_response(url, 'OPTIONS', strip_version=strip_version,
|
||||
api_version=(api_version or
|
||||
self.request_api_version),
|
||||
headers=headers)
|
||||
|
||||
def _do_get(self, url, strip_version=False, api_version=None,
|
||||
headers=None):
|
||||
return self._get_response(url, 'GET', strip_version=strip_version,
|
||||
api_version=(api_version or
|
||||
self.request_api_version))
|
||||
self.request_api_version),
|
||||
headers=headers)
|
||||
|
||||
def _do_post(self, url, name, subs, method='POST', api_version=None):
|
||||
def _do_post(self, url, name, subs, method='POST', api_version=None,
|
||||
headers=None):
|
||||
body = self._read_template(name) % subs
|
||||
sample = self._get_sample(name, self.request_api_version)
|
||||
if self.generate_samples and not os.path.exists(sample):
|
||||
self._write_sample(name, body)
|
||||
return self._get_response(url, method, body,
|
||||
api_version=(api_version or
|
||||
self.request_api_version))
|
||||
self.request_api_version),
|
||||
headers=headers)
|
||||
|
||||
def _do_put(self, url, name, subs, api_version=None):
|
||||
def _do_put(self, url, name, subs, api_version=None, headers=None):
|
||||
return self._do_post(url, name, subs, method='PUT',
|
||||
api_version=(api_version or
|
||||
self.request_api_version))
|
||||
self.request_api_version),
|
||||
headers=headers)
|
||||
|
||||
def _do_delete(self, url, api_version=None):
|
||||
def _do_delete(self, url, api_version=None, headers=None):
|
||||
return self._get_response(url, 'DELETE',
|
||||
api_version=(api_version or
|
||||
self.request_api_version))
|
||||
self.request_api_version),
|
||||
headers=headers)
|
||||
|
98
nova/tests/functional/test_middleware.py
Normal file
98
nova/tests/functional/test_middleware.py
Normal file
@ -0,0 +1,98 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
#
|
||||
# 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 to assert that various incorporated middleware works as expected.
|
||||
"""
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from nova.tests.functional.api_sample_tests import api_sample_base
|
||||
|
||||
|
||||
class TestCORSMiddleware(api_sample_base.ApiSampleTestBaseV21):
|
||||
'''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
|
||||
|
||||
def test_valid_cors_options_request(self):
|
||||
response = self._do_options('servers',
|
||||
headers={
|
||||
'Origin': 'http://valid.example.com',
|
||||
'Access-Control-Request-Method': 'GET'
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('Access-Control-Allow-Origin', response.headers)
|
||||
self.assertEqual('http://valid.example.com',
|
||||
response.headers['Access-Control-Allow-Origin'])
|
||||
|
||||
def test_invalid_cors_options_request(self):
|
||||
response = self._do_options('servers',
|
||||
headers={
|
||||
'Origin': 'http://invalid.example.com',
|
||||
'Access-Control-Request-Method': 'GET'
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotIn('Access-Control-Allow-Origin', response.headers)
|
||||
|
||||
def test_valid_cors_get_request(self):
|
||||
response = self._do_get('servers',
|
||||
headers={
|
||||
'Origin': 'http://valid.example.com',
|
||||
'Access-Control-Request-Method': 'GET'
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('Access-Control-Allow-Origin', response.headers)
|
||||
self.assertEqual('http://valid.example.com',
|
||||
response.headers['Access-Control-Allow-Origin'])
|
||||
|
||||
def test_invalid_cors_get_request(self):
|
||||
response = self._do_get('servers',
|
||||
headers={
|
||||
'Origin': 'http://invalid.example.com',
|
||||
'Access-Control-Request-Method': 'GET'
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotIn('Access-Control-Allow-Origin', response.headers)
|
Loading…
x
Reference in New Issue
Block a user