def _import_ldap_users_info(connection, user_info, sync_groups=False, import_by_dn=False): """ Import user_info found through ldap_access.find_users. """ imported_users = [] for ldap_info in user_info: # Extra validation in case import by DN and username has spaces or colons validate_username(ldap_info['username']) user, created = ldap_access.get_or_create_ldap_user(username=ldap_info['username']) profile = get_profile(user) if not created and profile.creation_method == str(UserProfile.CreationMethod.HUE): # This is a Hue user, and shouldn't be overwritten LOG.warn(_('There was a naming conflict while importing user %(username)s') % { 'username': ldap_info['username'] }) return None default_group = get_default_user_group() if created and default_group is not None: user.groups.add(default_group) if 'first' in ldap_info: user.first_name = ldap_info['first'] if 'last' in ldap_info: user.last_name = ldap_info['last'] if 'email' in ldap_info: user.email = ldap_info['email'] profile.creation_method = UserProfile.CreationMethod.EXTERNAL profile.save() user.save() imported_users.append(user) # sync groups if sync_groups and 'groups' in ldap_info: old_groups = set(user.groups.all()) new_groups = set() # Skip if 'memberOf' or 'isMemberOf' are not set for group_dn in ldap_info['groups']: group_ldap_info = connection.find_groups(group_dn, find_by_dn=True, scope=ldap.SCOPE_BASE) for group_info in group_ldap_info: # Add only if user isn't part of group. if not user.groups.filter(name=group_info['name']).exists(): groups = import_ldap_groups(connection, group_info['dn'], import_members=False, import_members_recursive=False, sync_users=False, import_by_dn=True) if groups: new_groups.update(groups) # Remove out of date groups remove_groups = old_groups - new_groups remove_ldap_groups = LdapGroup.objects.filter(group__in=remove_groups) remove_groups_filtered = [ldapgroup.group for ldapgroup in remove_ldap_groups] user.groups.filter(group__in=remove_groups_filtered).delete() user.groups.add(*new_groups) Group.objects.filter(group__in=remove_groups_filtered).delete() remove_ldap_groups.delete() return imported_users
def get_or_create_user(self, username, ldap_user): username = force_username_case(username) try: validate_username(username) if desktop.conf.LDAP.IGNORE_USERNAME_CASE.get(): try: return User.objects.get(username__iexact=username), False except User.DoesNotExist: return User.objects.get_or_create(username=username) else: return User.objects.get_or_create(username=username) except ValidationError, e: LOG.exception("LDAP username is invalid: %s" % username)
def get_or_create_user(self, username, ldap_user): username = force_username_case(username) try: #Avoid circular import from is_admin from useradmin.forms import validate_username validate_username(username) if LDAP.IGNORE_USERNAME_CASE.get(): try: return User.objects.get(username__iexact=username), False except User.DoesNotExist: return User.objects.get_or_create(username=username) else: return User.objects.get_or_create(username=username) except ValidationError as e: LOG.exception("LDAP username is invalid: %s" % username)
def get_or_create_user(self, username, ldap_user): username = force_username_case(username) try: #Avoid circular import from is_admin from useradmin.forms import validate_username validate_username(username) if desktop.conf.LDAP.IGNORE_USERNAME_CASE.get(): try: return User.objects.get(username__iexact=username), False except User.DoesNotExist: return User.objects.get_or_create(username=username) else: return User.objects.get_or_create(username=username) except ValidationError, e: LOG.exception("LDAP username is invalid: %s" % username)
def _import_ldap_users_info(connection, user_info, sync_groups=False, import_by_dn=False, server=None): """ Import user_info found through ldap_access.find_users. """ imported_users = [] for ldap_info in user_info: # Extra validation in case import by DN and username has spaces or colons try: validate_username(ldap_info['username']) user, created = ldap_access.get_or_create_ldap_user( username=ldap_info['username']) profile = get_profile(user) if not created and profile.creation_method == str( UserProfile.CreationMethod.HUE): # This is a Hue user, and shouldn't be overwritten LOG.warn( _('There was a naming conflict while importing user %(username)s' ) % {'username': ldap_info['username']}) return None default_group = get_default_user_group() if created and default_group is not None: user.groups.add(default_group) if 'first' in ldap_info: user.first_name = ldap_info['first'] if 'last' in ldap_info: user.last_name = ldap_info['last'] if 'email' in ldap_info: user.email = ldap_info['email'] profile.creation_method = UserProfile.CreationMethod.EXTERNAL profile.save() user.save() imported_users.append(user) # sync groups if sync_groups: old_groups = set(user.groups.all()) new_groups = set() current_ldap_groups = set() ldap_config = desktop.conf.LDAP.LDAP_SERVERS.get( )[server] if server else desktop.conf.LDAP group_member_attr = ldap_config.GROUPS.GROUP_MEMBER_ATTR.get() group_filter = ldap_config.GROUPS.GROUP_FILTER.get() # Search for groups based on group_member_attr=username and group_member_attr=dn # covers AD, Standard Ldap and posixAcount/posixGroup if not group_filter.startswith('('): group_filter = '(' + group_filter + ')' # Sanitizing the DN before using in a Search filter sanitized_dn = ldap.filter.escape_filter_chars( ldap_info['dn']).replace(r'\2a', r'*') sanitized_dn = sanitized_dn.replace(r'\5c,', r'\5c\2c') find_groups_filter = "(&" + group_filter + "(|(" + group_member_attr + "=" + ldap_info['username'] + ")(" + \ group_member_attr + "=" + sanitized_dn + ")))" group_ldap_info = connection.find_groups( "*", group_filter=find_groups_filter) for group_info in group_ldap_info: if Group.objects.filter(name=group_info['name']).exists(): # Add only if user isn't part of group. current_ldap_groups.add( Group.objects.get(name=group_info['name'])) if not user.groups.filter( name=group_info['name']).exists(): groups = import_ldap_groups( connection, group_info['dn'], import_members=False, import_members_recursive=False, sync_users=True, import_by_dn=True) if groups: new_groups.update(groups) # Remove out of date groups remove_groups = old_groups - current_ldap_groups remove_ldap_groups = LdapGroup.objects.filter( group__in=remove_groups) remove_groups_filtered = [ ldapgroup.group for ldapgroup in remove_ldap_groups ] for group in remove_groups_filtered: user.groups.remove(group) user.groups.add(*new_groups) Group.objects.filter(group__in=remove_groups_filtered).delete() except (AssertionError, RuntimeError) as e: LOG.warn('%s: %s' % (ldap_info['username'], e.message)) return imported_users
def _import_ldap_users_info(connection, user_info, sync_groups=False, import_by_dn=False, server=None, failed_users=None): """ Import user_info found through ldap_access.find_users. """ imported_users = [] for ldap_info in user_info: # Extra validation in case import by DN and username has spaces or colons try: validate_username(ldap_info['username']) user, created = ldap_access.get_or_create_ldap_user(username=ldap_info['username']) profile = get_profile(user) if not created and profile.creation_method == str(UserProfile.CreationMethod.HUE): # This is a Hue user, and shouldn't be overwritten LOG.warn(_('There was a naming conflict while importing user %(username)s') % { 'username': ldap_info['username'] }) return None default_group = get_default_user_group() if created and default_group is not None: user.groups.add(default_group) if 'first' in ldap_info: validate_first_name(ldap_info['first']) user.first_name = ldap_info['first'] if 'last' in ldap_info: validate_last_name(ldap_info['last']) user.last_name = ldap_info['last'] if 'email' in ldap_info: user.email = ldap_info['email'] profile.creation_method = UserProfile.CreationMethod.EXTERNAL profile.save() user.save() imported_users.append(user) # sync groups if sync_groups: old_groups = set(user.groups.all()) new_groups = set() current_ldap_groups = set() ldap_config = desktop.conf.LDAP.LDAP_SERVERS.get()[server] if server else desktop.conf.LDAP group_member_attr = ldap_config.GROUPS.GROUP_MEMBER_ATTR.get() group_filter = ldap_config.GROUPS.GROUP_FILTER.get() # Search for groups based on group_member_attr=username and group_member_attr=dn # covers AD, Standard Ldap and posixAcount/posixGroup if not group_filter.startswith('('): group_filter = '(' + group_filter + ')' # Sanitizing the DN before using in a Search filter sanitized_dn = ldap.filter.escape_filter_chars(ldap_info['dn']).replace(r'\2a', r'*') sanitized_dn = sanitized_dn.replace(r'\5c,', r'\5c\2c') find_groups_filter = "(&" + group_filter + "(|(" + group_member_attr + "=" + ldap_info['username'] + ")(" + \ group_member_attr + "=" + sanitized_dn + ")))" group_ldap_info = connection.find_groups("*", group_filter=find_groups_filter) for group_info in group_ldap_info: if Group.objects.filter(name=group_info['name']).exists(): # Add only if user isn't part of group. current_ldap_groups.add(Group.objects.get(name=group_info['name'])) if not user.groups.filter(name=group_info['name']).exists(): groups = import_ldap_groups(connection, group_info['dn'], import_members=False, import_members_recursive=False, sync_users=True, import_by_dn=True, failed_users=failed_users) if groups: new_groups.update(groups) # Remove out of date groups remove_groups = old_groups - current_ldap_groups remove_ldap_groups = LdapGroup.objects.filter(group__in=remove_groups) remove_groups_filtered = [ldapgroup.group for ldapgroup in remove_ldap_groups] for group in remove_groups_filtered: user.groups.remove(group) user.groups.add(*new_groups) Group.objects.filter(group__in=remove_groups_filtered).delete() except (ValidationError, LdapSearchException) as e: if failed_users is None: failed_users = [] failed_users.append(ldap_info['username']) LOG.warn('Could not import %s: %s' % (ldap_info['username'], e.message)) return imported_users
# Sync users if sync_users: for member in members: user_info = [] try: user_info = connection.find_users(member, find_by_dn=True) except LdapSearchException, e: LOG.warn("Failed to find LDAP user: %s" % e) if len(user_info) > 1: LOG.warn('Found multiple users for member %s.' % member) else: for ldap_info in user_info: try: validate_username(ldap_info['username']) user = ldap_access.get_ldap_user(username=ldap_info['username']) group.user_set.add(user) except ValidationError, e: if failed_users is None: failed_users = [] failed_users.append(ldap_info['username']) LOG.warn('Could not sync %s: %s' % (ldap_info['username'], e.message)) except User.DoesNotExist: pass # Import/fetch posix users and groups # Posix members if posix_members: if import_members: for posix_member in posix_members:
def _import_ldap_suboordinate_groups(connection, groupname_pattern, import_members=False, recursive_import_members=False, sync_users=True, import_by_dn=False): """ Import a group from LDAP. If import_members is true, this will also import any LDAP users that exist within the group. This will use suboordinate group logic. A suboordinate group is a group that is a subentry of another group. e.g. CN=subtest,CN=test,OU=groups,DC=exampe,DC=COM is a suboordinate group of CN=test,OU=groups,DC=exampe,DC=COM """ if import_by_dn: scope = ldap.SCOPE_BASE else: scope = ldap.SCOPE_SUBTREE group_info = connection.find_groups(groupname_pattern, find_by_dn=import_by_dn, scope=scope) if not group_info: LOG.warn("Could not get LDAP details for group pattern %s" % groupname_pattern) return None groups = [] for ldap_info in group_info: group, created = Group.objects.get_or_create(name=ldap_info['name']) if not created and not LdapGroup.objects.filter(group=group).exists(): # This is a Hue group, and shouldn't be overwritten LOG.warn(_('There was a naming conflict while importing group %(groupname)s in pattern %(groupname_pattern)s') % { 'groupname': ldap_info['name'], 'groupname_pattern': groupname_pattern }) return None LdapGroup.objects.get_or_create(group=group) group.user_set.clear() # Find members and posix members for group and subgoups members = ldap_info['members'] posix_members = ldap_info['posix_members'] # @TODO: Deprecate recursive_import_members as it may not be useful. if import_members: if recursive_import_members: for sub_ldap_info in connection.find_groups(ldap_info['dn'], find_by_dn=True): members += sub_ldap_info['members'] posix_members += sub_ldap_info['posix_members'] for member in members: LOG.debug("Importing user %s" % smart_str(member)) group.user_set.add( *( _import_ldap_users(connection, member, import_by_dn=True) or [] ) ) # Sync users if sync_users: for member in members: user_info = connection.find_users(member, find_by_dn=True) if len(user_info) > 1: LOG.warn('Found multiple users for member %s.' % member) else: for ldap_info in user_info: try: validate_username(ldap_info['username']) user = ldap_access.get_ldap_user(username=ldap_info['username']) group.user_set.add(user) except (AssertionError, RuntimeError), e: LOG.warn('Could not sync %s: %s' % (ldap_info['username'], e.message)) except User.DoesNotExist: pass
def _import_ldap_suboordinate_groups(connection, groupname_pattern, import_members=False, recursive_import_members=False, sync_users=True, import_by_dn=False): """ Import a group from LDAP. If import_members is true, this will also import any LDAP users that exist within the group. This will use suboordinate group logic. A suboordinate group is a group that is a subentry of another group. e.g. CN=subtest,CN=test,OU=groups,DC=exampe,DC=COM is a suboordinate group of CN=test,OU=groups,DC=exampe,DC=COM """ if import_by_dn: scope = ldap.SCOPE_BASE else: scope = ldap.SCOPE_SUBTREE group_info = connection.find_groups(groupname_pattern, find_by_dn=import_by_dn, scope=scope) if not group_info: LOG.warn("Could not get LDAP details for group pattern %s" % groupname_pattern) return None groups = [] for ldap_info in group_info: group, created = Group.objects.get_or_create(name=ldap_info['name']) if not created and not LdapGroup.objects.filter(group=group).exists(): # This is a Hue group, and shouldn't be overwritten LOG.warn( _('There was a naming conflict while importing group %(groupname)s in pattern %(groupname_pattern)s' ) % { 'groupname': ldap_info['name'], 'groupname_pattern': groupname_pattern }) return None LdapGroup.objects.get_or_create(group=group) group.user_set.clear() # Find members and posix members for group and subgoups members = ldap_info['members'] posix_members = ldap_info['posix_members'] # @TODO: Deprecate recursive_import_members as it may not be useful. if import_members: if recursive_import_members: for sub_ldap_info in connection.find_groups(ldap_info['dn'], find_by_dn=True): members += sub_ldap_info['members'] posix_members += sub_ldap_info['posix_members'] for member in members: LOG.debug("Importing user %s" % smart_str(member)) group.user_set.add( *(_import_ldap_users(connection, member, import_by_dn=True) or [])) # Sync users if sync_users: for member in members: user_info = connection.find_users(member, find_by_dn=True) if len(user_info) > 1: LOG.warn('Found multiple users for member %s.' % member) else: for ldap_info in user_info: try: validate_username(ldap_info['username']) user = ldap_access.get_ldap_user( username=ldap_info['username']) group.user_set.add(user) except (AssertionError, RuntimeError), e: LOG.warn('Could not sync %s: %s' % (ldap_info['username'], e.message)) except User.DoesNotExist: pass