Exemple #1
0
    def pre_callback(self, ldap, dn, *keys, **options):
        ca_enabled_check(self.api)

        # ensure operator has permission to delete CA
        # before contacting Dogtag
        if not ldap.can_delete(dn):
            raise errors.ACIError(info=_(
                "Insufficient privilege to delete a CA."))

        if keys[0] == IPA_CA_CN:
            raise errors.ProtectedEntryError(
                label=_("CA"),
                key=keys[0],
                reason=_("IPA CA cannot be deleted"))

        ca_id = self.api.Command.ca_show(keys[0])['result']['ipacaid'][0]
        with self.api.Backend.ra_lightweight_ca as ca_api:
            data = ca_api.read_ca(ca_id)
            if data['enabled']:
                raise errors.ProtectedEntryError(
                    label=_("CA"),
                    key=keys[0],
                    reason=_("Must be disabled first"))
            ca_api.delete_ca(ca_id)

        return dn
Exemple #2
0
    def pre_callback(self, ldap, dn, *keys, **options):
        if keys[0] in PROTECTED_HOSTGROUPS:
            raise errors.ProtectedEntryError(label=_(u'hostgroup'),
                                             key=keys[0],
                                             reason=_(u'privileged hostgroup'))

        return dn
Exemple #3
0
 def test_rename_trust_admins(self, trustadmins):
     """ Try to rename the protected 'trust admins' group """
     command = trustadmins.make_command('group_mod', *[trustadmins.cn],
                                        **dict(rename=renamedgroup1))
     with raises_exact(errors.ProtectedEntryError(label=u'group',
                       key=trustadmins.cn, reason='Cannot be renamed')):
         command()
    def test_try_rename_by_setattr(self, default_profile):
        command = default_profile.make_update_command(updates=dict(
            setattr=u'cn=bogus'))
        errmsg = RENAME_ERR_TEMPL.format(default_profile.name)

        with raises_exact(errors.ProtectedEntryError(message=errmsg)):
            command()
Exemple #5
0
 def test_rename_admins_using_setattr(self, admins):
     """ Try to rename the protected admins group using setattr """
     command = admins.make_command('group_mod', *[admins.cn],
                                   **dict(setattr=u'cn=%s' % renamedgroup1))
     with raises_exact(errors.ProtectedEntryError(label=u'group',
                       key=admins.cn, reason='Cannot be renamed')):
         command()
Exemple #6
0
 def pre_callback(self, ldap, dn, *keys, **options):
     if keys[0] == 'hosts_services_caIPAserviceCert':
         raise errors.ProtectedEntryError(
             label=_("CA ACL"),
             key=keys[0],
             reason=_("default CA ACL can be only disabled"))
     return dn
Exemple #7
0
 def test_delete_trust_admins(self, trustadmins):
     """ Try to delete the protected 'trust admins' group """
     command = trustadmins.make_delete_command()
     with raises_exact(
             errors.ProtectedEntryError(label=u'group',
                                        key=trustadmins.cn,
                                        reason='privileged group')):
         command()
Exemple #8
0
 def test_update_admins_to_support_external_membership(self, admins):
     """ Try to modify the admins group to support external membership """
     command = admins.make_command('group_mod', *[admins.cn],
                                   **dict(external=True))
     with raises_exact(errors.ProtectedEntryError(label=u'group',
                       key=admins.cn,
                       reason='Cannot support external non-IPA members')):
         command()
 def pre_callback(self, ldap, dn, *keys, **options):
     assert isinstance(dn, DN)
     if keys[0] in PROTECTED_CONSTRAINT_TARGETS:
         raise errors.ProtectedEntryError(
             label=_(u'service delegation target'),
             key=keys[0],
             reason=_(u'privileged service delegation target'))
     return dn
Exemple #10
0
    def execute(self, cn, **options):
        if cn == IPA_CA_CN:
            raise errors.ProtectedEntryError(
                label=_("CA"),
                key=cn,
                reason=_("IPA CA cannot be disabled"))

        return super(ca_disable, self).execute(cn, **options)
Exemple #11
0
    def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
        assert isinstance(dn, DN)

        is_protected_group = keys[-1] in PROTECTED_GROUPS

        if 'rename' in options or 'cn' in entry_attrs:
            if is_protected_group:
                raise errors.ProtectedEntryError(label=u'group',
                                                 key=keys[-1],
                                                 reason=u'Cannot be renamed')

        if ('posix' in options and options['posix']) or 'gidnumber' in options:
            old_entry_attrs = ldap.get_entry(dn, ['objectclass'])
            dn = old_entry_attrs.dn
            if 'ipaexternalgroup' in old_entry_attrs['objectclass']:
                raise errors.ExternalGroupViolation()
            if 'posixgroup' in old_entry_attrs['objectclass']:
                if options['posix']:
                    raise errors.AlreadyPosixGroup()
            else:
                old_entry_attrs['objectclass'].append('posixgroup')
                entry_attrs['objectclass'] = old_entry_attrs['objectclass']
                if 'gidnumber' not in options:
                    entry_attrs['gidnumber'] = baseldap.DNA_MAGIC

        if options['external']:
            if is_protected_group:
                raise errors.ProtectedEntryError(
                    label=u'group',
                    key=keys[-1],
                    reason=u'Cannot support external non-IPA members')
            old_entry_attrs = ldap.get_entry(dn, ['objectclass'])
            dn = old_entry_attrs.dn
            if 'posixgroup' in old_entry_attrs['objectclass']:
                raise errors.PosixGroupViolation()
            if 'ipaexternalgroup' in old_entry_attrs['objectclass']:
                raise errors.AlreadyExternalGroup()
            else:
                old_entry_attrs['objectclass'].append('ipaexternalgroup')
                entry_attrs['objectclass'] = old_entry_attrs['objectclass']

        # Can't check for this in a validator because we lack context
        if 'gidnumber' in options and options['gidnumber'] is None:
            raise errors.RequirementError(name='gidnumber')
        return dn
Exemple #12
0
    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
                     **options):
        assert isinstance(dn, DN)
        if keys[0] in PROTECTED_HOSTGROUPS and 'rename' in options:
            raise errors.ProtectedEntryError(label=_(u'hostgroup'),
                                             key=keys[0],
                                             reason=_(u'privileged hostgroup'))

        return dn
 def test_rename_ipaservers(self, ipaservers):
     """ Try to rename the protected ipaservers group """
     command = ipaservers.make_command('hostgroup_mod', *[ipaservers.cn],
                                       **dict(rename=renamedhostgroup1))
     reason = u'privileged hostgroup'
     with raises_exact(
             errors.ProtectedEntryError(label=u'hostgroup',
                                        key=ipaservers.cn,
                                        reason=reason)):
         command()
Exemple #14
0
    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
        ca_enabled_check(self.api)

        if 'rename' in options or 'cn' in entry_attrs:
            if keys[0] == IPA_CA_CN:
                raise errors.ProtectedEntryError(
                    label=_("CA"),
                    key=keys[0],
                    reason=u'IPA CA cannot be renamed')

        return dn
Exemple #15
0
    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
        ca_enabled_check()
        # Once a profile id is set it cannot be changed
        if 'cn' in entry_attrs:
            raise errors.ProtectedEntryError(label='certprofile', key=keys[0],
                reason=_('Certificate profiles cannot be renamed'))
        if 'file' in options:
            with self.api.Backend.ra_certprofile as profile_api:
                profile_api.disable_profile(keys[0])
                try:
                    profile_api.update_profile(keys[0], options['file'])
                finally:
                    profile_api.enable_profile(keys[0])

        return dn
Exemple #16
0
    def pre_callback(self, ldap, dn, *keys, **options):
        ca_enabled_check()

        if keys[0] == IPA_CA_CN:
            raise errors.ProtectedEntryError(
                label=_("CA"),
                key=keys[0],
                reason=_("IPA CA cannot be deleted"))

        ca_id = self.api.Command.ca_show(keys[0])['result']['ipacaid'][0]
        with self.api.Backend.ra_lightweight_ca as ca_api:
            ca_api.disable_ca(ca_id)
            ca_api.delete_ca(ca_id)

        return dn
Exemple #17
0
    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
        ca_enabled_check(self.api)
        # Once a profile id is set it cannot be changed
        if 'cn' in entry_attrs:
            raise errors.ProtectedEntryError(label='certprofile', key=keys[0],
                reason=_('Certificate profiles cannot be renamed'))
        if 'file' in options:
            # ensure operator has permission to update a certprofile
            if not ldap.can_write(dn, 'ipacertprofilestoreissued'):
                raise errors.ACIError(info=_(
                    "Insufficient privilege to modify a certificate profile."))

            with self.api.Backend.ra_certprofile as profile_api:
                profile_api.disable_profile(keys[0])
                try:
                    profile_api.update_profile(keys[0], options['file'])
                finally:
                    profile_api.enable_profile(keys[0])

        return dn
Exemple #18
0
    def pre_callback(self, ldap, dn, *keys, **options):
        assert isinstance(dn, DN)
        config = ldap.get_ipa_config()
        def_primary_group = config.get('ipadefaultprimarygroup', '')
        def_primary_group_dn = self.obj.get_dn(def_primary_group)
        if dn == def_primary_group_dn:
            raise errors.DefaultGroupError()
        group_attrs = self.obj.methods.show(
            self.obj.get_primary_key_from_dn(dn), all=True)['result']
        if keys[0] in PROTECTED_GROUPS:
            raise errors.ProtectedEntryError(label=_(u'group'),
                                             key=keys[0],
                                             reason=_(u'privileged group'))
        if 'mepmanagedby' in group_attrs:
            raise errors.ManagedGroupError()

        # Remove any ID overrides tied with this group
        remove_ipaobject_overrides(ldap, self.obj.api, dn)

        return dn
Exemple #19
0
__doc__ = _("""
ID Views

Manage ID Views

IPA allows to override certain properties of users and groups per each host.
This functionality is primarily used to allow migration from older systems or
other Identity Management solutions.
""")

register = Registry()

protected_default_trust_view_error = errors.ProtectedEntryError(
    label=_('ID View'),
    key=u"Default Trust View",
    reason=_('system ID View')
)

fallback_to_ldap_option = Flag(
    'fallback_to_ldap?',
    default=False,
    label=_('Fallback to AD DC LDAP'),
    doc=_("Allow falling back to AD DC LDAP when resolving AD "
          "trusted objects. For two-way trusts only."),
)

DEFAULT_TRUST_VIEW_NAME = "default trust view"

ANCHOR_REGEX = re.compile(
    r':IPA:.*:[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}'
Exemple #20
0
class test_group(Declarative):
    cleanup_commands = [
        ('group_del', [group1], {}),
        ('group_del', [group2], {}),
        ('group_del', [group3], {}),
        ('group_del', [renamedgroup1], {}),
        ('user_del', [user1], {}),
    ]

    tests = [

        ################
        # create group1:
        dict(
            desc='Try to retrieve non-existent %r' % group1,
            command=('group_show', [group1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % group1),
        ),
        dict(
            desc='Try to update non-existent %r' % group1,
            command=('group_mod', [group1], dict(description=u'Foo')),
            expected=errors.NotFound(reason=u'%s: group not found' % group1),
        ),
        dict(
            desc='Try to delete non-existent %r' % group1,
            command=('group_del', [group1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % group1),
        ),
        dict(
            desc='Try to rename non-existent %r' % group1,
            command=('group_mod', [group1],
                     dict(setattr=u'cn=%s' % renamedgroup1)),
            expected=errors.NotFound(reason=u'%s: group not found' % group1),
        ),
        dict(
            desc='Create non-POSIX %r' % group1,
            command=('group_add', [group1],
                     dict(description=u'Test desc 1', nonposix=True)),
            expected=dict(
                value=group1,
                summary=u'Added group "testgroup1"',
                result=dict(
                    cn=[group1],
                    description=[u'Test desc 1'],
                    objectclass=objectclasses.group,
                    ipauniqueid=[fuzzy_uuid],
                    dn=get_group_dn('testgroup1'),
                ),
            ),
        ),
        dict(
            desc='Try to create duplicate %r' % group1,
            command=('group_add', [group1], dict(description=u'Test desc 1')),
            expected=errors.DuplicateEntry(
                message=u'group with name "%s" already exists' % group1),
        ),
        dict(
            desc='Retrieve non-POSIX %r' % group1,
            command=('group_show', [group1], {}),
            expected=dict(
                value=group1,
                summary=None,
                result=dict(
                    cn=[group1],
                    description=[u'Test desc 1'],
                    dn=get_group_dn('testgroup1'),
                ),
            ),
        ),
        dict(
            desc='Updated non-POSIX %r' % group1,
            command=('group_mod', [group1], dict(description=u'New desc 1')),
            expected=dict(
                result=dict(
                    cn=[group1],
                    description=[u'New desc 1'],
                ),
                summary=u'Modified group "testgroup1"',
                value=group1,
            ),
        ),
        dict(
            desc='Retrieve %r to verify update' % group1,
            command=('group_show', [group1], {}),
            expected=dict(
                value=group1,
                result=dict(
                    cn=[group1],
                    description=[u'New desc 1'],
                    dn=get_group_dn('testgroup1'),
                ),
                summary=None,
            ),
        ),

        # FIXME: The return value is totally different here than from the above
        # group_mod() test.  I think that for all *_mod() commands we should
        # just return the entry exactly as *_show() does.
        dict(
            desc='Updated %r to promote it to a POSIX group' % group1,
            command=('group_mod', [group1], dict(posix=True)),
            expected=dict(
                result=dict(
                    cn=[group1],
                    description=[u'New desc 1'],
                    gidnumber=[fuzzy_digits],
                ),
                value=group1,
                summary=u'Modified group "testgroup1"',
            ),
        ),
        dict(
            desc="Retrieve %r to verify it's a POSIX group" % group1,
            command=('group_show', [group1], {}),
            expected=dict(
                value=group1,
                result=dict(
                    cn=[group1],
                    description=(u'New desc 1', ),
                    dn=get_group_dn('testgroup1'),
                    gidnumber=[fuzzy_digits],
                ),
                summary=None,
            ),
        ),
        dict(
            desc='Search for %r' % group1,
            command=('group_find', [], dict(cn=group1)),
            expected=dict(
                count=1,
                truncated=False,
                result=[
                    dict(
                        dn=get_group_dn(group1),
                        cn=[group1],
                        description=[u'New desc 1'],
                        gidnumber=[fuzzy_digits],
                    ),
                ],
                summary=u'1 group matched',
            ),
        ),

        ################
        # create group2:
        dict(
            desc='Try to retrieve non-existent %r' % group2,
            command=('group_show', [group2], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % group2),
        ),
        dict(
            desc='Try to update non-existent %r' % group2,
            command=('group_mod', [group2], dict(description=u'Foo')),
            expected=errors.NotFound(reason=u'%s: group not found' % group2),
        ),
        dict(
            desc='Try to delete non-existent %r' % group2,
            command=('group_del', [group2], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % 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=get_group_dn('testgroup2'),
                ),
            ),
        ),
        dict(
            desc='Try to create duplicate %r' % group2,
            command=('group_add', [group2], dict(description=u'Test desc 2')),
            expected=errors.DuplicateEntry(
                message=u'group with name "%s" already exists' % group2),
        ),
        dict(
            desc='Retrieve %r' % group2,
            command=('group_show', [group2], {}),
            expected=dict(
                value=group2,
                summary=None,
                result=dict(
                    cn=[group2],
                    description=[u'Test desc 2'],
                    gidnumber=[fuzzy_digits],
                    dn=get_group_dn('testgroup2'),
                ),
            ),
        ),
        dict(
            desc='Updated %r' % group2,
            command=('group_mod', [group2], dict(description=u'New desc 2')),
            expected=dict(
                result=dict(
                    cn=[group2],
                    gidnumber=[fuzzy_digits],
                    description=[u'New desc 2'],
                ),
                summary=u'Modified group "testgroup2"',
                value=group2,
            ),
        ),
        dict(
            desc='Retrieve %r to verify update' % group2,
            command=('group_show', [group2], {}),
            expected=dict(
                value=group2,
                result=dict(
                    cn=[group2],
                    description=[u'New desc 2'],
                    gidnumber=[fuzzy_digits],
                    dn=get_group_dn('testgroup2'),
                ),
                summary=None,
            ),
        ),
        dict(
            desc='Search for %r' % group2,
            command=('group_find', [], dict(cn=group2)),
            expected=dict(
                count=1,
                truncated=False,
                result=[
                    dict(
                        dn=get_group_dn('testgroup2'),
                        cn=[group2],
                        description=[u'New desc 2'],
                        gidnumber=[fuzzy_digits],
                    ),
                ],
                summary=u'1 group matched',
            ),
        ),
        dict(
            desc='Search for all groups',
            command=('group_find', [], {}),
            expected=dict(
                summary=u'6 groups matched',
                count=6,
                truncated=False,
                result=[
                    {
                        'dn': get_group_dn('admins'),
                        'member_user': [u'admin'],
                        'gidnumber': [fuzzy_digits],
                        'cn': [u'admins'],
                        'description': [u'Account administrators group'],
                    },
                    {
                        'dn':
                        get_group_dn('editors'),
                        'gidnumber': [fuzzy_digits],
                        'cn': [u'editors'],
                        'description':
                        [u'Limited admins who can edit other users'],
                    },
                    {
                        'dn': get_group_dn('ipausers'),
                        'cn': [u'ipausers'],
                        'description': [u'Default group for all users'],
                    },
                    dict(
                        dn=get_group_dn(group1),
                        cn=[group1],
                        description=[u'New desc 1'],
                        gidnumber=[fuzzy_digits],
                    ),
                    dict(
                        dn=get_group_dn(group2),
                        cn=[group2],
                        description=[u'New desc 2'],
                        gidnumber=[fuzzy_digits],
                    ),
                    {
                        'dn': get_group_dn('trust admins'),
                        'member_user': [u'admin'],
                        'cn': [u'trust admins'],
                        'description': [u'Trusts administrators group'],
                    },
                ],
            ),
        ),

        ###############
        # test external SID members for group3:
        dict(
            desc='Create external %r' % group3,
            command=('group_add', [group3],
                     dict(description=u'Test desc 3', external=True)),
            expected=dict(
                value=group3,
                summary=u'Added group "testgroup3"',
                result=dict(
                    cn=[group3],
                    description=[u'Test desc 3'],
                    objectclass=objectclasses.externalgroup,
                    ipauniqueid=[fuzzy_uuid],
                    dn=get_group_dn(group3),
                ),
            ),
        ),
        dict(
            desc='Convert posix group %r to support external membership' %
            (group2),
            command=('group_mod', [group2], dict(external=True)),
            expected=errors.PosixGroupViolation(),
        ),
        dict(
            desc='Convert external members group %r to posix' % (group3),
            command=('group_mod', [group3], dict(posix=True)),
            expected=errors.ExternalGroupViolation(),
        ),
        dict(
            desc='Add external member %r to %r' % (external_sid1, group3),
            command=('group_add_member', [group3],
                     dict(ipaexternalmember=external_sid1)),
            expected=lambda x, output: type(x) == errors.ValidationError or
            type(x) == errors.NotFound,
        ),
        dict(
            desc='Remove group %r with external membership' % (group3),
            command=('group_del', [group3], {}),
            expected=dict(
                result=dict(failed=u''),
                value=group3,
                summary=u'Deleted group "testgroup3"',
            ),
        ),

        ###############
        # member stuff:
        dict(
            desc='Add 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': get_group_dn(group1),
                    'member_group': (group2, ),
                    'gidnumber': [fuzzy_digits],
                    'cn': [group1],
                    'description': [u'New desc 1'],
                },
            ),
        ),
        dict(
            # FIXME: Shouldn't this raise a NotFound instead?
            desc='Try to add non-existent member to %r' % group1,
            command=('group_add_member', [group1], dict(group=u'notfound')),
            expected=dict(
                completed=0,
                failed=dict(member=dict(
                    group=[(u'notfound', u'no such entry')],
                    user=tuple(),
                ), ),
                result={
                    'dn': get_group_dn(group1),
                    'member_group': (group2, ),
                    'gidnumber': [fuzzy_digits],
                    'cn': [group1],
                    'description': [u'New desc 1'],
                },
            ),
        ),
        dict(
            desc='Remove member %r from %r' % (group2, group1),
            command=('group_remove_member', [group1], dict(group=group2)),
            expected=dict(
                completed=1,
                failed=dict(member=dict(
                    group=tuple(),
                    user=tuple(),
                ), ),
                result={
                    'dn': get_group_dn(group1),
                    'cn': [group1],
                    'gidnumber': [fuzzy_digits],
                    'description': [u'New desc 1'],
                },
            ),
        ),
        dict(
            # FIXME: Shouldn't this raise a NotFound instead?
            desc='Try to remove non-existent member from %r' % group1,
            command=('group_remove_member', [group1], dict(group=u'notfound')),
            expected=dict(
                completed=0,
                failed=dict(member=dict(
                    group=[(u'notfound', u'This entry is not a member')],
                    user=tuple(),
                ), ),
                result={
                    'dn': get_group_dn(group1),
                    'cn': [group1],
                    'gidnumber': [fuzzy_digits],
                    'description': [u'New desc 1'],
                },
            ),
        ),
        dict(desc='Rename %r' % group1,
             command=('group_mod', [group1],
                      dict(setattr=u'cn=%s' % renamedgroup1)),
             expected=dict(value=group1,
                           result=dict(
                               cn=[renamedgroup1],
                               description=[u'New desc 1'],
                               gidnumber=[fuzzy_digits],
                           ),
                           summary=u'Modified group "%s"' % group1)),
        dict(desc='Rename %r back' % renamedgroup1,
             command=('group_mod', [renamedgroup1],
                      dict(setattr=u'cn=%s' % group1)),
             expected=dict(value=renamedgroup1,
                           result=dict(
                               cn=[group1],
                               description=[u'New desc 1'],
                               gidnumber=[fuzzy_digits],
                           ),
                           summary=u'Modified group "%s"' % renamedgroup1)),

        ################
        # delete group1:
        dict(desc='Delete %r' % group1,
             command=('group_del', [group1], {}),
             expected=dict(
                 result=dict(failed=u''),
                 value=group1,
                 summary=u'Deleted group "testgroup1"',
             )),
        dict(
            desc='Try to delete non-existent %r' % group1,
            command=('group_del', [group1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % group1),
        ),
        dict(
            desc='Try to retrieve non-existent %r' % group1,
            command=('group_show', [group1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % group1),
        ),
        dict(
            desc='Try to update non-existent %r' % group1,
            command=('group_mod', [group1], dict(description=u'Foo')),
            expected=errors.NotFound(reason=u'%s: group not found' % group1),
        ),

        ################
        # delete group2:
        dict(desc='Delete %r' % group2,
             command=('group_del', [group2], {}),
             expected=dict(
                 result=dict(failed=u''),
                 value=group2,
                 summary=u'Deleted group "testgroup2"',
             )),
        dict(
            desc='Try to delete non-existent %r' % group2,
            command=('group_del', [group2], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % group2),
        ),
        dict(
            desc='Try to retrieve non-existent %r' % group2,
            command=('group_show', [group2], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % group2),
        ),
        dict(
            desc='Try to update non-existent %r' % group2,
            command=('group_mod', [group2], dict(description=u'Foo')),
            expected=errors.NotFound(reason=u'%s: group not found' % group2),
        ),
        dict(
            desc='Test an invalid group name %r' % invalidgroup1,
            command=('group_add', [invalidgroup1], dict(description=u'Test')),
            expected=errors.ValidationError(
                name='group_name',
                error=u'may only include letters, numbers, _, -, . and $'),
        ),

        # The assumption on these next 4 tests is that if we don't get a
        # validation error then the request was processed normally.
        dict(
            desc='Test that validation is disabled on mods',
            command=('group_mod', [invalidgroup1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' %
                                     invalidgroup1),
        ),
        dict(
            desc='Test that validation is disabled on deletes',
            command=('group_del', [invalidgroup1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' %
                                     invalidgroup1),
        ),
        dict(
            desc='Test that validation is disabled on show',
            command=('group_show', [invalidgroup1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' %
                                     invalidgroup1),
        ),

        ##### managed entry tests
        dict(
            desc='Create %r' % user1,
            command=('user_add', [], dict(givenname=u'Test', sn=u'User1')),
            expected=dict(
                value=user1,
                summary=u'Added user "%s"' % user1,
                result=dict(
                    gecos=[u'Test User1'],
                    givenname=[u'Test'],
                    homedirectory=[u'/home/%s' % user1],
                    krbprincipalname=[u'%s@%s' % (user1, api.env.realm)],
                    loginshell=[u'/bin/sh'],
                    objectclass=objectclasses.user,
                    sn=[u'User1'],
                    uid=[user1],
                    uidnumber=[fuzzy_digits],
                    gidnumber=[fuzzy_digits],
                    mail=[u'%s@%s' % (user1, api.env.domain)],
                    displayname=[u'Test User1'],
                    cn=[u'Test User1'],
                    initials=[u'TU'],
                    ipauniqueid=[fuzzy_uuid],
                    krbpwdpolicyreference=[
                        DN(('cn', 'global_policy'), ('cn', api.env.realm),
                           ('cn', 'kerberos'), api.env.basedn)
                    ],
                    mepmanagedentry=[get_group_dn(user1)],
                    memberof_group=[u'ipausers'],
                    dn=DN(('uid', user1), ('cn', 'users'), ('cn', 'accounts'),
                          api.env.basedn),
                    has_keytab=False,
                    has_password=False,
                ),
            ),
        ),
        dict(
            desc='Verify the managed group %r was created' % user1,
            command=('group_show', [user1], {}),
            expected=dict(
                value=user1,
                summary=None,
                result=dict(
                    cn=[user1],
                    description=[u'User private group for %s' % user1],
                    gidnumber=[fuzzy_digits],
                    dn=get_group_dn(user1),
                ),
            ),
        ),
        dict(
            desc='Verify that managed group %r can be found' % user1,
            command=('group_find', [], {
                'cn': user1,
                'private': True
            }),
            expected=dict(
                count=1,
                truncated=False,
                result=[
                    dict(
                        dn=get_group_dn(user1),
                        cn=[user1],
                        description=[u'User private group for %s' % user1],
                        gidnumber=[fuzzy_digits],
                    ),
                ],
                summary=u'1 group matched',
            ),
        ),
        dict(
            desc='Try to delete a managed group %r' % user1,
            command=('group_del', [user1], {}),
            expected=errors.ManagedGroupError(),
        ),
        dict(
            desc='Detach managed group %r' % user1,
            command=('group_detach', [user1], {}),
            expected=dict(
                result=True,
                value=user1,
                summary=u'Detached group "%s" from user "%s"' % (user1, user1),
            ),
        ),
        dict(desc='Now delete the unmanaged group %r' % user1,
             command=('group_del', [user1], {}),
             expected=dict(
                 result=dict(failed=u''),
                 value=user1,
                 summary=u'Deleted group "%s"' % user1,
             )),
        dict(
            desc='Verify that %r is really gone' % user1,
            command=('group_show', [user1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % user1),
        ),
        dict(
            desc='Delete %r' % user1,
            command=('user_del', [user1], {}),
            expected=dict(
                result=dict(failed=u''),
                summary=u'Deleted user "tuser1"',
                value=user1,
            ),
        ),
        dict(
            desc='Create %r without User Private Group' % user1,
            command=('user_add', [user1],
                     dict(givenname=u'Test',
                          sn=u'User1',
                          noprivate=True,
                          gidnumber=1000)),
            expected=dict(
                value=user1,
                summary=u'Added user "tuser1"',
                result=dict(
                    gecos=[u'Test User1'],
                    givenname=[u'Test'],
                    description=[],
                    homedirectory=[u'/home/tuser1'],
                    krbprincipalname=[u'tuser1@' + api.env.realm],
                    loginshell=[u'/bin/sh'],
                    objectclass=objectclasses.user_base,
                    sn=[u'User1'],
                    uid=[user1],
                    uidnumber=[fuzzy_digits],
                    gidnumber=[u'1000'],
                    mail=[u'%s@%s' % (user1, api.env.domain)],
                    displayname=[u'Test User1'],
                    cn=[u'Test User1'],
                    initials=[u'TU'],
                    ipauniqueid=[fuzzy_uuid],
                    dn=DN(('uid', 'tuser1'), ('cn', 'users'),
                          ('cn', 'accounts'), api.env.basedn),
                    krbpwdpolicyreference=[
                        DN(('cn', 'global_policy'), ('cn', api.env.realm),
                           ('cn', 'kerberos'), api.env.basedn)
                    ],
                    memberof_group=[u'ipausers'],
                    has_keytab=False,
                    has_password=False,
                ),
            ),
        ),
        dict(
            desc='Verify the managed group %r was not created' % user1,
            command=('group_show', [user1], {}),
            expected=errors.NotFound(reason=u'%s: group not found' % user1),
        ),
        dict(
            desc='Try to remove the admin user from the admins group',
            command=('group_remove_member', [u'admins'],
                     dict(user=[u'admin'])),
            expected=errors.LastMemberError(key=u'admin',
                                            label=u'group',
                                            container='admins'),
        ),
        dict(
            desc='Add %r to the admins group' % user1,
            command=('group_add_member', [u'admins'], dict(user=user1)),
            expected=dict(
                completed=1,
                failed=dict(member=dict(
                    group=tuple(),
                    user=tuple(),
                ), ),
                result={
                    'dn': get_group_dn('admins'),
                    'member_user': [u'admin', user1],
                    'gidnumber': [fuzzy_digits],
                    'cn': [u'admins'],
                    'description': [u'Account administrators group'],
                },
            ),
        ),
        dict(
            desc='Try to remove admin and %r from the admins group' % user1,
            command=('group_remove_member', [u'admins'],
                     dict(user=[u'admin', user1])),
            expected=errors.LastMemberError(key=u'admin',
                                            label=u'group',
                                            container='admins'),
        ),
        dict(
            desc='Try to delete the admins group',
            command=('group_del', [u'admins'], {}),
            expected=errors.ProtectedEntryError(label=u'group',
                                                key='admins',
                                                reason='privileged group'),
        ),
        dict(
            desc='Try to rename the admins group',
            command=('group_mod', [u'admins'], dict(rename=u'loosers')),
            expected=errors.ProtectedEntryError(label=u'group',
                                                key='admins',
                                                reason='Cannot be renamed'),
        ),
        dict(
            desc=
            'Try to modify the admins group to support external membership',
            command=('group_mod', [u'admins'], dict(external=True)),
            expected=errors.ProtectedEntryError(
                label=u'group',
                key='admins',
                reason='Cannot support external non-IPA members'),
        ),
        dict(
            desc='Try to delete the trust admins group',
            command=('group_del', [u'trust admins'], {}),
            expected=errors.ProtectedEntryError(label=u'group',
                                                key='trust admins',
                                                reason='privileged group'),
        ),
        dict(
            desc='Try to rename the trust admins group',
            command=('group_mod', [u'trust admins'], dict(rename=u'loosers')),
            expected=errors.ProtectedEntryError(label=u'group',
                                                key='trust admins',
                                                reason='Cannot be renamed'),
        ),
        dict(
            desc=
            'Try to modify the trust admins group to support external membership',
            command=('group_mod', [u'trust admins'], dict(external=True)),
            expected=errors.ProtectedEntryError(
                label=u'group',
                key='trust admins',
                reason='Cannot support external non-IPA members'),
        ),
        dict(
            desc='Delete %r' % user1,
            command=('user_del', [user1], {}),
            expected=dict(
                result=dict(failed=u''),
                summary=u'Deleted user "%s"' % user1,
                value=user1,
            ),
        ),
    ]