From 7b8643889f05044743a7abec398a96c3eb1d2397 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Aug 28 2023 07:18:14 +0000 Subject: [PATCH 1/5] Inherit group permissions Related: https://pagure.io/koji/issue/3849 --- diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py index 69b262d..adb927f 100644 --- a/cli/koji_cli/commands.py +++ b/cli/koji_cli/commands.py @@ -2168,15 +2168,19 @@ def handle_list_permissions(goptions, session, args): parser.error("This command takes no arguments") activate_session(session, goptions) perms = [] + if options.mine: + options.user = session.getLoggedInUser()['id'] if options.user: user = session.getUser(options.user) if not user: error("No such user: %s" % options.user) - for p in session.getUserPerms(user['id']): - perms.append({'name': p}) - elif options.mine: - for p in session.getPerms(): - perms.append({'name': p}) + all = set(session.getUserPerms(user['id'])) + own = set(session.getUserPerms(user['id'], with_groups=False)) + for p in all: + p = {'name': p} + if p['name'] not in own: + p['description'] = '[inherited]' + perms.append(p) else: for p in session.getAllPerms(): perms.append({'name': p['name'], 'description': p['description']}) diff --git a/docs/source/permissions.rst b/docs/source/permissions.rst index 700f1be..7576f80 100644 --- a/docs/source/permissions.rst +++ b/docs/source/permissions.rst @@ -17,6 +17,8 @@ referenced in :doc:`hub policies `. Note, that you need to first understand the policy mechanism as most permissions are reflected in policy rules. +Any user can be part of user group. User group permissions are inherited by the user. + Permission management ===================== diff --git a/kojihub/auth.py b/kojihub/auth.py index dc52b81..5ea2ded 100644 --- a/kojihub/auth.py +++ b/kojihub/auth.py @@ -772,7 +772,7 @@ def get_user_groups(user_id): are the group names""" t_group = koji.USERTYPES['GROUP'] query = QueryProcessor(tables=['user_groups'], columns=['group_id', 'name'], - clauses=['active = TRUE', 'users.usertype=%(t_group)i', + clauses=['active IS TRUE', 'users.usertype=%(t_group)i', 'user_id=%(user_id)i'], joins=['users ON group_id = users.id'], values={'t_group': t_group, 'user_id': user_id}) @@ -782,13 +782,30 @@ def get_user_groups(user_id): return groups -def get_user_perms(user_id): +def get_user_perms(user_id, with_groups=True): + # individual permissions query = QueryProcessor(tables=['user_perms'], columns=['name'], - clauses=['active = TRUE', 'user_id=%(user_id)s'], + clauses=['active IS TRUE', 'user_id=%(user_id)s'], joins=['permissions ON perm_id = permissions.id'], values={'user_id': user_id}) result = query.execute() - return [r['name'] for r in result] + perms = {r['name'] for r in result} + + # inherited group permissions + if with_groups: + query = QueryProcessor(tables=['user_groups'], columns=['name'], + clauses=[ + 'user_groups.active IS TRUE', + 'user_perms.active IS TRUE', + 'user_groups.user_id=%(user_id)s'], + joins=[ + 'LEFT JOIN user_perms ON ' + 'user_perms.user_id = user_groups.group_id', + 'permissions ON perm_id = permissions.id'], + values={'user_id': user_id}) + result = query.execute() + perms |= {r['name'] for r in result} + return list(perms) def get_user_data(user_id): diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index 775cb5d..3e07748 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -13382,13 +13382,13 @@ class RootExports(object): """Get a list of the permissions granted to the currently logged-in user.""" return context.session.getPerms() - def getUserPerms(self, userID=None): + def getUserPerms(self, userID=None, with_groups=True): """Get a list of the permissions granted to the user with the given ID/name. Options: - userID: User ID or username. If no userID provided, current login user's permissions will be listed.""" user_info = get_user(userID, strict=True) - return get_user_perms(user_info['id']) + return get_user_perms(user_info['id'], with_groups=with_groups) def getAllPerms(self): """Get a list of all permissions in the system. Returns a list of maps. Each diff --git a/tests/test_cli/test_list_permissions.py b/tests/test_cli/test_list_permissions.py index 4f0afd1..fbb0224 100644 --- a/tests/test_cli/test_list_permissions.py +++ b/tests/test_cli/test_list_permissions.py @@ -85,7 +85,7 @@ class TestListPermissions(utils.CliTestCase): self.activate_session_mock.assert_called_once() self.session.getUser.assert_called_once() - self.session.getUserPerms.assert_called_once() + self.session.getUserPerms.assert_called() self.session.getPerms.assert_not_called() self.session.getAllPerms.assert_not_called() @@ -108,7 +108,7 @@ repo self.activate_session_mock.assert_called_once() self.session.getUser.assert_called_once() - self.session.getUserPerms.assert_called_once() + self.session.getUserPerms.assert_called() self.session.getPerms.assert_not_called() self.session.getAllPerms.assert_not_called() @@ -119,14 +119,15 @@ repo repo """ perms = [p['name'] for p in self.all_perms[1:3]] - self.session.getPerms.return_value = perms + self.session.getLoggedInUser.return_value = {'id': 1, 'name': 'user'} + self.session.getUserPerms.return_value = perms handle_list_permissions(self.options, self.session, ['--mine']) self.assert_console_message(stdout, expected) self.activate_session_mock.assert_called_once() - self.session.getUser.assert_not_called() - self.session.getUserPerms.assert_not_called() - self.session.getPerms.assert_called_once() + self.session.getUser.assert_called_once() + self.session.getUserPerms.assert_called() + self.session.getPerms.assert_not_called() self.session.getAllPerms.assert_not_called() @mock.patch('sys.stdout', new_callable=six.StringIO) diff --git a/tests/test_hub/test_get_user_perms.py b/tests/test_hub/test_get_user_perms.py index 948f22a..52355e3 100644 --- a/tests/test_hub/test_get_user_perms.py +++ b/tests/test_hub/test_get_user_perms.py @@ -21,4 +21,4 @@ class TestGetUserPerms(unittest.TestCase): def test_normal(self): self.get_user.return_value = {'id': 123, 'name': 'testuser'} kojihub.RootExports().getUserPerms(123) - self.get_user_perms.assert_called_once_with(123) + self.get_user_perms.assert_called_once_with(123, with_groups=True) diff --git a/tests/test_lib/test_auth.py b/tests/test_lib/test_auth.py index 6735664..6428ec4 100644 --- a/tests/test_lib/test_auth.py +++ b/tests/test_lib/test_auth.py @@ -703,19 +703,37 @@ class TestAuthSession(unittest.TestCase): query = self.queries[0] self.assertEqual(query.tables, ['user_groups']) self.assertEqual(query.joins, ['users ON group_id = users.id']) - self.assertEqual(query.clauses, ['active = TRUE', 'user_id=%(user_id)i', + self.assertEqual(query.clauses, ['active IS TRUE', 'user_id=%(user_id)i', 'users.usertype=%(t_group)i']) self.assertEqual(query.columns, ['group_id', 'name']) def test_get_user_perms(self): """auth.get_user_perms""" kojihub.auth.get_user_perms(1) - self.assertEqual(len(self.queries), 1) + self.assertEqual(len(self.queries), 2) query = self.queries[0] self.assertEqual(query.tables, ['user_perms']) self.assertEqual(query.joins, ['permissions ON perm_id = permissions.id']) - self.assertEqual(query.clauses, ['active = TRUE', 'user_id=%(user_id)s']) + self.assertEqual(query.clauses, ['active IS TRUE', 'user_id=%(user_id)s']) self.assertEqual(query.columns, ['name']) + query = self.queries[1] + self.assertEqual(query.tables, ['user_groups']) + self.assertEqual(query.joins, [ + 'LEFT JOIN user_perms ON user_perms.user_id = user_groups.group_id', + 'permissions ON perm_id = permissions.id']) + self.assertEqual(sorted(query.clauses), sorted([ + 'user_groups.active IS TRUE', + 'user_perms.active IS TRUE', + 'user_groups.user_id=%(user_id)s'])) + self.assertEqual(query.columns, ['name']) + + def test_get_user_perms_inherited(self): + self.query_execute.side_effect = [ + [{'id': 1, 'name': 'perm1'}, {'id': 2, 'name': 'perm2'}], + [{'id': 3, 'name': 'perm3'}] + ] + result = kojihub.auth.get_user_perms(1) + self.assertEqual(set(result), {'perm1', 'perm2', 'perm3'}) def test_logout_logged_not_owner(self): s, _ = self.get_session() From bf9060ab682d9dc7b09daee8eb2fe6e10eb37c03 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Aug 28 2023 07:18:14 +0000 Subject: [PATCH 2/5] fix sanity checks in revoke/grantPermission --- diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index 3e07748..93d2739 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -12668,7 +12668,7 @@ class RootExports(object): values={'perm_id': perm_id}) update.set(description=description) update.execute() - if perm['name'] in get_user_perms(user_id): + if perm['name'] in get_user_perms(user_id, with_groups=False): raise koji.GenericError('user %s already has permission: %s' % (userinfo, perm['name'])) insert = InsertProcessor('user_perms') @@ -12682,7 +12682,7 @@ class RootExports(object): user_id = get_user(userinfo, strict=True)['id'] perm = lookup_perm(permission, strict=True) perm_id = perm['id'] - if perm['name'] not in get_user_perms(user_id): + if perm['name'] not in get_user_perms(user_id, with_groups=False): raise koji.GenericError('user %s does not have permission: %s' % (userinfo, perm['name'])) update = UpdateProcessor('user_perms', values=locals(), From e74d8f91fdc4fce0108e8ae856c5dae573f8129d Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Aug 28 2023 07:18:14 +0000 Subject: [PATCH 3/5] fix query --- diff --git a/kojihub/auth.py b/kojihub/auth.py index 5ea2ded..cdd3d2b 100644 --- a/kojihub/auth.py +++ b/kojihub/auth.py @@ -799,8 +799,7 @@ def get_user_perms(user_id, with_groups=True): 'user_perms.active IS TRUE', 'user_groups.user_id=%(user_id)s'], joins=[ - 'LEFT JOIN user_perms ON ' - 'user_perms.user_id = user_groups.group_id', + 'user_perms ON user_perms.user_id = user_groups.group_id', 'permissions ON perm_id = permissions.id'], values={'user_id': user_id}) result = query.execute() From 87e33e4926ec6ace015909480fdd7a081cd7c80a Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Aug 28 2023 07:18:14 +0000 Subject: [PATCH 4/5] getUserPermsInheritance --- diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index 93d2739..594ad87 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -13390,6 +13390,34 @@ class RootExports(object): user_info = get_user(userID, strict=True) return get_user_perms(user_info['id'], with_groups=with_groups) + def getUserPermsInheritance(self, userID): + """Get a dict of the permissions granted directly to user or inherited from groups + with the sources. + + :param int userID: User id + :returns dict[str, list[str]]: list of permissions with source (None/group) + """ + user_info = get_user(userID, strict=True) + perms = {} + for perm in get_user_perms(user_info['id'], with_groups=False): + perms[perm] = [None] + + query = QueryProcessor(tables=['user_groups'], + columns=['permissions.name', 'users.name'], + aliases=['permission', 'group'], + clauses=[ + 'user_groups.active IS TRUE', + 'user_perms.active IS TRUE', + 'user_groups.user_id=%(user_id)s'], + joins=[ + 'user_perms ON user_perms.user_id = user_groups.group_id', + 'permissions ON perm_id = permissions.id', + 'users ON user_groups.group_id = users.id'], + values={'user_id': user_info['id']}) + for row in query.execute(): + perms.setdefault(row['permission'], []).append(row['group']) + return perms + def getAllPerms(self): """Get a list of all permissions in the system. Returns a list of maps. Each map contains the following keys: diff --git a/tests/test_hub/test_get_user_perms.py b/tests/test_hub/test_get_user_perms.py index 52355e3..9af6bf0 100644 --- a/tests/test_hub/test_get_user_perms.py +++ b/tests/test_hub/test_get_user_perms.py @@ -1,6 +1,7 @@ import mock import unittest import koji +from .utils import DBQueryTestCase import kojihub @@ -22,3 +23,36 @@ class TestGetUserPerms(unittest.TestCase): self.get_user.return_value = {'id': 123, 'name': 'testuser'} kojihub.RootExports().getUserPerms(123) self.get_user_perms.assert_called_once_with(123, with_groups=True) + + +class TestGetUserPermsInheritance(DBQueryTestCase): + def setUp(self): + super(TestGetUserPermsInheritance, self).setUp() + self.get_user = mock.patch('kojihub.kojihub.get_user').start() + self.get_user_perms = mock.patch('kojihub.kojihub.get_user_perms').start() + + def tearDown(self): + mock.patch.stopall() + + def test_no_user(self): + self.get_user.side_effect = koji.GenericError + with self.assertRaises(koji.GenericError): + kojihub.RootExports().getUserPermsInheritance(123) + self.get_user_perms.assert_not_called() + + def test_normal(self): + self.get_user.return_value = {'id': 123, 'name': 'testuser'} + self.get_user_perms.return_value = ['test1', 'test2'] + self.qp_execute_return_value = [ + {'permission': 'test2', 'group': 'group1'}, + {'permission': 'test3', 'group': 'group1'}, + {'permission': 'test3', 'group': 'group2'}, + ] + result = kojihub.RootExports().getUserPermsInheritance(123) + self.assertEqual(result, { + 'test1': [None], + 'test2': [None, 'group1'], + 'test3': ['group1', 'group2'], + }) + self.get_user.assert_called_once_with(123, strict=True) + self.get_user_perms.assert_called_once_with(123, with_groups=False) diff --git a/tests/test_lib/test_auth.py b/tests/test_lib/test_auth.py index 6428ec4..3ac4fef 100644 --- a/tests/test_lib/test_auth.py +++ b/tests/test_lib/test_auth.py @@ -719,7 +719,7 @@ class TestAuthSession(unittest.TestCase): query = self.queries[1] self.assertEqual(query.tables, ['user_groups']) self.assertEqual(query.joins, [ - 'LEFT JOIN user_perms ON user_perms.user_id = user_groups.group_id', + 'user_perms ON user_perms.user_id = user_groups.group_id', 'permissions ON perm_id = permissions.id']) self.assertEqual(sorted(query.clauses), sorted([ 'user_groups.active IS TRUE', From c0f25ad09892e313e926443a2703d00eb36a71a9 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Aug 28 2023 07:18:14 +0000 Subject: [PATCH 5/5] refactor get_user_perms --- diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py index adb927f..7a3c7a8 100644 --- a/cli/koji_cli/commands.py +++ b/cli/koji_cli/commands.py @@ -2174,12 +2174,10 @@ def handle_list_permissions(goptions, session, args): user = session.getUser(options.user) if not user: error("No such user: %s" % options.user) - all = set(session.getUserPerms(user['id'])) - own = set(session.getUserPerms(user['id'], with_groups=False)) - for p in all: + for p, groups in session.getUserPermsInheritance(user['id']).items(): p = {'name': p} - if p['name'] not in own: - p['description'] = '[inherited]' + if groups != [None]: + p['description'] = 'inherited from: %s' % ', '.join(groups) perms.append(p) else: for p in session.getAllPerms(): diff --git a/kojihub/auth.py b/kojihub/auth.py index cdd3d2b..cd774ce 100644 --- a/kojihub/auth.py +++ b/kojihub/auth.py @@ -782,29 +782,61 @@ def get_user_groups(user_id): return groups -def get_user_perms(user_id, with_groups=True): +def get_user_perms(user_id, with_groups=True, inheritance_data=False): + """ + :param int user_id: User ID + :param bool with_groups: Add also permissions from all groups and their inheritance chain + :param bool inheritance_data: Return extended data about permissions sources + :returns list[str]: in case of inheritance_data=False + :returns dict[str, list[str]]: in case of inheritance_data=True - keys are permissions' names, + values list of groups which are in inheritance and provides + given permission. + """ + if inheritance_data and not with_groups: + raise koji.ParameterError("inheritance option implies with_groups") + # individual permissions + perms = {} query = QueryProcessor(tables=['user_perms'], columns=['name'], clauses=['active IS TRUE', 'user_id=%(user_id)s'], joins=['permissions ON perm_id = permissions.id'], values={'user_id': user_id}) - result = query.execute() - perms = {r['name'] for r in result} + for perm in query.execute(): + perms[perm['name']] = [None] - # inherited group permissions if with_groups: - query = QueryProcessor(tables=['user_groups'], columns=['name'], + columns = ['permissions.name'] + aliases = ['name'] + joins = [ + 'user_perms ON user_perms.user_id = user_groups.group_id', + 'permissions ON perm_id = permissions.id', + ] + if inheritance_data: + # inheritance data adds one more join and as function + # can be called relatively often (e.g. in hub policy tests) + # it is a bit faster to ignore this join for "default" code path + columns.append('users.name') + aliases.append('group') + joins.append('users ON user_groups.group_id = users.id') + query = QueryProcessor(tables=['user_groups'], + columns=columns, + aliases=aliases, clauses=[ 'user_groups.active IS TRUE', 'user_perms.active IS TRUE', 'user_groups.user_id=%(user_id)s'], - joins=[ - 'user_perms ON user_perms.user_id = user_groups.group_id', - 'permissions ON perm_id = permissions.id'], + joins=joins, values={'user_id': user_id}) - result = query.execute() - perms |= {r['name'] for r in result} - return list(perms) + for row in query.execute(): + if inheritance_data: + perms.setdefault(row['name'], []).append(row['group']) + else: + # group name wouldn't be used in this case + perms.setdefault(row['name'], []) + if inheritance_data: + return perms + else: + return list(perms.keys()) def get_user_data(user_id): diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index 594ad87..d103a0d 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -13388,7 +13388,7 @@ class RootExports(object): - userID: User ID or username. If no userID provided, current login user's permissions will be listed.""" user_info = get_user(userID, strict=True) - return get_user_perms(user_info['id'], with_groups=with_groups) + return get_user_perms(user_info['id'], with_groups=with_groups, inheritance_data=False) def getUserPermsInheritance(self, userID): """Get a dict of the permissions granted directly to user or inherited from groups @@ -13398,25 +13398,7 @@ class RootExports(object): :returns dict[str, list[str]]: list of permissions with source (None/group) """ user_info = get_user(userID, strict=True) - perms = {} - for perm in get_user_perms(user_info['id'], with_groups=False): - perms[perm] = [None] - - query = QueryProcessor(tables=['user_groups'], - columns=['permissions.name', 'users.name'], - aliases=['permission', 'group'], - clauses=[ - 'user_groups.active IS TRUE', - 'user_perms.active IS TRUE', - 'user_groups.user_id=%(user_id)s'], - joins=[ - 'user_perms ON user_perms.user_id = user_groups.group_id', - 'permissions ON perm_id = permissions.id', - 'users ON user_groups.group_id = users.id'], - values={'user_id': user_info['id']}) - for row in query.execute(): - perms.setdefault(row['permission'], []).append(row['group']) - return perms + return get_user_perms(user_info['id'], inheritance_data=True) def getAllPerms(self): """Get a list of all permissions in the system. Returns a list of maps. Each diff --git a/tests/test_cli/test_list_permissions.py b/tests/test_cli/test_list_permissions.py index fbb0224..2b8a0b0 100644 --- a/tests/test_cli/test_list_permissions.py +++ b/tests/test_cli/test_list_permissions.py @@ -79,13 +79,14 @@ class TestListPermissions(utils.CliTestCase): """ self.options.quiet = False self.session.getUser.return_value = self.userinfo - self.session.getUserPerms.return_value = [] + self.session.getUserPermsInheritance.return_value = {} handle_list_permissions(self.options, self.session, ['--user', self.user]) self.assert_console_message(stdout, expected) self.activate_session_mock.assert_called_once() self.session.getUser.assert_called_once() - self.session.getUserPerms.assert_called() + self.session.getUserPerms.assert_not_called() + self.session.getUserPermsInheritance.assert_called_once() self.session.getPerms.assert_not_called() self.session.getAllPerms.assert_not_called() @@ -100,15 +101,16 @@ livecd long-permission-appliance repo """ - perms = [p['name'] for p in self.all_perms[::1]] - self.session.getUserPerms.return_value = perms + perms = {p['name']: [None] for p in self.all_perms[::1]} + self.session.getUserPermsInheritance.return_value = perms self.session.getUser.return_value = self.userinfo handle_list_permissions(self.options, self.session, ['--user', self.user]) self.assert_console_message(stdout, expected) self.activate_session_mock.assert_called_once() self.session.getUser.assert_called_once() - self.session.getUserPerms.assert_called() + self.session.getUserPerms.assert_not_called() + self.session.getUserPermsInheritance.assert_called_once_with(self.userinfo['id']) self.session.getPerms.assert_not_called() self.session.getAllPerms.assert_not_called() @@ -118,15 +120,16 @@ repo expected = """build repo """ - perms = [p['name'] for p in self.all_perms[1:3]] + perms = {p['name']: [None] for p in self.all_perms[1:3]} self.session.getLoggedInUser.return_value = {'id': 1, 'name': 'user'} - self.session.getUserPerms.return_value = perms + self.session.getUserPermsInheritance.return_value = perms handle_list_permissions(self.options, self.session, ['--mine']) self.assert_console_message(stdout, expected) self.activate_session_mock.assert_called_once() self.session.getUser.assert_called_once() - self.session.getUserPerms.assert_called() + self.session.getUserPerms.assert_not_called() + self.session.getUserPermsInheritance.assert_called_once() self.session.getPerms.assert_not_called() self.session.getAllPerms.assert_not_called() diff --git a/tests/test_hub/test_get_user_perms.py b/tests/test_hub/test_get_user_perms.py index 9af6bf0..35aba52 100644 --- a/tests/test_hub/test_get_user_perms.py +++ b/tests/test_hub/test_get_user_perms.py @@ -3,6 +3,7 @@ import unittest import koji from .utils import DBQueryTestCase import kojihub +from kojihub.auth import get_user_perms class TestGetUserPerms(unittest.TestCase): @@ -22,7 +23,7 @@ class TestGetUserPerms(unittest.TestCase): def test_normal(self): self.get_user.return_value = {'id': 123, 'name': 'testuser'} kojihub.RootExports().getUserPerms(123) - self.get_user_perms.assert_called_once_with(123, with_groups=True) + self.get_user_perms.assert_called_once_with(123, with_groups=True, inheritance_data=False) class TestGetUserPermsInheritance(DBQueryTestCase): @@ -41,18 +42,14 @@ class TestGetUserPermsInheritance(DBQueryTestCase): self.get_user_perms.assert_not_called() def test_normal(self): - self.get_user.return_value = {'id': 123, 'name': 'testuser'} - self.get_user_perms.return_value = ['test1', 'test2'] - self.qp_execute_return_value = [ - {'permission': 'test2', 'group': 'group1'}, - {'permission': 'test3', 'group': 'group1'}, - {'permission': 'test3', 'group': 'group2'}, - ] - result = kojihub.RootExports().getUserPermsInheritance(123) - self.assertEqual(result, { + data = { 'test1': [None], 'test2': [None, 'group1'], 'test3': ['group1', 'group2'], - }) + } + self.get_user.return_value = {'id': 123, 'name': 'testuser'} + self.get_user_perms.return_value = data + result = kojihub.RootExports().getUserPermsInheritance(123) + self.assertEqual(result, data) self.get_user.assert_called_once_with(123, strict=True) - self.get_user_perms.assert_called_once_with(123, with_groups=False) + self.get_user_perms.assert_called_once_with(123, inheritance_data=True) diff --git a/tests/test_lib/test_auth.py b/tests/test_lib/test_auth.py index 3ac4fef..a8672df 100644 --- a/tests/test_lib/test_auth.py +++ b/tests/test_lib/test_auth.py @@ -725,16 +725,31 @@ class TestAuthSession(unittest.TestCase): 'user_groups.active IS TRUE', 'user_perms.active IS TRUE', 'user_groups.user_id=%(user_id)s'])) - self.assertEqual(query.columns, ['name']) + self.assertEqual(query.columns, ['permissions.name']) def test_get_user_perms_inherited(self): self.query_execute.side_effect = [ [{'id': 1, 'name': 'perm1'}, {'id': 2, 'name': 'perm2'}], - [{'id': 3, 'name': 'perm3'}] + [{'name': 'perm3'}] ] result = kojihub.auth.get_user_perms(1) self.assertEqual(set(result), {'perm1', 'perm2', 'perm3'}) + def test_get_user_perms_inherited_data(self): + self.query_execute.side_effect = [ + [{'id': 1, 'name': 'perm1'}, {'id': 2, 'name': 'perm2'}], + [{'name': 'perm3', 'group': 'group_a'}, + {'name': 'perm4', 'group': 'group_b'}, + {'name': 'perm4', 'group': 'group_c'}] + ] + result = kojihub.auth.get_user_perms(1, inheritance_data=True) + self.assertEqual(result, { + 'perm1': [None], + 'perm2': [None], + 'perm3': ['group_a'], + 'perm4': ['group_b', 'group_c'], + }) + def test_logout_logged_not_owner(self): s, _ = self.get_session()