baseldap: when adding external objects, differentiate between them and failures

It was possible to add external members without any validation. Any
object that was not found in IPA LDAP was considered an external object
and a command such as sudorule could have added it to the list of values
for externalUser attribute.

With member validator support, real external members from trusted
domains can be differentiated from the objects that were not found in
IPA and in trusted domains.

Use information from the ID Views plugin to treat external objects
accordingly. Not found objects will be part of the error messaging
instead.

Fixes: https://pagure.io/freeipa/issue/3226
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
This commit is contained in:
Alexander Bokovoy 2021-01-25 17:41:02 +02:00 committed by Rob Crittenden
parent 172e4b9770
commit 5fae809d92

View File

@ -380,6 +380,60 @@ def add_external_pre_callback(membertype, ldap, dn, keys, options):
return dn
EXTERNAL_OBJ_PREFIX = 'external '
def pre_callback_process_external_objects(member_attr, object_desc,
ldap, dn, found, not_found,
*keys, **options):
"""
Takes the following arguments:
member_attr - member attribute to process external members for
object_desc - a tuple (type, prefix) to identify a type of an object
('user', 'group', ...) to associate and a prefix to skip
when comparing with an external object. Prefix should be
None for objects that do not have prefixes.
found - the dictionary with all members that were found
not_found - the dictionary with all members which weren't found
keys - list of arguments to the command where this callback is used
options - list of options to the command where this callback is used.
The callback performs validation of objects as external (not existing in
IPA LDAP) and then adds them to a list of not found objects with a mark
'external ..' object if they were resolved as an object from a trusted
domain.
Returns a DN object used for processing dn.
"""
(o_type, o_prefix) = object_desc
if o_type not in options:
return dn
dn = add_external_pre_callback(o_type, ldap, dn, keys, options)
if 'trusted_objects' in options:
trusted_objects = options.pop('trusted_objects')
found_members = found.get(member_attr, {})
found_objects = found_members.get(o_type, [])
filtered_objects = []
for o_id in found_objects:
for obj in trusted_objects:
m = obj
if o_prefix is not None and obj.startswith(o_prefix):
m = obj[len(o_prefix):]
if o_id[0].value.lower() == m.lower():
filtered_objects.append(o_id)
found[member_attr][o_type] = list(
set(found_objects) - set(filtered_objects))
notfound_members = not_found.get(member_attr, {})
notfound_objects = notfound_members.get(o_type, [])
notfound_objects.extend(
[(m, EXTERNAL_OBJ_PREFIX + o_type) for m in trusted_objects])
notfound_members[o_type] = notfound_objects
return dn
def add_external_post_callback(ldap, dn, entry_attrs, failed, completed,
memberattr, membertype, externalattr,
normalize=True):
@ -414,13 +468,19 @@ def add_external_post_callback(ldap, dn, entry_attrs, failed, completed,
failed_entries = []
for entry in failed[memberattr][membertype]:
# entry is a tuple (name, error)
membername = entry[0].lower()
member_dn = api.Object[membertype].get_dn(membername)
assert isinstance(member_dn, DN)
if (membername not in lc_external_entries and
member_dn not in members):
# Not an IPA entry, assume external
# Not an IPA entry, only add if it has been marked
# as an external entry during the pre-callback validation
if not entry[1].startswith(EXTERNAL_OBJ_PREFIX):
# Really a failure
failed_entries.append(membername)
continue
if normalize:
external_entries.append(membername)
else: