From 8c7ca01ea7ee0943d5b3078b941c15932f6eecff Mon Sep 17 00:00:00 2001 From: Yuxin Wang Date: Wed, 4 Jul 2018 17:13:49 +0800 Subject: [PATCH] Unquote URL before using splited parts. Keystone EC2 access keys may contain URL reserved/unsafe chars, then the access key in PATH_INFO can't be replace by account name. ie. /v1/abc%3D/c/o --> /v1/AUTH_PROJECT_ID/c/o Change-Id: I034b0902f620cbb274647e24566dff2031beeae5 Closes-Bug: 1776476 --- swift/common/middleware/s3api/s3token.py | 2 +- .../common/middleware/s3api/test_s3token.py | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/swift/common/middleware/s3api/s3token.py b/swift/common/middleware/s3api/s3token.py index bf20bb823f..e8990c0e14 100644 --- a/swift/common/middleware/s3api/s3token.py +++ b/swift/common/middleware/s3api/s3token.py @@ -199,7 +199,7 @@ class S3Token(object): req.headers.update({h: None for h in KEYSTONE_AUTH_HEADERS}) try: - parts = split_path(req.path, 1, 4, True) + parts = split_path(urllib.parse.unquote(req.path), 1, 4, True) version, account, container, obj = parts except ValueError: msg = 'Not a path query: %s, skipping.' % req.path diff --git a/test/unit/common/middleware/s3api/test_s3token.py b/test/unit/common/middleware/s3api/test_s3token.py index 0ce3eae55b..4e9251c01f 100644 --- a/test/unit/common/middleware/s3api/test_s3token.py +++ b/test/unit/common/middleware/s3api/test_s3token.py @@ -482,6 +482,28 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase): req.get_response(self.middleware) self._assert_authorized(req) + def test_authorize_with_access_key(self): + req = Request.blank('/v1/accesskey/c/o') + req.environ['s3api.auth_details'] = { + 'access_key': u'access', + 'signature': u'signature', + 'string_to_sign': u'token', + } + req.get_response(self.middleware) + self._assert_authorized(req, account_path='/v1/') + self.assertEqual(req.environ['PATH_INFO'], '/v1/AUTH_TENANT_ID/c/o') + + def test_authorize_with_access_key_and_unquote_chars(self): + req = Request.blank('/v1/access%key=/c/o') + req.environ['s3api.auth_details'] = { + 'access_key': u'access', + 'signature': u'signature', + 'string_to_sign': u'token', + } + req.get_response(self.middleware) + self._assert_authorized(req, account_path='/v1/') + self.assertEqual(req.environ['PATH_INFO'], '/v1/AUTH_TENANT_ID/c/o') + class S3TokenMiddlewareTestBad(S3TokenMiddlewareTestBase): def test_unauthorized_token(self): @@ -819,3 +841,25 @@ class S3TokenMiddlewareTestV3(S3TokenMiddlewareTestBase): self._test_bad_reply_missing_parts('token', 'project', 'domain') self._test_bad_reply_missing_parts('token', 'project') self._test_bad_reply_missing_parts('token', 'roles') + + def test_authorize_with_access_key(self): + req = Request.blank('/v1/accesskey/c/o') + req.environ['s3api.auth_details'] = { + 'access_key': u'access', + 'signature': u'signature', + 'string_to_sign': u'token', + } + req.get_response(self.middleware) + self._assert_authorized(req, account_path='/v1/') + self.assertEqual(req.environ['PATH_INFO'], '/v1/AUTH_PROJECT_ID/c/o') + + def test_authorize_with_access_key_and_unquote_chars(self): + req = Request.blank('/v1/ab%c=/c/o') + req.environ['s3api.auth_details'] = { + 'access_key': u'access', + 'signature': u'signature', + 'string_to_sign': u'token', + } + req.get_response(self.middleware) + self._assert_authorized(req, account_path='/v1/') + self.assertEqual(req.environ['PATH_INFO'], '/v1/AUTH_PROJECT_ID/c/o')