Support CORS

Add the new middleware CORS for Zaqar

It only supports for WSGI.

Websocket doesn't need this feature.

Change-Id: Ifc6d2d1c5dde5152cab6e3aa2f3cf9f207481267
Implements: blueprint support-cors
This commit is contained in:
wangxiyuan 2017-02-21 15:39:20 -05:00
parent 66e90d3b25
commit e501f4013e
10 changed files with 213 additions and 3 deletions

View File

@ -111,6 +111,11 @@ function configure_zaqar {
iniset $ZAQAR_CONF DEFAULT pooling True
iniset $ZAQAR_CONF 'pooling:catalog' enable_virtual_pool True
if [ "CORS_ENABLED" == 'true'] ; then
iniset $ZAQAR_CONF cors
iniset $ZAQAR_CONF 'cors' enabled True
fi
# NOTE(flaper87): Configure mongodb regardless so we can use it as a pool
# in tests.
configure_mongodb

View File

@ -45,5 +45,7 @@ ZAQAR_TRUSTEE_DOMAIN=${ZAQAR_TRUSTEE_DOMAIN:-default}
# Tell Tempest this project is present
TEMPEST_SERVICES+=,zaqar
# CORS
CORS_ENABLED=${CORS_ENABLED:-false}
enable_service zaqar-websocket zaqar-wsgi

125
doc/source/CORS.rst Normal file
View File

@ -0,0 +1,125 @@
..
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.
==========
CORS Guide
==========
Zaqar supports Cross-Origin Resource Sharing (CORS) now. The function is
provided by oslo.middleware. Please see `Official Doc`_ and `OpenStack Spec`_
for more detail. This guide is mainly tell users how to use it in Zaqar.
New Config Options
------------------
There are some new config options.
**enabled**
Enables CORS functions for Zaqar. The default value is "False" at this moment.
It will be turn to "True" in the future once it's stable enough.
**allowed_origin**
Indicate whether this resource may be shared with the domain received in the
requests "origin" header. Format: "<protocol>://<host>[:<port>]", no trailing
slash. Example: https://horizon.example.com'.
**allow_credentials**
Indicate that the actual request can include user credentials. The default
value is True.
**expose_headers**
Indicate which headers are safe to expose to the API. Defaults to HTTP Simple
Headers. The default value is [].
**max_age**
Maximum cache age of CORS preflight requests. The default value is 3600.
**allow_methods**
Indicate which methods can be used during the actual request. The default value
is ['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'PATCH'].
**allow_headers**
Indicate which header field names may be used during the actual request. The
default value is [].
Request and Response example
----------------------------
To use CORS, you should make sure that the feature is enabled::
[cors]
enabled = true
allowed_origin = http://example
allow_methods = GET
the above example config options mean that Zaqar only receive the GET request
from http://example domain. Here are some example request:
1. Zaqar will do nothing if the request doesn't contain "Origin" header::
# curl -I -X GET http://10.229.47.217:8888 -H "Accept: application/json"
HTTP/1.1 300 Multiple Choices
content-length: 668
content-type: application/json; charset=UTF-8
Connection: close
2. Zaqar will return nothing in response headers if the "Origin" is not in
``allowed_origin``::
# curl -I -X GET http://10.229.47.217:8888 -H "Accept: application/json" -H "Origin: http://"
HTTP/1.1 300 Multiple Choices
content-length: 668
content-type: application/json; charset=UTF-8
Connection: close
In the Zaqar log, we can see a message::
CORS request from origin 'http://' not permitted.
3. Zaqar will return CORS information if the "Origin" header is in
``allowed_origin``::
# curl -I -X GET http://10.229.47.217:8888 -H "Accept: application/json" -H "Origin: http://example"
HTTP/1.1 300 Multiple Choices
content-length: 668
content-type: application/json; charset=UTF-8
Vary: Origin
Access-Control-Allow-Origin: http://example
Access-Control-Allow-Credentials: true
Connection: close
4. Zaqar will return more information if the request doesn't follow Zaqar's\
CORS rule::
# curl -I -X PUT http://10.229.47.217:8888 -H "Accept: application/json" -H "Origin: http://example"
HTTP/1.1 405 Method Not Allowed
content-length: 0
content-type: application/json; charset=UTF-8
allow: GET, OPTIONS
Vary: Origin
Access-Control-Allow-Origin: http://example
Access-Control-Allow-Credentials: true
Connection: close
.. _Official Doc: http://docs.openstack.org/developer/osprofiler/background.html
.. _OpenStack Spec: http://specs.openstack.org/openstack/openstack-specs/specs/cors-support.html

View File

@ -16,7 +16,7 @@ OSprofiler Guide
================
OSprofiler is a library from oslo. It's used for performance analysis. Please
see `Office Doc`_ for more detail.
see `Official Doc`_ for more detail.
Preparation
-----------
@ -121,4 +121,4 @@ Then you can open the file "list_test" to get the result.
.. note:: If you used MQ for data transfer, the "--connection-string" here
could be ignored or set it to your Ceilometer endpoint.
.. _Office Doc: http://docs.openstack.org/developer/osprofiler/background.html
.. _Official Doc: http://docs.openstack.org/developer/osprofiler/background.html

View File

@ -189,6 +189,7 @@ Feature Guide
subscription_confirm
OSprofiler
CORS
Other resources
===============

View File

@ -15,5 +15,6 @@ namespace = zaqar.transport.validation
namespace = keystonemiddleware.auth_token
namespace = oslo.cache
namespace = oslo.messaging
namespace = oslo.middleware.cors
namespace = osprofiler
namespace = oslo.reports

View File

@ -0,0 +1,4 @@
---
features:
- Zaqar now supports Cross-Origin Resource Sharing (CORS). It turns off by
default. Use "enable=True" in [cors] section from zaqar.conf to use it.

View File

@ -104,6 +104,7 @@ _NOTIFICATION_OPTIONS = (
_NOTIFICATION_GROUP = 'notification'
_PROFILER_OPTIONS = [
cfg.BoolOpt("trace_wsgi_transport", default=False,
help="If False doesn't trace any transport requests."
@ -117,9 +118,19 @@ _PROFILER_OPTIONS = [
_PROFILER_GROUP = "profiler"
_CORS_OPTIONS = [
cfg.BoolOpt("enabled", default=False,
help="Whether enable Cross Origin Resource Sharing(CORS) "
"function from oslo.middleware"),
]
_CORS_GROUP = "cors"
def _config_options():
return [(None, _GENERAL_OPTIONS),
(_DRIVER_GROUP, _DRIVER_OPTIONS),
(_SIGNED_URL_GROUP, _SIGNED_URL_OPTIONS),
(_NOTIFICATION_GROUP, _NOTIFICATION_OPTIONS),
(_PROFILER_GROUP, _PROFILER_OPTIONS)]
(_PROFILER_GROUP, _PROFILER_OPTIONS),
(_CORS_GROUP, _CORS_OPTIONS)]

View File

@ -0,0 +1,55 @@
# Copyright 2017 OpenStack, Inc.
# 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.
from oslo_log import log
from oslo_middleware import cors
LOG = log.getLogger(__name__)
class CORSMiddleware(object):
@classmethod
def install(cls, app, conf):
LOG.debug(u'Installing CORS middleware.')
cors.set_defaults(
allow_headers=['X-Auth-Token',
'X-Identity-Status',
'X-Roles',
'X-Service-Catalog',
'X-User-Id',
'X-Tenant-Id',
'X-OpenStack-Request-ID',
'X-Trace-Info',
'X-Trace-HMAC',
'Client-id'],
expose_headers=['X-Auth-Token',
'X-Subject-Token',
'X-Service-Token',
'X-OpenStack-Request-ID'],
allow_methods=['GET',
'PUT',
'POST',
'DELETE',
'PATCH',
'HEAD']
)
return cors.CORS(app, conf)
def install_cors(app, conf):
return CORSMiddleware.install(app, conf)

View File

@ -29,6 +29,7 @@ from zaqar.i18n import _
from zaqar import transport
from zaqar.transport import acl
from zaqar.transport.middleware import auth
from zaqar.transport.middleware import cors
from zaqar.transport.middleware import profile
from zaqar.transport import validation
from zaqar.transport.wsgi import v1_0
@ -153,6 +154,11 @@ class Driver(transport.DriverBase):
self.app = auth.SignedHeadersAuth(self.app, auth_app)
# NOTE(wangxiyuan): Install CORS, this middleware should be called
# before Keystone auth.
if self._conf.cors.enabled:
self.app = cors.install_cors(self.app, self._conf)
acl.setup_policy(self._conf)
def _error_handler(self, exc, request, response, params):