コード例 #1
0
    def _enable_sid(self, ldap, options):
        # the user must have the Replication Administrators privilege
        privilege = 'Replication Administrators'
        if not principal_has_privilege(self.api, context.principal, privilege):
            raise errors.ACIError(
                info=_("not allowed to enable SID generation"))

        # NetBIOS name is either taken from options or generated
        try:
            netbios_name, reset_netbios_name = set_and_check_netbios_name(
                options.get('netbios_name', None), True, self.api)
        except ScriptError:
            raise errors.ValidationError(
                name="NetBIOS name",
                error=_('Up to 15 characters and only uppercase ASCII letters'
                        ', digits and dashes are allowed. Empty string is '
                        'not allowed.'))

        _ret = 0
        _stdout = ''
        _stderr = ''

        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

        method_options = []
        if options.get('add_sids', False):
            method_options.extend(["--add-sids"])
        method_options.extend(["--netbios-name", netbios_name])
        if reset_netbios_name:
            method_options.append("--reset-netbios-name")
        # Dbus definition expects up to 10 arguments
        method_options.extend([''] * (10 - len(method_options)))

        try:
            bus = dbus.SystemBus()
            obj = bus.get_object('org.freeipa.server',
                                 '/',
                                 follow_name_owner_changes=True)
            server = dbus.Interface(obj, 'org.freeipa.server')
            _ret, _stdout, _stderr = server.config_enable_sid(*method_options)
        except dbus.DBusException as e:
            logger.error(
                'Failed to call org.freeipa.server.config_enable_sid.'
                'DBus exception is %s', str(e))
            raise errors.ExecutionError(message=_('Failed to call DBus'))

        # The oddjob restarts dirsrv, we need to re-establish the conn
        if self.api.Backend.ldap2.isconnected():
            self.api.Backend.ldap2.disconnect()
        self.api.Backend.ldap2.connect(ccache=context.ccache_name)

        if _ret != 0:
            logger.error("Helper config_enable_sid return code is %d", _ret)
            raise errors.ExecutionError(
                message=_('Configuration of SID failed. '
                          'See details in the error log'))
コード例 #2
0
    def new_session_id(self, max_retries=5):
        '''
        Returns a new *unique* session id. See `generate_session_id()`
        for how the session id's are formulated.

        The scope of the uniqueness of the id is limited to id's
        generated by this instance of the `SessionManager` and session
        id's currently stored in the memcache instance.

        :parameters:
          max_retries
            Maximum number of attempts to produce a unique id.
        :returns:
          Unique session id as a string.
        '''
        n_retries = 0
        while n_retries < max_retries:
            session_id = super(MemcacheSessionManager,
                               self).new_session_id(max_retries)
            session_data = self.get_session_data(session_id)
            if session_data is None:
                break
            n_retries += 1
        if n_retries >= max_retries:
            self.error(
                'could not allocate unique new session_id, %d retries exhausted',
                n_retries)
            raise errors.ExecutionError(
                message=_('could not allocate unique new session_id'))
        return session_id
コード例 #3
0
    def new_session_id(self, max_retries=5):
        '''
        Returns a new *unique* session id. See `generate_session_id()`
        for how the session id's are formulated.

        The scope of the uniqueness of the id is limited to id's
        generated by this instance of the `SessionManager`.

        :parameters:
          max_retries
            Maximum number of attempts to produce a unique id.
        :returns:
          Unique session id as a string.
        '''
        n_retries = 0
        while n_retries < max_retries:
            session_id = self.generate_session_id()
            if not session_id in self.generated_session_ids:
                break
            n_retries += 1
        if n_retries >= max_retries:
            self.error(
                'could not allocate unique new session_id, %d retries exhausted',
                n_retries)
            raise errors.ExecutionError(
                message=_('could not allocate unique new session_id'))
        self.generated_session_ids.add(session_id)
        return session_id
コード例 #4
0
    def _preserve_user(self, pkey, delete_container, **options):
        assert isinstance(delete_container, DN)

        dn = self.obj.get_either_dn(pkey, **options)
        delete_dn = DN(dn[0], delete_container)
        ldap = self.obj.backend
        logger.debug("preserve move %s -> %s", dn, delete_dn)

        if dn.endswith(delete_container):
            raise errors.ExecutionError(
                _('%s: user is already preserved' % pkey)
            )
        # Check that this value is a Active user
        try:
            original_entry_attrs = self._exc_wrapper(
                pkey, options, ldap.get_entry)(dn, ['dn'])
        except errors.NotFound:
            raise self.obj.handle_not_found(pkey)

        for callback in self.get_callbacks('pre'):
            dn = callback(self, ldap, dn, pkey, **options)
            assert isinstance(dn, DN)

        # start to move the entry to Delete container
        self._exc_wrapper(pkey, options, ldap.move_entry)(dn, delete_dn,
                                                          del_old=True)

        # Then clear the credential attributes
        attrs_to_clear = ['krbPrincipalKey', 'krbLastPwdChange',
                          'krbPasswordExpiration', 'userPassword']

        entry_attrs = self._exc_wrapper(pkey, options, ldap.get_entry)(
            delete_dn, attrs_to_clear)

        clearedCredential = False
        for attr in attrs_to_clear:
            if attr.lower() in entry_attrs:
                del entry_attrs[attr]
                clearedCredential = True
        if clearedCredential:
            self._exc_wrapper(pkey, options, ldap.update_entry)(entry_attrs)

        # Then restore some original entry attributes
        attrs_to_restore = ['secretary', 'managedby', 'manager', 'ipauniqueid',
                            'uidnumber', 'gidnumber', 'passwordHistory']

        entry_attrs = self._exc_wrapper(
            pkey, options, ldap.get_entry)(delete_dn, attrs_to_restore)

        restoreAttr = False
        for attr in attrs_to_restore:
            if ((attr.lower() in original_entry_attrs) and
                    not (attr.lower() in entry_attrs)):
                restoreAttr = True
                entry_attrs[attr.lower()] = original_entry_attrs[attr.lower()]
        if restoreAttr:
            self._exc_wrapper(pkey, options, ldap.update_entry)(entry_attrs)
コード例 #5
0
 def fail(self, *args, **kwargs):
     assert args == (1, 2)
     assert kwargs == dict(a=1, b=2)
     raise errors.ExecutionError('failure')
コード例 #6
0
 def fail(self, *args, **kwargs):
     """Raise an error"""
     raise errors.ExecutionError('failure')
コード例 #7
0
ファイル: idrange.py プロジェクト: zz22394/freeipa
    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
                     **options):
        assert isinstance(dn, DN)
        attrs_list.append('objectclass')

        try:
            old_attrs = ldap.get_entry(dn, ['*'])
        except errors.NotFound:
            raise self.obj.handle_not_found(*keys)

        if old_attrs['iparangetype'][0] == 'ipa-local':
            raise errors.ExecutionError(
                message=_('This command can not be used to change ID '
                          'allocation for local IPA domain. Run '
                          '`ipa help idrange` for more information'))

        is_set = lambda x: (x in entry_attrs) and (entry_attrs[x] is not None)
        in_updated_attrs = lambda x:\
            (x in entry_attrs and entry_attrs[x] is not None) or\
            (x not in entry_attrs and x in old_attrs
                and old_attrs[x] is not None)

        # This needs to stay in options since there is no
        # ipanttrusteddomainname attribute in LDAP
        if 'ipanttrusteddomainname' in options:
            if is_set('ipanttrusteddomainsid'):
                raise errors.ValidationError(
                    name='ID Range setup',
                    error=_('Options dom-sid and dom-name '
                            'cannot be used together'))

            sid = self.obj.get_trusted_domain_sid_from_name(
                options['ipanttrusteddomainname'])

            # we translate the name into sid so further validation can rely
            # on ipanttrusteddomainsid attribute only
            if sid is not None:
                entry_attrs['ipanttrusteddomainsid'] = sid
            else:
                raise errors.ValidationError(
                    name='ID Range setup',
                    error=_('SID for the specified trusted domain name could '
                            'not be found. Please specify the SID directly '
                            'using dom-sid option.'))

        if in_updated_attrs('ipanttrusteddomainsid'):
            if in_updated_attrs('ipasecondarybaserid'):
                raise errors.ValidationError(
                    name='ID Range setup',
                    error=_('Options dom-sid and secondary-rid-base cannot '
                            'be used together'))
            range_type = old_attrs['iparangetype'][0]
            if range_type == u'ipa-ad-trust':
                if not in_updated_attrs('ipabaserid'):
                    raise errors.ValidationError(
                        name='ID Range setup',
                        error=_('Options dom-sid and rid-base must '
                                'be used together'))
            elif (range_type == u'ipa-ad-trust-posix'
                  and 'ipabaserid' in entry_attrs):
                if entry_attrs['ipabaserid'] is None:
                    entry_attrs['ipabaserid'] = 0
                elif entry_attrs['ipabaserid'] != 0:
                    raise errors.ValidationError(
                        name='ID Range setup',
                        error=_('Option rid-base must not be used when IPA '
                                'range type is ipa-ad-trust-posix'))

            if is_set('ipanttrusteddomainsid'):
                # Validate SID as the one of trusted domains
                # perform this check only if the attribute was changed
                self.obj.validate_trusted_domain_sid(
                    entry_attrs['ipanttrusteddomainsid'])

            # Add trusted AD domain range object class, if it wasn't there
            if not 'ipatrustedaddomainrange' in old_attrs['objectclass']:
                entry_attrs['objectclass'].append('ipatrustedaddomainrange')

        else:
            # secondary base rid must be set if and only if base rid is set
            if in_updated_attrs('ipasecondarybaserid') !=\
                in_updated_attrs('ipabaserid'):
                raise errors.ValidationError(
                    name='ID Range setup',
                    error=_('Options secondary-rid-base and rid-base must '
                            'be used together'))

        # ensure that primary and secondary rid ranges do not overlap
        if all(
                in_updated_attrs(base)
                for base in ('ipabaserid', 'ipasecondarybaserid')):

            # make sure we are working with updated attributes
            rid_range_attributes = ('ipabaserid', 'ipasecondarybaserid',
                                    'ipaidrangesize')
            updated_values = dict()

            for attr in rid_range_attributes:
                if is_set(attr):
                    updated_values[attr] = entry_attrs[attr]
                else:
                    updated_values[attr] = int(old_attrs[attr][0])

            if self.obj.are_rid_ranges_overlapping(
                    updated_values['ipabaserid'],
                    updated_values['ipasecondarybaserid'],
                    updated_values['ipaidrangesize']):
                raise errors.ValidationError(
                    name='ID Range setup',
                    error=_("Primary RID range and secondary RID range"
                            " cannot overlap"))

        # check whether ids are in modified range
        old_base_id = int(old_attrs.get('ipabaseid', [0])[0])
        old_range_size = int(old_attrs.get('ipaidrangesize', [0])[0])
        new_base_id = entry_attrs.get('ipabaseid')

        if new_base_id is not None:
            new_base_id = int(new_base_id)

        new_range_size = entry_attrs.get('ipaidrangesize')

        if new_range_size is not None:
            new_range_size = int(new_range_size)

        self.obj.check_ids_in_modified_range(old_base_id, old_range_size,
                                             new_base_id, new_range_size)

        return dn
コード例 #8
0
ファイル: test_range_plugin.py プロジェクト: zavarat/freeipa
class test_range(Declarative):
    mockldap = None

    @pytest.fixture(autouse=True, scope="class")
    def range_setup(self, request, declarative_setup):
        cls = request.cls

        def fin():
            cls.mockldap = MockLDAP()

            cls.mockldap.del_entry(domain2_dn)
            cls.mockldap.del_entry(domain3_dn)
            cls.mockldap.del_entry(domain4_dn)
            cls.mockldap.del_entry(domain5_dn)
            cls.mockldap.del_entry(domain6_dn)
            cls.mockldap.del_entry(domain7_dn)

            cls.mockldap.del_entry(domain1range1_dn)
            cls.mockldap.del_entry(domain2range1_dn)
            cls.mockldap.del_entry(domain2range2_dn)
            cls.mockldap.del_entry(domain3range1_dn)
            cls.mockldap.del_entry(domain3range2_dn)
            cls.mockldap.del_entry(domain4range1_dn)
            cls.mockldap.del_entry(domain5range1_dn)
            cls.mockldap.del_entry(domain5range2_dn)
            cls.mockldap.del_entry(domain6range1_dn)
            cls.mockldap.del_entry(domain7range1_dn)
            cls.mockldap.del_entry(trust_container_dn)
            cls.mockldap.del_entry(trust_local_dn)
            cls.mockldap.del_entry(smb_cont_dn)
            cls.mockldap.unbind()

        fin()
        cls.mockldap = MockLDAP()
        cls.mockldap.add_entry(trust_container_dn, trust_container_add)
        cls.mockldap.add_entry(smb_cont_dn, smb_cont_add)
        cls.mockldap.add_entry(trust_local_dn, trust_local_add)

        cls.mockldap.add_entry(domain2_dn, domain2_add)
        cls.mockldap.add_entry(domain3_dn, domain3_add)
        cls.mockldap.add_entry(domain4_dn, domain4_add)
        cls.mockldap.add_entry(domain5_dn, domain5_add)
        cls.mockldap.add_entry(domain6_dn, domain6_add)
        cls.mockldap.add_entry(domain7_dn, domain7_add)

        cls.mockldap.add_entry(domain1range1_dn, domain1range1_add)
        cls.mockldap.add_entry(domain2range1_dn, domain2range1_add)
        cls.mockldap.add_entry(domain2range2_dn, domain2range2_add)
        cls.mockldap.add_entry(domain3range1_dn, domain3range1_add)
        cls.mockldap.add_entry(domain3range2_dn, domain3range2_add)
        cls.mockldap.add_entry(domain4range1_dn, domain4range1_add)
        cls.mockldap.add_entry(domain5range1_dn, domain5range1_add)
        cls.mockldap.add_entry(domain5range2_dn, domain5range2_add)
        cls.mockldap.add_entry(domain6range1_dn, domain6range1_add)
        cls.mockldap.unbind()

        request.addfinalizer(fin)

    cleanup_commands = [
        ('idrange_del', [
            testrange1, testrange2, testrange3, testrange4, testrange5,
            testrange6, testrange7, testrange8, testrange9
        ], {
            'continue': True
        }),
        ('user_del', [user1], {}),
        ('group_del', [group1], {}),
    ]

    # Basic tests.

    tests = [
        dict(
            desc='Create ID range %r' % (testrange1),
            command=('idrange_add', [testrange1],
                     dict(ipabaseid=testrange1_base_id,
                          ipaidrangesize=testrange1_size,
                          ipabaserid=testrange1_base_rid,
                          ipasecondarybaserid=testrange1_secondary_base_rid)),
            expected=dict(
                result=dict(
                    dn=DN(('cn', testrange1), ('cn', 'ranges'), ('cn', 'etc'),
                          api.env.basedn),
                    cn=[testrange1],
                    objectclass=[u'ipaIDrange', u'ipadomainidrange'],
                    ipabaseid=[unicode(testrange1_base_id)],
                    ipabaserid=[unicode(testrange1_base_rid)],
                    ipasecondarybaserid=[
                        unicode(testrange1_secondary_base_rid)
                    ],
                    ipaidrangesize=[unicode(testrange1_size)],
                    iparangetyperaw=[u'ipa-local'],
                    iparangetype=[u'local domain range'],
                ),
                value=testrange1,
                summary=u'Added ID range "%s"' % (testrange1),
            ),
        ),
        dict(
            desc='Retrieve ID range %r' % (testrange1),
            command=('idrange_show', [testrange1], dict()),
            expected=dict(
                result=dict(
                    dn=DN(('cn', testrange1), ('cn', 'ranges'), ('cn', 'etc'),
                          api.env.basedn),
                    cn=[testrange1],
                    ipabaseid=[unicode(testrange1_base_id)],
                    ipabaserid=[unicode(testrange1_base_rid)],
                    ipasecondarybaserid=[
                        unicode(testrange1_secondary_base_rid)
                    ],
                    ipaidrangesize=[unicode(testrange1_size)],
                    iparangetyperaw=[u'ipa-local'],
                    iparangetype=[u'local domain range'],
                ),
                value=testrange1,
                summary=None,
            ),
        ),

        # Checks for modifications leaving objects outside of the range.
        dict(
            desc='Create user %r in ID range %r' % (user1, testrange1),
            command=('user_add', [user1],
                     dict(givenname=u'Test', sn=u'User1',
                          uidnumber=user1_uid)),
            expected=dict(
                value=user1,
                summary=u'Added user "%s"' % user1,
                result=get_user_result(
                    user1,
                    u'Test',
                    u'User1',
                    'add',
                    uidnumber=[unicode(user1_uid)],
                    gidnumber=[unicode(user1_uid)],
                ),
            ),
        ),
        dict(
            desc='Create group %r in ID range %r' % (group1, testrange1),
            command=('group_add', [group1],
                     dict(description=u'Test desc 1', gidnumber=group1_gid)),
            expected=dict(
                value=group1,
                summary=u'Added group "%s"' % group1,
                result=dict(
                    cn=[group1],
                    description=[u'Test desc 1'],
                    gidnumber=[unicode(group1_gid)],
                    objectclass=objectclasses.group + [u'posixgroup'],
                    ipauniqueid=[fuzzy_uuid],
                    dn=DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'),
                          api.env.basedn),
                ),
            ),
        ),
        dict(
            desc='Try to modify ID range %r to get out bounds object #1' %
            (testrange1),
            command=('idrange_mod', [testrange1],
                     dict(ipabaseid=user1_uid + 1)),
            expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR),
        ),
        dict(
            desc='Try to modify ID range %r to get out bounds object #2' %
            (testrange1),
            command=('idrange_mod', [testrange1], dict(ipaidrangesize=100)),
            expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR),
        ),
        dict(
            desc='Try to modify ID range %r to get out bounds object #3' %
            (testrange1),
            command=('idrange_mod', [testrange1],
                     dict(ipabaseid=100, ipaidrangesize=100)),
            expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR),
        ),
        dict(desc='Modify ID range %r' % (testrange1),
             command=('idrange_mod', [testrange1], dict(ipaidrangesize=90000)),
             expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR)),
        dict(
            desc='Try to delete ID range %r with active IDs inside it' %
            testrange1,
            command=('idrange_del', [testrange1], {}),
            expected=errors.ValidationError(
                name='ipabaseid,ipaidrangesize',
                error=u'range modification leaving objects with ID out of the'
                u' defined range is not allowed'),
        ),
        dict(
            desc='Delete user %r' % user1,
            command=('user_del', [user1], {}),
            expected=dict(
                result=dict(failed=[]),
                value=[user1],
                summary=u'Deleted user "%s"' % user1,
            ),
        ),
        dict(
            desc='Delete group %r' % group1,
            command=('group_del', [group1], {}),
            expected=dict(
                result=dict(failed=[]),
                value=[group1],
                summary=u'Deleted group "%s"' % group1,
            ),
        ),

        # Framework validation: mod local idrange with auto-private-groups
        # is prohibited
        dict(desc=('Try to modify local range %r with --auto-private-groups' %
                   (testrange1)),
             command=('idrange_mod', [testrange1],
                      dict(ipaautoprivategroups='true')),
             expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR)),
        dict(
            desc='Delete ID range %r' % testrange1,
            command=('idrange_del', [testrange1], {}),
            expected=dict(
                result=dict(failed=[]),
                value=[testrange1],
                summary=u'Deleted ID range "%s"' % testrange1,
            ),
        ),

        # Tests for overlapping local ranges.
        dict(
            desc='Create ID range %r' % (testrange2),
            command=('idrange_add', [testrange2],
                     dict(ipabaseid=testrange2_base_id,
                          ipaidrangesize=testrange2_size,
                          ipabaserid=testrange2_base_rid,
                          ipasecondarybaserid=testrange2_secondary_base_rid)),
            expected=dict(
                result=dict(
                    dn=DN(('cn', testrange2), ('cn', 'ranges'), ('cn', 'etc'),
                          api.env.basedn),
                    cn=[testrange2],
                    objectclass=[u'ipaIDrange', u'ipadomainidrange'],
                    ipabaseid=[unicode(testrange2_base_id)],
                    ipabaserid=[unicode(testrange2_base_rid)],
                    ipasecondarybaserid=[
                        unicode(testrange2_secondary_base_rid)
                    ],
                    ipaidrangesize=[unicode(testrange2_size)],
                    iparangetyperaw=[u'ipa-local'],
                    iparangetype=[u'local domain range'],
                ),
                value=testrange2,
                summary=u'Added ID range "%s"' % (testrange2),
            ),
        ),
        dict(
            desc=
            'Try to modify ID range %r so that its rid ranges are overlapping themselves'
            % (testrange2),
            command=('idrange_mod', [testrange2],
                     dict(ipabaserid=(testrange2_secondary_base_rid))),
            expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR),
        ),
        dict(
            desc='Try to create ID range %r with overlapping rid range' %
            (testrange3),
            command=('idrange_add', [testrange3],
                     dict(ipabaseid=testrange3_base_id,
                          ipaidrangesize=testrange3_size,
                          ipabaserid=testrange3_base_rid,
                          ipasecondarybaserid=testrange3_secondary_base_rid)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info=
                'New primary rid range overlaps with existing primary rid range.'
            ),
        ),
        dict(
            desc=
            'Try to create ID range %r with overlapping secondary rid range' %
            (testrange4),
            command=('idrange_add', [testrange4],
                     dict(ipabaseid=testrange4_base_id,
                          ipaidrangesize=testrange4_size,
                          ipabaserid=testrange4_base_rid,
                          ipasecondarybaserid=testrange4_secondary_base_rid)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info=
                'New secondary rid range overlaps with existing secondary rid range.'
            ),
        ),
        dict(
            desc=
            'Try to create ID range %r with primary range overlapping secondary rid range'
            % (testrange5),
            command=('idrange_add', [testrange5],
                     dict(ipabaseid=testrange5_base_id,
                          ipaidrangesize=testrange5_size,
                          ipabaserid=testrange5_base_rid,
                          ipasecondarybaserid=testrange5_secondary_base_rid)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info=
                'New primary rid range overlaps with existing secondary rid range.'
            ),
        ),
        dict(
            desc='Try to create ID range %r with overlapping id range' %
            (testrange6),
            command=('idrange_add', [testrange6],
                     dict(ipabaseid=testrange6_base_id,
                          ipaidrangesize=testrange6_size,
                          ipabaserid=testrange6_base_rid,
                          ipasecondarybaserid=testrange6_secondary_base_rid)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info='New base range overlaps with existing base range.'),
        ),
        dict(
            desc=
            'Try to create ID range %r with rid ranges overlapping themselves'
            % (testrange7),
            command=('idrange_add', [testrange7],
                     dict(ipabaseid=testrange7_base_id,
                          ipaidrangesize=testrange7_size,
                          ipabaserid=testrange7_base_rid,
                          ipasecondarybaserid=testrange7_secondary_base_rid)),
            expected=errors.ValidationError(
                name='ID Range setup',
                error='Primary RID range and secondary RID range cannot overlap'
            ),
        ),
        dict(
            desc='Delete ID range %r' % testrange2,
            command=('idrange_del', [testrange2], {}),
            expected=dict(
                result=dict(failed=[]),
                value=[testrange2],
                summary=u'Deleted ID range "%s"' % testrange2,
            ),
        ),

        # Testing framework validation: --dom-sid/--dom-name and secondary RID
        #                               base cannot be used together
        dict(
            desc='Create ID range %r' % (testrange8),
            command=('idrange_add', [testrange8],
                     dict(ipabaseid=testrange8_base_id,
                          ipaidrangesize=testrange8_size,
                          ipabaserid=testrange8_base_rid,
                          ipasecondarybaserid=testrange8_secondary_base_rid,
                          ipanttrusteddomainsid=domain1_sid)),
            expected=errors.ValidationError(
                name='ID Range setup',
                error='Options dom-sid/dom-name and '
                'secondary-rid-base cannot be used together'),
        ),

        # Testing framework validation: --auto-private-groups is prohibited
        # with ipa-local range
        dict(
            desc='Local ID range %r with auto-private-groups' % (testrange8),
            command=('idrange_add', [testrange8],
                     dict(ipabaseid=testrange8_base_id,
                          ipaidrangesize=testrange8_size,
                          ipaautoprivategroups='true')),
            expected=errors.ValidationError(
                name='ID Range setup',
                error='IPA Range type must be one of ipa-ad-trust '
                'or ipa-ad-trust-posix when '
                'auto-private-groups is specified'),
        ),

        # Testing framework validation: --rid-base is prohibited with ipa-ad-posix
        dict(
            desc='Try to create ipa-ad-trust-posix ID range %r with base RID' %
            (domain7range1),
            command=('idrange_add', [domain7range1],
                     dict(ipabaseid=domain7range1_base_id,
                          ipaidrangesize=domain7range1_size,
                          ipabaserid=domain7range1_base_rid,
                          iparangetype=domain7range1_type,
                          ipanttrusteddomainsid=domain7_sid)),
            expected=errors.ValidationError(
                name='ID Range setup',
                error='Option rid-base must not be used when IPA range '
                'type is ipa-ad-trust-posix'),
        ),

        # Testing framework validation: --auto-private-groups can only be
        # one of true, false, hybrid
        dict(
            desc=('Create ID range %r with bogus --auto-private-groups' %
                  (domain7range1)),
            command=('idrange_add', [domain7range1],
                     dict(ipabaseid=domain7range1_base_id,
                          ipaidrangesize=domain7range1_size,
                          iparangetype=domain7range1_type,
                          ipanttrusteddomainsid=domain7_sid,
                          ipaautoprivategroups='bogus')),
            expected=errors.ValidationError(
                name='auto_private_groups',
                error="must be one of 'true', 'false', 'hybrid'"),
        ),
        dict(
            desc='Create ID range %r' % (domain7range1),
            command=('idrange_add', [domain7range1],
                     dict(ipabaseid=domain7range1_base_id,
                          ipaidrangesize=domain7range1_size,
                          iparangetype=domain7range1_type,
                          ipanttrusteddomainsid=domain7_sid)),
            expected=dict(
                result=dict(
                    dn=unicode(domain7range1_dn),
                    cn=[domain7range1],
                    objectclass=[u'ipaIDrange', u'ipatrustedaddomainrange'],
                    ipabaseid=[unicode(domain7range1_base_id)],
                    ipaidrangesize=[unicode(domain7range1_size)],
                    ipanttrusteddomainsid=[unicode(domain7_sid)],
                    iparangetyperaw=[u'ipa-ad-trust-posix'],
                    iparangetype=[
                        u'Active Directory trust range with POSIX attributes'
                    ],
                ),
                value=unicode(domain7range1),
                summary=u'Added ID range "%s"' % (domain7range1),
            ),
        ),
        dict(
            desc='Try to modify ipa-ad-trust-posix ID range %r with base RID' %
            (domain7range1),
            command=('idrange_mod', [domain7range1],
                     dict(ipabaserid=domain7range1_base_rid)),
            expected=errors.ValidationError(
                name='ID Range setup',
                error='Option rid-base must not be used when IPA range '
                'type is ipa-ad-trust-posix'),
        ),

        # Testing prohibition of deletion of ranges belonging to active
        # trusted domains.
        dict(
            desc='Delete non-active AD trusted range %r' % domain1range1,
            command=('idrange_del', [domain1range1], {}),
            expected=dict(
                result=dict(failed=[]),
                value=[domain1range1],
                summary=u'Deleted ID range "%s"' % domain1range1,
            ),
        ),
        dict(
            desc='Try to delete active AD trusted range %r' % domain2range1,
            command=('idrange_del', [domain2range1], {}),
            expected=errors.DependentEntry(label='Active Trust domain',
                                           key=domain2range1,
                                           dependent=domain2),
        ),

        # Testing base range overlaps for ranges of different types and
        # different domains

        # - Base range overlaps

        # 1. ipa-ad-trust-posix type ranges from the same forest can overlap
        # on base ranges, use domain3range1 and domain3range2
        dict(
            desc=('Modify ipa-ad-trust-posix range %r to overlap on base range'
                  ' with posix range from the same domain' % (domain3range2)),
            command=('idrange_mod', [domain3range2],
                     dict(ipabaseid=domain3range1_base_id)),
            expected=dict(
                messages=(messages.ServiceRestartRequired(
                    service=services.knownservices['sssd'].systemd_name,
                    server=domain3range2).to_dict(), ),
                result=dict(
                    cn=[domain3range2],
                    ipabaseid=[unicode(domain3range1_base_id)],
                    ipaidrangesize=[unicode(domain3range2_size)],
                    ipanttrusteddomainsid=[unicode(domain3_sid)],
                    iparangetyperaw=[u'ipa-ad-trust-posix'],
                    iparangetype=[
                        u'Active Directory trust range with POSIX '
                        'attributes'
                    ],
                ),
                value=domain3range2,
                summary=u'Modified ID range "%s"' % (domain3range2),
            ),
        ),

        # 2. ipa-ad-trust-posix type ranges from different forests cannot
        # overlap on base ranges, use domain3range1 and domain4range1
        dict(
            desc=('Modify ipa-ad-trust-posix range %r to overlap on base range'
                  ' with posix range from different domain' % (domain3range1)),
            command=('idrange_mod', [domain3range1],
                     dict(ipabaseid=domain4range1_base_id)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info='New base range overlaps with existing base range.'),
        ),

        # 3. ipa-ad-trust ranges from same forest cannot overlap on base ranges,
        # use domain5range1 and domain5range2
        dict(
            desc=('Modify ipa-ad-trust range %r to overlap on base range'
                  ' with posix range from the same domain' % (domain5range1)),
            command=('idrange_mod', [domain5range1],
                     dict(ipabaseid=domain5range2_base_id)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info='New base range overlaps with existing base range.'),
        ),

        # 4. ipa-ad-trust ranges from different forests cannot overlap on base
        # ranges, use domain5range1 and domain6range1
        dict(
            desc=('Modify ipa-ad-trust range %r to overlap on base range'
                  ' with posix range from different domain' % (domain5range1)),
            command=('idrange_mod', [domain5range1],
                     dict(ipabaseid=domain6range1_base_id)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info='New base range overlaps with existing base range.'),
        ),

        # - RID range overlaps

        # 1. Overlaps on base RID ranges are allowed for ranges from different
        # domains, use domain2range1 and domain5range1
        dict(
            desc=('Modify ipa-ad-trust range %r to overlap on base RID'
                  ' range with nonposix range from different domain' %
                  (domain2range1)),
            command=('idrange_mod', [domain2range1],
                     dict(ipabaserid=domain5range1_base_rid)),
            expected=dict(
                messages=(messages.ServiceRestartRequired(
                    service=services.knownservices['sssd'].systemd_name,
                    server=domain2range1).to_dict(), ),
                result=dict(
                    cn=[domain2range1],
                    ipabaseid=[unicode(domain2range1_base_id)],
                    ipabaserid=[unicode(domain5range1_base_rid)],
                    ipaidrangesize=[unicode(domain2range1_size)],
                    ipanttrusteddomainsid=[unicode(domain2_sid)],
                    iparangetyperaw=[u'ipa-ad-trust'],
                    iparangetype=[u'Active Directory domain range'],
                ),
                value=domain2range1,
                summary=u'Modified ID range "%s"' % (domain2range1),
            ),
        ),

        # 2. ipa-ad-trust ranges from the same forest cannot overlap on base
        # RID ranges, use domain5range1 and domain5range2
        dict(
            desc=('Modify ipa-ad-trust range %r to overlap on base RID range'
                  ' with range from the same domain' % (domain2range1)),
            command=('idrange_mod', [domain2range1],
                     dict(ipabaserid=domain2range2_base_rid)),
            expected=errors.DatabaseError(
                desc='Constraint violation',
                info='New primary rid range overlaps with existing primary rid '
                'range.'),
        ),
        dict(
            desc=('Modify ipa-ad-trust range %r with --auto-private-groups='
                  'true' % (domain2range1)),
            command=('idrange_mod', [domain2range1],
                     dict(ipaautoprivategroups='true')),
            expected=dict(
                messages=(messages.ServiceRestartRequired(
                    service=services.knownservices['sssd'].systemd_name,
                    server=domain2range1).to_dict(), ),
                result=dict(
                    cn=[domain2range1],
                    ipabaseid=[unicode(domain2range1_base_id)],
                    ipabaserid=[unicode(domain5range1_base_rid)],
                    ipaidrangesize=[unicode(domain2range1_size)],
                    ipanttrusteddomainsid=[unicode(domain2_sid)],
                    iparangetyperaw=[u'ipa-ad-trust'],
                    ipaautoprivategroups=[u'true'],
                    iparangetype=[u'Active Directory domain range'],
                ),
                value=domain2range1,
                summary=u'Modified ID range "%s"' % (domain2range1),
            ),
        ),
        dict(
            desc=('Modify ipa-ad-trust range %r with --auto-private-groups='
                  'false' % (domain2range1)),
            command=('idrange_mod', [domain2range1],
                     dict(ipaautoprivategroups='false')),
            expected=dict(
                messages=(messages.ServiceRestartRequired(
                    service=services.knownservices['sssd'].systemd_name,
                    server=domain2range1).to_dict(), ),
                result=dict(
                    cn=[domain2range1],
                    ipabaseid=[unicode(domain2range1_base_id)],
                    ipabaserid=[unicode(domain5range1_base_rid)],
                    ipaidrangesize=[unicode(domain2range1_size)],
                    ipanttrusteddomainsid=[unicode(domain2_sid)],
                    iparangetyperaw=[u'ipa-ad-trust'],
                    ipaautoprivategroups=[u'false'],
                    iparangetype=[u'Active Directory domain range'],
                ),
                value=domain2range1,
                summary=u'Modified ID range "%s"' % (domain2range1),
            ),
        ),
        dict(
            desc=('Modify ipa-ad-trust range %r with --auto-private-groups='
                  'hybrid' % (domain2range1)),
            command=('idrange_mod', [domain2range1],
                     dict(ipaautoprivategroups='hybrid')),
            expected=dict(
                messages=(messages.ServiceRestartRequired(
                    service=services.knownservices['sssd'].systemd_name,
                    server=domain2range1).to_dict(), ),
                result=dict(
                    cn=[domain2range1],
                    ipabaseid=[unicode(domain2range1_base_id)],
                    ipabaserid=[unicode(domain5range1_base_rid)],
                    ipaidrangesize=[unicode(domain2range1_size)],
                    ipanttrusteddomainsid=[unicode(domain2_sid)],
                    iparangetyperaw=[u'ipa-ad-trust'],
                    ipaautoprivategroups=[u'hybrid'],
                    iparangetype=[u'Active Directory domain range'],
                ),
                value=domain2range1,
                summary=u'Modified ID range "%s"' % (domain2range1),
            ),
        ),
        dict(
            desc=('Modify ipa-ad-trust range %r with --auto-private-groups='
                  '<empty>' % (domain2range1)),
            command=('idrange_mod', [domain2range1],
                     dict(ipaautoprivategroups='')),
            expected=dict(
                messages=(messages.ServiceRestartRequired(
                    service=services.knownservices['sssd'].systemd_name,
                    server=domain2range1).to_dict(), ),
                result=dict(
                    cn=[domain2range1],
                    ipabaseid=[unicode(domain2range1_base_id)],
                    ipabaserid=[unicode(domain5range1_base_rid)],
                    ipaidrangesize=[unicode(domain2range1_size)],
                    ipanttrusteddomainsid=[unicode(domain2_sid)],
                    iparangetyperaw=[u'ipa-ad-trust'],
                    iparangetype=[u'Active Directory domain range'],
                ),
                value=domain2range1,
                summary=u'Modified ID range "%s"' % (domain2range1),
            ),
        ),

        # Test for bug 6404
        # if dom-name is empty, add should not fail
        dict(
            desc='Create ID range %r' % (testrange9),
            command=('idrange_add', [testrange9],
                     dict(ipanttrusteddomainname=None,
                          ipabaseid=testrange9_base_id,
                          ipaidrangesize=testrange9_size,
                          ipabaserid=testrange9_base_rid,
                          ipasecondarybaserid=testrange9_secondary_base_rid)),
            expected=dict(
                result=dict(
                    dn=DN(('cn', testrange9), ('cn', 'ranges'), ('cn', 'etc'),
                          api.env.basedn),
                    cn=[testrange9],
                    objectclass=[u'ipaIDrange', u'ipadomainidrange'],
                    ipabaseid=[unicode(testrange9_base_id)],
                    ipabaserid=[unicode(testrange9_base_rid)],
                    ipasecondarybaserid=[
                        unicode(testrange9_secondary_base_rid)
                    ],
                    ipaidrangesize=[unicode(testrange9_size)],
                    iparangetyperaw=[u'ipa-local'],
                    iparangetype=[u'local domain range'],
                ),
                value=testrange9,
                summary=u'Added ID range "%s"' % (testrange9),
            ),
        ),
        dict(
            desc='Delete ID range %r' % testrange9,
            command=('idrange_del', [testrange9], {}),
            expected=dict(
                result=dict(failed=[]),
                value=[testrange9],
                summary=u'Deleted ID range "%s"' % testrange9,
            ),
        ),
    ]