def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: entry_attrs = ldap.get_entry(dn, attrs_list) dn = entry_attrs.dn except errors.NotFound: raise self.obj.handle_not_found(*keys) if is_all(options, 'usercategory') and 'memberuser' in entry_attrs: raise errors.MutuallyExclusiveError( reason=_("user category cannot be set to 'all' while there " "are allowed users") ) if is_all(options, 'hostcategory') and 'memberhost' in entry_attrs: raise errors.MutuallyExclusiveError( reason=_("host category cannot be set to 'all' while there " "are allowed hosts") ) if (is_all(options, 'servicecategory') and 'memberservice' in entry_attrs): raise errors.MutuallyExclusiveError( reason=_("service category cannot be set to 'all' while " "there are allowed services") ) return dn
def validate(self, **kw): """ Validation rules: - at least one of 'type', 'users', 'hosts' is required - 'users' and 'hosts' cannot be combined together - if 'users' and 'type' are specified, 'type' must be 'group' - if 'hosts' and 'type' are specified, 'type' must be 'hostgroup' """ super(automember_rebuild, self).validate(**kw) users, hosts, gtype = kw.get('users'), kw.get('hosts'), kw.get('type') if not (gtype or users or hosts): raise errors.MutuallyExclusiveError( reason=_('at least one of options: type, users, hosts must be ' 'specified')) if users and hosts: raise errors.MutuallyExclusiveError( reason=_("users and hosts cannot both be set")) if gtype == 'group' and hosts: raise errors.MutuallyExclusiveError( reason=_("hosts cannot be set when type is 'group'")) if gtype == 'hostgroup' and users: raise errors.MutuallyExclusiveError( reason=_("users cannot be set when type is 'hostgroup'"))
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: entry_attrs = ldap.get_entry(dn, attrs_list) dn = entry_attrs.dn except errors.NotFound: self.obj.handle_not_found(*keys) # Commented until subca plugin arrives #if is_all(options, 'ipacacategory') and 'ipamemberca' in entry_attrs: # raise errors.MutuallyExclusiveError(reason=_( # "CA category cannot be set to 'all' " # "while there are allowed CAs")) if (is_all(options, 'ipacertprofilecategory') and 'ipamembercertprofile' in entry_attrs): raise errors.MutuallyExclusiveError( reason=_("profile category cannot be set to 'all' " "while there are allowed profiles")) if is_all(options, 'usercategory') and 'memberuser' in entry_attrs: raise errors.MutuallyExclusiveError( reason=_("user category cannot be set to 'all' " "while there are allowed users")) if is_all(options, 'hostcategory') and 'memberhost' in entry_attrs: raise errors.MutuallyExclusiveError( reason=_("host category cannot be set to 'all' " "while there are allowed hosts")) if is_all(options, 'servicecategory') and 'memberservice' in entry_attrs: raise errors.MutuallyExclusiveError( reason=_("service category cannot be set to 'all' " "while there are allowed services")) return dn
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: _entry_attrs = ldap.get_entry(dn, attrs_list) except errors.NotFound: raise self.obj.handle_not_found(*keys) def is_to_be_deleted(x): return ( (x in _entry_attrs and x in entry_attrs) and entry_attrs[x] is None ) # makes sure the local members and hbacrule is not set at the same time # memberuser or memberhost could have been set using --setattr def is_to_be_set(x): return ( ( (x in _entry_attrs and _entry_attrs[x] is not None) or (x in entry_attrs and entry_attrs[x] is not None) ) and not is_to_be_deleted(x) ) are_local_members_to_be_set = any(is_to_be_set(attr) for attr in ('usercategory', 'hostcategory', 'memberuser', 'memberhost')) is_hbacrule_to_be_set = is_to_be_set('seealso') # this can disable all modifications if hbacrule and local members were # set at the same time bypassing this commad, e.g. using ldapmodify if are_local_members_to_be_set and is_hbacrule_to_be_set: raise errors.MutuallyExclusiveError(reason=notboth_err) if (is_all(entry_attrs, 'usercategory') and 'memberuser' in entry_attrs): raise errors.MutuallyExclusiveError( reason="user category cannot be set to 'all' while there " "are allowed users" ) if (is_all(entry_attrs, 'hostcategory') and 'memberhost' in entry_attrs): raise errors.MutuallyExclusiveError( reason="host category cannot be set to 'all' while there " "are allowed hosts" ) if 'ipaselinuxuser' in entry_attrs: validate_selinuxuser_inlist(ldap, entry_attrs['ipaselinuxuser']) if 'seealso' in entry_attrs: entry_attrs['seealso'] = self.obj._normalize_seealso( entry_attrs['seealso'] ) return dn
def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if 'hostcategory' in entry_attrs and \ entry_attrs['hostcategory'][0].lower() == 'all': raise errors.MutuallyExclusiveError( reason=_("hosts cannot be added when host category='all'")) if 'seealso' in entry_attrs: raise errors.MutuallyExclusiveError(reason=notboth_err) return dn
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): # The 3 valid calls are # ipa user-add-certmapdata LOGIN --subject xx --issuer yy # ipa user-add-certmapdata LOGIN [DATA] --certificate xx # ipa user-add-certmapdata LOGIN DATA # Check that at least one of the 3 formats is used try: certmapdatas = keys[1] or [] except IndexError: certmapdatas = [] issuer = options.get('issuer') subject = options.get('subject') certificates = options.get('certificate', []) # If only LOGIN is supplied, then we need either subject or issuer or # certificate if (not certmapdatas and not issuer and not subject and not certificates): raise errors.RequirementError(name='ipacertmapdata') # If subject or issuer is provided, other options are not allowed if subject or issuer: if certificates: raise errors.MutuallyExclusiveError( reason=_('cannot specify both subject/issuer ' 'and certificate')) if certmapdatas: raise errors.MutuallyExclusiveError( reason=_('cannot specify both subject/issuer ' 'and ipacertmapdata')) # If subject or issuer is provided, then the other one is required if not subject: raise errors.RequirementError(name='subject') if not issuer: raise errors.RequirementError(name='issuer') # if the command is called with --subject --issuer or --certificate # we need to add ipacertmapdata to the attrs_list in order to # display the resulting value in the command output if 'ipacertmapdata' not in attrs_list: attrs_list.append('ipacertmapdata') self._convert_options_to_certmap( entry_attrs, issuer=issuer, subject=subject, certificates=certificates) return dn
def test_delete_preserve_nopreserve(self, user): user.ensure_exists() command = user.make_delete_command(no_preserve=True, preserve=True) with raises_exact( errors.MutuallyExclusiveError( message=u'preserve and no-preserve cannot be both set')): command()
def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) def check_validity(runas): v = unicode(runas) if v.upper() == u'ALL': return False return True try: _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: raise self.obj.handle_not_found(*keys) if (is_all(_entry_attrs, 'ipasudorunasusercategory') or is_all(_entry_attrs, 'ipasudorunasgroupcategory')): raise errors.MutuallyExclusiveError( reason=_("users cannot be added when runAs user or runAs " "group category='all'")) if 'group' in options: for name in options['group']: if not check_validity(name): raise errors.ValidationError( name='runas-group', error=unicode( _("RunAsGroup does not accept " "'%(name)s' as a group name")) % dict(name=name)) return pre_callback_process_external_objects('ipasudorunasgroup', GROUP_OBJ_SPEC, ldap, dn, found, not_found, *keys, **options)
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) if not self.api.Command.kra_is_enabled()['result']: raise errors.InvocationError( format=_('KRA service is not enabled')) if options.get('users') or options.get('services'): mutex = ['service', 'services', 'shared', 'username', 'users'] count = sum(bool(options.get(option)) for option in mutex) if count > 1: raise errors.MutuallyExclusiveError( reason=_('Service(s), shared, and user(s) options ' + 'cannot be specified simultaneously')) scope = ldap.SCOPE_SUBTREE container_dn = DN(self.obj.container_dn, self.api.env.basedn) if options.get('services'): base_dn = DN(('cn', 'services'), container_dn) else: base_dn = DN(('cn', 'users'), container_dn) else: base_dn = self.obj.get_dn(None, **options) return filter, base_dn, scope
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # rules are enabled by default entry_attrs['ipaenabledflag'] = 'TRUE' # hbacrule is not allowed when usercat or hostcat is set is_to_be_set = lambda x: x in entry_attrs and entry_attrs[x] != None are_local_members_to_be_set = any( is_to_be_set(attr) for attr in ('usercategory', 'hostcategory')) is_hbacrule_to_be_set = is_to_be_set('seealso') if is_hbacrule_to_be_set and are_local_members_to_be_set: raise errors.MutuallyExclusiveError(reason=notboth_err) if is_hbacrule_to_be_set: entry_attrs['seealso'] = self.obj._normalize_seealso( entry_attrs['seealso']) entry_attrs['ipadeskprofiletarget'] = \ self.obj._normalize_profile(entry_attrs['ipadeskprofiletarget']) return dn
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if 'sudoorder' in options: new_order = options.get('sudoorder') old_entry = self.api.Command.sudorule_show(keys[-1])['result'] if 'sudoorder' in old_entry: old_order = int(old_entry['sudoorder'][0]) if old_order != new_order: self.obj.check_order_uniqueness(*keys, **options) else: self.obj.check_order_uniqueness(*keys, **options) try: _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: raise self.obj.handle_not_found(*keys) error = _("%(type)s category cannot be set to 'all' " "while there are allowed %(objects)s") category_info = [ ('usercategory', ['memberuser', 'externaluser'], error % { 'type': _('user'), 'objects': _('users') }), ('hostcategory', ['memberhost', 'externalhost', 'hostmask'], error % { 'type': _('host'), 'objects': _('hosts') }), ('cmdcategory', ['memberallowcmd'], error % { 'type': _('command'), 'objects': _('commands') }), ('ipasudorunasusercategory', [ 'ipasudorunas', 'ipasudorunasextuser', 'ipasudorunasextusergroup' ], error % { 'type': _('runAs user'), 'objects': _('runAs users') }), ('ipasudorunasgroupcategory', ['ipasudorunasgroup', 'ipasudorunasextgroup'], error % { 'type': _('group runAs'), 'objects': _('runAs groups') }), ] # Enforce the checks for all the categories for category, member_attrs, error in category_info: any_member_attrs_set = any(attr in _entry_attrs for attr in member_attrs) if is_all(options, category) and any_member_attrs_set: raise errors.MutuallyExclusiveError(reason=error) return dn
def test_rebuild_membership_hosts_incorrectly(self, automember_hostgroup): """ Try to issue rebuild automember command without 'type' parameter """ command = automember_hostgroup.make_rebuild_command() with raises_exact(errors.MutuallyExclusiveError( reason=u'at least one of options: ' 'type, users, hosts must be specified')): command()
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if 'sudoorder' in options: new_order = options.get('sudoorder') old_entry = self.api.Command.sudorule_show(keys[-1])['result'] if 'sudoorder' in old_entry: old_order = int(old_entry['sudoorder'][0]) if old_order != new_order: self.obj.check_order_uniqueness(*keys, **options) else: self.obj.check_order_uniqueness(*keys, **options) try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(options, 'usercategory') and 'memberuser' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_( "user category cannot be set to 'all' while there are allowed users" )) if is_all(options, 'hostcategory') and 'memberhost' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_( "host category cannot be set to 'all' while there are allowed hosts" )) if is_all(options, 'cmdcategory') and ('memberallowcmd' or 'memberdenywcmd') in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_( "command category cannot be set to 'all' while there are allow or deny commands" )) if is_all( options, 'ipasudorunasusercategory') and 'ipasudorunas' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_( "user runAs category cannot be set to 'all' while there are users" )) if is_all(options, 'ipasudorunasgroupcategory' ) and 'ipasudorunasgroup' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_( "group runAs category cannot be set to 'all' while there are groups" )) return dn
def test_rebuild_membership_user_hosts(self, automember_hostgroup, user1, host1): """ Try to issue rebuild membership command with --users and --hosts together """ command = automember_hostgroup.make_rebuild_command(users=user1.name, hosts=host1.fqdn) with raises_exact(errors.MutuallyExclusiveError( reason=u'users and hosts cannot both be set')): command()
def forward(self, *args, **options): if self.api.env.context == 'cli': if 'certificate' in options and 'file' in options: raise errors.MutuallyExclusiveError( reason=_("cannot specify both raw certificate and file")) if 'certificate' not in options and 'file' in options: options['certificate'] = x509.strip_header(options.pop('file')) return super(cert_find, self).forward(*args, **options)
def test_rebuild_membership_hosts_group(self, automember_hostgroup, user1, host1): """ Try to issue rebuild membership command with type --users and hosts specified """ command = automember_hostgroup.make_rebuild_command(hosts=host1.fqdn, type=u'group') with raises_exact(errors.MutuallyExclusiveError( reason=u"hosts cannot be set when type is 'group'")): command()
def test_rebuild_membership_users_hostgroup(self, automember_hostgroup, user1): """ Try to issue rebuild membership command with type --hosts and users specified """ command = automember_hostgroup.make_rebuild_command(users=user1.name, type=u'hostgroup') with raises_exact(errors.MutuallyExclusiveError( reason=u"users cannot be set when type is 'hostgroup'")): command()
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) associateddomain = entry_attrs.get('associateddomain') add_domain = entry_attrs.get('add_domain') del_domain = entry_attrs.get('del_domain') force = options.get('force') current_domain = self.api.env.domain # User specified the list of domains explicitly if associateddomain: if add_domain or del_domain: raise errors.MutuallyExclusiveError(reason=_( "The --domain option cannot be used together " "with --add-domain or --del-domain. Use --domain " "to specify the whole realm domain list explicitly, " "to add/remove individual domains, use " "--add-domain/del-domain.")) # Make sure our domain is included in the list if current_domain not in associateddomain: raise errors.ValidationError( name='realmdomain list', error=_("IPA server domain cannot be omitted")) # Validate that each domain satisfies the requirements # for realmdomain self.validate_domains(domains=associateddomain, force=force) return dn # If --add-domain or --del-domain options were provided, read # the curent list from LDAP, modify it, and write the changes back domains = ldap.get_entry(dn)['associateddomain'] if add_domain: self.validate_domains(domains=[add_domain], force=force) del entry_attrs['add_domain'] domains.append(add_domain) if del_domain: if del_domain == current_domain: raise errors.ValidationError( name='del_domain', error=_("IPA server domain cannot be deleted")) del entry_attrs['del_domain'] try: domains.remove(del_domain) except ValueError: raise errors.AttrValueNotFound(attr='associateddomain', value=del_domain) entry_attrs['associateddomain'] = domains return dn
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) associateddomain = entry_attrs.get('associateddomain') add_domain = entry_attrs.get('add_domain') del_domain = entry_attrs.get('del_domain') force = options.get('force') if associateddomain: if add_domain or del_domain: raise errors.MutuallyExclusiveError(reason=_( "you cannot specify the --domain option together with --add-domain or --del-domain" )) if get_domain_name() not in associateddomain: raise errors.ValidationError( name='domain', error=_("cannot delete domain of IPA server")) if not force: bad_domains = [ d for d in associateddomain if not has_soa_or_ns_record(d) ] if bad_domains: bad_domains = ', '.join(bad_domains) raise errors.ValidationError( name='domain', error=_("no SOA or NS records found for domains: %s" % bad_domains)) return dn # If --add-domain or --del-domain options were provided, read # the curent list from LDAP, modify it, and write the changes back domains = ldap.get_entry(dn)['associateddomain'] if add_domain: if not force and not has_soa_or_ns_record(add_domain): raise errors.ValidationError( name='add_domain', error=_("no SOA or NS records found for domain %s" % add_domain)) del entry_attrs['add_domain'] domains.append(add_domain) if del_domain: if del_domain == get_domain_name(): raise errors.ValidationError( name='del_domain', error=_("cannot delete domain of IPA server")) del entry_attrs['del_domain'] try: domains.remove(del_domain) except ValueError: raise errors.AttrValueNotFound(attr='associateddomain', value=del_domain) entry_attrs['associateddomain'] = domains return dn
def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: entry_attrs = ldap.get_entry(dn, self.obj.default_attributes) dn = entry_attrs.dn except errors.NotFound: raise self.obj.handle_not_found(*keys) if is_all(entry_attrs, 'ipacacategory'): raise errors.MutuallyExclusiveError(reason=_( "CAs cannot be added when CA category='all'")) return dn
def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'hostcategory'): raise errors.MutuallyExclusiveError( reason=_("hosts cannot be added when host category='all'")) return add_external_pre_callback('host', ldap, dn, keys, options)
def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: entry_attrs = ldap.get_entry(dn, self.obj.default_attributes) dn = entry_attrs.dn except errors.NotFound: raise self.obj.handle_not_found(*keys) if ('servicecategory' in entry_attrs and entry_attrs['servicecategory'][0].lower() == 'all'): raise errors.MutuallyExclusiveError(reason=_( "services cannot be added when service category='all'")) return dn
def forward(self, *keys, **options): if self.api.env.context == 'cli': if options['no_preserve'] and options['preserve']: raise errors.MutuallyExclusiveError( reason=_("preserve and no-preserve cannot be both set")) elif options['no_preserve']: options['preserve'] = False elif not options['preserve']: del options['preserve'] del options['no_preserve'] return super(user_del, self).forward(*keys, **options)
def forward(self, *args, **options): if self.api.env.context == 'cli': if args and 'certificate' in options: raise errors.MutuallyExclusiveError( reason=_("cannot specify both raw certificate and file")) if args: args = [x509.load_unknown_x509_certificate(args[0])] elif 'certificate' in options: args = [options.pop('certificate')] else: args = [] return super(certmap_match, self).forward(*args, **options)
def forward(self, *keys, **options): if self.api.env.context == 'cli': no_preserve = options.pop('no_preserve', False) preserve = options.pop('preserve', False) if no_preserve and preserve: raise errors.MutuallyExclusiveError( reason=_("preserve and no-preserve cannot be both set")) elif no_preserve: options['preserve'] = False elif preserve: options['preserve'] = True return super(user_del, self).forward(*keys, **options)
def forward(self, csr=None, **options): database = options.pop('database', None) private_key = options.pop('private_key', None) csr_profile_id = options.pop('csr_profile_id', None) password_file = options.pop('password_file', None) if csr is None: # Deferred import, ipaclient.csrgen is expensive to load. # see https://pagure.io/freeipa/issue/7484 from ipaclient import csrgen if database: adaptor = csrgen.NSSAdaptor(database, password_file) elif private_key: adaptor = csrgen.OpenSSLAdaptor( key_filename=private_key, password_filename=password_file) else: raise errors.InvocationError( message=u"One of 'database' or 'private_key' is required") pubkey_info = adaptor.get_subject_public_key_info() pubkey_info_b64 = base64.b64encode(pubkey_info) # If csr_profile_id is passed, that takes precedence. # Otherwise, use profile_id. If neither are passed, the default # in cert_get_requestdata will be used. profile_id = csr_profile_id if profile_id is None: profile_id = options.get('profile_id') response = self.api.Command.cert_get_requestdata( profile_id=profile_id, principal=options.get('principal'), public_key_info=pubkey_info_b64) req_info_b64 = response['result']['request_info'] req_info = base64.b64decode(req_info_b64) csr = adaptor.sign_csr(req_info) if not csr: raise errors.CertificateOperationError( error=(_('Generated CSR was empty'))) else: if database is not None or private_key is not None: raise errors.MutuallyExclusiveError(reason=_( "Options 'database' and 'private_key' are not compatible" " with 'csr'")) return super(cert_request, self).forward(csr, **options)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): # As both 'external' and 'nonposix' options have default= set for # them, they will always be present in options dict, thus we can # safely reference the values assert isinstance(dn, DN) if options['external']: entry_attrs['objectclass'].append('ipaexternalgroup') if 'gidnumber' in options: raise errors.MutuallyExclusiveError(reason=_('gid cannot be set for external group')) elif not options['nonposix']: entry_attrs['objectclass'].append('posixgroup') if 'gidnumber' not in options: entry_attrs['gidnumber'] = baseldap.DNA_MAGIC return dn
def forward(self, csr=None, **options): database = options.pop('database', None) private_key = options.pop('private_key', None) csr_profile_id = options.pop('csr_profile_id', None) password_file = options.pop('password_file', None) if csr is None: if database: adaptor = csrgen.NSSAdaptor(database, password_file) elif private_key: adaptor = csrgen.OpenSSLAdaptor(private_key, password_file) else: raise errors.InvocationError( message=u"One of 'database' or 'private_key' is required") pubkey_info = adaptor.get_subject_public_key_info() pubkey_info_b64 = base64.b64encode(pubkey_info) # If csr_profile_id is passed, that takes precedence. # Otherwise, use profile_id. If neither are passed, the default # in cert_get_requestdata will be used. profile_id = csr_profile_id if profile_id is None: profile_id = options.get('profile_id') response = self.api.Command.cert_get_requestdata( profile_id=profile_id, principal=options.get('principal'), public_key_info=unicode(pubkey_info_b64)) req_info_b64 = response['result']['request_info'] req_info = base64.b64decode(req_info_b64) csr = adaptor.sign_csr(req_info) if not csr: raise errors.CertificateOperationError( error=(_('Generated CSR was empty'))) # cert_request requires the CSR to be base64-encoded (but PEM # header and footer are not required) csr = unicode(base64.b64encode(csr)) else: if database is not None or private_key is not None: raise errors.MutuallyExclusiveError(reason=_( "Options 'database' and 'private_key' are not compatible" " with 'csr'")) return super(cert_request, self).forward(csr, **options)
def test_create_with_provider_and_tokenendpoint(self): """ Creation with --provider parameter and --token-uri""" idp_with_provider = IdpTracker('idp_with_provider', ipaidpprovider='google', ipaidptokenendpoint=google_token, ipaidpdevauthendpoint=google_devauth, ipaidpclientid="idpclient1") idp_with_provider.track_create() command = idp_with_provider.make_create_command() with raises_exact( errors.MutuallyExclusiveError( reason= 'cannot specify both individual endpoints and IdP provider' )): command()
def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: raise self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'usercategory'): raise errors.MutuallyExclusiveError( reason=_("users cannot be added when user category='all'")) for o_desc in (USER_OBJ_SPEC, GROUP_OBJ_SPEC): dn = pre_callback_process_external_objects( 'memberuser', o_desc, ldap, dn, found, not_found, *keys, **options) return dn