diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py index 91aa39650..f764efbb7 100644 --- a/ipalib/plugins/baseldap.py +++ b/ipalib/plugins/baseldap.py @@ -32,6 +32,93 @@ from ipalib import output from ipalib.text import _ from ipalib.util import json_serialize +global_output_params = ( + Str('member', + label=_('Failed members'), + ), + Str('member_user?', + label=_('Member users'), + ), + Str('member_group?', + label=_('Member groups'), + ), + Str('member_host?', + label=_('Member hosts'), + ), + Str('memberof_hostgroup?', + label=_('Member of host-groups'), + ), + Str('memberof_taskgroup?', + label=_('Member of task-groups'), + ), + Str('member_rolegroup?', + label=_('Member role-groups'), + ), + Str('member_netgroup?', + label=_('Member netgroups'), + ), + Str('memberof_netgroup?', + label=_('Member of netgroups'), + ), + Str('member_service?', + label=_('Member services'), + ), + Str('member_servicegroup?', + label=_('Member service groups'), + ), + Str('memberof_servicegroup?', + label='Member of service groups', + ), + Str('member_hbacsvcgroup?', + label=_('Member HBAC service groups'), + ), + Str('memberof_hbacsvcgroup?', + label='Member of HBAC service groups', + ), + Str('member_sudocmdgroup?', + label='Member SUDO command groups', + ), + Str('member_sudocmd?', + label='Member SUDO commands', + ), + Str('memberindirect_user?', + label=_('Indirect Member users'), + ), + Str('memberindirect_group?', + label=_('Indirect Member groups'), + ), + Str('memberindirect_host?', + label=_('Indirect Member hosts'), + ), + Str('memberindirect_hostgroup?', + label=_('Indirect Member host-groups'), + ), + Str('memberindirect_rolegroup?', + label=_('Indirect Member role-groups'), + ), + Str('memberindirect_taskgroup?', + label=_('Indirect Member role-groups'), + ), + Str('memberindirect_hbacsvc?', + label=_('Indirect Member HBAC service'), + ), + Str('memberindirect_hbacsvcgrp?', + label=_('Indirect Member HBAC service group'), + ), + Str('memberindirect_netgroup?', + label=_('Indirect Member netgroups'), + ), + Str('memberindirect_sudocmdgroup?', + label='Indirect Member SUDO command groups', + ), + Str('memberindirect_sudocmd?', + label='Indirect Member SUDO commands', + ), + Str('externalhost?', + label=_('External host'), + ), +) + def validate_add_attribute(ugettext, attr): validate_attribute(ugettext, 'addattr', attr) @@ -273,6 +360,8 @@ class LDAPCreate(CallbackInterface, crud.Create): for arg in super(crud.Create, self).get_args(): yield arg + has_output_params = global_output_params + def execute(self, *keys, **options): ldap = self.obj.backend @@ -425,6 +514,7 @@ class LDAPRetrieve(LDAPQuery): Retrieve an LDAP entry. """ has_output = output.standard_entry + has_output_params = global_output_params takes_options = ( Flag('rights', @@ -502,6 +592,8 @@ class LDAPUpdate(LDAPQuery, crud.Update): takes_options = _attr_options + has_output_params = global_output_params + def execute(self, *keys, **options): ldap = self.obj.backend @@ -630,6 +722,8 @@ class LDAPDelete(LDAPMultiQuery): """ has_output = output.standard_delete + has_output_params = global_output_params + def execute(self, *keys, **options): ldap = self.obj.backend @@ -765,11 +859,7 @@ class LDAPAddMember(LDAPModMember): ), ) - has_output_params = ( - Str('member', - label=_('Failed members'), - ), - ) + has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend @@ -870,11 +960,7 @@ class LDAPRemoveMember(LDAPModMember): ), ) - has_output_params = ( - Str('member', - label=_('Failed members'), - ), - ) + has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend @@ -989,6 +1075,8 @@ class LDAPSearch(CallbackInterface, crud.Search): for option in super(LDAPSearch, self).get_options(): yield option + has_output_params = global_output_params + def execute(self, *args, **options): ldap = self.obj.backend diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py index 975915b42..aec5ce057 100644 --- a/ipalib/plugins/group.py +++ b/ipalib/plugins/group.py @@ -83,12 +83,14 @@ class group(LDAPObject): object_class_config = 'ipagroupobjectclasses' search_attributes_config = 'ipagroupsearchfields' default_attributes = [ - 'cn', 'description', 'gidnumber', 'member', 'memberof' + 'cn', 'description', 'gidnumber', 'member', 'memberof', + 'memberindirect', ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['user', 'group'], 'memberof': ['group', 'netgroup', 'rolegroup', 'taskgroup'], + 'memberindirect': ['user', 'group', 'netgroup', 'rolegroup', 'taskgroup'], } rdnattr = 'cn' @@ -114,14 +116,6 @@ class group(LDAPObject): label=_('GID'), doc=_('GID (use this option to set it manually)'), ), - Str('member_group?', - label=_('Member groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('member_user?', - label=_('Member users'), - flags=['no_create', 'no_update', 'no_search'], - ), ) api.register(group) diff --git a/ipalib/plugins/hbacsvc.py b/ipalib/plugins/hbacsvc.py index d5302cdee..4074eb33d 100644 --- a/ipalib/plugins/hbacsvc.py +++ b/ipalib/plugins/hbacsvc.py @@ -51,10 +51,10 @@ class hbacsvc(LDAPObject): HBAC Service object. """ container_dn = api.env.container_hbacservice - object_name = 'service' - object_name_plural = 'services' + object_name = 'hbacsvc' + object_name_plural = 'hbacsvcs' object_class = [ 'ipaobject', 'ipahbacservice' ] - default_attributes = ['cn', 'description'] + default_attributes = ['cn', 'description', 'memberindirect',] uuid_attribute = 'ipauniqueid' label = _('Services') diff --git a/ipalib/plugins/hbacsvcgroup.py b/ipalib/plugins/hbacsvcgroup.py index 70dd32b13..682a6c4e6 100644 --- a/ipalib/plugins/hbacsvcgroup.py +++ b/ipalib/plugins/hbacsvcgroup.py @@ -53,14 +53,17 @@ class hbacsvcgroup(LDAPObject): HBAC service group object. """ container_dn = api.env.container_hbacservicegroup - object_name = 'servicegroup' - object_name_plural = 'servicegroups' + object_name = 'hbacsvcgroup' + object_name_plural = 'hbacsvcgroups' object_class = ['ipaobject', 'ipahbacservicegroup'] - default_attributes = [ 'cn', 'description', 'member', 'memberof', ] + default_attributes = [ 'cn', 'description', 'member', 'memberof', + 'memberindirect', + ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['hbacsvc', 'hbacsvcgroup'], 'memberof': ['hbacsvcgroup'], + 'memberindirect': ['hbacsvc', 'hbacsvcgroup'], } label = _('HBAC Service Groups') @@ -77,18 +80,6 @@ class hbacsvcgroup(LDAPObject): label=_('Description'), doc=_('HBAC service group description'), ), - Str('member_service?', - label=_('Member services'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('member_servicegroup?', - label=_('Member service groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_servicegroup?', - label='Member of service groups', - flags=['no_create', 'no_update', 'no_search'], - ), ) api.register(hbacsvcgroup) diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py index 3a63d212f..2c032f3e7 100644 --- a/ipalib/plugins/host.py +++ b/ipalib/plugins/host.py @@ -159,18 +159,6 @@ class host(LDAPObject): label=_('Principal name'), flags=['no_create', 'no_update', 'no_search'], ), - Str('memberof_hostgroup?', - label=_('Member of host-groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_netgroup?', - label=_('Member of net-groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_rolegroup?', - label=_('Member of role-groups'), - flags=['no_create', 'no_update', 'no_search'], - ), ) def get_dn(self, *keys, **options): diff --git a/ipalib/plugins/hostgroup.py b/ipalib/plugins/hostgroup.py index 2f9cbab2c..51d058369 100644 --- a/ipalib/plugins/hostgroup.py +++ b/ipalib/plugins/hostgroup.py @@ -59,11 +59,14 @@ class hostgroup(LDAPObject): object_name = 'hostgroup' object_name_plural = 'hostgroups' object_class = ['ipaobject', 'ipahostgroup'] - default_attributes = ['cn', 'description', 'member', 'memberof'] + default_attributes = ['cn', 'description', 'member', 'memberof', + 'memberindirect' + ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['host', 'hostgroup'], 'memberof': ['hostgroup'], + 'memberindirect': ['host', 'hostgroup'], } label = _('Host Groups') @@ -81,18 +84,6 @@ class hostgroup(LDAPObject): label=_('Description'), doc=_('A description of this host-group'), ), - Str('member_host?', - label=_('Member hosts'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('member_hostgroup?', - label=_('Member host-groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_hostgroup?', - label=_('Member of host-groups'), - flags=['no_create', 'no_update', 'no_search'], - ), ) api.register(hostgroup) diff --git a/ipalib/plugins/netgroup.py b/ipalib/plugins/netgroup.py index 9edc45e55..3b714213a 100644 --- a/ipalib/plugins/netgroup.py +++ b/ipalib/plugins/netgroup.py @@ -46,23 +46,6 @@ from ipalib.plugins.baseldap import * from ipalib import _, ngettext -output_params = ( - Str('memberuser_user?', - label='Member User', - ), - Str('memberuser_group?', - label='Member Group', - ), - Str('memberhost_host?', - label=_('Member Host'), - ), - Str('memberhost_hostgroup?', - label='Member Hostgroup', - ), - Str('externalhost?', - label=_('External host'), - ), - ) class netgroup(LDAPObject): """ Netgroup object. @@ -72,13 +55,15 @@ class netgroup(LDAPObject): object_name_plural = 'netgroups' object_class = ['ipaobject', 'ipaassociation', 'ipanisnetgroup'] default_attributes = [ - 'cn', 'description', 'memberof', 'externalhost', - 'nisdomainname', 'memberuser', 'memberhost', + 'cn', 'description', 'memberof', 'externalhost', 'nisdomainname', + 'memberuser', 'memberhost','member', 'memberindirect', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { + 'member': ['netgroup'], 'memberof': ['netgroup'], + 'memberindirect': ['netgroup'], 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], } @@ -116,7 +101,6 @@ class netgroup_add(LDAPCreate): """ Add a new netgroup. """ - has_output_params = output_params def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): entry_attrs.setdefault('nisdomainname', self.api.env.domain) return dn @@ -128,6 +112,7 @@ class netgroup_del(LDAPDelete): """ Delete a netgroup. """ + msg_summary = _('Deleted netgroup "%(value)s"') api.register(netgroup_del) @@ -136,7 +121,6 @@ class netgroup_mod(LDAPUpdate): """ Modify a netgroup. """ - has_output_params = output_params api.register(netgroup_mod) @@ -145,7 +129,6 @@ class netgroup_find(LDAPSearch): """ Search for a netgroup. """ - has_output_params = output_params api.register(netgroup_find) @@ -154,7 +137,6 @@ class netgroup_show(LDAPRetrieve): """ Display information about a netgroup. """ - has_output_params = output_params api.register(netgroup_show) @@ -163,8 +145,7 @@ class netgroup_add_member(LDAPAddMember): """ Add members to a netgroup. """ - has_output_params = LDAPAddMember.has_output_params + output_params - member_attributes = ['memberuser', 'memberhost'] + member_attributes = ['memberuser', 'memberhost', 'member'] def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): completed_external = 0 # Sift through the host failures. We assume that these are all @@ -199,7 +180,6 @@ class netgroup_remove_member(LDAPRemoveMember): """ Remove members from a netgroup. """ - has_output_params = LDAPRemoveMember.has_output_params + output_params member_attributes = ['memberuser', 'memberhost'] def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): # Run through the host failures and gracefully remove any defined as diff --git a/ipalib/plugins/rolegroup.py b/ipalib/plugins/rolegroup.py index feffa0d49..e0b6fbc4e 100644 --- a/ipalib/plugins/rolegroup.py +++ b/ipalib/plugins/rolegroup.py @@ -70,10 +70,13 @@ class rolegroup(LDAPObject): object_name = 'rolegroup' object_name_plural = 'rolegroups' object_class = ['groupofnames', 'nestedgroup'] - default_attributes = ['cn', 'description', 'member', 'memberof'] + default_attributes = ['cn', 'description', 'member', 'memberof', + 'memberindirect' + ] attribute_members = { 'member': ['user', 'group', 'host', 'hostgroup'], 'memberof': ['taskgroup'], + 'memberindirect': ['user', 'group', 'host', 'hostgroup'], } rdnattr='cn' @@ -91,18 +94,6 @@ class rolegroup(LDAPObject): label=_('Description'), doc=_('A description of this role-group'), ), - Str('member_group?', - label=_('Member groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('member_user?', - label=_('Member users'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_taskgroup?', - label=_('Member of task-groups'), - flags=['no_create', 'no_update', 'no_search'], - ), ) api.register(rolegroup) diff --git a/ipalib/plugins/sudocmdgroup.py b/ipalib/plugins/sudocmdgroup.py index 75b3efbdb..5476f99cf 100644 --- a/ipalib/plugins/sudocmdgroup.py +++ b/ipalib/plugins/sudocmdgroup.py @@ -55,12 +55,13 @@ class sudocmdgroup(LDAPObject): object_name_plural = 'sudocmdgroups' object_class = ['ipaobject', 'ipasudocmdgrp'] default_attributes = [ - 'cn', 'description', 'member', 'memberof' + 'cn', 'description', 'member', 'memberof', 'memberindirect', ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['sudocmd', 'sudocmdgroup'], 'memberof': ['sudocmdgroup'], + 'memberindirect': ['sudocmd', 'sudocmdgroup'], } label = _('Sudo Command Groups') diff --git a/ipalib/plugins/taskgroup.py b/ipalib/plugins/taskgroup.py index 11bef4860..ba3f50738 100644 --- a/ipalib/plugins/taskgroup.py +++ b/ipalib/plugins/taskgroup.py @@ -33,7 +33,6 @@ from ipalib.plugins.baseldap import * from ipalib import api, _, ngettext - class taskgroup(LDAPObject): """ Taskgroup object. @@ -42,9 +41,12 @@ class taskgroup(LDAPObject): object_name = 'taskgroup' object_name_plural = 'taskgroups' object_class = ['groupofnames'] - default_attributes = ['cn', 'description', 'member', 'memberof'] + default_attributes = ['cn', 'description', 'member', 'memberof', + 'memberindirect' + ] attribute_members = { 'member': ['user', 'group', 'rolegroup'], + 'memberindirect': ['user', 'group', 'rolegroup'], # FIXME: taskgroup can be member of ??? } rdnattr='cn' @@ -63,18 +65,6 @@ class taskgroup(LDAPObject): label=_('Description'), doc=_('Task-group description'), ), - Str('member_group?', - label=_('Member groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('member_user?', - label=_('Member users'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('member_rolegroup?', - label=_('Member role-groups'), - flags=['no_create', 'no_update', 'no_search'], - ), ) api.register(taskgroup) diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py index fb0da4800..6bfb7b6fb 100644 --- a/ipalib/plugins/user.py +++ b/ipalib/plugins/user.py @@ -139,22 +139,6 @@ class user(LDAPObject): cli_name='street', label=_('Street address'), ), - Str('memberof_group?', - label=_('Groups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_netgroup?', - label=_('Netgroups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_rolegroup?', - label=_('Rolegroups'), - flags=['no_create', 'no_update', 'no_search'], - ), - Str('memberof_taskgroup?', - label=_('Taskgroups'), - flags=['no_create', 'no_update', 'no_search'], - ), Str('telephonenumber*', cli_name='phone', label=_('Telephone Number') ), diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index 4117e47b7..b5efc428e 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -49,6 +49,11 @@ from ipalib.encoder import Encoder, encode_args, decode_retval from ipalib.request import context +# Group Member types +MEMBERS_ALL = 0 +MEMBERS_DIRECT = 1 +MEMBERS_INDIRECT = 2 + # SASL authentication mechanism SASL_AUTH = _ldap_sasl.sasl({}, 'GSSAPI') @@ -543,6 +548,13 @@ class ldap2(CrudBackend, Encoder): if not res: raise errors.NotFound(reason='no such entry') + if attrs_list and ('memberindirect' in attrs_list or '*' in attrs_list): + for r in res: + indirect = self.get_members(r[0], membertype=MEMBERS_INDIRECT, + time_limit=time_limit, size_limit=size_limit, normalize=normalize) + if len(indirect) > 0: + r[1]['memberindirect'] = indirect + return (res, truncated) def find_entry_by_attr(self, attr, value, object_class, attrs_list=None, @@ -814,6 +826,65 @@ class ldap2(CrudBackend, Encoder): # update group entry self.update_entry(group_dn, group_entry_attrs) + def get_members(self, group_dn, attr_list=[], membertype=MEMBERS_ALL, time_limit=None, size_limit=None, normalize=True): + """Do a memberOf search of groupdn and return the attributes in + attr_list (an empty list returns all attributes). + + membertype = MEMBERS_ALL all members returned + membertype = MEMBERS_DIRECT only direct members are returned + membertype = MEMBERS_INDIRECT only inherited members are returned + + Members may be included in a group as a result of being a member + of a group that is a member of the group being queried. + + Returns a list of DNs. + """ + if membertype not in [MEMBERS_ALL, MEMBERS_DIRECT, MEMBERS_INDIRECT]: + return None + + searchfilter = "(memberof=%s)" % group_dn + + attr_list.append("member") + + # We have to do two searches because netgroups are not within the + # accounts container. + try: + (results, truncated) = self.find_entries(searchfilter, attr_list, + api.env.container_accounts, time_limit=time_limit, size_limit = size_limit, normalize=normalize) + except errors.NotFound: + results = [] + try: + (netresults, truncated) = self.find_entries(searchfilter, attr_list, + api.env.container_netgroup, time_limit=time_limit, size_limit = size_limit, normalize=normalize) + except errors.NotFound: + netresults = [] + results = results + netresults + + if membertype == MEMBERS_ALL: + entries = [] + for e in results: + entries.append(e[0]) + + return entries + + (dn, group) = self.get_entry(group_dn, ['dn', 'member']) + real_members = group.get('member') + if isinstance(real_members, basestring): + real_members = [real_members] + if real_members is None: + real_members = [] + + entries = [] + for e in results: + if unicode(e[0]) not in real_members: + if membertype == MEMBERS_INDIRECT: + entries.append(e[0]) + else: + if membertype == MEMBERS_DIRECT: + entries.append(e[0]) + + return entries + def set_entry_active(self, dn, active): """Mark entry active/inactive.""" assert isinstance(active, bool) diff --git a/tests/test_xmlrpc/test_hbac_plugin.py b/tests/test_xmlrpc/test_hbac_plugin.py index 2405355c0..3c1cfaed5 100644 --- a/tests/test_xmlrpc/test_hbac_plugin.py +++ b/tests/test_xmlrpc/test_hbac_plugin.py @@ -267,7 +267,7 @@ class test_hbac(XMLRPC_test): assert 'hbacsvc' in failed['memberservice'] assert not failed['memberservice']['hbacsvc'] entry = ret['result'] - assert_attr_equal(entry, 'memberservice_service', self.test_service) + assert_attr_equal(entry, 'memberservice_hbacsvc', self.test_service) def test_a_hbac_remove_service(self): """ diff --git a/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py b/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py index 8264ae903..da347f22d 100644 --- a/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py +++ b/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py @@ -130,7 +130,7 @@ class test_hbacsvcgroup(Declarative): 'dn': dn1, 'cn': [hbacsvcgroup1], 'description': [u'Test hbacsvcgroup 1'], - 'member_service': [hbacsvc1], + 'member_hbacsvc': [hbacsvc1], }, ), ), @@ -144,7 +144,7 @@ class test_hbacsvcgroup(Declarative): summary=None, result={ 'dn': dn1, - 'member_service': [hbacsvc1], + 'member_hbacsvc': [hbacsvc1], 'cn': [hbacsvcgroup1], 'description': [u'Test hbacsvcgroup 1'], }, @@ -162,7 +162,7 @@ class test_hbacsvcgroup(Declarative): result=[ { 'dn': dn1, - 'member_service': [hbacsvc1], + 'member_hbacsvc': [hbacsvc1], 'cn': [hbacsvcgroup1], 'description': [u'Test hbacsvcgroup 1'], }, @@ -182,7 +182,7 @@ class test_hbacsvcgroup(Declarative): result=dict( cn=[hbacsvcgroup1], description=[u'Updated hbacsvcgroup 1'], - member_service=[hbacsvc1], + member_hbacsvc=[hbacsvc1], ), ), ), @@ -196,7 +196,7 @@ class test_hbacsvcgroup(Declarative): summary=None, result={ 'dn': dn1, - 'member_service': [hbacsvc1], + 'member_hbacsvc': [hbacsvc1], 'cn': [hbacsvcgroup1], 'description': [u'Updated hbacsvcgroup 1'], }, diff --git a/tests/test_xmlrpc/test_nesting.py b/tests/test_xmlrpc/test_nesting.py new file mode 100644 index 000000000..8c9e4b25f --- /dev/null +++ b/tests/test_xmlrpc/test_nesting.py @@ -0,0 +1,350 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2010 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" +Test group nexting an indirect members +""" + +from ipalib import api, errors +from tests.test_xmlrpc import objectclasses +from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid + +group1 = u'testgroup1' +group2 = u'testgroup2' +group3 = u'testgroup3' +user1 = u'tuser1' +user2 = u'tuser2' + + +class test_group(Declarative): + cleanup_commands = [ + ('group_del', [group1], {}), + ('group_del', [group2], {}), + ('group_del', [group3], {}), + ('user_del', [user1], {}), + ('user_del', [user2], {}), + ] + + tests = [ + + ################ + # create group1: + + dict( + desc='Create %r' % group1, + command=( + 'group_add', [group1], dict(description=u'Test desc 1') + ), + expected=dict( + value=group1, + summary=u'Added group "testgroup1"', + result=dict( + cn=[group1], + description=[u'Test desc 1'], + objectclass=objectclasses.group + [u'posixgroup'], + ipauniqueid=[fuzzy_uuid], + gidnumber=[fuzzy_digits], + dn=u'cn=testgroup1,cn=groups,cn=accounts,' + api.env.basedn, + ), + ), + ), + + + ################ + # create group2: + dict( + desc='Create %r' % group2, + command=( + 'group_add', [group2], dict(description=u'Test desc 2') + ), + expected=dict( + value=group2, + summary=u'Added group "testgroup2"', + result=dict( + cn=[group2], + description=[u'Test desc 2'], + gidnumber=[fuzzy_digits], + objectclass=objectclasses.group + [u'posixgroup'], + ipauniqueid=[fuzzy_uuid], + dn=u'cn=testgroup2,cn=groups,cn=accounts,' + api.env.basedn, + ), + ), + ), + + + dict( + desc='Create %r' % group3, + command=( + 'group_add', [group3], dict(description=u'Test desc 3') + ), + expected=dict( + value=group3, + summary=u'Added group "testgroup3"', + result=dict( + cn=[group3], + description=[u'Test desc 3'], + gidnumber=[fuzzy_digits], + objectclass=objectclasses.group + [u'posixgroup'], + ipauniqueid=[fuzzy_uuid], + dn=u'cn=testgroup3,cn=groups,cn=accounts,' + api.env.basedn, + ), + ), + ), + + + dict( + desc='Create %r' % user1, + command=( + 'user_add', [user1], dict(givenname=u'Test', sn=u'User1') + ), + expected=dict( + value=user1, + summary=u'Added user "%s"' % user1, + result=dict( + gecos=[user1], + givenname=[u'Test'], + homedirectory=[u'/home/tuser1'], + krbprincipalname=[u'tuser1@' + api.env.realm], + loginshell=[u'/bin/sh'], + objectclass=objectclasses.user, + sn=[u'User1'], + uid=[user1], + uidnumber=[fuzzy_digits], + ipauniqueid=[fuzzy_uuid], + dn=u'uid=%s,cn=users,cn=accounts,%s' % (user1, api.env.basedn) + ), + ), + ), + + + dict( + desc='Create %r' % user2, + command=( + 'user_add', [user2], dict(givenname=u'Test', sn=u'User2') + ), + expected=dict( + value=user2, + summary=u'Added user "%s"' % user2, + result=dict( + gecos=[user2], + givenname=[u'Test'], + homedirectory=[u'/home/tuser2'], + krbprincipalname=[u'tuser2@' + api.env.realm], + loginshell=[u'/bin/sh'], + objectclass=objectclasses.user, + sn=[u'User2'], + uid=[user2], + uidnumber=[fuzzy_digits], + ipauniqueid=[fuzzy_uuid], + dn=u'uid=%s,cn=users,cn=accounts,%s' % (user2, api.env.basedn) + ), + ), + ), + + + ############### + # member stuff + # + # Create 3 groups and 2 users and set the following membership: + # + # g1: + # member: g2 + # + # g2: + # member: g3 + # member: user1 + # + # g3: + # member: user2 + # + # So when we do a show it looks like: + # + # g1: + # member: g2 + # indirect group: g3 + # indirect users: user1, user2 + # + # g2: + # member group: g3 + # member user: tuser1 + # indirect users: user2 + # memberof: g1 + # + # g3: + # member: user2 + # memberof: g1, g2 + + + dict( + desc='Add a group member %r to %r' % (group2, group1), + command=( + 'group_add_member', [group1], dict(group=group2) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + group=tuple(), + user=tuple(), + ), + ), + result={ + 'dn': u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn), + 'member_group': (group2,), + 'gidnumber': [fuzzy_digits], + 'cn': [group1], + 'description': [u'Test desc 1'], + }, + ), + ), + + + dict( + desc='Add a group member %r to %r' % (group3, group2), + command=( + 'group_add_member', [group2], dict(group=group3) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + group=tuple(), + user=tuple(), + ), + ), + result={ + 'dn': u'cn=%s,cn=groups,cn=accounts,%s' % (group2, api.env.basedn), + 'member_group': (group3,), + 'memberof_group': (u'testgroup1',), + 'gidnumber': [fuzzy_digits], + 'cn': [group2], + 'description': [u'Test desc 2'], + }, + ), + ), + + + dict( + desc='Add a user member %r to %r' % (user1, group2), + command=( + 'group_add_member', [group2], dict(user=user1) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + group=tuple(), + user=tuple(), + ), + ), + result={ + 'dn': u'cn=%s,cn=groups,cn=accounts,%s' % (group2, api.env.basedn), + 'member_user': (u'tuser1',), + 'member_group': (group3,), + 'memberof_group': (u'testgroup1',), + 'gidnumber': [fuzzy_digits], + 'cn': [group2], + 'description': [u'Test desc 2'], + }, + ), + ), + + + dict( + desc='Add a user member %r to %r' % (user2, group3), + command=( + 'group_add_member', [group3], dict(user=user2) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + group=tuple(), + user=tuple(), + ), + ), + result={ + 'dn': u'cn=%s,cn=groups,cn=accounts,%s' % (group3, api.env.basedn), + 'member_user': (u'tuser2',), + 'memberof_group': (u'testgroup2', u'testgroup1'), + 'gidnumber': [fuzzy_digits], + 'cn': [group3], + 'description': [u'Test desc 3'], + }, + ), + ), + + + dict( + desc='Retrieve group %r' % group1, + command=('group_show', [group1], {}), + expected=dict( + value=group1, + summary=None, + result=dict( + cn=[group1], + description=[u'Test desc 1'], + gidnumber= [fuzzy_digits], + memberindirect_group = (u'testgroup3',), + member_group = (u'testgroup2',), + memberindirect_user = (u'tuser1',u'tuser2',), + dn=u'cn=testgroup1,cn=groups,cn=accounts,' + api.env.basedn, + ), + ), + ), + + + dict( + desc='Retrieve group %r' % group2, + command=('group_show', [group2], {}), + expected=dict( + value=group2, + summary=None, + result=dict( + cn=[group2], + description=[u'Test desc 2'], + gidnumber= [fuzzy_digits], + memberof_group = (u'testgroup1',), + member_group = (u'testgroup3',), + member_user = (u'tuser1',), + memberindirect_user = (u'tuser2',), + dn=u'cn=testgroup2,cn=groups,cn=accounts,' + api.env.basedn, + ), + ), + ), + + + dict( + desc='Retrieve group %r' % group3, + command=('group_show', [group3], {}), + expected=dict( + value=group3, + summary=None, + result=dict( + cn=[group3], + description=[u'Test desc 3'], + gidnumber= [fuzzy_digits], + memberof_group = (u'testgroup2', u'testgroup1',), + member_user = (u'tuser2',), + dn=u'cn=testgroup3,cn=groups,cn=accounts,' + api.env.basedn, + ), + ), + ), + + + ]