From b0d0b1d0ba7b9d1fadca0e7932c5886bc6cc7825 Mon Sep 17 00:00:00 2001
From: Jamie Lennox <jamielennox@gmail.com>
Date: Wed, 8 Jun 2016 11:59:09 +1000
Subject: [PATCH] Use http-proxy-to-wsgi middleware from oslo.middleware

The HTTP_X_FORWARDED_PROTO handling fails to handle the case of
redirecting the /v1 request to /v1/ because it is handled purely by
routes and does not enter the glance wsgi code. This means a https
request is redirect to http and fails.

oslo.middleware has middleware for handling the X-Forwarded-Proto header
in a standard way so that services don't have to and so we should use
that instead of our own mechanism.

Leaving the existing header handling around until removal should not be
a problem as the worst that will happen is it overwrites an existing
'https' header value set by the middleware.

Closes-Bug: #1558683
Closes-Bug: #1590608
Change-Id: I481d88020b6e8420ce4b9072dd30ec82fe3fb4f7
---
 etc/glance-api-paste.ini                  | 19 +++++++++++--------
 etc/glance-api.conf                       | 11 +++++++++++
 etc/oslo-config-generator/glance-api.conf |  1 +
 glance/common/wsgi.py                     |  3 +++
 4 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/etc/glance-api-paste.ini b/etc/glance-api-paste.ini
index 9efd19f719..687902743a 100644
--- a/etc/glance-api-paste.ini
+++ b/etc/glance-api-paste.ini
@@ -1,38 +1,38 @@
 # Use this pipeline for no auth or image caching - DEFAULT
 [pipeline:glance-api]
-pipeline = cors healthcheck versionnegotiation osprofiler unauthenticated-context rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi versionnegotiation osprofiler unauthenticated-context rootapp
 
 # Use this pipeline for image caching and no auth
 [pipeline:glance-api-caching]
-pipeline = cors healthcheck versionnegotiation osprofiler unauthenticated-context cache rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi versionnegotiation osprofiler unauthenticated-context cache rootapp
 
 # Use this pipeline for caching w/ management interface but no auth
 [pipeline:glance-api-cachemanagement]
-pipeline = cors healthcheck versionnegotiation osprofiler unauthenticated-context cache cachemanage rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi versionnegotiation osprofiler unauthenticated-context cache cachemanage rootapp
 
 # Use this pipeline for keystone auth
 [pipeline:glance-api-keystone]
-pipeline = cors healthcheck versionnegotiation osprofiler authtoken context  rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi versionnegotiation osprofiler authtoken context  rootapp
 
 # Use this pipeline for keystone auth with image caching
 [pipeline:glance-api-keystone+caching]
-pipeline = cors healthcheck versionnegotiation osprofiler authtoken context cache rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi versionnegotiation osprofiler authtoken context cache rootapp
 
 # Use this pipeline for keystone auth with caching and cache management
 [pipeline:glance-api-keystone+cachemanagement]
-pipeline = cors healthcheck versionnegotiation osprofiler authtoken context cache cachemanage rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi 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 = cors healthcheck versionnegotiation osprofiler context rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi 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 = cors healthcheck versionnegotiation osprofiler context cache cachemanage rootapp
+pipeline = cors healthcheck http_proxy_to_wsgi versionnegotiation osprofiler context cache cachemanage rootapp
 
 [composite:rootapp]
 paste.composite_factory = glance.api:root_app_factory
@@ -85,3 +85,6 @@ enabled = yes  #DEPRECATED
 paste.filter_factory =  oslo_middleware.cors:filter_factory
 oslo_config_project = glance
 oslo_config_program = glance-api
+
+[filter:http_proxy_to_wsgi]
+paste.filter_factory = oslo_middleware:HTTPProxyToWSGI.factory
diff --git a/etc/glance-api.conf b/etc/glance-api.conf
index 228b892616..9362b122a3 100644
--- a/etc/glance-api.conf
+++ b/etc/glance-api.conf
@@ -1649,6 +1649,17 @@
 #rpc_retry_delay = 0.25
 
 
+[oslo_middleware]
+
+#
+# From oslo.middleware.http_proxy_to_wsgi
+#
+
+# Wether the application is behind a proxy or not. This determines if
+# the middleware should parse the headers or not. (boolean value)
+#enable_proxy_headers_parsing = false
+
+
 [oslo_policy]
 
 #
diff --git a/etc/oslo-config-generator/glance-api.conf b/etc/oslo-config-generator/glance-api.conf
index 07466068c2..141d294ad3 100644
--- a/etc/oslo-config-generator/glance-api.conf
+++ b/etc/oslo-config-generator/glance-api.conf
@@ -10,4 +10,5 @@ namespace = oslo.policy
 namespace = keystonemiddleware.auth_token
 namespace = oslo.log
 namespace = oslo.middleware.cors
+namespace = oslo.middleware.http_proxy_to_wsgi
 namespace = osprofiler
diff --git a/glance/common/wsgi.py b/glance/common/wsgi.py
index 2eba5cbde0..5786a39f87 100644
--- a/glance/common/wsgi.py
+++ b/glance/common/wsgi.py
@@ -107,6 +107,9 @@ eventlet_opts = [
 
 wsgi_opts = [
     cfg.StrOpt('secure_proxy_ssl_header',
+               deprecated_for_removal=True,
+               deprecated_reason=_('Use the http_proxy_to_wsgi middleware '
+                                   'instead.'),
                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 '