Merge "Added CORS support to Glance"

This commit is contained in:
Jenkins 2015-12-20 20:27:45 +00:00 committed by Gerrit Code Review
commit 74eadaa36c
5 changed files with 190 additions and 12 deletions

View File

@ -1,38 +1,38 @@
# Use this pipeline for no auth or image caching - DEFAULT # Use this pipeline for no auth or image caching - DEFAULT
[pipeline:glance-api] [pipeline:glance-api]
pipeline = healthcheck versionnegotiation osprofiler unauthenticated-context rootapp pipeline = cors healthcheck versionnegotiation osprofiler unauthenticated-context rootapp
# Use this pipeline for image caching and no auth # Use this pipeline for image caching and no auth
[pipeline:glance-api-caching] [pipeline:glance-api-caching]
pipeline = healthcheck versionnegotiation osprofiler unauthenticated-context cache rootapp pipeline = cors healthcheck versionnegotiation osprofiler unauthenticated-context cache rootapp
# Use this pipeline for caching w/ management interface but no auth # Use this pipeline for caching w/ management interface but no auth
[pipeline:glance-api-cachemanagement] [pipeline:glance-api-cachemanagement]
pipeline = healthcheck versionnegotiation osprofiler unauthenticated-context cache cachemanage rootapp pipeline = cors healthcheck versionnegotiation osprofiler unauthenticated-context cache cachemanage rootapp
# Use this pipeline for keystone auth # Use this pipeline for keystone auth
[pipeline:glance-api-keystone] [pipeline:glance-api-keystone]
pipeline = healthcheck versionnegotiation osprofiler authtoken context rootapp pipeline = cors healthcheck versionnegotiation osprofiler authtoken context rootapp
# Use this pipeline for keystone auth with image caching # Use this pipeline for keystone auth with image caching
[pipeline:glance-api-keystone+caching] [pipeline:glance-api-keystone+caching]
pipeline = healthcheck versionnegotiation osprofiler authtoken context cache rootapp pipeline = cors healthcheck versionnegotiation osprofiler authtoken context cache rootapp
# Use this pipeline for keystone auth with caching and cache management # Use this pipeline for keystone auth with caching and cache management
[pipeline:glance-api-keystone+cachemanagement] [pipeline:glance-api-keystone+cachemanagement]
pipeline = healthcheck versionnegotiation osprofiler authtoken context cache cachemanage rootapp pipeline = cors healthcheck versionnegotiation osprofiler authtoken context cache cachemanage rootapp
# Use this pipeline for authZ only. This means that the registry will treat a # Use this pipeline for authZ only. This means that the registry will treat a
# user as authenticated without making requests to keystone to reauthenticate # user as authenticated without making requests to keystone to reauthenticate
# the user. # the user.
[pipeline:glance-api-trusted-auth] [pipeline:glance-api-trusted-auth]
pipeline = healthcheck versionnegotiation osprofiler context rootapp pipeline = cors healthcheck versionnegotiation osprofiler context rootapp
# Use this pipeline for authZ only. This means that the registry will treat a # Use this pipeline for authZ only. This means that the registry will treat a
# user as authenticated without making requests to keystone to reauthenticate # user as authenticated without making requests to keystone to reauthenticate
# the user and uses cache management # the user and uses cache management
[pipeline:glance-api-trusted-auth+cachemanagement] [pipeline:glance-api-trusted-auth+cachemanagement]
pipeline = healthcheck versionnegotiation osprofiler context cache cachemanage rootapp pipeline = cors healthcheck versionnegotiation osprofiler context cache cachemanage rootapp
[composite:rootapp] [composite:rootapp]
paste.composite_factory = glance.api:root_app_factory paste.composite_factory = glance.api:root_app_factory
@ -84,3 +84,25 @@ paste.filter_factory = glance.api.middleware.gzip:GzipMiddleware.factory
paste.filter_factory = osprofiler.web:WsgiMiddleware.factory paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
hmac_keys = SECRET_KEY hmac_keys = SECRET_KEY
enabled = yes enabled = yes
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = glance
oslo_config_program = glance-api
# Basic Headers (Automatic)
# Accept = Origin, Accept, Accept-Language, Content-Type, Cache-Control, Content-Language, Expires, Last-Modified, Pragma
# Expose = Origin, Accept, Accept-Language, Content-Type, Cache-Control, Content-Language, Expires, Last-Modified, Pragma
# Glance Headers
# Accept = Content-MD5, X-Image-Meta-Checksum, X-Storage-Token, Accept-Encoding
# Expose = X-Image-Meta-Checksum
# Keystone Headers
# Accept = X-Auth-Token, X-Identity-Status, X-Roles, X-Service-Catalog, X-User-Id, X-Tenant-Id
# Expose = X-Auth-Token, X-Subject-Token, X-Service-Token
# Request ID Middleware Headers
# Accept = X-OpenStack-Request-ID
# Expose = X-OpenStack-Request-ID
latent_allow_headers = Content-MD5, X-Image-Meta-Checksum, X-Storage-Token, Accept-Encoding, X-Auth-Token, X-Identity-Status, X-Roles, X-Service-Catalog, X-User-Id, X-Tenant-Id, X-OpenStack-Request-ID
latent_expose_headers = X-Image-Meta-Checksum, X-Auth-Token, X-Subject-Token, X-Service-Token, X-OpenStack-Request-ID

View File

@ -627,6 +627,65 @@
#use_tpool = false #use_tpool = false
[cors]
#
# From oslo.middleware.cors
#
# Indicate whether this resource may be shared with the domain
# received in the requests "origin" header. (string 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,DELETE,OPTIONS
# Indicate which header field names may be used during the actual
# request. (list value)
#allow_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma
[cors.subdomain]
#
# From oslo.middleware.cors
#
# Indicate whether this resource may be shared with the domain
# received in the requests "origin" header. (string 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,DELETE,OPTIONS
# Indicate which header field names may be used during the actual
# request. (list value)
#allow_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma
[glance_store] [glance_store]
# #

View File

@ -9,3 +9,4 @@ namespace = oslo.db.concurrency
namespace = oslo.policy namespace = oslo.policy
namespace = keystonemiddleware.auth_token namespace = keystonemiddleware.auth_token
namespace = oslo.log namespace = oslo.log
namespace = oslo.middleware.cors

View File

@ -370,14 +370,21 @@ filesystem_store_datadir=%(image_dir)s
default_store = %(default_store)s default_store = %(default_store)s
""" """
self.paste_conf_base = """[pipeline:glance-api] self.paste_conf_base = """[pipeline:glance-api]
pipeline = healthcheck versionnegotiation gzip unauthenticated-context rootapp pipeline =
cors
healthcheck
versionnegotiation
gzip
unauthenticated-context
rootapp
[pipeline:glance-api-caching] [pipeline:glance-api-caching]
pipeline = healthcheck versionnegotiation gzip unauthenticated-context pipeline = cors healthcheck versionnegotiation gzip unauthenticated-context
cache rootapp cache rootapp
[pipeline:glance-api-cachemanagement] [pipeline:glance-api-cachemanagement]
pipeline = pipeline =
cors
healthcheck healthcheck
versionnegotiation versionnegotiation
gzip gzip
@ -387,10 +394,10 @@ pipeline =
rootapp rootapp
[pipeline:glance-api-fakeauth] [pipeline:glance-api-fakeauth]
pipeline = healthcheck versionnegotiation gzip fakeauth context rootapp pipeline = cors healthcheck versionnegotiation gzip fakeauth context rootapp
[pipeline:glance-api-noauth] [pipeline:glance-api-noauth]
pipeline = healthcheck versionnegotiation gzip context rootapp pipeline = cors healthcheck versionnegotiation gzip context rootapp
[composite:rootapp] [composite:rootapp]
paste.composite_factory = glance.api:root_app_factory paste.composite_factory = glance.api:root_app_factory
@ -439,6 +446,10 @@ paste.filter_factory =
[filter:fakeauth] [filter:fakeauth]
paste.filter_factory = glance.tests.utils:FakeAuthMiddleware.factory paste.filter_factory = glance.tests.utils:FakeAuthMiddleware.factory
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
allowed_origin=http://valid.example.com
""" """

View File

@ -0,0 +1,85 @@
# 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.
"""Tests cors middleware."""
import httplib2
from glance.tests import functional
class TestCORSMiddleware(functional.FunctionalTest):
'''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):
super(TestCORSMiddleware, self).setUp()
# Cleanup is handled in teardown of the parent class.
self.start_servers(**self.__dict__.copy())
self.http = httplib2.Http()
self.api_path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
def test_valid_cors_options_request(self):
(r_headers, content) = self.http.request(
self.api_path,
'OPTIONS',
headers={
'Origin': 'http://valid.example.com',
'Access-Control-Request-Method': 'GET'
})
self.assertEqual(r_headers.status, 200)
self.assertIn('access-control-allow-origin', r_headers)
self.assertEqual('http://valid.example.com',
r_headers['access-control-allow-origin'])
def test_invalid_cors_options_request(self):
(r_headers, content) = self.http.request(
self.api_path,
'OPTIONS',
headers={
'Origin': 'http://invalid.example.com',
'Access-Control-Request-Method': 'GET'
})
self.assertEqual(r_headers.status, 200)
self.assertNotIn('access-control-allow-origin', r_headers)
def test_valid_cors_get_request(self):
(r_headers, content) = self.http.request(
self.api_path,
'GET',
headers={
'Origin': 'http://valid.example.com'
})
self.assertEqual(r_headers.status, 200)
self.assertIn('access-control-allow-origin', r_headers)
self.assertEqual('http://valid.example.com',
r_headers['access-control-allow-origin'])
def test_invalid_cors_get_request(self):
(r_headers, content) = self.http.request(
self.api_path,
'GET',
headers={
'Origin': 'http://invalid.example.com'
})
self.assertEqual(r_headers.status, 200)
self.assertNotIn('access-control-allow-origin', r_headers)