Fix Swift3 to skip S3 authorization after initial authentication
Fix Swift3 never to send "Authorization" header again after the initial authentication at S3AclRequest with keystone authentication. This problem occurs following operations which check permission of object. - HEAD Object - GET Object - PUT Object Copy - Upload Part Copy The keystone authentication expects both a token generated by _canonical_string() and an user name written in the "Authorization" header. S3AclRequest will bypass the keystone authentication process after authenticate() method call for some reasons (e.g. performance and object acl). To bypass the authentication, Swift3 has a couple of things to do. One is to delete "Authentication" header. The other is to keep (and pass) a token retrieved from keystone server.(NOTE: the token is different from a token generated by _canonical_string()) However, current Swift3 still tries to keep the "Authorization" header in Request class and might pass it to the keystone authentication. It causes unexpected (unnecessary) authentication failure. To prevent the failure, Swift3 should delete the "Authentication" header explicitly from Request.headers. Change-Id: Id81e393d51b389610d9fa470f307f61e846a78a3
This commit is contained in:
@@ -437,10 +437,7 @@ class Request(swob.Request):
|
||||
env['REQUEST_METHOD'] = method
|
||||
|
||||
if self.keystone_token:
|
||||
# Need to skip S3 authorization since authtoken middleware
|
||||
# overwrites account in PATH_INFO
|
||||
env['HTTP_X_AUTH_TOKEN'] = self.keystone_token
|
||||
del env['HTTP_AUTHORIZATION']
|
||||
else:
|
||||
env['HTTP_X_AUTH_TOKEN'] = self.token
|
||||
|
||||
@@ -715,6 +712,9 @@ class S3AclRequest(Request):
|
||||
sw_resp.environ['HTTP_X_USER_NAME'])
|
||||
self.user_id = utf8encode(self.user_id)
|
||||
self.keystone_token = sw_req.environ['HTTP_X_AUTH_TOKEN']
|
||||
# Need to skip S3 authorization since authtoken middleware
|
||||
# overwrites account in PATH_INFO
|
||||
del self.headers['Authorization']
|
||||
else:
|
||||
# tempauth
|
||||
self.user_id = self.access_key
|
||||
|
||||
@@ -17,6 +17,7 @@ import unittest
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
from os.path import join
|
||||
from mock import patch
|
||||
|
||||
from swift.common import swob
|
||||
from swift.common.swob import Request
|
||||
@@ -25,6 +26,27 @@ from swift3.test.unit import Swift3TestCase
|
||||
from swift3.test.unit.test_s3_acl import s3acl
|
||||
from swift3.subresource import ACL, User, encode_acl, Owner, Grant
|
||||
from swift3.etree import fromstring
|
||||
from swift3.test.unit.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 TestSwift3Obj(Swift3TestCase):
|
||||
@@ -217,6 +239,19 @@ class TestSwift3Obj(Swift3TestCase):
|
||||
def test_object_GET(self):
|
||||
self._test_object_GETorHEAD('GET')
|
||||
|
||||
@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)):
|
||||
|
||||
self._test_object_GETorHEAD('GET')
|
||||
_, _, headers = self.swift.calls_with_headers[-1]
|
||||
self.assertTrue('Authorization' not in headers)
|
||||
_, _, headers = self.swift.calls_with_headers[0]
|
||||
self.assertTrue('Authorization' not in headers)
|
||||
|
||||
@s3acl
|
||||
def test_object_GET_Range(self):
|
||||
req = Request.blank('/bucket/object',
|
||||
|
||||
@@ -70,6 +70,16 @@ class FakeResponse(object):
|
||||
resource='object'))
|
||||
|
||||
|
||||
class FakeSwiftResponse(object):
|
||||
def __init__(self):
|
||||
self.environ = {
|
||||
'PATH_INFO': '/v1/AUTH_test',
|
||||
'HTTP_X_TENANT_NAME': 'test',
|
||||
'HTTP_X_USER_NAME': 'tester',
|
||||
'HTTP_X_AUTH_TOKEN': 'token',
|
||||
}
|
||||
|
||||
|
||||
class TestRequest(Swift3TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@@ -186,6 +196,36 @@ class TestRequest(Swift3TestCase):
|
||||
self.assertTrue(
|
||||
'not an integer or within integer range' in result.exception.body)
|
||||
|
||||
def test_authenticate_delete_Authorization_from_s3req_headers(self):
|
||||
req = Request.blank('/bucket/obj',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
with nested(patch.object(Request, 'get_response'),
|
||||
patch.object(Request, 'remote_user', 'authorized')) \
|
||||
as (m_swift_resp, m_remote_user):
|
||||
|
||||
m_swift_resp.return_value = FakeSwiftResponse()
|
||||
s3_req = S3AclRequest(req.environ, MagicMock())
|
||||
self.assertTrue('HTTP_AUTHORIZATION' not in s3_req.environ)
|
||||
self.assertTrue('Authorization' not in s3_req.headers)
|
||||
|
||||
def test_to_swift_req_Authorization_not_exist_in_swreq_headers(self):
|
||||
container = 'bucket'
|
||||
obj = 'obj'
|
||||
method = 'GET'
|
||||
req = Request.blank('/%s/%s' % (container, obj),
|
||||
environ={'REQUEST_METHOD': method},
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
with nested(patch.object(Request, 'get_response'),
|
||||
patch.object(Request, 'remote_user', 'authorized')) \
|
||||
as (m_swift_resp, m_remote_user):
|
||||
|
||||
m_swift_resp.return_value = FakeSwiftResponse()
|
||||
s3_req = S3AclRequest(req.environ, MagicMock())
|
||||
sw_req = s3_req.to_swift_req(method, container, obj)
|
||||
self.assertTrue('HTTP_AUTHORIZATION' not in sw_req.environ)
|
||||
self.assertTrue('Authorization' not in sw_req.headers)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user