properly quote www-authenticate header value

HTTP header values should be quoted. Since the WWW-Authenticate
header value contains user-supplied strings, it's important to
ensure it's properly quoted to ensure the integrity of the protocol.

Previous to this patch, the URL was unquoted and then the unquoted
value was returned in the header. This patch re-quotes the value
when it is set on the response.

This is filed as CVS-2014-3497

Fixes bug 1327414

Change-Id: If8bd8842f2ce821756e9b4461a18a8ac8d42fb8c
This commit is contained in:
John Dickinson 2014-06-06 11:46:41 -07:00
parent 6946240c75
commit b223322ed1
3 changed files with 36 additions and 1 deletions

View File

@ -1203,7 +1203,7 @@ class Response(object):
realm = 'unknown'
except (AttributeError, ValueError):
realm = 'unknown'
return 'Swift realm="%s"' % realm
return 'Swift realm="%s"' % urllib2.quote(realm)
@property
def is_success(self):

View File

@ -333,6 +333,19 @@ class TestAccount(Base):
self.assertEqual(sorted(containers, cmp=locale.strcoll),
containers)
def testQuotedWWWAuthenticateHeader(self):
conn = Connection(config)
conn.authenticate()
inserted_html = '<b>Hello World'
hax = 'AUTH_haxx"\nContent-Length: %d\n\n%s' % (len(inserted_html),
inserted_html)
quoted_hax = urllib.quote(hax)
conn.connection.request('GET', '/v1/' + quoted_hax, None, {})
resp = conn.connection.getresponse()
resp_headers = resp.getheaders()
expected = ('www-authenticate', 'Swift realm="%s"' % quoted_hax)
self.assert_(expected in resp_headers)
class TestAccountUTF8(Base2, TestAccount):
set_up = False

View File

@ -601,6 +601,28 @@ class TestRequest(unittest.TestCase):
self.assertEquals('Me realm="whatever"',
resp.headers['Www-Authenticate'])
def test_401_www_authenticate_is_quoted(self):
def test_app(environ, start_response):
start_response('401 Unauthorized', [])
return ['hi']
hacker = 'account-name\n\n<b>foo<br>' # url injection test
quoted_hacker = quote(hacker)
req = swift.common.swob.Request.blank('/v1/' + hacker)
resp = req.get_response(test_app)
self.assertEquals(resp.status_int, 401)
self.assert_('Www-Authenticate' in resp.headers)
self.assertEquals('Swift realm="%s"' % quoted_hacker,
resp.headers['Www-Authenticate'])
req = swift.common.swob.Request.blank('/v1/' + quoted_hacker)
resp = req.get_response(test_app)
self.assertEquals(resp.status_int, 401)
self.assert_('Www-Authenticate' in resp.headers)
self.assertEquals('Swift realm="%s"' % quoted_hacker,
resp.headers['Www-Authenticate'])
def test_not_401(self):
# Other status codes should not have WWW-Authenticate in response