From fd10eaaa8594feb2aa985c9bdeac79f683584145 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Nov 11 2019 12:31:21 +0000 Subject: Add tests for member management Signed-off-by: Christian Heimes Reviewed-By: Alexander Bokovoy Reviewed-By: Simo Sorce Reviewed-By: Alexander Bokovoy --- diff --git a/ipatests/prci_definitions/gating.yaml b/ipatests/prci_definitions/gating.yaml index e40d4d1..297fad0 100644 --- a/ipatests/prci_definitions/gating.yaml +++ b/ipatests/prci_definitions/gating.yaml @@ -15,6 +15,10 @@ topologies: name: ad_master_2client cpu: 4 memory: 12000 + ipaserver: &ipaserver + name: ipaserver + cpu: 2 + memory: 2400 jobs: fedora-30/build: @@ -247,3 +251,14 @@ jobs: timeout: 3600 topology: *master_1repl + fedora-30/membermanager: + requires: [fedora-30/build] + priority: 100 + job: + class: RunPytest + args: + build_url: '{fedora-30/build_url}' + test_suite: test_integration/test_membermanager.py + template: *ci-master-f30 + timeout: 1800 + topology: *ipaserver diff --git a/ipatests/prci_definitions/nightly_ipa-4-8.yaml b/ipatests/prci_definitions/nightly_ipa-4-8.yaml index 824e82c..4fa6b20 100644 --- a/ipatests/prci_definitions/nightly_ipa-4-8.yaml +++ b/ipatests/prci_definitions/nightly_ipa-4-8.yaml @@ -1360,3 +1360,15 @@ jobs: template: *ci-master-f30 timeout: 7200 topology: *master_1repl + + fedora-30/membermanager: + requires: [fedora-30/build] + priority: 50 + job: + class: RunPytest + args: + build_url: '{fedora-30/build_url}' + test_suite: test_integration/test_membermanager.py + template: *ci-master-f30 + timeout: 1800 + topology: *ipaserver diff --git a/ipatests/test_integration/test_membermanager.py b/ipatests/test_integration/test_membermanager.py new file mode 100644 index 0000000..20bf53f --- /dev/null +++ b/ipatests/test_integration/test_membermanager.py @@ -0,0 +1,179 @@ +# +# Copyright (C) 2019 FreeIPA Contributors see COPYING for license +# +"""Tests for member manager feature +""" +from ipatests.test_integration.base import IntegrationTest +from ipatests.pytest_ipa.integration import tasks + + +PASSWORD = "DummyPassword123" +# direct member manager +USER_MM = "mmuser" +# indirect member manager through group membership +USER_INDIRECT = "indirect_mmuser" +GROUP_INDIRECT = "group_indirect" + +USER1 = "testuser1" +USER2 = "testuser2" +GROUP1 = "testgroup1" +GROUP2 = "testgroup2" +HOSTGROUP1 = "testhostgroup1" + + +class TestMemberManager(IntegrationTest): + """Tests for member manager feature for groups and hostgroups + """ + @classmethod + def install(cls, mh): + super(TestMemberManager, cls).install(mh) + master = cls.master + + tasks.create_active_user(master, USER_MM, PASSWORD) + tasks.create_active_user(master, USER_INDIRECT, PASSWORD) + + tasks.kinit_admin(master) + tasks.group_add(master, GROUP_INDIRECT) + master.run_command([ + 'ipa', 'group-add-member', GROUP_INDIRECT, '--users', USER_INDIRECT + ]) + + tasks.user_add(master, USER1) + tasks.user_add(master, USER2) + tasks.group_add(master, GROUP1) + tasks.group_add(master, GROUP2) + master.run_command(['ipa', 'hostgroup-add', HOSTGROUP1]) + + # make mmuser a member manager for group and hostgroup + master.run_command([ + 'ipa', 'group-add-member-manager', GROUP1, + '--users', USER_MM + ]) + master.run_command([ + 'ipa', 'hostgroup-add-member-manager', HOSTGROUP1, + '--users', USER_MM + ]) + # make indirect group member manager for group and hostgroup + master.run_command([ + 'ipa', 'group-add-member-manager', GROUP1, + '--groups', GROUP_INDIRECT + ]) + master.run_command([ + 'ipa', 'hostgroup-add-member-manager', HOSTGROUP1, + '--groups', GROUP_INDIRECT + ]) + tasks.kdestroy_all(master) + + def test_show_member_manager(self): + master = self.master + tasks.kinit_admin(master) + + result = master.run_command(['ipa', 'group-show', GROUP1]) + out = result.stdout_text + assert f"Membership managed by groups: {GROUP_INDIRECT}" in out + assert f"Membership managed by users: {USER_MM}" in out + + result = master.run_command(['ipa', 'hostgroup-show', HOSTGROUP1]) + out = result.stdout_text + assert f"Membership managed by groups: {GROUP_INDIRECT}" in out + assert f"Membership managed by users: {USER_MM}" in out + + tasks.kdestroy_all(master) + + def test_find_by_member_manager(self): + master = self.master + tasks.kinit_admin(master) + + result = master.run_command([ + 'ipa', 'group-find', '--membermanager-users', USER_MM + ]) + assert GROUP1 in result.stdout_text + + result = master.run_command([ + 'ipa', 'group-find', '--membermanager-groups', GROUP_INDIRECT + ]) + assert GROUP1 in result.stdout_text + + result = master.run_command( + [ + 'ipa', 'group-find', '--membermanager-users', USER1 + ], + raiseonerr=False + ) + assert result.returncode == 1 + assert "0 groups matched" in result.stdout_text + + result = master.run_command([ + 'ipa', 'hostgroup-find', '--membermanager-users', USER_MM + ]) + assert HOSTGROUP1 in result.stdout_text + + result = master.run_command([ + 'ipa', 'hostgroup-find', '--membermanager-groups', GROUP_INDIRECT + ]) + assert HOSTGROUP1 in result.stdout_text + + result = master.run_command( + [ + 'ipa', 'hostgroup-find', '--membermanager-users', USER1 + ], + raiseonerr=False + ) + assert result.returncode == 1 + assert "0 hostgroups matched" in result.stdout_text + + def test_group_member_manager_user(self): + master = self.master + # mmuser: add user1 to group + tasks.kinit_as_user(master, USER_MM, PASSWORD) + master.run_command([ + 'ipa', 'group-add-member', GROUP1, '--users', USER1 + ]) + result = master.run_command(['ipa', 'group-show', GROUP1]) + assert USER1 in result.stdout_text + + # indirect: add user2 to group + tasks.kinit_as_user(master, USER_INDIRECT, PASSWORD) + master.run_command([ + 'ipa', 'group-add-member', GROUP1, '--users', USER2 + ]) + # verify + master.run_command(['ipa', 'group-show', GROUP1]) + result = master.run_command(['ipa', 'group-show', GROUP1]) + assert USER2 in result.stdout_text + + def test_group_member_manager_group(self): + master = self.master + # mmuser: add group2 to group + tasks.kinit_as_user(master, USER_MM, PASSWORD) + master.run_command([ + 'ipa', 'group-add-member', GROUP1, '--groups', GROUP2 + ]) + result = master.run_command(['ipa', 'group-show', GROUP1]) + assert GROUP2 in result.stdout_text + + def test_hostgroup_member_manager_user(self): + master = self.master + # mmuser: add a host to host group + tasks.kinit_as_user(master, USER_MM, PASSWORD) + master.run_command([ + 'ipa', 'hostgroup-add-member', HOSTGROUP1, + '--hosts', master.hostname + ]) + result = master.run_command(['ipa', 'hostgroup-show', HOSTGROUP1]) + assert master.hostname in result.stdout_text + master.run_command([ + 'ipa', 'hostgroup-remove-member', HOSTGROUP1, + '--hosts', master.hostname + ]) + result = master.run_command(['ipa', 'hostgroup-show', HOSTGROUP1]) + assert master.hostname not in result.stdout_text + + # indirect: + tasks.kinit_as_user(master, USER_INDIRECT, PASSWORD) + master.run_command([ + 'ipa', 'hostgroup-add-member', HOSTGROUP1, + '--hosts', master.hostname + ]) + result = master.run_command(['ipa', 'hostgroup-show', HOSTGROUP1]) + assert master.hostname in result.stdout_text diff --git a/ipatests/test_xmlrpc/test_group_plugin.py b/ipatests/test_xmlrpc/test_group_plugin.py index c89de66..3a4b778 100644 --- a/ipatests/test_xmlrpc/test_group_plugin.py +++ b/ipatests/test_xmlrpc/test_group_plugin.py @@ -757,3 +757,35 @@ class TestTrustAdminGroup(XMLRPC_test): key=trustadmins.cn, reason='Cannot support external non-IPA members')): command() + + +@pytest.mark.tier1 +class TestGroupMemberManager(XMLRPC_test): + def test_add_member_manager_user(self, user, group): + user.ensure_exists() + group.ensure_exists() + group.add_member_manager({"user": user.uid}) + + def test_remove_member_manager_user(self, user, group): + user.ensure_exists() + group.ensure_exists() + group.remove_member_manager({"user": user.uid}) + + def test_add_member_manager_group(self, group, group2): + group.ensure_exists() + group2.ensure_exists() + group.add_member_manager({"group": group2.cn}) + + def test_remove_member_manager_group(self, group, group2): + group.ensure_exists() + group2.ensure_exists() + group.remove_member_manager({"group": group2.cn}) + + def test_member_manager_delete_user(self, user, group): + user.ensure_exists() + group.ensure_exists() + group.add_member_manager({"user": user.uid}) + user.delete() + # deleting a user also deletes member manager reference + group.attrs.pop("membermanager_user") + group.retrieve() diff --git a/ipatests/test_xmlrpc/tracker/group_plugin.py b/ipatests/test_xmlrpc/tracker/group_plugin.py index 3bf2169..23c2cf1 100644 --- a/ipatests/test_xmlrpc/tracker/group_plugin.py +++ b/ipatests/test_xmlrpc/tracker/group_plugin.py @@ -11,11 +11,13 @@ from ipatests.util import assert_deepequal, get_group_dn class GroupTracker(Tracker): """ Class for host plugin like tests """ - retrieve_keys = {u'dn', u'cn', u'gidnumber', u'member_user', - u'member_group', u'member_service', u'description', - u'memberof_group', u'memberofindirect_group', - u'memberindirect_group', u'memberindirect_user', - u'memberindirect_service'} + retrieve_keys = { + 'dn', 'cn', 'gidnumber', 'member_user', 'member_group', + 'member_service', 'description', 'memberof_group', + 'memberofindirect_group', 'memberindirect_group', + 'memberindirect_user', 'memberindirect_service', + 'membermanager_group', 'membermanager_user' + } retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass'} @@ -69,6 +71,16 @@ class GroupTracker(Tracker): self.exists = True return self.make_command('group_detach', self.cn) + def make_add_member_manager_command(self, options={}): + return self.make_command( + 'group_add_member_manager', self.cn, **options + ) + + def make_remove_member_manager_command(self, options={}): + return self.make_command( + 'group_remove_member_manager', self.cn, **options + ) + def track_create(self): """ Updates expected state for group creation""" self.attrs = dict( @@ -166,6 +178,40 @@ class GroupTracker(Tracker): result = command() self.check_remove_member(result) + def add_member_manager(self, options): + """Add a member manager (user or group) and perform checks""" + if "user" in options: + members = self.attrs.setdefault("membermanager_user", []) + members.append(options["user"]) + elif "group" in options: + members = self.attrs.setdefault("membermanager_group", []) + members.append(options["group"]) + + command = self.make_add_member_manager_command(options) + result = command() + self.check_add_member_manager(result) + + def remove_member_manager(self, options): + if "user" in options: + members = self.attrs["membermanager_user"] + members.remove(options["user"]) + if not members: + self.attrs.pop("membermanager_user") + elif "group" in options: + members = self.attrs["membermanager_group"] + members.remove(options["group"]) + if not members: + self.attrs.pop("membermanager_group") + + command = self.make_remove_member_manager_command(options) + result = command() + self.check_remove_member_manager(result) + + def retrieve(self, all=False, raw=False): + command = self.make_retrieve_command(all=all, raw=raw) + result = command() + self.check_retrieve(result, all=all, raw=raw) + def check_create(self, result): """ Checks 'group_add' command result """ assert_deepequal(dict( @@ -274,6 +320,16 @@ class GroupTracker(Tracker): """ Checks 'group_remove_member' command result """ self.check_add_member(result) + def check_add_member_manager(self, result): + assert_deepequal(dict( + completed=1, + failed={'membermanager': {'group': (), 'user': ()}}, + result=self.filter_attrs(self.add_member_keys) + ), result) + + def check_remove_member_manager(self, result): + self.check_add_member_manager(result) + def check_detach(self, result): """ Checks 'group_detach' command result """ assert_deepequal(dict(