From 5582f166c25f2bc7562c38e13b8e72f7b017c79d Mon Sep 17 00:00:00 2001 From: Darrell Bishop Date: Mon, 1 Oct 2012 21:43:34 -0700 Subject: [PATCH] Allow underscores in account/user in tempauth via encoding. This patch introduces a new user format to tempauth which starts with "user64_" and in which the account and user are base64 encoded (sans padding equal signs): user64__ = [group] [group] [...] [storage_url] This allows unambiguous parsing and adds the ability to have a user or account name containing underscores. The handling of tempauth configuration is fully backward compatible and this only adds new, optional functionality. Also beefed up unit tests to get full coverage of the user parsing code in tempauth's __init__(). Change-Id: Id06304934ab8055a28921f2e1aa3c58a2036d8f8 --- doc/source/deployment_guide.rst | 9 +++ etc/proxy-server.conf-sample | 3 + swift/common/middleware/tempauth.py | 19 +++++- test/unit/common/middleware/test_tempauth.py | 63 ++++++++++++++++++-- 4 files changed, 87 insertions(+), 7 deletions(-) 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()