diff --git a/swauth/middleware.py b/swauth/middleware.py index 6f5f8fe..94be7e0 100644 --- a/swauth/middleware.py +++ b/swauth/middleware.py @@ -15,6 +15,7 @@ import base64 from hashlib import sha1 +from hashlib import sha512 import hmac from httplib import HTTPConnection from httplib import HTTPSConnection @@ -50,6 +51,8 @@ from swift.common.middleware.acl import referrer_allowed from swift.common.utils import cache_from_env from swift.common.utils import get_logger from swift.common.utils import get_remote_client +from swift.common.utils import HASH_PATH_PREFIX +from swift.common.utils import HASH_PATH_SUFFIX from swift.common.utils import split_path from swift.common.utils import TRUE_VALUES from swift.common.utils import urlparse @@ -289,6 +292,15 @@ class Swauth(object): env['swift.clean_acl'] = clean_acl return self.app(env, start_response) + def _get_concealed_token(self, token): + """Returns hashed token to be used as object name in Swift. + + Tokens are stored in auth account but object names are visible in Swift + logs. Object names are hashed from token. + """ + enc_key = "%s:%s:%s" % (HASH_PATH_PREFIX, token, HASH_PATH_SUFFIX) + return sha512(enc_key).hexdigest() + def get_groups(self, env, token): """Get groups for the given token. @@ -397,8 +409,9 @@ class Swauth(object): memcache_key, (time() + expires_from_now, groups), time=expires_from_now) else: + object_name = self._get_concealed_token(token) path = quote('/v1/%s/.token_%s/%s' % - (self.auth_account, token[-1], token)) + (self.auth_account, object_name[-1], object_name)) resp = self.make_pre_authed_request( env, 'GET', path).get_response(self.app) if resp.status_int // 100 != 2: @@ -1168,8 +1181,9 @@ class Swauth(object): (path, resp.status)) candidate_token = resp.headers.get('x-object-meta-auth-token') if candidate_token: + object_name = self._get_concealed_token(candidate_token) path = quote('/v1/%s/.token_%s/%s' % - (self.auth_account, candidate_token[-1], candidate_token)) + (self.auth_account, object_name[-1], object_name)) resp = self.make_pre_authed_request( req.environ, 'DELETE', path).get_response(self.app) if resp.status_int // 100 != 2 and resp.status_int != 404: @@ -1318,8 +1332,9 @@ class Swauth(object): expires = None candidate_token = resp.headers.get('x-object-meta-auth-token') if candidate_token: + object_name = self._get_concealed_token(candidate_token) path = quote('/v1/%s/.token_%s/%s' % - (self.auth_account, candidate_token[-1], candidate_token)) + (self.auth_account, object_name[-1], object_name)) delete_token = False try: if req.headers.get('x-auth-new-token', 'false').lower() in \ @@ -1362,8 +1377,9 @@ class Swauth(object): # Generate new token token = '%stk%s' % (self.reseller_prefix, uuid4().hex) # Save token info + object_name = self._get_concealed_token(token) path = quote('/v1/%s/.token_%s/%s' % - (self.auth_account, token[-1], token)) + (self.auth_account, object_name[-1], object_name)) try: token_life = min( int(req.headers.get('x-auth-token-lifetime', @@ -1439,8 +1455,9 @@ class Swauth(object): if expires < time(): groups = None if not groups: + object_name = self._get_concealed_token(token) path = quote('/v1/%s/.token_%s/%s' % - (self.auth_account, token[-1], token)) + (self.auth_account, object_name[-1], object_name)) resp = self.make_pre_authed_request( req.environ, 'GET', path).get_response(self.app) if resp.status_int // 100 != 2: diff --git a/test/unit/test_authtypes.py b/test/unit/test_authtypes.py index 91d67b9..669af90 100644 --- a/test/unit/test_authtypes.py +++ b/test/unit/test_authtypes.py @@ -202,5 +202,6 @@ class TestSha512(unittest.TestCase): match = self.auth_encoder.match('keystring2', creds, **creds_dict) self.assertEqual(match, False) + if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_middleware.py b/test/unit/test_middleware.py index 26bd26a..b4afcb0 100644 --- a/test/unit/test_middleware.py +++ b/test/unit/test_middleware.py @@ -4125,6 +4125,42 @@ class TestAuth(unittest.TestCase): # Assert that string passed to hmac.new is only the hash self.assertEqual(mock_hmac_new.call_args[0][0], key_hash) + def test_get_concealed_token(self): + auth.HASH_PATH_PREFIX = 'start' + auth.HASH_PATH_SUFFIX = 'end' + token = 'token' + + # Check sha512 of "start:token:end" + hashed_token = self.test_auth._get_concealed_token(token) + self.assertEqual(hashed_token, + 'cb320540b0b4c69eb83de2ffb80714cb6766e2d06b5579d1a35a9c4c3fb62' + '981ec50bcc3fb94521133e69a87d1efcb83efd78f35a06b6375e410201476' + '0722f6') + + # Check sha512 of "start:token2:end" + token = 'token2' + hashed_token = self.test_auth._get_concealed_token(token) + self.assertEqual(hashed_token, + 'ca400a6f884c168357f6af0609fda66aecd5aa613147167487495dd9f39fd' + '8a77288568e65857294f01e398d7f14328e855f18517ccf94185d849e7f34' + 'f4259d') + + # Check sha512 of "start2:token2:end" + auth.HASH_PATH_PREFIX = 'start2' + hashed_token = self.test_auth._get_concealed_token(token) + self.assertEqual(hashed_token, + 'ad594a69f44dd6e0aad54e360b01f15bd4833ccb4dcd9116d7aba0c25fb95' + '670155b8cc7175def7aeeb4624a0f2bb7da5f0b204a4680ea7947d3d6a045' + '22bdde') + + # Check sha512 of "start2:token2:end2" + auth.HASH_PATH_SUFFIX = 'end2' + hashed_token = self.test_auth._get_concealed_token(token) + self.assertEqual(hashed_token, + '446af2473ad6b28319a0fe02719a9d715b9941d12e0709851aedb4f53b890' + '693e7f1328e68d870fe114f35f4ed9648b16a5013182db50d3d1f79a660f2' + '0e078e') + if __name__ == '__main__': unittest.main()