diff --git a/doc/source/deployment_guide.rst b/doc/source/deployment_guide.rst index 423dc9a59c..c72b7a165a 100644 --- a/doc/source/deployment_guide.rst +++ b/doc/source/deployment_guide.rst @@ -644,6 +644,12 @@ is:: user__ = [group] [group] [...] [storage_url] +or if you want to be able to include underscores in the ```` or +```` portions, you can base64 encode them (with *no* equal signs) in a +line like this:: + + user64__ = [group] [group] [...] [storage_url] + There are special groups of:: .reseller_admin = can do anything to any account for this auth @@ -669,6 +675,9 @@ Here are example entries, required for running the tests:: user_test2_tester2 = testing2 .admin user_test_tester3 = testing3 + # account "test_y" and user "tester_y" (note the lack of padding = chars) + user64_dGVzdF95_dGVzdGVyX3k = testing4 .admin + ------------------------ Memcached Considerations ------------------------ diff --git a/etc/proxy-server.conf-sample b/etc/proxy-server.conf-sample index 4a507b6f36..36265cc5cd 100644 --- a/etc/proxy-server.conf-sample +++ b/etc/proxy-server.conf-sample @@ -106,6 +106,9 @@ use = egg:swift#tempauth # allow_overrides = true # Lastly, you need to list all the accounts/users you want here. The format is: # user__ = [group] [group] [...] [storage_url] +# or if you want underscores in or , you can base64 encode them +# (with no equal signs) and use this format: +# user64__ = [group] [group] [...] [storage_url] # There are special groups of: # .reseller_admin = can do anything to any account for this auth # .admin = can do anything within the account diff --git a/swift/common/middleware/tempauth.py b/swift/common/middleware/tempauth.py index 2979f0cb49..9491154fe2 100644 --- a/swift/common/middleware/tempauth.py +++ b/swift/common/middleware/tempauth.py @@ -54,6 +54,11 @@ class TempAuth(object): user_test_tester = testing .admin user_test2_tester2 = testing2 .admin user_test_tester3 = testing3 + # To allow accounts/users with underscores you can base64 encode them. + # Here is the account "under_score" and username "a_b" (note the lack + # of padding equal signs): + user64_dW5kZXJfc2NvcmU_YV9i = testing4 + See the proxy-server.conf-sample for more information. @@ -86,7 +91,15 @@ class TempAuth(object): conf.get('allow_overrides', 't').lower() in TRUE_VALUES self.users = {} for conf_key in conf: - if conf_key.startswith('user_'): + if conf_key.startswith('user_') or conf_key.startswith('user64_'): + account, username = conf_key.split('_', 1)[1].split('_') + if conf_key.startswith('user64_'): + # Because trailing equal signs would screw up config file + # parsing, we auto-pad with '=' chars. + account += '=' * (len(account) % 4) + account = base64.b64decode(account) + username += '=' * (len(username) % 4) + username = base64.b64decode(username) values = conf[conf_key].split() if not values: raise ValueError('%s has no key set' % conf_key) @@ -100,8 +113,8 @@ class TempAuth(object): ip = '127.0.0.1' url += ip url += ':' + conf.get('bind_port', '8080') + '/v1/' + \ - self.reseller_prefix + conf_key.split('_')[1] - self.users[conf_key.split('_', 1)[1].replace('_', ':')] = { + self.reseller_prefix + account + self.users[account + ':' + username] = { 'key': key, 'url': url, 'groups': values} def __call__(self, env, start_response): diff --git a/test/unit/common/middleware/test_tempauth.py b/test/unit/common/middleware/test_tempauth.py index 2c836bde5b..5b047f9a29 100644 --- a/test/unit/common/middleware/test_tempauth.py +++ b/test/unit/common/middleware/test_tempauth.py @@ -20,6 +20,7 @@ except ImportError: import unittest from contextlib import contextmanager from time import time +from base64 import b64encode from webob import Request, Response @@ -578,20 +579,74 @@ class TestAuth(unittest.TestCase): class TestParseUserCreation(unittest.TestCase): def test_parse_user_creation(self): auth_filter = auth.filter_factory({ + 'reseller_prefix': 'ABC', + 'bind_ip': '1.2.3.4', 'user_test_tester3': 'testing', + 'user_has_url': 'urlly .admin http://a.b/v1/DEF_has', 'user_admin_admin': 'admin .admin .reseller_admin', })(FakeApp()) self.assertEquals(auth_filter.users, { 'admin:admin': { - 'url': 'http://127.0.0.1:8080/v1/AUTH_admin', - 'groups': ['.admin', '.reseller_admin'], + 'url': 'http://1.2.3.4:8080/v1/ABC_admin', + 'groups': ['.admin', '.reseller_admin'], 'key': 'admin' }, 'test:tester3': { - 'url': 'http://127.0.0.1:8080/v1/AUTH_test', - 'groups': [], + 'url': 'http://1.2.3.4:8080/v1/ABC_test', + 'groups': [], 'key': 'testing' + }, 'has:url': { + 'url': 'http://a.b/v1/DEF_has', + 'groups': ['.admin'], + 'key': 'urlly' }, }) + def test_base64_encoding(self): + auth_filter = auth.filter_factory({ + 'reseller_prefix': 'ABC', + 'bind_ip': '1.2.3.4', + 'user64_%s_%s' % ( + b64encode('test').rstrip('='), + b64encode('tester3').rstrip('=')): + 'testing .reseller_admin', + 'user64_%s_%s' % ( + b64encode('user_foo').rstrip('='), + b64encode('ab').rstrip('=')): + 'urlly .admin http://a.b/v1/DEF_has', + })(FakeApp()) + self.assertEquals(auth_filter.users, { + 'test:tester3': { + 'url': 'http://1.2.3.4:8080/v1/ABC_test', + 'groups': ['.reseller_admin'], + 'key': 'testing' + }, 'user_foo:ab': { + 'url': 'http://a.b/v1/DEF_has', + 'groups': ['.admin'], + 'key': 'urlly' + }, + }) + + def test_bind_ip_all_zeroes(self): + auth_filter = auth.filter_factory({ + 'reseller_prefix': 'ABC', + 'bind_ip': '0.0.0.0', + 'user_admin_admin': 'admin .admin .reseller_admin', + })(FakeApp()) + self.assertEquals(auth_filter.users, { + 'admin:admin': { + 'url': 'http://127.0.0.1:8080/v1/ABC_admin', + 'groups': ['.admin', '.reseller_admin'], + 'key': 'admin', + }, + }) + + def test_key_with_no_value(self): + self.assertRaises(ValueError, auth.filter_factory({ + 'user_test_tester3': 'testing', + 'user_bob_bobby': '', + 'user_admin_admin': 'admin .admin .reseller_admin', + }), FakeApp()) + + if __name__ == '__main__': unittest.main()