Handle SSL termination proxies for version list
Return correct scheme in version URLs if service behind an SSL termination proxy. This is done by adding a new configuration option, secure_proxy_ssl_header, which, when defined, makes the wsgi application take the host_url scheme from that header. By default, when this option is not specified, there is no difference in behavior. The intention is to configure any ssl-decrypting proxy to set that header, so that glance-api knows which protocol to use in the URLs in response. This patch is largely based on the equivalent nova patch: https://review.openstack.org/#/c/206479. Partial-bug: 1558683 Change-Id: I9a9c0e42a6ad3c18d197f10095958b48d5cb879a
This commit is contained in:
parent
35f134e214
commit
513d717d28
|
@ -104,6 +104,14 @@ eventlet_opts = [
|
|||
'wait forever.')),
|
||||
]
|
||||
|
||||
wsgi_opts = [
|
||||
cfg.StrOpt('secure_proxy_ssl_header',
|
||||
help=_('The HTTP header used to determine the scheme for the '
|
||||
'original request, even if it was removed by an SSL '
|
||||
'terminating proxy. Typical value is '
|
||||
'"HTTP_X_FORWARDED_PROTO".')),
|
||||
]
|
||||
|
||||
profiler_opts = [
|
||||
cfg.BoolOpt("enabled", default=False,
|
||||
help=_('If False fully disable profiling feature.')),
|
||||
|
@ -121,6 +129,7 @@ CONF = cfg.CONF
|
|||
CONF.register_opts(bind_opts)
|
||||
CONF.register_opts(socket_opts)
|
||||
CONF.register_opts(eventlet_opts)
|
||||
CONF.register_opts(wsgi_opts)
|
||||
CONF.register_opts(profiler_opts, group="profiler")
|
||||
|
||||
ASYNC_EVENTLET_THREAD_POOL_LIST = []
|
||||
|
@ -732,6 +741,13 @@ class Router(object):
|
|||
class Request(webob.Request):
|
||||
"""Add some OpenStack API-specific logic to the base webob.Request."""
|
||||
|
||||
def __init__(self, environ, *args, **kwargs):
|
||||
if CONF.secure_proxy_ssl_header:
|
||||
scheme = environ.get(CONF.secure_proxy_ssl_header)
|
||||
if scheme:
|
||||
environ['wsgi.url_scheme'] = scheme
|
||||
super(Request, self).__init__(environ, *args, **kwargs)
|
||||
|
||||
def best_match_content_type(self):
|
||||
"""Determine the requested response content-type."""
|
||||
supported = ('application/json',)
|
||||
|
|
|
@ -18,6 +18,7 @@ import webob
|
|||
|
||||
from glance.api.middleware import version_negotiation
|
||||
from glance.api import versions
|
||||
from glance.common.wsgi import Request as WsgiRequest
|
||||
from glance.tests.unit import base
|
||||
|
||||
|
||||
|
@ -122,6 +123,103 @@ class VersionsTest(base.IsolatedUnitTest):
|
|||
]
|
||||
self.assertEqual(expected, results)
|
||||
|
||||
def test_get_version_list_secure_proxy_ssl_header(self):
|
||||
self.config(secure_proxy_ssl_header='HTTP_X_FORWARDED_PROTO')
|
||||
environ = webob.request.environ_from_url('http://localhost:9292')
|
||||
req = WsgiRequest(environ)
|
||||
res = versions.Controller().index(req)
|
||||
self.assertEqual(300, res.status_int)
|
||||
self.assertEqual('application/json', res.content_type)
|
||||
results = jsonutils.loads(res.body)['versions']
|
||||
expected = [
|
||||
{
|
||||
'id': 'v2.3',
|
||||
'status': 'CURRENT',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'http://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v2.2',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'http://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v2.1',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'http://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v2.0',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'http://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v1.1',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'http://localhost:9292/v1/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v1.0',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'http://localhost:9292/v1/'}],
|
||||
},
|
||||
]
|
||||
self.assertEqual(expected, results)
|
||||
|
||||
def test_get_version_list_secure_proxy_ssl_header_https(self):
|
||||
self.config(secure_proxy_ssl_header='HTTP_X_FORWARDED_PROTO')
|
||||
environ = webob.request.environ_from_url('http://localhost:9292')
|
||||
environ['HTTP_X_FORWARDED_PROTO'] = "https"
|
||||
req = WsgiRequest(environ)
|
||||
res = versions.Controller().index(req)
|
||||
self.assertEqual(300, res.status_int)
|
||||
self.assertEqual('application/json', res.content_type)
|
||||
results = jsonutils.loads(res.body)['versions']
|
||||
expected = [
|
||||
{
|
||||
'id': 'v2.3',
|
||||
'status': 'CURRENT',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'https://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v2.2',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'https://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v2.1',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'https://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v2.0',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'https://localhost:9292/v2/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v1.1',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'https://localhost:9292/v1/'}],
|
||||
},
|
||||
{
|
||||
'id': 'v1.0',
|
||||
'status': 'SUPPORTED',
|
||||
'links': [{'rel': 'self',
|
||||
'href': 'https://localhost:9292/v1/'}],
|
||||
},
|
||||
]
|
||||
self.assertEqual(expected, results)
|
||||
|
||||
|
||||
class VersionNegotiationTest(base.IsolatedUnitTest):
|
||||
|
||||
|
|
Loading…
Reference in New Issue