Merge "Added CORS support to Glance"
This commit is contained in:
commit
74eadaa36c
@ -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
|
@ -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]
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
85
glance/tests/functional/test_cors_middleware.py
Normal file
85
glance/tests/functional/test_cors_middleware.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user