From df6b4adfc5d1180860e0d2f9dcbe780a8796714f Mon Sep 17 00:00:00 2001 From: Thiago da Silva Date: Mon, 16 Dec 2013 12:00:38 -0500 Subject: Fix bug where admin is able to delete reseller_admin Changed the code to only allow the super_admin to delete a reseller_admin. This follows the same logic of user creation, where only the super_admin can create a reseller_admin. Also, took the opportunity to refactor some code and implemented get_user_detail method to remove duplicated code Bug 1260239: https://bugs.launchpad.net/gluster-swift/+bug/1260239 Change-Id: I9e4866cd7ad08698f427846be566ab2364ad4850 Signed-off-by: Thiago da Silva Reviewed-on: http://review.gluster.org/6516 Reviewed-by: Luis Pabon Tested-by: Luis Pabon Reviewed-on: http://review.gluster.org/6690 Reviewed-by: pushpesh sharma Tested-by: pushpesh sharma --- test/functional_auth/gswauth/test_gswauth_cli.py | 4 +- .../middleware/gswauth/swauth/test_middleware.py | 160 +++++++++++++++++++-- 2 files changed, 154 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/test/functional_auth/gswauth/test_gswauth_cli.py b/test/functional_auth/gswauth/test_gswauth_cli.py index bbaab5e..e228f31 100644 --- a/test/functional_auth/gswauth/test_gswauth_cli.py +++ b/test/functional_auth/gswauth/test_gswauth_cli.py @@ -493,12 +493,12 @@ class TestUser(unittest.TestCase): self.assertEqual('403 Forbidden' in output,True, 're_admin deletion succeeded with re_admin user of other account: '+output) ''' Utils.addResellerAdminUser('test2', 're_admintobedeletedbyotheraccountusers2', 'testing') - (status,output) = Utils.deleteUser('test2', 're_admintobedeletedbyotherusers2',user='test:admin',key='testing') + (status,output) = Utils.deleteUser('test2', 're_admintobedeletedbyotheraccountusers2',user='test:admin',key='testing') self.assertNotEqual(status, 0, 're_admin deletion succeeded with admin user of other account: '+output) self.assertEqual('403 Forbidden' in output,True, 're_admin deletion succeeded with admin user of other account: '+output) Utils.addResellerAdminUser('test2', 're_admintobedeletedbyotheraccountusers3', 'testing') - (status,output) = Utils.deleteUser('test2', 're_admintobedeletedbyotherusers3',user='test:tester',key='testing') + (status,output) = Utils.deleteUser('test2', 're_admintobedeletedbyotheraccountusers3',user='test:tester',key='testing') self.assertNotEqual(status, 0, 're_admin deletion succeeded with regular user of other account: '+output) self.assertEqual('403 Forbidden' in output,True, 're_admin deletion succeeded with user of other account: '+output) diff --git a/test/unit/common/middleware/gswauth/swauth/test_middleware.py b/test/unit/common/middleware/gswauth/swauth/test_middleware.py index bce734d..e0d4ce8 100644 --- a/test/unit/common/middleware/gswauth/swauth/test_middleware.py +++ b/test/unit/common/middleware/gswauth/swauth/test_middleware.py @@ -3543,6 +3543,9 @@ class TestAuth(unittest.TestCase): def test_delete_user_bad_creds(self): self.test_auth.app = FakeApp(iter([ + ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"}, + {"name": "test"}, {"name": ".admin"}], + "auth": "plaintext:key"})), # GET of user object (account admin, but wrong # account) ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"}, @@ -3557,9 +3560,11 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'key'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 403) - self.assertEquals(self.test_auth.app.calls, 1) + self.assertEquals(self.test_auth.app.calls, 2) self.test_auth.app = FakeApp(iter([ + ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, + {"name": "test"}], "auth": "plaintext:key"})), # GET of user object (regular user) ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, {"name": "test"}], "auth": "plaintext:key"}))])) @@ -3572,8 +3577,55 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'key'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 403) + self.assertEquals(self.test_auth.app.calls, 2) + + def test_delete_reseller_admin_user_fail(self): + self.test_auth.app = FakeApp(iter([ + # is user being deleted a reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:re_adm"}, + {"name": "act2"}, {"name": ".admin"}, + {"name": ".reseller_admin"}], "auth": "plaintext:key"})), + # GET of user object + ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"}, + {"name": "act2"}, {"name": ".admin"}], + "auth": "plaintext:key"}))])) + + resp = Request.blank('/auth/v2/act2/re_adm', + environ={ + 'REQUEST_METHOD': 'DELETE'}, + headers={ + 'X-Auth-Admin-User': + 'act2:adm', + 'X-Auth-Admin-Key': 'key'} + ).get_response(self.test_auth) + self.assertEquals(resp.status_int, 403) self.assertEquals(self.test_auth.app.calls, 1) + def test_delete_reseller_admin_user_success(self): + self.test_auth.app = FakeApp(iter([ + # is user being deleted a reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:re_adm"}, + {"name": "act2"}, {"name": ".admin"}, + {"name": ".reseller_admin"}], "auth": "plaintext:key"})), + # HEAD of user object + ('200 Ok', + {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''), + # DELETE of token + ('204 No Content', {}, ''), + # DELETE of user object + ('204 No Content', {}, '')])) + + resp = Request.blank('/auth/v2/act2/re_adm', + environ={ + 'REQUEST_METHOD': 'DELETE'}, + headers={ + 'X-Auth-Admin-User': + '.super_admin', + 'X-Auth-Admin-Key': 'supertest'} + ).get_response(self.test_auth) + self.assertEquals(resp.status_int, 204) + self.assertEquals(self.test_auth.app.calls, 4) + def test_delete_user_invalid_account(self): resp = Request.blank('/auth/v2/.invalid/usr', environ={ @@ -3628,6 +3680,9 @@ class TestAuth(unittest.TestCase): def test_delete_user_fail_delete_token(self): self.test_auth.app = FakeApp(iter([ + # is user reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, + {"name": "test"}], "auth": "plaintext:key"})), # HEAD of user object ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''), @@ -3642,10 +3697,13 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'supertest'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 500) - self.assertEquals(self.test_auth.app.calls, 2) + self.assertEquals(self.test_auth.app.calls, 3) def test_delete_user_fail_delete_user(self): self.test_auth.app = FakeApp(iter([ + # is user reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, + {"name": "test"}], "auth": "plaintext:key"})), # HEAD of user object ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''), @@ -3662,10 +3720,13 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'supertest'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 500) - self.assertEquals(self.test_auth.app.calls, 3) + self.assertEquals(self.test_auth.app.calls, 4) def test_delete_user_success(self): self.test_auth.app = FakeApp(iter([ + # is user reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, + {"name": "test"}], "auth": "plaintext:key"})), # HEAD of user object ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''), @@ -3682,10 +3743,13 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'supertest'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 204) - self.assertEquals(self.test_auth.app.calls, 3) + self.assertEquals(self.test_auth.app.calls, 4) def test_delete_user_success_missing_user_at_end(self): self.test_auth.app = FakeApp(iter([ + # is user reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, + {"name": "test"}], "auth": "plaintext:key"})), # HEAD of user object ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''), @@ -3702,10 +3766,13 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'supertest'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 204) - self.assertEquals(self.test_auth.app.calls, 3) + self.assertEquals(self.test_auth.app.calls, 4) def test_delete_user_success_missing_token(self): self.test_auth.app = FakeApp(iter([ + # is user reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, + {"name": "test"}], "auth": "plaintext:key"})), # HEAD of user object ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''), @@ -3722,10 +3789,13 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'supertest'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 204) - self.assertEquals(self.test_auth.app.calls, 3) + self.assertEquals(self.test_auth.app.calls, 4) def test_delete_user_success_no_token(self): self.test_auth.app = FakeApp(iter([ + # is user reseller_admin + ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"}, + {"name": "test"}], "auth": "plaintext:key"})), # HEAD of user object ('200 Ok', {}, ''), # DELETE of user object @@ -3739,7 +3809,7 @@ class TestAuth(unittest.TestCase): 'X-Auth-Admin-Key': 'supertest'} ).get_response(self.test_auth) self.assertEquals(resp.status_int, 204) - self.assertEquals(self.test_auth.app.calls, 2) + self.assertEquals(self.test_auth.app.calls, 3) def test_validate_token_bad_prefix(self): resp = Request.blank('/auth/v2/.token/BAD_token' @@ -3934,7 +4004,7 @@ class TestAuth(unittest.TestCase): headers={'X-Auth-Admin-User': 'act:usr'})) except Exception as err: exc = err - self.assertEquals(str(exc), 'Could not get admin user object: ' + self.assertEquals(str(exc), 'Could not get user object: ' '/v1/AUTH_gsmetadata/act/usr 503 Service Unavailable') self.assertEquals(self.test_auth.app.calls, 1) @@ -3954,6 +4024,80 @@ class TestAuth(unittest.TestCase): 'groups': [{'name': 'act:usr'}, {'name': 'act'}, {'name': '.admin'}]}) + def test_get_user_detail_success(self): + self.test_auth.app = FakeApp(iter([ + ('200 Ok', {}, + json.dumps({"auth": "plaintext:key", + "groups": [{'name': "act:usr"}, {'name': "act"}, + {'name': ".admin"}]}))])) + detail = self.test_auth.get_user_detail( + Request.blank('/', + headers={'X-Auth-Admin-User': 'act:usr'}), + 'act', 'usr') + self.assertEquals(self.test_auth.app.calls, 1) + detail_json = json.loads(detail) + self.assertEquals("plaintext:key", detail_json['auth']) + + def test_get_user_detail_fail_user_doesnt_exist(self): + self.test_auth.app = FakeApp( + iter([('404 Not Found', {}, '')])) + detail = self.test_auth.get_user_detail( + Request.blank('/', + headers={'X-Auth-Admin-User': 'act:usr'}), + 'act', 'usr') + self.assertEquals(self.test_auth.app.calls, 1) + self.assertEquals(detail, None) + + def test_get_user_detail_fail_exception(self): + self.test_auth.app = FakeApp(iter([ + ('503 Service Unavailable', {}, '')])) + exc = None + try: + detail = self.test_auth.get_user_detail( + Request.blank('/', + headers={'X-Auth-Admin-User': 'act:usr'}), + 'act', 'usr') + except Exception as err: + exc = err + self.assertEquals(str(exc), 'Could not get user object: ' + '/v1/AUTH_gsmetadata/act/usr 503 Service Unavailable') + self.assertEquals(self.test_auth.app.calls, 1) + + def test_is_user_reseller_admin_success(self): + self.test_auth.app = FakeApp(iter([ + ('200 Ok', {}, + json.dumps({"auth": "plaintext:key", + "groups": [{'name': "act:usr"}, {'name': "act"}, + {'name': ".reseller_admin"}]}))])) + result = self.test_auth.is_user_reseller_admin( + Request.blank('/', + headers={'X-Auth-Admin-User': 'act:usr'}), + 'act', 'usr') + self.assertEquals(self.test_auth.app.calls, 1) + self.assertTrue(result) + + def test_is_user_reseller_admin_fail(self): + self.test_auth.app = FakeApp(iter([ + ('200 Ok', {}, + json.dumps({"auth": "plaintext:key", + "groups": [{'name': "act:usr"}, {'name': "act"}, + {'name': ".admin"}]}))])) + result = self.test_auth.is_user_reseller_admin( + Request.blank('/', + headers={'X-Auth-Admin-User': 'act:usr'}), + 'act', 'usr') + self.assertEquals(self.test_auth.app.calls, 1) + self.assertFalse(result) + + def test_is_user_reseller_admin_fail_user_doesnt_exist(self): + self.test_auth.app = FakeApp( + iter([('404 Not Found', {}, '')])) + req = Request.blank('/', headers={'X-Auth-Admin-User': 'act:usr'}) + result = self.test_auth.is_user_reseller_admin(req, 'act', 'usr') + self.assertEquals(self.test_auth.app.calls, 1) + self.assertFalse(result) + self.assertFalse(req.credentials_valid) + def test_credentials_match_success(self): self.assert_(self.test_auth.credentials_match( {'auth': 'plaintext:key'}, 'key')) -- cgit