Merge "s3api: Stop mangling Authorization header for v4 signatures"

This commit is contained in:
Zuul 2019-01-02 18:02:06 +00:00 committed by Gerrit Code Review
commit 7b1679b9b2
6 changed files with 30 additions and 60 deletions

View File

@ -491,15 +491,6 @@ class S3Request(swob.Request):
self.user_id = None
self.slo_enabled = slo_enabled
# NOTE(andrey-mp): substitute authorization header for next modules
# in pipeline (s3token). it uses this and X-Auth-Token in specific
# format.
# (kota_): yeah, the reason we need this is s3token only supports
# v2 like header consists of AWS access:signature. Since the commit
# b626a3ca86e467fc7564eac236b9ee2efd49bdcc, the s3token is in swift3
# repo so probably we need to change s3token to support v4 format.
self.headers['Authorization'] = 'AWS %s:%s' % (
self.access_key, self.signature)
# Avoids that swift.swob.Response replaces Location header value
# by full URL when absolute path given. See swift.swob for more detail.
self.environ['swift.leave_relative_location'] = True
@ -1460,7 +1451,6 @@ class S3AclRequest(S3Request):
# Need to skip S3 authorization on subsequent requests to prevent
# overwriting the account in PATH_INFO
del self.headers['Authorization']
del self.environ['s3api.auth_details']
def to_swift_req(self, method, container, obj, query=None,

View File

@ -38,15 +38,14 @@ class FakeApp(object):
E.g. '/v1/test:tester/bucket/object' will become
'/v1/AUTH_test/bucket/object'. This method emulates the behavior.
"""
_, authorization = env['HTTP_AUTHORIZATION'].split(' ')
tenant_user, sign = authorization.rsplit(':', 1)
tenant_user = env['s3api.auth_details']['access_key']
tenant, user = tenant_user.rsplit(':', 1)
path = env['PATH_INFO']
env['PATH_INFO'] = path.replace(tenant_user, 'AUTH_' + tenant)
def __call__(self, env, start_response):
if 'HTTP_AUTHORIZATION' in env:
if 's3api.auth_details' in env:
self._update_s3_path_info(env)
return self.swift(env, start_response)

View File

@ -41,11 +41,10 @@ class FakeSwift(object):
if 'swift.authorize_override' in env:
return
if 'HTTP_AUTHORIZATION' not in env:
if 's3api.auth_details' not in env:
return
_, authorization = env['HTTP_AUTHORIZATION'].split(' ')
tenant_user, sign = authorization.rsplit(':', 1)
tenant_user = env['s3api.auth_details']['access_key']
tenant, user = tenant_user.rsplit(':', 1)
path = env['PATH_INFO']

View File

@ -30,27 +30,6 @@ from swift.common.middleware.s3api.subresource import ACL, User, encode_acl, \
Owner, Grant
from swift.common.middleware.s3api.etree import fromstring
from swift.common.middleware.s3api.utils import mktime, S3Timestamp
from test.unit.common.middleware.s3api.helpers import FakeSwift
def _wrap_fake_auth_middleware(org_func):
def fake_fake_auth_middleware(self, env):
org_func(env)
if 'swift.authorize_override' in env:
return
if 'HTTP_AUTHORIZATION' not in env:
return
_, authorization = env['HTTP_AUTHORIZATION'].split(' ')
tenant_user, sign = authorization.rsplit(':', 1)
tenant, user = tenant_user.rsplit(':', 1)
env['HTTP_X_TENANT_NAME'] = tenant
env['HTTP_X_USER_NAME'] = user
return fake_fake_auth_middleware
class TestS3ApiObj(S3ApiTestCase):
@ -320,15 +299,20 @@ class TestS3ApiObj(S3ApiTestCase):
@s3acl(s3acl_only=True)
def test_object_GET_with_s3acl_and_keystone(self):
# for passing keystone authentication root
fake_auth = self.swift._fake_auth_middleware
with patch.object(FakeSwift, '_fake_auth_middleware',
_wrap_fake_auth_middleware(fake_auth)):
orig_auth = self.swift._fake_auth_middleware
calls = []
def wrapped_auth(env):
calls.append((env['REQUEST_METHOD'], 's3api.auth_details' in env))
orig_auth(env)
with patch.object(self.swift, '_fake_auth_middleware', wrapped_auth):
self._test_object_GETorHEAD('GET')
_, _, headers = self.swift.calls_with_headers[-1]
self.assertNotIn('Authorization', headers)
_, _, headers = self.swift.calls_with_headers[0]
self.assertNotIn('Authorization', headers)
self.assertEqual(calls, [
('TEST', True),
('HEAD', False),
('GET', False),
])
@s3acl
def test_object_GET_Range(self):

View File

@ -267,8 +267,8 @@ class TestS3ApiMiddleware(S3ApiTestCase):
req.content_type = 'text/plain'
status, headers, body = self.call_s3api(req)
self.assertEqual(status.split()[0], '200')
for _, _, headers in self.swift.calls_with_headers:
self.assertEqual(headers['Authorization'], 'AWS test:tester:X')
for _, path, headers in self.swift.calls_with_headers:
self.assertNotIn('Authorization', headers)
def test_signed_urls_no_timestamp(self):
expire = '2147483647' # 19 Jan 2038 03:14:07
@ -281,7 +281,7 @@ class TestS3ApiMiddleware(S3ApiTestCase):
# for signed_url access and it also doesn't check timestamp
self.assertEqual(status.split()[0], '200')
for _, _, headers in self.swift.calls_with_headers:
self.assertEqual(headers['Authorization'], 'AWS test:tester:X')
self.assertNotIn('Authorization', headers)
def test_signed_urls_invalid_expire(self):
expire = 'invalid'
@ -332,8 +332,8 @@ class TestS3ApiMiddleware(S3ApiTestCase):
status, headers, body = self.call_s3api(req)
self.assertEqual(status.split()[0], '200', body)
for _, _, headers in self.swift.calls_with_headers:
self.assertEqual('AWS test:tester:X', headers['Authorization'])
self.assertIn('X-Auth-Token', headers)
self.assertNotIn('Authorization', headers)
self.assertIsNone(headers['X-Auth-Token'])
def test_signed_urls_v4_bad_credential(self):
def test(credential, message, extra=''):
@ -740,12 +740,14 @@ class TestS3ApiMiddleware(S3ApiTestCase):
def test_signature_v4(self):
environ = {
'REQUEST_METHOD': 'GET'}
authz_header = 'AWS4-HMAC-SHA256 ' + ', '.join([
'Credential=test:tester/%s/us-east-1/s3/aws4_request' %
self.get_v4_amz_date_header().split('T', 1)[0],
'SignedHeaders=host;x-amz-date',
'Signature=X',
])
headers = {
'Authorization':
'AWS4-HMAC-SHA256 '
'Credential=test:tester/%s/us-east-1/s3/aws4_request, '
'SignedHeaders=host;x-amz-date,'
'Signature=X' % self.get_v4_amz_date_header().split('T', 1)[0],
'Authorization': authz_header,
'X-Amz-Date': self.get_v4_amz_date_header(),
'X-Amz-Content-SHA256': '0123456789'}
req = Request.blank('/bucket/object', environ=environ, headers=headers)
@ -753,8 +755,8 @@ class TestS3ApiMiddleware(S3ApiTestCase):
status, headers, body = self.call_s3api(req)
self.assertEqual(status.split()[0], '200', body)
for _, _, headers in self.swift.calls_with_headers:
self.assertEqual('AWS test:tester:X', headers['Authorization'])
self.assertIn('X-Auth-Token', headers)
self.assertEqual(authz_header, headers['Authorization'])
self.assertIsNone(headers['X-Auth-Token'])
def test_signature_v4_no_date(self):
environ = {

View File

@ -246,8 +246,6 @@ class TestRequest(S3ApiTestCase):
m_swift_resp.return_value = FakeSwiftResponse()
s3_req = S3AclRequest(req.environ, MagicMock())
self.assertNotIn('s3api.auth_details', s3_req.environ)
self.assertNotIn('HTTP_AUTHORIZATION', s3_req.environ)
self.assertNotIn('Authorization', s3_req.headers)
self.assertEqual(s3_req.token, 'token')
def test_to_swift_req_Authorization_not_exist_in_swreq(self):
@ -265,8 +263,6 @@ class TestRequest(S3ApiTestCase):
s3_req = S3AclRequest(req.environ, MagicMock())
sw_req = s3_req.to_swift_req(method, container, obj)
self.assertNotIn('s3api.auth_details', sw_req.environ)
self.assertNotIn('HTTP_AUTHORIZATION', sw_req.environ)
self.assertNotIn('Authorization', sw_req.headers)
self.assertEqual(sw_req.headers['X-Auth-Token'], 'token')
def test_to_swift_req_subrequest_proxy_access_log(self):