|
Pete Zaitcev |
8bb9a30 |
From 3b945a2fcbcc8df63cb9e1987741fa12b8f54a8c Mon Sep 17 00:00:00 2001
|
|
Pete Zaitcev |
8bb9a30 |
From: John Dickinson <me@not.mn>
|
|
Pete Zaitcev |
8bb9a30 |
Date: Fri, 6 Jun 2014 11:46:41 -0700
|
|
Pete Zaitcev |
8bb9a30 |
Subject: [PATCH] properly quote www-authenticate header value
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
HTTP header values should be quoted. Since the WWW-Authenticate
|
|
Pete Zaitcev |
8bb9a30 |
header value contains user-supplied strings, it's important to
|
|
Pete Zaitcev |
8bb9a30 |
ensure it's properly quoted to ensure the integrity of the protocol.
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
Previous to this patch, the URL was unquoted and then the unquoted
|
|
Pete Zaitcev |
8bb9a30 |
value was returned in the header. This patch re-quotes the value
|
|
Pete Zaitcev |
8bb9a30 |
when it is set on the response.
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
This is filed as CVS-2014-3497
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
Fixes bug 1327414
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
Change-Id: If8bd8842f2ce821756e9b4461a18a8ac8d42fb8c
|
|
Pete Zaitcev |
8bb9a30 |
(cherry picked from commit b223322ed1ef44f61490f820240aa01f1047ae2e)
|
|
Pete Zaitcev |
8bb9a30 |
---
|
|
Pete Zaitcev |
8bb9a30 |
swift/common/swob.py | 2 +-
|
|
Pete Zaitcev |
8bb9a30 |
test/functional/tests.py | 13 +++++++++++++
|
|
Pete Zaitcev |
8bb9a30 |
test/unit/common/test_swob.py | 22 ++++++++++++++++++++++
|
|
Pete Zaitcev |
8bb9a30 |
3 files changed, 36 insertions(+), 1 deletion(-)
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
diff --git a/swift/common/swob.py b/swift/common/swob.py
|
|
Pete Zaitcev |
8bb9a30 |
index 638086e..f4f38c7 100644
|
|
Pete Zaitcev |
8bb9a30 |
--- a/swift/common/swob.py
|
|
Pete Zaitcev |
8bb9a30 |
+++ b/swift/common/swob.py
|
|
Pete Zaitcev |
8bb9a30 |
@@ -1203,7 +1203,7 @@ class Response(object):
|
|
Pete Zaitcev |
8bb9a30 |
realm = 'unknown'
|
|
Pete Zaitcev |
8bb9a30 |
except (AttributeError, ValueError):
|
|
Pete Zaitcev |
8bb9a30 |
realm = 'unknown'
|
|
Pete Zaitcev |
8bb9a30 |
- return 'Swift realm="%s"' % realm
|
|
Pete Zaitcev |
8bb9a30 |
+ return 'Swift realm="%s"' % urllib2.quote(realm)
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
@property
|
|
Pete Zaitcev |
8bb9a30 |
def is_success(self):
|
|
Pete Zaitcev |
8bb9a30 |
diff --git a/test/functional/tests.py b/test/functional/tests.py
|
|
Pete Zaitcev |
8bb9a30 |
index ad8c398..7983815 100644
|
|
Pete Zaitcev |
8bb9a30 |
--- a/test/functional/tests.py
|
|
Pete Zaitcev |
8bb9a30 |
+++ b/test/functional/tests.py
|
|
Pete Zaitcev |
8bb9a30 |
@@ -333,6 +333,19 @@ class TestAccount(Base):
|
|
Pete Zaitcev |
8bb9a30 |
self.assertEqual(sorted(containers, cmp=locale.strcoll),
|
|
Pete Zaitcev |
8bb9a30 |
containers)
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
+ def testQuotedWWWAuthenticateHeader(self):
|
|
Pete Zaitcev |
8bb9a30 |
+ conn = Connection(config)
|
|
Pete Zaitcev |
8bb9a30 |
+ conn.authenticate()
|
|
Pete Zaitcev |
8bb9a30 |
+ inserted_html = 'Hello World'
|
|
Pete Zaitcev |
8bb9a30 |
+ hax = 'AUTH_haxx"\nContent-Length: %d\n\n%s' % (len(inserted_html),
|
|
Pete Zaitcev |
8bb9a30 |
+ inserted_html)
|
|
Pete Zaitcev |
8bb9a30 |
+ quoted_hax = urllib.quote(hax)
|
|
Pete Zaitcev |
8bb9a30 |
+ conn.connection.request('GET', '/v1/' + quoted_hax, None, {})
|
|
Pete Zaitcev |
8bb9a30 |
+ resp = conn.connection.getresponse()
|
|
Pete Zaitcev |
8bb9a30 |
+ resp_headers = resp.getheaders()
|
|
Pete Zaitcev |
8bb9a30 |
+ expected = ('www-authenticate', 'Swift realm="%s"' % quoted_hax)
|
|
Pete Zaitcev |
8bb9a30 |
+ self.assert_(expected in resp_headers)
|
|
Pete Zaitcev |
8bb9a30 |
+
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
class TestAccountUTF8(Base2, TestAccount):
|
|
Pete Zaitcev |
8bb9a30 |
set_up = False
|
|
Pete Zaitcev |
8bb9a30 |
diff --git a/test/unit/common/test_swob.py b/test/unit/common/test_swob.py
|
|
Pete Zaitcev |
8bb9a30 |
index 7cc5439..b0452b9 100644
|
|
Pete Zaitcev |
8bb9a30 |
--- a/test/unit/common/test_swob.py
|
|
Pete Zaitcev |
8bb9a30 |
+++ b/test/unit/common/test_swob.py
|
|
Pete Zaitcev |
8bb9a30 |
@@ -601,6 +601,28 @@ class TestRequest(unittest.TestCase):
|
|
Pete Zaitcev |
8bb9a30 |
self.assertEquals('Me realm="whatever"',
|
|
Pete Zaitcev |
8bb9a30 |
resp.headers['Www-Authenticate'])
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
+ def test_401_www_authenticate_is_quoted(self):
|
|
Pete Zaitcev |
8bb9a30 |
+
|
|
Pete Zaitcev |
8bb9a30 |
+ def test_app(environ, start_response):
|
|
Pete Zaitcev |
8bb9a30 |
+ start_response('401 Unauthorized', [])
|
|
Pete Zaitcev |
8bb9a30 |
+ return ['hi']
|
|
Pete Zaitcev |
8bb9a30 |
+
|
|
Pete Zaitcev |
8bb9a30 |
+ hacker = 'account-name\n\nfoo ' # url injection test
|
|
Pete Zaitcev |
8bb9a30 |
+ quoted_hacker = quote(hacker)
|
|
Pete Zaitcev |
8bb9a30 |
+ req = swift.common.swob.Request.blank('/v1/' + hacker)
|
|
Pete Zaitcev |
8bb9a30 |
+ resp = req.get_response(test_app)
|
|
Pete Zaitcev |
8bb9a30 |
+ self.assertEquals(resp.status_int, 401)
|
|
Pete Zaitcev |
8bb9a30 |
+ self.assert_('Www-Authenticate' in resp.headers)
|
|
Pete Zaitcev |
8bb9a30 |
+ self.assertEquals('Swift realm="%s"' % quoted_hacker,
|
|
Pete Zaitcev |
8bb9a30 |
+ resp.headers['Www-Authenticate'])
|
|
Pete Zaitcev |
8bb9a30 |
+
|
|
Pete Zaitcev |
8bb9a30 |
+ req = swift.common.swob.Request.blank('/v1/' + quoted_hacker)
|
|
Pete Zaitcev |
8bb9a30 |
+ resp = req.get_response(test_app)
|
|
Pete Zaitcev |
8bb9a30 |
+ self.assertEquals(resp.status_int, 401)
|
|
Pete Zaitcev |
8bb9a30 |
+ self.assert_('Www-Authenticate' in resp.headers)
|
|
Pete Zaitcev |
8bb9a30 |
+ self.assertEquals('Swift realm="%s"' % quoted_hacker,
|
|
Pete Zaitcev |
8bb9a30 |
+ resp.headers['Www-Authenticate'])
|
|
Pete Zaitcev |
8bb9a30 |
+
|
|
Pete Zaitcev |
8bb9a30 |
def test_not_401(self):
|
|
Pete Zaitcev |
8bb9a30 |
|
|
Pete Zaitcev |
8bb9a30 |
# Other status codes should not have WWW-Authenticate in response
|