Added CORS support to Ironic Inspector
This adds the CORS support middleware to Ironic Inspector, allowing a deployer to optionally configure rules under which a javascript client may break the single-origin policy and access the API directly. 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: I467d4e14b27f1d4808786d431aff66808c707a99
This commit is contained in:
parent
aea60cdc4a
commit
19fe16fd42
@ -7,3 +7,4 @@ namespace = ironic_inspector.plugins.discovery
|
||||
namespace = keystonemiddleware.auth_token
|
||||
namespace = oslo.db
|
||||
namespace = oslo.log
|
||||
namespace = oslo.middleware.cors
|
||||
|
60
example.conf
60
example.conf
@ -166,6 +166,66 @@
|
||||
#fatal_deprecations = false
|
||||
|
||||
|
||||
[cors]
|
||||
|
||||
#
|
||||
# From oslo.middleware.cors
|
||||
#
|
||||
|
||||
# Indicate whether this resource may be shared with the domain
|
||||
# received in the requests "origin" header. (list value)
|
||||
#allowed_origin = <None>
|
||||
|
||||
# Indicate that the actual request can include user credentials
|
||||
# (boolean value)
|
||||
#allow_credentials = true
|
||||
|
||||
# Indicate which headers are safe to expose to the API. Defaults to
|
||||
# HTTP Simple Headers. (list value)
|
||||
#expose_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma
|
||||
|
||||
# Maximum cache age of CORS preflight requests. (integer value)
|
||||
#max_age = 3600
|
||||
|
||||
# Indicate which methods can be used during the actual request. (list
|
||||
# value)
|
||||
#allow_methods = GET,POST,PUT,HEAD,PATCH,DELETE,OPTIONS
|
||||
|
||||
# Indicate which header field names may be used during the actual
|
||||
# request. (list value)
|
||||
#allow_headers = X-Auth-Token,X-OpenStack-Ironic-Inspector-API-Minimum-Version,X-OpenStack-Ironic-Inspector-API-Maximum-Version,X-OpenStack-Ironic-Inspector-API-Version
|
||||
|
||||
|
||||
[cors.subdomain]
|
||||
|
||||
#
|
||||
# From oslo.middleware.cors
|
||||
#
|
||||
|
||||
# Indicate whether this resource may be shared with the domain
|
||||
# received in the requests "origin" header. (list value)
|
||||
#allowed_origin = <None>
|
||||
|
||||
# Indicate that the actual request can include user credentials
|
||||
# (boolean value)
|
||||
#allow_credentials = true
|
||||
|
||||
# Indicate which headers are safe to expose to the API. Defaults to
|
||||
# HTTP Simple Headers. (list value)
|
||||
#expose_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma
|
||||
|
||||
# Maximum cache age of CORS preflight requests. (integer value)
|
||||
#max_age = 3600
|
||||
|
||||
# Indicate which methods can be used during the actual request. (list
|
||||
# value)
|
||||
#allow_methods = GET,POST,PUT,HEAD,PATCH,DELETE,OPTIONS
|
||||
|
||||
# Indicate which header field names may be used during the actual
|
||||
# request. (list value)
|
||||
#allow_headers = X-Auth-Token,X-OpenStack-Ironic-Inspector-API-Minimum-Version,X-OpenStack-Ironic-Inspector-API-Maximum-Version,X-OpenStack-Ironic-Inspector-API-Version
|
||||
|
||||
|
||||
[database]
|
||||
|
||||
#
|
||||
|
@ -12,8 +12,13 @@
|
||||
# limitations under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_middleware import cors
|
||||
|
||||
|
||||
MIN_VERSION_HEADER = 'X-OpenStack-Ironic-Inspector-API-Minimum-Version'
|
||||
MAX_VERSION_HEADER = 'X-OpenStack-Ironic-Inspector-API-Maximum-Version'
|
||||
VERSION_HEADER = 'X-OpenStack-Ironic-Inspector-API-Version'
|
||||
|
||||
VALID_ADD_PORTS_VALUES = ('all', 'active', 'pxe')
|
||||
VALID_KEEP_PORTS_VALUES = ('all', 'present', 'added')
|
||||
VALID_STORE_DATA_VALUES = ('none', 'swift')
|
||||
@ -215,3 +220,22 @@ def list_opts():
|
||||
('processing', PROCESSING_OPTS),
|
||||
('discoverd', DISCOVERD_OPTS),
|
||||
]
|
||||
|
||||
|
||||
def set_config_defaults():
|
||||
"""This method updates all configuration default values."""
|
||||
set_cors_middleware_defaults()
|
||||
|
||||
|
||||
def set_cors_middleware_defaults():
|
||||
"""Update default configuration options for oslo.middleware."""
|
||||
# TODO(krotscheck): Update with https://review.openstack.org/#/c/285368/
|
||||
cfg.set_defaults(
|
||||
cors.CORS_OPTS,
|
||||
allow_headers=['X-Auth-Token',
|
||||
MIN_VERSION_HEADER,
|
||||
MAX_VERSION_HEADER,
|
||||
VERSION_HEADER],
|
||||
allow_methods=['GET', 'POST', 'PUT', 'HEAD',
|
||||
'PATCH', 'DELETE', 'OPTIONS']
|
||||
)
|
||||
|
@ -48,9 +48,6 @@ LOG = utils.getProcessingLogger(__name__)
|
||||
|
||||
MINIMUM_API_VERSION = (1, 0)
|
||||
CURRENT_API_VERSION = (1, 3)
|
||||
_MIN_VERSION_HEADER = 'X-OpenStack-Ironic-Inspector-API-Minimum-Version'
|
||||
_MAX_VERSION_HEADER = 'X-OpenStack-Ironic-Inspector-API-Maximum-Version'
|
||||
_VERSION_HEADER = 'X-OpenStack-Ironic-Inspector-API-Version'
|
||||
_LOGGING_EXCLUDED_KEYS = ('logs',)
|
||||
|
||||
|
||||
@ -89,7 +86,7 @@ def convert_exceptions(func):
|
||||
|
||||
@app.before_request
|
||||
def check_api_version():
|
||||
requested = flask.request.headers.get(_VERSION_HEADER,
|
||||
requested = flask.request.headers.get(conf.VERSION_HEADER,
|
||||
_DEFAULT_API_VERSION)
|
||||
try:
|
||||
requested = tuple(int(x) for x in requested.split('.'))
|
||||
@ -108,8 +105,8 @@ def check_api_version():
|
||||
|
||||
@app.after_request
|
||||
def add_version_headers(res):
|
||||
res.headers[_MIN_VERSION_HEADER] = '%s.%s' % MINIMUM_API_VERSION
|
||||
res.headers[_MAX_VERSION_HEADER] = '%s.%s' % CURRENT_API_VERSION
|
||||
res.headers[conf.MIN_VERSION_HEADER] = '%s.%s' % MINIMUM_API_VERSION
|
||||
res.headers[conf.MAX_VERSION_HEADER] = '%s.%s' % CURRENT_API_VERSION
|
||||
return res
|
||||
|
||||
|
||||
@ -383,6 +380,8 @@ class Service(object):
|
||||
LOG.info(_LI('Introspection data will be stored in Swift in the '
|
||||
'container %s'), CONF.swift.container)
|
||||
|
||||
utils.add_cors_middleware(app)
|
||||
|
||||
db.init()
|
||||
|
||||
try:
|
||||
|
@ -20,6 +20,7 @@ import mock
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from ironic_inspector.common import ironic as ir_utils
|
||||
from ironic_inspector import conf
|
||||
from ironic_inspector import db
|
||||
from ironic_inspector import firewall
|
||||
from ironic_inspector import introspect
|
||||
@ -352,9 +353,9 @@ class TestApiMisc(BaseAPITest):
|
||||
class TestApiVersions(BaseAPITest):
|
||||
def _check_version_present(self, res):
|
||||
self.assertEqual('%d.%d' % main.MINIMUM_API_VERSION,
|
||||
res.headers.get(main._MIN_VERSION_HEADER))
|
||||
res.headers.get(conf.MIN_VERSION_HEADER))
|
||||
self.assertEqual('%d.%d' % main.CURRENT_API_VERSION,
|
||||
res.headers.get(main._MAX_VERSION_HEADER))
|
||||
res.headers.get(conf.MAX_VERSION_HEADER))
|
||||
|
||||
def test_root_endpoint(self):
|
||||
res = self.app.get("/")
|
||||
@ -420,14 +421,14 @@ class TestApiVersions(BaseAPITest):
|
||||
self.app.post('/v1/introspection/foobar'))
|
||||
|
||||
def test_request_correct_version(self):
|
||||
headers = {main._VERSION_HEADER:
|
||||
headers = {conf.VERSION_HEADER:
|
||||
main._format_version(main.CURRENT_API_VERSION)}
|
||||
self._check_version_present(self.app.get('/', headers=headers))
|
||||
|
||||
def test_request_unsupported_version(self):
|
||||
bad_version = (main.CURRENT_API_VERSION[0],
|
||||
main.CURRENT_API_VERSION[1] + 1)
|
||||
headers = {main._VERSION_HEADER:
|
||||
headers = {conf.VERSION_HEADER:
|
||||
main._format_version(bad_version)}
|
||||
res = self.app.get('/', headers=headers)
|
||||
self._check_version_present(res)
|
||||
|
@ -18,6 +18,7 @@ import futurist
|
||||
from keystonemiddleware import auth_token
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_middleware import cors as cors_middleware
|
||||
import six
|
||||
|
||||
from ironic_inspector.common.i18n import _, _LE
|
||||
@ -159,6 +160,17 @@ def add_auth_middleware(app):
|
||||
app.wsgi_app = auth_token.AuthProtocol(app.wsgi_app, auth_conf)
|
||||
|
||||
|
||||
def add_cors_middleware(app):
|
||||
"""Create a CORS wrapper
|
||||
|
||||
Attach ironic-inspector-specific defaults that must be included
|
||||
in all CORS responses.
|
||||
|
||||
:param app: application
|
||||
"""
|
||||
app.wsgi_app = cors_middleware.CORS(app.wsgi_app, CONF)
|
||||
|
||||
|
||||
def check_auth(request):
|
||||
"""Check authentication on request.
|
||||
|
||||
|
13
releasenotes/notes/cors-5f345c65da7f5c99.yaml
Normal file
13
releasenotes/notes/cors-5f345c65da7f5c99.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added CORS support middleware to Ironic Inspector, allowing a deployer
|
||||
to optionally configure rules under which a javascript client may
|
||||
break the single-origin policy and access the API directly.
|
||||
|
||||
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
|
@ -19,6 +19,7 @@ oslo.config>=3.7.0 # Apache-2.0
|
||||
oslo.db>=4.1.0 # Apache-2.0
|
||||
oslo.i18n>=2.1.0 # Apache-2.0
|
||||
oslo.log>=1.14.0 # Apache-2.0
|
||||
oslo.middleware>=3.0.0 # Apache-2.0
|
||||
oslo.rootwrap>=2.0.0 # Apache-2.0
|
||||
oslo.utils>=3.5.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
|
@ -58,6 +58,8 @@ oslo.config.opts =
|
||||
ironic_inspector.common.ironic = ironic_inspector.common.ironic:list_opts
|
||||
ironic_inspector.common.swift = ironic_inspector.common.swift:list_opts
|
||||
ironic_inspector.plugins.discovery = ironic_inspector.plugins.discovery:list_opts
|
||||
oslo.config.opts.defaults =
|
||||
ironic_inspector = ironic_inspector.conf:set_config_defaults
|
||||
|
||||
[compile_catalog]
|
||||
directory = ironic_inspector/locale
|
||||
|
Loading…
Reference in New Issue
Block a user