Added CORS support to Aodh

This adds the CORS support middleware to Aodh, allowing a deployer
to optionally configure rules under which a javascript client may
break the single-origin policy and access the API directly.

In previous patches, proper paste support for gabbi was added. This patch
modifies the paste.ini file for both aodh and gabbi, adds the CORS
configuration fixture to support unit tests, and adds CORS into configgen.

OpenStack CrossProject Spec:
   http://specs.openstack.org/openstack/openstack-specs/specs/cors-support.html
Oslo_Middleware Docs:
   http://docs.openstack.org/developer/oslo.middleware/cors.html
OpenStack Cloud Admin Guide:
   http://docs.openstack.org/admin-guide-cloud/cross_project_cors.html
DocImpact: Add link to CORS configuration in admin cloud guide.

Change-Id: I27673b8581069c9ef02525756d1079b3904d8349
This commit is contained in:
Michael Krotscheck 2016-01-08 08:03:11 -08:00
parent 4ed768d549
commit ab70d21919
6 changed files with 83 additions and 3 deletions

View File

@ -21,6 +21,7 @@ import uuid
from gabbi import fixture
import mock
from oslo_config import cfg
from oslo_config import fixture as fixture_config
from oslo_policy import opts
from six.moves.urllib import parse as urlparse
@ -95,3 +96,24 @@ class ConfigFixture(fixture.GabbiFixture):
storage.get_connection_from_config(self.conf).clear()
self.conf.reset()
service.prepare_service = self.prepare_service
class CORSConfigFixture(fixture.GabbiFixture):
"""Inject mock configuration for the CORS middleware."""
def start_fixture(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.
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
def stop_fixture(self):
"""Remove the monkeypatch."""
cfg.ConfigOpts.GroupAttr.__getattr__ = self._original_call_method

View File

@ -8,10 +8,17 @@
# Remove authtoken from the pipeline if you don't want to use keystone authentication
[pipeline:main]
pipeline = request_id api-server
pipeline = cors request_id api-server
[app:api-server]
paste.app_factory = aodh.api.app:app_factory
[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = aodh
latent_allow_headers = X-Auth-Token, X-Openstack-Request-Id, X-Subject-Token
latent_expose_headers = X-Auth-Token, X-Openstack-Request-Id, X-Subject-Token
latent_allow_methods = GET, PUT, POST, DELETE, PATCH

View File

@ -0,0 +1,44 @@
#
# Test the middlewares. Just CORS for now.
#
fixtures:
- ConfigFixture
- CORSConfigFixture
tests:
- name: valid cors options
OPTIONS: /
status: 200
request_headers:
origin: http://valid.example.com
access-control-request-method: GET
response_headers:
access-control-allow-origin: http://valid.example.com
- name: invalid cors options
OPTIONS: /
status: 200
request_headers:
origin: http://invalid.example.com
access-control-request-method: GET
response_forbidden_headers:
- access-control-allow-origin
- name: valid cors get
GET: /
status: 200
request_headers:
origin: http://valid.example.com
access-control-request-method: GET
response_headers:
access-control-allow-origin: http://valid.example.com
- name: invalid cors get
GET: /
status: 200
request_headers:
origin: http://invalid.example.com
response_forbidden_headers:
- access-control-allow-origin

View File

@ -6,6 +6,7 @@ namespace = aodh-auth
namespace = oslo.db
namespace = oslo.log
namespace = oslo.messaging
namespace = oslo.middleware.cors
namespace = oslo.policy
namespace = oslo.service.service
namespace = keystonemiddleware.auth_token

View File

@ -5,7 +5,7 @@
# Remove authtoken from the pipeline if you don't want to use keystone authentication
[pipeline:main]
pipeline = request_id authtoken api-server
pipeline = cors request_id authtoken api-server
[app:api-server]
paste.app_factory = aodh.api.app:app_factory
@ -17,3 +17,9 @@ oslo_config_project = aodh
[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = aodh
latent_allow_headers = X-Auth-Token, X-Openstack-Request-Id, X-Subject-Token
latent_expose_headers = X-Auth-Token, X-Openstack-Request-Id, X-Subject-Token
latent_allow_methods = GET, PUT, POST, DELETE, PATCH

View File

@ -19,7 +19,7 @@ PasteDeploy>=1.5.0
pbr<2.0,>=0.11
pecan>=0.8.0
oslo.messaging>2.6.1,!=2.8.0 # Apache-2.0
oslo.middleware!=2.0.0,>=1.2.0 # Apache-2.0
oslo.middleware>=3.0.0 # Apache-2.0
oslo.serialization>=1.4.0 # Apache-2.0
oslo.utils>=1.9.0 # Apache-2.0
python-ceilometerclient>=1.5.0