s3 compat additions for swauth

This commit is contained in:
gholt
2011-01-25 00:25:51 +00:00
committed by Tarmac
2 changed files with 65 additions and 9 deletions

View File

@@ -23,6 +23,9 @@ from traceback import format_exc
from urllib import quote, unquote from urllib import quote, unquote
from urlparse import urlparse from urlparse import urlparse
from uuid import uuid4 from uuid import uuid4
from hashlib import md5, sha1
import hmac
import base64
from eventlet.timeout import Timeout from eventlet.timeout import Timeout
from webob import Response, Request from webob import Response, Request
@@ -123,8 +126,9 @@ class Swauth(object):
env['HTTP_X_CF_TRANS_ID'] = 'tx' + str(uuid4()) env['HTTP_X_CF_TRANS_ID'] = 'tx' + str(uuid4())
if env.get('PATH_INFO', '').startswith(self.auth_prefix): if env.get('PATH_INFO', '').startswith(self.auth_prefix):
return self.handle(env, start_response) return self.handle(env, start_response)
s3 = env.get('HTTP_AUTHORIZATION')
token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN')) token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
if token and token.startswith(self.reseller_prefix): if s3 or (token and token.startswith(self.reseller_prefix)):
# Note: Empty reseller_prefix will match all tokens. # Note: Empty reseller_prefix will match all tokens.
groups = self.get_groups(env, token) groups = self.get_groups(env, token)
if groups: if groups:
@@ -132,7 +136,8 @@ class Swauth(object):
user = groups and groups.split(',', 1)[0] or '' user = groups and groups.split(',', 1)[0] or ''
# We know the proxy logs the token, so we augment it just a bit # We know the proxy logs the token, so we augment it just a bit
# to also log the authenticated user. # to also log the authenticated user.
env['HTTP_X_AUTH_TOKEN'] = '%s,%s' % (user, token) env['HTTP_X_AUTH_TOKEN'] = \
'%s,%s' % (user, 's3' if s3 else token)
env['swift.authorize'] = self.authorize env['swift.authorize'] = self.authorize
env['swift.clean_acl'] = clean_acl env['swift.clean_acl'] = clean_acl
else: else:
@@ -192,6 +197,43 @@ class Swauth(object):
expires, groups = cached_auth_data expires, groups = cached_auth_data
if expires < time(): if expires < time():
groups = None groups = None
if env.get('HTTP_AUTHORIZATION'):
account = env['HTTP_AUTHORIZATION'].split(' ')[1]
account, user, sign = account.split(':')
path = quote('/v1/%s/%s/%s' % (self.auth_account, account, user))
resp = self.make_request(env, 'GET', path).get_response(self.app)
if resp.status_int // 100 != 2:
return None
if 'x-object-meta-account-id' in resp.headers:
account_id = resp.headers['x-object-meta-account-id']
else:
path = quote('/v1/%s/%s' % (self.auth_account, account))
resp2 = self.make_request(env, 'HEAD',
path).get_response(self.app)
if resp2.status_int // 100 != 2:
return None
account_id = resp2.headers['x-container-meta-account-id']
path = env['PATH_INFO']
env['PATH_INFO'] = path.replace("%s:%s" % (account, user),
account_id, 1)
detail = json.loads(resp.body)
password = detail['auth'].split(':')[-1]
msg = base64.urlsafe_b64decode(unquote(token))
s = base64.encodestring(hmac.new(detail['auth'].split(':')[-1],
msg, sha1).digest()).strip()
if s != sign:
return None
groups = [g['name'] for g in detail['groups']]
if '.admin' in groups:
groups.remove('.admin')
groups.append(account_id)
groups = ','.join(groups)
return groups
if not groups: if not groups:
path = quote('/v1/%s/.token_%s/%s' % path = quote('/v1/%s/.token_%s/%s' %
(self.auth_account, token[-1], token)) (self.auth_account, token[-1], token))
@@ -839,6 +881,15 @@ class Swauth(object):
return HTTPForbidden(request=req) return HTTPForbidden(request=req)
elif not self.is_account_admin(req, account): elif not self.is_account_admin(req, account):
return HTTPForbidden(request=req) return HTTPForbidden(request=req)
path = quote('/v1/%s/%s' % (self.auth_account, account))
resp = self.make_request(req.environ, 'HEAD',
path).get_response(self.app)
if resp.status_int // 100 != 2:
raise Exception('Could not retrieve account id value: %s %s' %
(path, resp.status))
headers = {'X-Object-Meta-Account-Id':
resp.headers['x-container-meta-account-id']}
# Create the object in the main auth account (this object represents # Create the object in the main auth account (this object represents
# the user) # the user)
path = quote('/v1/%s/%s/%s' % (self.auth_account, account, user)) path = quote('/v1/%s/%s/%s' % (self.auth_account, account, user))
@@ -847,9 +898,10 @@ class Swauth(object):
groups.append('.admin') groups.append('.admin')
if reseller_admin: if reseller_admin:
groups.append('.reseller_admin') groups.append('.reseller_admin')
resp = self.make_request(req.environ, 'PUT', path, json.dumps({'auth': resp = self.make_request(req.environ, 'PUT', path,
'plaintext:%s' % key, json.dumps({'auth': 'plaintext:%s' % key,
'groups': [{'name': g} for g in groups]})).get_response(self.app) 'groups': [{'name': g} for g in groups]}),
headers=headers).get_response(self.app)
if resp.status_int == 404: if resp.status_int == 404:
return HTTPNotFound(request=req) return HTTPNotFound(request=req)
if resp.status_int // 100 != 2: if resp.status_int // 100 != 2:

View File

@@ -2561,6 +2561,7 @@ class TestAuth(unittest.TestCase):
def test_put_user_regular_success(self): def test_put_user_regular_success(self):
self.test_auth.app = FakeApp(iter([ self.test_auth.app = FakeApp(iter([
('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
# PUT of user object # PUT of user object
('201 Created', {}, '')])) ('201 Created', {}, '')]))
resp = Request.blank('/auth/v2/act/usr', resp = Request.blank('/auth/v2/act/usr',
@@ -2570,13 +2571,14 @@ class TestAuth(unittest.TestCase):
'X-Auth-User-Key': 'key'} 'X-Auth-User-Key': 'key'}
).get_response(self.test_auth) ).get_response(self.test_auth)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
self.assertEquals(self.test_auth.app.calls, 1) self.assertEquals(self.test_auth.app.calls, 2)
self.assertEquals(json.loads(self.test_auth.app.request.body), self.assertEquals(json.loads(self.test_auth.app.request.body),
{"groups": [{"name": "act:usr"}, {"name": "act"}], {"groups": [{"name": "act:usr"}, {"name": "act"}],
"auth": "plaintext:key"}) "auth": "plaintext:key"})
def test_put_user_account_admin_success(self): def test_put_user_account_admin_success(self):
self.test_auth.app = FakeApp(iter([ self.test_auth.app = FakeApp(iter([
('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
# PUT of user object # PUT of user object
('201 Created', {}, '')])) ('201 Created', {}, '')]))
resp = Request.blank('/auth/v2/act/usr', resp = Request.blank('/auth/v2/act/usr',
@@ -2587,7 +2589,7 @@ class TestAuth(unittest.TestCase):
'X-Auth-User-Admin': 'true'} 'X-Auth-User-Admin': 'true'}
).get_response(self.test_auth) ).get_response(self.test_auth)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
self.assertEquals(self.test_auth.app.calls, 1) self.assertEquals(self.test_auth.app.calls, 2)
self.assertEquals(json.loads(self.test_auth.app.request.body), self.assertEquals(json.loads(self.test_auth.app.request.body),
{"groups": [{"name": "act:usr"}, {"name": "act"}, {"groups": [{"name": "act:usr"}, {"name": "act"},
{"name": ".admin"}], {"name": ".admin"}],
@@ -2595,6 +2597,7 @@ class TestAuth(unittest.TestCase):
def test_put_user_reseller_admin_success(self): def test_put_user_reseller_admin_success(self):
self.test_auth.app = FakeApp(iter([ self.test_auth.app = FakeApp(iter([
('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
# PUT of user object # PUT of user object
('201 Created', {}, '')])) ('201 Created', {}, '')]))
resp = Request.blank('/auth/v2/act/usr', resp = Request.blank('/auth/v2/act/usr',
@@ -2605,7 +2608,7 @@ class TestAuth(unittest.TestCase):
'X-Auth-User-Reseller-Admin': 'true'} 'X-Auth-User-Reseller-Admin': 'true'}
).get_response(self.test_auth) ).get_response(self.test_auth)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
self.assertEquals(self.test_auth.app.calls, 1) self.assertEquals(self.test_auth.app.calls, 2)
self.assertEquals(json.loads(self.test_auth.app.request.body), self.assertEquals(json.loads(self.test_auth.app.request.body),
{"groups": [{"name": "act:usr"}, {"name": "act"}, {"groups": [{"name": "act:usr"}, {"name": "act"},
{"name": ".admin"}, {"name": ".reseller_admin"}], {"name": ".admin"}, {"name": ".reseller_admin"}],
@@ -2613,6 +2616,7 @@ class TestAuth(unittest.TestCase):
def test_put_user_fail_not_found(self): def test_put_user_fail_not_found(self):
self.test_auth.app = FakeApp(iter([ self.test_auth.app = FakeApp(iter([
('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
# PUT of user object # PUT of user object
('404 Not Found', {}, '')])) ('404 Not Found', {}, '')]))
resp = Request.blank('/auth/v2/act/usr', resp = Request.blank('/auth/v2/act/usr',
@@ -2622,7 +2626,7 @@ class TestAuth(unittest.TestCase):
'X-Auth-User-Key': 'key'} 'X-Auth-User-Key': 'key'}
).get_response(self.test_auth) ).get_response(self.test_auth)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
self.assertEquals(self.test_auth.app.calls, 1) self.assertEquals(self.test_auth.app.calls, 2)
def test_put_user_fail(self): def test_put_user_fail(self):
self.test_auth.app = FakeApp(iter([ self.test_auth.app = FakeApp(iter([