summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-06-11 03:08:38 +0000
committerGerrit Code Review <review@openstack.org>2015-06-11 03:08:38 +0000
commita999eedb2729da293561e60d9c4a85fc4f57b077 (patch)
tree54739ee20c81fad77cc48c9464fe7ce0d65911b9
parent98e4f3ca2d6710abe848ef8014787491904d2875 (diff)
parent6b4e821e14af7ed2362b02f2b42e9a8a5bc49672 (diff)
downloadoslo-middleware-a999eedb2729da293561e60d9c4a85fc4f57b077.tar.gz
Merge "Add middleware to support ssl termination proxies"
-rw-r--r--oslo_middleware/__init__.py4
-rw-r--r--oslo_middleware/opts.py3
-rw-r--r--oslo_middleware/ssl.py43
-rw-r--r--oslo_middleware/tests/test_ssl.py56
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)