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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
# user as authenticated without making requests to keystone to reauthenticate
|
||||
# the user.
|
||||
[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
|
||||
# user as authenticated without making requests to keystone to reauthenticate
|
||||
# the user and uses cache management
|
||||
[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]
|
||||
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
|
||||
hmac_keys = SECRET_KEY
|
||||
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
|
||||
|
||||
|
||||
[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]
|
||||
|
||||
#
|
||||
|
@ -9,3 +9,4 @@ namespace = oslo.db.concurrency
|
||||
namespace = oslo.policy
|
||||
namespace = keystonemiddleware.auth_token
|
||||
namespace = oslo.log
|
||||
namespace = oslo.middleware.cors
|
||||
|
@ -370,14 +370,21 @@ filesystem_store_datadir=%(image_dir)s
|
||||
default_store = %(default_store)s
|
||||
"""
|
||||
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 = healthcheck versionnegotiation gzip unauthenticated-context
|
||||
pipeline = cors healthcheck versionnegotiation gzip unauthenticated-context
|
||||
cache rootapp
|
||||
|
||||
[pipeline:glance-api-cachemanagement]
|
||||
pipeline =
|
||||
cors
|
||||
healthcheck
|
||||
versionnegotiation
|
||||
gzip
|
||||
@ -387,10 +394,10 @@ pipeline =
|
||||
rootapp
|
||||
|
||||
[pipeline:glance-api-fakeauth]
|
||||
pipeline = healthcheck versionnegotiation gzip fakeauth context rootapp
|
||||
pipeline = cors healthcheck versionnegotiation gzip fakeauth context rootapp
|
||||
|
||||
[pipeline:glance-api-noauth]
|
||||
pipeline = healthcheck versionnegotiation gzip context rootapp
|
||||
pipeline = cors healthcheck versionnegotiation gzip context rootapp
|
||||
|
||||
[composite:rootapp]
|
||||
paste.composite_factory = glance.api:root_app_factory
|
||||
@ -439,6 +446,10 @@ paste.filter_factory =
|
||||
|
||||
[filter:fakeauth]
|
||||
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