diff --git a/README.md b/README.md index f48621d..38cfeb1 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,33 @@ Tool to force update memberOf attributes of users on OpenLDAP directory using me ## Requirements - * [python-mylib](https://gogs.zionetrix.net/bn8/python-mylib) (legacy branch) + * [python-mylib](https://gogs.zionetrix.net/bn8/python-mylib) ## Installation ``` -git clone -b legacy https://gogs.zionetrix.net/bn8/updateMemberOf.git /usr/local/src/updateMemberOf +git clone https://gogs.zionetrix.net/bn8/updateMemberOf.git /usr/local/src/updateMemberOf ln -s /usr/local/src/updateMemberOf/updateMemberOf /usr/local/sbin/updateMemberOf ``` ## Usage ``` -usage: updateMemberOf [-h] [-d] [-H HOST] [-D DN] [-P PWD] [-f FILTER] [-b BASE] [--v2] [-a ATTR] [-p] +usage: updateMemberOf [-h] [-v] [-d] [-l LOGFILE] [-C] [-j] [-p] [-H HOST] [-D DN] [-P PWD] [-f FILTER] [-b BASE] [--v2] [-a ATTR] Update memberOf attributes optional arguments: -h, --help show this help message and exit + -v, --verbose Enable verbose mode -d, --debug Enable debug mode + -l LOGFILE, --log-file LOGFILE + Log file path (default: None) + -C, --console Always log on console (even if log file is configured) + -j, --just-try Enable just-try mode + -p, --progress Enable progress bar + +LDAP options: -H HOST, --host HOST LDAP server URI (default: ldapi:///) -D DN, --dn DN LDAP bind DN -P PWD, --password PWD @@ -32,7 +40,6 @@ optional arguments: -b BASE, --base BASE LDAP group base DN --v2 Utiliser le protocole LDAP v2. -a ATTR, --attr ATTR Group members attribute (default: uniqueMember) - -p, --progress Show progress bar ``` ## Copyright diff --git a/updateMemberOf b/updateMemberOf index 4af2b59..fa9f90c 100755 --- a/updateMemberOf +++ b/updateMemberOf @@ -1,29 +1,26 @@ #!/usr/bin/python -import argparse +""" Tool to force update memberOf attributes of users on OpenLDAP directory using memberOf overlay """ + import getpass import logging -import sys -sys.path.insert(0,'/usr/local/src/python-mylib/') -import LdapServer -import Pbar +from mylib.ldap import LdapClient +from mylib.ldap import LdapServer +from mylib.pbar import Pbar +from mylib.scripts.helpers import get_opts_parser +from mylib.scripts.helpers import init_logging default_host = 'ldapi:///' default_filter = '(objectClass=posixGroup)' default_attr = 'uniqueMember' -parser = argparse.ArgumentParser(description="Update memberOf attributes") +parser = get_opts_parser(desc="Update memberOf attributes", just_try=True, progress=True) # options -parser.add_argument( - '-d', '--debug', - action='store_true', - dest='debug', - help='Enable debug mode', - default=False -) -parser.add_argument( +ldap_opts = parser.add_argument_group('LDAP options') + +ldap_opts.add_argument( '-H', '--host', action="store", type=str, @@ -31,7 +28,7 @@ parser.add_argument( help="LDAP server URI (default: %s)" % default_host, default=default_host ) -parser.add_argument( +ldap_opts.add_argument( '-D', '--dn', action="store", type=str, @@ -39,7 +36,7 @@ parser.add_argument( help="LDAP bind DN", default=None ) -parser.add_argument( +ldap_opts.add_argument( '-P', '--password', action="store", type=str, @@ -47,7 +44,7 @@ parser.add_argument( help="LDAP bind password", default=None ) -parser.add_argument( +ldap_opts.add_argument( '-f', '--filter', action="store", type=str, @@ -55,7 +52,7 @@ parser.add_argument( help="LDAP groups filter (default: %s)" % default_filter, default=default_filter ) -parser.add_argument( +ldap_opts.add_argument( '-b', '--base', action="store", type=str, @@ -63,14 +60,14 @@ parser.add_argument( help="LDAP group base DN", default=None ) -parser.add_argument( +ldap_opts.add_argument( '--v2', action="store_true", dest="ldapv2", help="Utiliser le protocole LDAP v2.", default=None ) -parser.add_argument( +ldap_opts.add_argument( '-a', '--attr', action="store", type=str, @@ -78,49 +75,61 @@ parser.add_argument( help="Group members attribute (default: %s)" % default_attr, default=default_attr ) -parser.add_argument( - '-p', '--progress', - action='store_true', - dest='progress', - help='Show progress bar', - default=False -) options = parser.parse_args() -if options.debug: - logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(levelname)s - %(message)s') -else: - logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s') - if options.base is None: - parser.error('You must specify base DN using --base parameter') + parser.error('You must specify base DN using --base parameter') + +init_logging(options, "Update memberOf") if options.dn and not options.pwd: - options.pwd=getpass.getpass() + options.pwd = getpass.getpass() + +class MyLdapClient(LdapClient): + """ Implement a custom LdapClient to handle group objects """ + + def __init__(self, scripts_options): # pylint: disable=super-init-not-called + self.options = scripts_options + logging.info(u"Connect to LDAP server %s", self.options.host) + self.cnx = LdapServer(self.options.host, dn=self.options.dn, pwd=self.options.pwd, v2=self.options.ldapv2) + self.cnx.connect() + + def get_groups(self): + """ Retreive groups form LDAP server """ + return self.get_objects( + 'group', + self.options.filter, + self.options.base, + [ self.options.attr ] + ) + + def touch_group_members(self, obj): + """ Touch group members attribute """ + current = self.get_attr(obj, self.options.attr, all_values=True) + if not current: + return True + + logging.debug('Update - remove values of %s', obj['dn']) + changes = self.get_changes(obj, {options.attr: []}) + logging.debug('Changes:\n%s', self.format_changes(changes)) + if self.update_object(obj, changes): + obj[options.attr] = [] + logging.debug('Update - restore values of %s', obj['dn']) + changes = self.get_changes(obj, {options.attr: current}) + logging.debug('Changes:\n%s', self.format_changes(changes)) + return myldap.update_object(obj, changes) + return False # Start LDAP connection -myldap = LdapServer.LdapServer(options.host, options.dn, options.pwd, options.ldapv2) -myldap.connect() +myldap = MyLdapClient(options) +groups = myldap.get_groups() -ldap_data=myldap.search(options.base, options.filter, [ options.attr ]) +logging.info('%s groups found', len(groups)) -logging.info('%s groups found', len(ldap_data)) - -pbar = Pbar.Pbar('Update memberOf', len(ldap_data), enabled=options.progress) -for dn in ldap_data: - old = myldap.get_attr(ldap_data[dn], options.attr, all=True) - if old is None: - continue - - logging.debug('Update - remove values of %s', dn) - if myldap.update_object( - dn, {options.attr: old}, {options.attr: []} - ): - logging.debug('Update - restore values of %s', dn) - myldap.update_object(dn, {options.attr: []}, {options.attr: old}) - - pbar.increment() +pbar = Pbar('Update memberOf', len(groups), enabled=options.progress) +for dn, group in groups.items(): + myldap.touch_group_members(group) + pbar.increment() pbar.finish() -