s3api: fix AWSAccessKeyId
We use cfaccount as AWSAccessKeyId (something like AUTH_89308df71f274e33af17779606f08fa0). However, users with the same account use the same cfaccount. In such case, we can't know which password should be used as a secret key to calculate the HMAC. This changes AWSAccessKeyId to the combination of account and user: Authorization: AWS test:tester:xQE0diMbLRepdf3YB+FIEXAMPLE= The auth validates the HMAC and sends a cfaccount back to the proxy. The proxy rewrites the path with the cfaccount.
This commit is contained in:
commit
0996cd9b3a
@ -243,18 +243,17 @@ YOU HAVE A FEW OPTIONS:
|
||||
raise err
|
||||
|
||||
def validate_s3_sign(self, request, token):
|
||||
cfaccount, sign = request.headers['Authorization'].split(' ')[-1].split(':')
|
||||
account, user, sign = request.headers['Authorization'].split(' ')[-1].split(':')
|
||||
msg = base64.urlsafe_b64decode(unquote(token))
|
||||
rv = False
|
||||
with self.get_conn() as conn:
|
||||
row = conn.execute('''
|
||||
SELECT account, user, password FROM account
|
||||
WHERE cfaccount = ?''',
|
||||
(cfaccount,)).fetchone()
|
||||
rv = (84000, row[0], row[1], cfaccount)
|
||||
|
||||
SELECT password, cfaccount FROM account
|
||||
WHERE account = ? AND user = ?''',
|
||||
(account, user)).fetchone()
|
||||
rv = (84000, account, user, row[1])
|
||||
if rv:
|
||||
s = base64.encodestring(hmac.new(row[2], msg, sha1).digest()).strip()
|
||||
s = base64.encodestring(hmac.new(row[0], msg, sha1).digest()).strip()
|
||||
self.logger.info("orig %s, calc %s" % (sign, s))
|
||||
if sign != s:
|
||||
rv = False
|
||||
@ -440,8 +439,10 @@ YOU HAVE A FEW OPTIONS:
|
||||
except ValueError:
|
||||
return HTTPBadRequest()
|
||||
# Retrieves (TTL, account, user, cfaccount) if valid, False otherwise
|
||||
headers = {}
|
||||
if 'Authorization' in request.headers:
|
||||
validation = self.validate_s3_sign(request, token)
|
||||
headers['X-Auth-Account-Suffix'] = validation[3]
|
||||
else:
|
||||
validation = self.validate_token(token)
|
||||
if not validation:
|
||||
@ -451,8 +452,9 @@ YOU HAVE A FEW OPTIONS:
|
||||
# admin access to a cfaccount or ".reseller_admin" to access to all
|
||||
# accounts, including creating new ones.
|
||||
groups.append(validation[3])
|
||||
return HTTPNoContent(headers={'X-Auth-TTL': validation[0],
|
||||
'X-Auth-Groups': ','.join(groups)})
|
||||
headers['X-Auth-TTL'] = validation[0]
|
||||
headers['X-Auth-Groups'] = ','.join(groups)
|
||||
return HTTPNoContent(headers=headers)
|
||||
|
||||
def handle_add_user(self, request):
|
||||
"""
|
||||
|
@ -134,8 +134,7 @@ class DevAuth(object):
|
||||
headers = {}
|
||||
if env.get('HTTP_AUTHORIZATION'):
|
||||
groups = None
|
||||
if env.get('HTTP_AUTHORIZATION'):
|
||||
headers["Authorization"] = env.get('HTTP_AUTHORIZATION')
|
||||
headers["Authorization"] = env.get('HTTP_AUTHORIZATION')
|
||||
|
||||
if not groups:
|
||||
with Timeout(self.timeout):
|
||||
@ -153,6 +152,13 @@ class DevAuth(object):
|
||||
if memcache_client:
|
||||
memcache_client.set(key, (time(), expiration, groups),
|
||||
timeout=expiration)
|
||||
|
||||
if env.get('HTTP_AUTHORIZATION'):
|
||||
account, user, sign = env['HTTP_AUTHORIZATION'].split(' ')[-1].split(':')
|
||||
cfaccount = resp.getheader('x-auth-account-suffix')
|
||||
path = env['PATH_INFO']
|
||||
env['PATH_INFO'] = path.replace("%s:%s" % (account, user), cfaccount, 1)
|
||||
|
||||
return groups
|
||||
|
||||
def authorize(self, req):
|
||||
|
@ -400,11 +400,11 @@ class Swift3Middleware(object):
|
||||
h += header.lower() + ":" + str(req.headers[header]) + "\n"
|
||||
h += req.path
|
||||
try:
|
||||
account, _ = req.headers['Authorization'].split(' ')[-1].split(':')
|
||||
account, user, _ = req.headers['Authorization'].split(' ')[-1].split(':')
|
||||
except:
|
||||
return None, None
|
||||
token = base64.urlsafe_b64encode(h)
|
||||
return account, token
|
||||
return '%s:%s' % (account, user), token
|
||||
|
||||
def __call__(self, env, start_response):
|
||||
req = Request(env)
|
||||
|
@ -209,7 +209,7 @@ class TestSwift3(unittest.TestCase):
|
||||
def test_bad_path(self):
|
||||
req = Request.blank('/bucket/object/bad',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'Authorization': 'AUTH_something:hoge'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = self.app(req.environ, start_response)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.firstChild.nodeName, 'Error')
|
||||
@ -219,7 +219,7 @@ class TestSwift3(unittest.TestCase):
|
||||
def test_bad_method(self):
|
||||
req = Request.blank('/',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Authorization': 'AUTH_something:hoge'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = self.app(req.environ, start_response)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.firstChild.nodeName, 'Error')
|
||||
@ -230,7 +230,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(cl(status))
|
||||
req = Request.blank(path,
|
||||
environ={'REQUEST_METHOD': method},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, start_response)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.firstChild.nodeName, 'Error')
|
||||
@ -246,7 +246,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(FakeAppService())
|
||||
req = Request.blank('/',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
self.assertEquals(local_app.app.response_args[0].split()[0], '200')
|
||||
|
||||
@ -279,7 +279,7 @@ class TestSwift3(unittest.TestCase):
|
||||
bucket_name = 'junk'
|
||||
req = Request.blank('/%s' % bucket_name,
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
self.assertEquals(local_app.app.response_args[0].split()[0], '200')
|
||||
|
||||
@ -307,7 +307,7 @@ class TestSwift3(unittest.TestCase):
|
||||
req = Request.blank('/%s' % bucket_name,
|
||||
environ={'REQUEST_METHOD': 'GET',
|
||||
'QUERY_STRING': 'max-keys=3'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.getElementsByTagName('IsTruncated')[0].
|
||||
@ -316,7 +316,7 @@ class TestSwift3(unittest.TestCase):
|
||||
req = Request.blank('/%s' % bucket_name,
|
||||
environ={'REQUEST_METHOD': 'GET',
|
||||
'QUERY_STRING': 'max-keys=2'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.getElementsByTagName('IsTruncated')[0].
|
||||
@ -335,7 +335,7 @@ class TestSwift3(unittest.TestCase):
|
||||
req = Request.blank('/%s' % bucket_name,
|
||||
environ={'REQUEST_METHOD': 'GET',
|
||||
'QUERY_STRING': 'max-keys=5'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, lambda *args: None)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.getElementsByTagName('MaxKeys')[0].
|
||||
@ -346,7 +346,7 @@ class TestSwift3(unittest.TestCase):
|
||||
req = Request.blank('/%s' % bucket_name,
|
||||
environ={'REQUEST_METHOD': 'GET',
|
||||
'QUERY_STRING': 'max-keys=5000'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, lambda *args: None)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.getElementsByTagName('MaxKeys')[0].
|
||||
@ -366,7 +366,7 @@ class TestSwift3(unittest.TestCase):
|
||||
req = Request.blank('/%s' % bucket_name,
|
||||
environ={'REQUEST_METHOD': 'GET', 'QUERY_STRING':
|
||||
'delimiter=a&marker=b&prefix=c'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, lambda *args: None)
|
||||
dom = xml.dom.minidom.parseString("".join(resp))
|
||||
self.assertEquals(dom.getElementsByTagName('Prefix')[0].
|
||||
@ -392,7 +392,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(FakeAppBucket(201))
|
||||
req = Request.blank('/bucket',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
self.assertEquals(local_app.app.response_args[0].split()[0], '200')
|
||||
|
||||
@ -410,7 +410,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(FakeAppBucket(204))
|
||||
req = Request.blank('/bucket',
|
||||
environ={'REQUEST_METHOD': 'DELETE'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
self.assertEquals(local_app.app.response_args[0].split()[0], '204')
|
||||
|
||||
@ -418,7 +418,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(FakeAppObject())
|
||||
req = Request.blank('/bucket/object',
|
||||
environ={'REQUEST_METHOD': method},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
self.assertEquals(local_app.app.response_args[0].split()[0], '200')
|
||||
|
||||
@ -468,7 +468,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(FakeAppObject(201))
|
||||
req = Request.blank('/bucket/object',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Authorization': 'AUTH_who:password',
|
||||
headers={'Authorization': 'AWS test:tester:hmac',
|
||||
'x-amz-storage-class': 'REDUCED_REDUNDANCY',
|
||||
'Content-MD5': 'Gyz1NfJ3Mcl0NDZFo5hTKA=='})
|
||||
req.date = datetime.now()
|
||||
@ -490,7 +490,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(app)
|
||||
req = Request.blank('/bucket/object',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Authorization': 'AUTH_who:password',
|
||||
headers={'Authorization': 'AWS test:tester:hmac',
|
||||
'X-Amz-Storage-Class': 'REDUCED_REDUNDANCY',
|
||||
'X-Amz-Meta-Something': 'oh hai',
|
||||
'X-Amz-Copy-Source': '/some/source',
|
||||
@ -518,7 +518,7 @@ class TestSwift3(unittest.TestCase):
|
||||
local_app = swift3.filter_factory({})(FakeAppObject(204))
|
||||
req = Request.blank('/bucket/object',
|
||||
environ={'REQUEST_METHOD': 'DELETE'},
|
||||
headers={'Authorization': 'AUTH_who:password'})
|
||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||
resp = local_app(req.environ, local_app.app.do_start_response)
|
||||
self.assertEquals(local_app.app.response_args[0].split()[0], '204')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user