From b4c2590ade19475458e24dabc2729ed3bbb22242 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Fri, 2 Sep 2016 15:56:48 -0700 Subject: [PATCH] Add more validation for auth_uri Change-Id: Ic5114dc3291f03355e0b245f7af78935ee98ca0d --- swift3/s3_token_middleware.py | 11 +++++ swift3/test/unit/test_s3_token_middleware.py | 43 ++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/swift3/s3_token_middleware.py b/swift3/s3_token_middleware.py index 842652e7..a2d8ebc4 100644 --- a/swift3/s3_token_middleware.py +++ b/swift3/s3_token_middleware.py @@ -37,6 +37,7 @@ import logging import requests import six +from six.moves import urllib from swift.common.swob import Request, HTTPBadRequest, HTTPUnauthorized, \ HTTPException @@ -149,6 +150,16 @@ class S3Token(object): self._request_uri = '%s://%s:%s' % (auth_protocol, auth_host, auth_port) self._request_uri = self._request_uri.rstrip('/') + parsed = urllib.parse.urlsplit(self._request_uri) + if not parsed.scheme or not parsed.hostname: + raise ConfigFileError( + 'Invalid auth_uri; must include scheme and host') + if parsed.scheme not in ('http', 'https'): + raise ConfigFileError( + 'Invalid auth_uri; scheme must be http or https') + if parsed.query or parsed.fragment or '@' in parsed.netloc: + raise ConfigFileError('Invalid auth_uri; must not include ' + 'username, query, or fragment') # SSL insecure = config_true_value(conf.get('insecure')) diff --git a/swift3/test/unit/test_s3_token_middleware.py b/swift3/test/unit/test_s3_token_middleware.py index b33939bf..c7414bba 100644 --- a/swift3/test/unit/test_s3_token_middleware.py +++ b/swift3/test/unit/test_s3_token_middleware.py @@ -427,6 +427,49 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase): 'auth_uri': 'http://example.com'})(FakeApp()) self.assertEqual(10, middleware._timeout) + def test_bad_auth_uris(self): + for auth_uri in [ + '/not/a/uri', + 'http://', + '//example.com/path']: + with self.assertRaises(ConfigFileError) as cm: + s3_token.filter_factory({'auth_uri': auth_uri})(self.app) + self.assertEqual('Invalid auth_uri; must include scheme and host', + cm.exception.message) + with self.assertRaises(ConfigFileError) as cm: + s3_token.filter_factory({ + 'auth_uri': 'nonhttp://example.com'})(self.app) + self.assertEqual('Invalid auth_uri; scheme must be http or https', + cm.exception.message) + for auth_uri in [ + 'http://user@example.com/', + 'http://example.com/?with=query', + 'http://example.com/#with-fragment']: + with self.assertRaises(ConfigFileError) as cm: + s3_token.filter_factory({'auth_uri': auth_uri})(self.app) + self.assertEqual('Invalid auth_uri; must not include username, ' + 'query, or fragment', cm.exception.message) + + def test_bad_auth_parts(self): + with self.assertRaises(ConfigFileError) as cm: + s3_token.filter_factory({ + 'auth_host': 'example.com', 'auth_protocol': ''})(self.app) + self.assertEqual('Invalid auth_uri; must include scheme and host', + cm.exception.message) + with self.assertRaises(ConfigFileError) as cm: + s3_token.filter_factory({ + 'auth_host': 'example.com', 'auth_protocol': 'ftp'})(self.app) + self.assertEqual('Invalid auth_uri; scheme must be http or https', + cm.exception.message) + for conf in [ + {'auth_host': 'example.com/?with=query'}, + {'auth_host': 'user:password@example.com'}, + {'auth_host': 'example.com/#with-fragment'}]: + with self.assertRaises(ConfigFileError) as cm: + s3_token.filter_factory(conf)(self.app) + self.assertEqual('Invalid auth_uri; must not include username, ' + 'query, or fragment', cm.exception.message) + def test_unicode_path(self): url = u'/v1/AUTH_cfa/c/euro\u20ac'.encode('utf8') req = Request.blank(urllib.parse.quote(url))