diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-06-11 03:08:38 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-06-11 03:08:38 +0000 |
commit | a999eedb2729da293561e60d9c4a85fc4f57b077 (patch) | |
tree | 54739ee20c81fad77cc48c9464fe7ce0d65911b9 | |
parent | 98e4f3ca2d6710abe848ef8014787491904d2875 (diff) | |
parent | 6b4e821e14af7ed2362b02f2b42e9a8a5bc49672 (diff) | |
download | oslo-middleware-a999eedb2729da293561e60d9c4a85fc4f57b077.tar.gz |
Merge "Add middleware to support ssl termination proxies"
-rw-r--r-- | oslo_middleware/__init__.py | 4 | ||||
-rw-r--r-- | oslo_middleware/opts.py | 3 | ||||
-rw-r--r-- | oslo_middleware/ssl.py | 43 | ||||
-rw-r--r-- | oslo_middleware/tests/test_ssl.py | 56 |
4 files changed, 104 insertions, 2 deletions
diff --git a/oslo_middleware/__init__.py b/oslo_middleware/__init__.py index ae0965b..b2ea8c0 100644 --- a/oslo_middleware/__init__.py +++ b/oslo_middleware/__init__.py @@ -16,7 +16,8 @@ __all__ = ['CatchErrors', 'Debug', 'Healthcheck', 'RequestId', - 'RequestBodySizeLimiter'] + 'RequestBodySizeLimiter', + 'SSLMiddleware'] from oslo_middleware.catch_errors import CatchErrors from oslo_middleware.correlation_id import CorrelationId @@ -25,3 +26,4 @@ from oslo_middleware.debug import Debug from oslo_middleware.healthcheck import Healthcheck from oslo_middleware.request_id import RequestId from oslo_middleware.sizelimit import RequestBodySizeLimiter +from oslo_middleware.ssl import SSLMiddleware diff --git a/oslo_middleware/opts.py b/oslo_middleware/opts.py index d322291..c19f272 100644 --- a/oslo_middleware/opts.py +++ b/oslo_middleware/opts.py @@ -22,6 +22,7 @@ import copy from oslo_middleware import cors from oslo_middleware import sizelimit +from oslo_middleware import ssl def list_opts(): @@ -44,7 +45,7 @@ def list_opts(): :returns: a list of (group_name, opts) tuples """ return [ - ('oslo_middleware', copy.deepcopy(sizelimit._opts)), + ('oslo_middleware', copy.deepcopy(sizelimit._opts + ssl.OPTS)), ('cors', copy.deepcopy(cors.CORS_OPTS)), ('cors.subdomain', copy.deepcopy(cors.CORS_OPTS)) ] diff --git a/oslo_middleware/ssl.py b/oslo_middleware/ssl.py new file mode 100644 index 0000000..97293f3 --- /dev/null +++ b/oslo_middleware/ssl.py @@ -0,0 +1,43 @@ +# 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.config import cfg +from oslo_middleware import base + + +OPTS = [ + cfg.StrOpt('secure_proxy_ssl_header', + default='X-Forwarded-Proto', + help="The HTTP Header that will be used to determine what " + "the original request protocol scheme was, even if it was " + "hidden by an SSL termination proxy.") +] +cfg.CONF.register_opts(OPTS, group='oslo_middleware') + + +class SSLMiddleware(base.Middleware): + """SSL termination proxies middleware. + + This middleware overloads wsgi.url_scheme with the one provided in + secure_proxy_ssl_header header. This is useful when behind a SSL + termination proxy. + """ + + def __init__(self, application): + super(SSLMiddleware, self).__init__(application) + self.header_name = 'HTTP_{0}'.format( + cfg.CONF.oslo_middleware.secure_proxy_ssl_header.upper() + .replace('-', '_')) + + def process_request(self, req): + req.environ['wsgi.url_scheme'] = req.environ.get( + self.header_name, req.environ['wsgi.url_scheme']) diff --git a/oslo_middleware/tests/test_ssl.py b/oslo_middleware/tests/test_ssl.py new file mode 100644 index 0000000..7314260 --- /dev/null +++ b/oslo_middleware/tests/test_ssl.py @@ -0,0 +1,56 @@ +# Copyright (c) 2015 Thales Services SAS +# 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_config import cfg +from oslo_config import fixture as config +from oslotest import base +import webob + +from oslo_middleware import ssl + + +class SSLMiddlewareTest(base.BaseTestCase): + + def setUp(self): + super(SSLMiddlewareTest, self).setUp() + self.useFixture(config.Config()) + + def _test_scheme(self, expected, headers): + middleware = ssl.SSLMiddleware(None) + request = webob.Request.blank('http://example.com/', headers=headers) + + # Ensure ssl middleware does not stop pipeline execution + self.assertIsNone(middleware.process_request(request)) + + self.assertEqual(expected, request.scheme) + + def test_without_forwarded_protocol(self): + self._test_scheme('http', {}) + + def test_with_forwarded_protocol(self): + headers = {'X-Forwarded-Proto': 'https'} + self._test_scheme('https', headers) + + def test_with_custom_header(self): + cfg.CONF.set_override('secure_proxy_ssl_header', 'X-My-Header', + group='oslo_middleware') + headers = {'X-Forwarded-Proto': 'https'} + self._test_scheme('http', headers) + + def test_with_custom_header_and_forwarded_protocol(self): + cfg.CONF.set_override('secure_proxy_ssl_header', 'X-My-Header', + group='oslo_middleware') + headers = {'X-My-Header': 'https'} + self._test_scheme('https', headers) |