From 4f0f30b2f558cbe1f4bb2ee13c600748e43630f5 Mon Sep 17 00:00:00 2001 From: Nikolai R Kristiansen Date: Sat, 9 May 2015 18:07:10 +0200 Subject: [PATCH] Work on stale ldap/homedir stuff --- .../commands/clean_up_internal_users.py | 84 ------------------- .../management/commands/stale_users.py | 64 ++++++++++++++ neuf_userinfo/ssh.py | 48 +++++++---- neuf_userinfo/utils.py | 18 ---- scripts/create_home_directory.sh | 2 +- 5 files changed, 98 insertions(+), 118 deletions(-) delete mode 100644 neuf_userinfo/management/commands/clean_up_internal_users.py create mode 100644 neuf_userinfo/management/commands/stale_users.py diff --git a/neuf_userinfo/management/commands/clean_up_internal_users.py b/neuf_userinfo/management/commands/clean_up_internal_users.py deleted file mode 100644 index 9c0d44e..0000000 --- a/neuf_userinfo/management/commands/clean_up_internal_users.py +++ /dev/null @@ -1,84 +0,0 @@ -from django.core.management.base import BaseCommand -from django.db.models import Q - -from inside.models import InsideGroup, InsideUser -from neuf_ldap.models import LdapGroup, LdapUser - -from optparse import make_option - -ACTIVE_USERS_GROUP = 'dns-aktiv' - - -class Command(BaseCommand): - # TODO: Actually clean up stuff - help = 'Clean up stale LDAP/ users not in group dns-aktiv from Inside' - option_list = BaseCommand.option_list + ( - make_option( - '--dry-run', - action='store_true', - dest='dry_run', - default=False, - help='Dry run when syncronizing, does not save anything.' - ),) - - SYNC_GROUP_PREFIX = 'dns-' - options = {} - - def handle(self, *args, **options): - self.options = options - - # Get all active user from Inside - inside_users_diffable = self.get_inside_users_diffable() - - # Get existing users in LDAP - ldap_users_diffable = self.get_ldap_users_diffable() - - # Are any LDAP users stale? - self.stale_ldap_users(inside_users_diffable, ldap_users_diffable) - - def get_inside_users_diffable(self): - inside_users_diffable = {} - group = InsideGroup.objects.get(posix_group=ACTIVE_USERS_GROUP) - inside_users = InsideUser.objects.filter(group_rels__group=group) - inside_users = inside_users.exclude(Q(ldap_username__isnull=True) | Q(registration_status='partial')) - - for u in inside_users: - inside_groups = InsideGroup.objects.filter(user_rels__user=u).exclude(posix_group='') - inside_groups = inside_groups.values_list('posix_group', flat=True) - inside_users_diffable[u.ldap_username] = { - 'username': u.ldap_username, - 'first_name': u.first_name, - 'last_name': u.last_name, - 'email': u.email, - 'groups': inside_groups - } - if self.options['verbosity'] == '3': - self.stdout.write('Found {} Inside users'.format(len(inside_users_diffable))) - - return inside_users_diffable - - def get_ldap_users_diffable(self): - ldap_users_diffable = {} - ldap_active_members = LdapGroup.objects.get(name=ACTIVE_USERS_GROUP).members - ldap_users = LdapUser.objects.filter(username__in=ldap_active_members) - - for u in ldap_users: - ldap_groups = LdapGroup.objects\ - .filter(name__startswith=self.SYNC_GROUP_PREFIX, members__contains=u.username)\ - .values_list('name', flat=True) - ldap_users_diffable[u.username] = { - 'username': u.username, - 'first_name': u.first_name, - 'last_name': u.last_name, - 'email': u.email, - 'groups': ldap_groups - } - if self.options['verbosity'] == '3': - self.stdout.write('Found {} LDAP users'.format(len(ldap_users_diffable))) - - return ldap_users_diffable - - def stale_ldap_users(self, inside_users_diffable, ldap_users_diffable): - for username, u in ldap_users_diffable.iteritems(): - if username not in inside_users_diffable: - self.stdout.write('LDAP user {} is not in group {} in Inside'.format(username, ACTIVE_USERS_GROUP)) \ No newline at end of file diff --git a/neuf_userinfo/management/commands/stale_users.py b/neuf_userinfo/management/commands/stale_users.py new file mode 100644 index 0000000..440d895 --- /dev/null +++ b/neuf_userinfo/management/commands/stale_users.py @@ -0,0 +1,64 @@ +from django.core.management.base import BaseCommand +from django.db.models import Q + +from inside.models import InsideGroup, InsideUser +from neuf_ldap.models import LdapUser + +from optparse import make_option +from neuf_userinfo.ssh import get_home_dirs + + +class Command(BaseCommand): + help = 'List stale LDAP/ users not in group dns-aktiv from Inside' + option_list = BaseCommand.option_list + ( + make_option( + '--dry-run', + action='store_true', + dest='dry_run', + default=False, + help='Dry run when syncronizing, does not save anything.' + ), + ) + + ACTIVE_USERS_GROUP = 'dns-aktiv' + SYNC_GROUP_PREFIX = 'dns-' + options = {} + + def handle(self, *args, **options): + self.options = options + home_dirs = get_home_dirs() + inside_users_active = self.get_inside_users() + ldap_users_all = self.get_ldap_users() + stale_ldap_users = ldap_users_all - inside_users_active + stale_homedirs = set(home_dirs) - inside_users_active + + self.stdout.write('{} LDAP users not in group {} in Inside:\n{}'.format( + len(stale_ldap_users), + self.ACTIVE_USERS_GROUP, + '\n'.join(stale_ldap_users))) + self.stdout.write('') + self.stdout.write('{} stale home directories:\n{}'.format( + len(stale_homedirs), + '\n'.join(stale_homedirs))) + + def get_inside_users(self): + group = InsideGroup.objects.get(posix_group=self.ACTIVE_USERS_GROUP) + inside_users = InsideUser.objects.filter(group_rels__group=group) + inside_users = inside_users.exclude( + Q(ldap_username__isnull=True) + | Q(registration_status='partial') + | Q(ldap_password__isnull=True)).values_list('username', flat=True) + + if self.options['verbosity'] == '3': + self.stdout.write('Found {} Inside users'.format(len(inside_users))) + + return set(inside_users) + + def get_ldap_users(self): + # TODO: What about system users, should they be whitelisted? + ldap_users = LdapUser.objects.values_list('username', flat=True) + + if self.options['verbosity'] == '3': + self.stdout.write('Found {} LDAP users'.format(len(ldap_users))) + + return set(ldap_users) \ No newline at end of file diff --git a/neuf_userinfo/ssh.py b/neuf_userinfo/ssh.py index 6856d78..ffa3284 100644 --- a/neuf_userinfo/ssh.py +++ b/neuf_userinfo/ssh.py @@ -1,11 +1,22 @@ from django.conf import settings from fabric.api import settings as fab_settings -from fabric.operations import sudo +from fabric.context_managers import hide +from fabric.operations import sudo, run import logging logger = logging.getLogger(__name__) +def _get_fabric_settings(host_string): + my_fab_settings = { + 'user': settings.FILESERVER_SSH_USER, + 'key_filename': settings.FILESERVER_SSH_KEY_PATH, + 'host_string': host_string, + 'warn_only': True + } + return my_fab_settings + + def create_home_dir(username, dry_run=False): """ Create homedir for username via shell script on fileserver host @@ -15,21 +26,28 @@ def create_home_dir(username, dry_run=False): Ref: http://stackoverflow.com/questions/6741523/using-python-fabric-without-the-command-line-tool-fab """ host_string = '{}@{}'.format(settings.FILESERVER_SSH_USER, settings.FILESERVER_HOST) - path = settings.FILESERVER_HOME_PATH - my_fab_settings = { - 'user': settings.FILESERVER_SSH_USER, - 'key_filename': settings.FILESERVER_SSH_KEY_PATH, - 'host_string': host_string, - 'warn_only': True - } + fabric_settings = _get_fabric_settings(host_string) - with fab_settings(**my_fab_settings): - script_cmd = '{} {} {}'.format(settings.FILESERVER_CREATE_HOMEDIR_SCRIPT, path, username) + with fab_settings(**fabric_settings): + with hide('running', 'stdout', 'stderr'): + script_cmd = ' '.join([settings.FILESERVER_CREATE_HOMEDIR_SCRIPT, settings.FILESERVER_HOME_PATH, username]) - logger.debug('Creating homedir on {} with command: {}'.format(host_string, script_cmd)) - if not dry_run: - return_val = sudo(script_cmd, shell=False) - if not return_val: - return False + logger.debug('Creating homedir on {} with command: {}'.format(host_string, script_cmd)) + if not dry_run: + return_val = sudo(script_cmd, shell=False) + if not return_val: + return False return True + + +def get_home_dirs(): + host_string = '{}@{}'.format(settings.FILESERVER_SSH_USER, settings.FILESERVER_HOST) + fabric_settings = _get_fabric_settings(host_string) + + with fab_settings(**fabric_settings): + with hide('running', 'stdout', 'stderr'): + homedirs_str = run('find {} -maxdepth 1 -type d'.format(settings.FILESERVER_HOME_PATH)) + homedirs = homedirs_str.split('\r\n{}'.format(settings.FILESERVER_HOME_PATH))[1:] + + return homedirs \ No newline at end of file diff --git a/neuf_userinfo/utils.py b/neuf_userinfo/utils.py index abfabcf..3cc4835 100644 --- a/neuf_userinfo/utils.py +++ b/neuf_userinfo/utils.py @@ -4,9 +4,7 @@ import base64 import logging from neuf_kerberos.utils import add_kerberos_principal -from neuf_ldap.utils import create_ldap_user, create_ldap_automount from neuf_radius.utils import create_radius_user -from neuf_userinfo.ssh import create_home_dir import rijndael logger = logging.getLogger(__name__) @@ -14,25 +12,9 @@ logger = logging.getLogger(__name__) def add_new_user_sync(user): """ - Currently does the following: - Create kerberos principal and set password - Create/set RADIUS user and password - - Previously (before 2015-04-03) did the following: - - Create new user in LDAP (username, first_name, last_name, email) - - Add to groups (usergroup, dns-alle), it not exists, create - - Set LDAP password - - Create homedir on fileserver - - Create automount entry - Note: Now handled by userinfo command sync_active_to_internal_systems """ - # if not create_ldap_user(user): - # logger.debug('Could not create user \'{}\'.'.format(user['username'])) - # return - # - # create_home_dir(user['username']) - # create_ldap_automount(user['username']) - # Requires raw password add_kerberos_principal(user['username'], user['password']) create_radius_user(user['username'], user['password']) diff --git a/scripts/create_home_directory.sh b/scripts/create_home_directory.sh index 2de7e55..3b78d34 100755 --- a/scripts/create_home_directory.sh +++ b/scripts/create_home_directory.sh @@ -14,7 +14,7 @@ fi HOME_DIRS_PATH=$1 USERNAME=$2 -if ! id -u $USERNAME; then +if ! id -u ${USERNAME} &>/dev/null; then echo "Cannot find user ${USERNAME}. Be sure the user is added to the ldap directory before running this script." exit 1 fi