Repository: urllib3/urllib3

Issue:
authorization header be forwarded to cross-site when redirecting
#1346 fixes only "Authorization" header. "authorization" header isn't supported.

RFC7230 section 3.2 "Header Fields" (https://tools.ietf.org/html/rfc7230#section-3.2) says the following.

> Each header field consists of a case-insensitive field name followed
   by a colon (":"), optional leading whitespace, the field value, and
   optional trailing whitespace.


Discussion:

Resolving patch:
diff --git a/src/urllib3/poolmanager.py b/src/urllib3/poolmanager.py
--- a/src/urllib3/poolmanager.py
+++ b/src/urllib3/poolmanager.py
@@ -7,6 +7,7 @@
 from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool
 from .connectionpool import port_by_scheme
 from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown
+from .packages import six
 from .packages.six.moves.urllib.parse import urljoin
 from .request import RequestMethods
 from .util.url import parse_url
@@ -342,8 +343,10 @@ def urlopen(self, method, url, redirect=True, **kw):
         # conn.is_same_host() which may use socket.gethostbyname() in the future.
         if (retries.remove_headers_on_redirect
                 and not conn.is_same_host(redirect_location)):
-            for header in retries.remove_headers_on_redirect:
-                kw['headers'].pop(header, None)
+            headers = list(six.iterkeys(kw['headers']))
+            for header in headers:
+                if header.lower() in retries.remove_headers_on_redirect:
+                    kw['headers'].pop(header, None)
 
         try:
             retries = retries.increment(method, url, response=response, _pool=conn)
diff --git a/src/urllib3/util/retry.py b/src/urllib3/util/retry.py
--- a/src/urllib3/util/retry.py
+++ b/src/urllib3/util/retry.py
@@ -179,7 +179,8 @@ def __init__(self, total=10, connect=None, read=None, redirect=None, status=None
         self.raise_on_status = raise_on_status
         self.history = history or tuple()
         self.respect_retry_after_header = respect_retry_after_header
-        self.remove_headers_on_redirect = remove_headers_on_redirect
+        self.remove_headers_on_redirect = frozenset([
+            h.lower() for h in remove_headers_on_redirect])
 
     def new(self, **kw):
         params = dict(


Test patch:
diff --git a/test/test_retry.py b/test/test_retry.py
--- a/test/test_retry.py
+++ b/test/test_retry.py
@@ -253,9 +253,9 @@ def test_retry_method_not_in_whitelist(self):
     def test_retry_default_remove_headers_on_redirect(self):
         retry = Retry()
 
-        assert list(retry.remove_headers_on_redirect) == ['Authorization']
+        assert list(retry.remove_headers_on_redirect) == ['authorization']
 
     def test_retry_set_remove_headers_on_redirect(self):
         retry = Retry(remove_headers_on_redirect=['X-API-Secret'])
 
-        assert list(retry.remove_headers_on_redirect) == ['X-API-Secret']
+        assert list(retry.remove_headers_on_redirect) == ['x-api-secret']
diff --git a/test/with_dummyserver/test_poolmanager.py b/test/with_dummyserver/test_poolmanager.py
--- a/test/with_dummyserver/test_poolmanager.py
+++ b/test/with_dummyserver/test_poolmanager.py
@@ -123,6 +123,17 @@ def test_redirect_cross_host_remove_headers(self):
 
         self.assertNotIn('Authorization', data)
 
+        r = http.request('GET', '%s/redirect' % self.base_url,
+                         fields={'target': '%s/headers' % self.base_url_alt},
+                         headers={'authorization': 'foo'})
+
+        self.assertEqual(r.status, 200)
+
+        data = json.loads(r.data.decode('utf-8'))
+
+        self.assertNotIn('authorization', data)
+        self.assertNotIn('Authorization', data)
+
     def test_redirect_cross_host_no_remove_headers(self):
         http = PoolManager()
         self.addCleanup(http.clear)
@@ -155,6 +166,20 @@ def test_redirect_cross_host_set_removed_headers(self):
         self.assertNotIn('X-API-Secret', data)
         self.assertEqual(data['Authorization'], 'bar')
 
+        r = http.request('GET', '%s/redirect' % self.base_url,
+                         fields={'target': '%s/headers' % self.base_url_alt},
+                         headers={'x-api-secret': 'foo',
+                                  'authorization': 'bar'},
+                         retries=Retry(remove_headers_on_redirect=['X-API-Secret']))
+
+        self.assertEqual(r.status, 200)
+
+        data = json.loads(r.data.decode('utf-8'))
+
+        self.assertNotIn('x-api-secret', data)
+        self.assertNotIn('X-API-Secret', data)
+        self.assertEqual(data['Authorization'], 'bar')
+
     def test_raise_on_redirect(self):
         http = PoolManager()
         self.addCleanup(http.clear)