Yuvipanda has uploaded a new change for review. https://gerrit.wikimedia.org/r/301058
Change subject: WIP replacement of modify-ldap-groups ...................................................................... WIP replacement of modify-ldap-groups Change-Id: Ibc9e5bf28826804e90b9ae143bcdd4cf0020b11d --- M modules/ldap/files/scripts/modify-ldap-group 1 file changed, 91 insertions(+), 132 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/operations/puppet refs/changes/58/301058/1 diff --git a/modules/ldap/files/scripts/modify-ldap-group b/modules/ldap/files/scripts/modify-ldap-group index 6c7978d..9dd3c22 100755 --- a/modules/ldap/files/scripts/modify-ldap-group +++ b/modules/ldap/files/scripts/modify-ldap-group @@ -1,143 +1,102 @@ -#!/usr/bin/python - -##################################################################### -### THIS FILE IS MANAGED BY PUPPET -### puppet:///modules/ldap/scripts/modify-ldap-group -##################################################################### - -import sys -import grp -import traceback -import ldapsupportlib -import copy -from optparse import OptionParser - -try: - import ldap - import ldap.modlist -except ImportError: - sys.stderr.write("Unable to import LDAP library.\n") - sys.exit(1) +#!/usr/bin/python3 +""" +Add / Remove users from LDAP group +""" +import ldap3 +import yaml +import argparse -def main(): - parser = OptionParser(conflict_handler="resolve") - parser.set_usage('modify-ldap-group [options] <groupname> [--rename <newusergroup>]\nexample: modify-ldap-group --gid=501 wikidev') +def get_members_list(conn, basedn, group, user): + """ + Get list of members of the given group + """ + conn.search( + 'ou=groups,{base}'.format(base=basedn), + '(cn={group})'.format(group=group), + ldap3.SEARCH_SCOPE_WHOLE_SUBTREE, + attributes=['member'] + ) + return conn.response[0]['attributes']['member'] - ldapSupportLib = ldapsupportlib.LDAPSupportLib() - ldapSupportLib.addParserOptions(parser, "scriptuser") - parser.add_option("-m", "--directorymanager", action="store_true", dest="directorymanager", help="Use the Directory Manager's credentials, rather than your own") - parser.add_option("--gid", action="store", dest="gidNumber", help="Set the group's gid") - parser.add_option("--rename", action="store_true", dest="rename", help="Rename the user") - parser.add_option("--addmembers", action="store", dest="addMembers", help="Add a comma separated list of users to this group") - parser.add_option("--deletemembers", action="store", dest="deleteMembers", help="Delete a comma separated list of users from this") - (options, args) = parser.parse_args() +def add_member(conn, basedn, group, user): + """ + Adds user to group as a mmeber + """ + userdn = 'uid={user},ou=people,{base}'.format( + user=user, + base=basedn, + ) + groupdn = 'cn={group},ou=groups,{base}'.format( + group=group, + base=basedn, + ) + members = get_members_list(conn, basedn, group, user) + if userdn in members: + raise Exception("User already is member of given group") + members.append(userdn) + op = { + 'member': [(ldap3.MODIFY_REPLACE, [members])] + } + return conn.modify(groupdn, op).result - if len(args) != 1: - if options.rename and len(args) != 2: - parser.error("modify-ldap-group expects exactly two arguments when using rename.") - elif not options.rename: - parser.error("modify-ldap-group expects exactly one argument, unless using --rename.") - ldapSupportLib.setBindInfoByOptions(options, parser) +def remove_member(conn, basedn, group, user): + """ + Remove user from group as a member + """ + userdn = 'uid={user},ou=people,{base}'.format( + user=user, + base=basedn, + ) + groupdn = 'cn={group},ou=groups,{base}'.format( + group=group, + base=basedn, + ) + members = get_members_list(conn, basedn, group, user) + if userdn not in members: + raise Exception("User already is not a member of given group") + members.remove(userdn) + op = { + 'member': [(ldap3.MODIFY_REPLACE, [members])] + } + return conn.modify(groupdn, op).result - base = ldapSupportLib.getBase() - ds = ldapSupportLib.connect() +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument( + 'action', + help='Action to perform', + choices=['adduser', 'removeuser'], + ) + parser.add_argument( + 'group', + help='Name of group to modify', + ) + parser.add_argument( + 'user', + help='Name of user to add/remove' + ) + parser.add_argument( + '--ldapconfig', + help='Path to LDAP connection config in YAML format', + default='/etc/ldap.scriptuser.yaml', + ) - # w00t We're in! - try: - groupname = args[0] - PosixData = ds.search_s("ou=groups," + base, ldap.SCOPE_SUBTREE, "(&(objectclass=posixGroup)(cn=" + groupname + "))") - if not PosixData: - raise ldap.NO_SUCH_OBJECT() - dn = PosixData[0][0] + args = parser.parse_args() - if options.rename: - newgroupname = args[1] + with open(args.ldapconfig, encoding='utf-8') as f: + ldapconfig = yaml.safe_load(f) - # Rename the entry - newrdn = 'cn=' + newgroupname - ds.rename_s(dn, newrdn) - else: - PosixData = PosixData[0][1] - NewPosixData = copy.deepcopy(PosixData) - if options.gidNumber: - try: - groupcheck = grp.getgrgid(options.gidNumber) - raise ldap.TYPE_OR_VALUE_EXISTS() - except KeyError: - NewPosixData['gidNumber'] = options.gidNumber - if options.addMembers: - raw_members = options.addMembers.split(',') - for raw_member in raw_members: - try: - user=ds.search_s("ou=people," + base, ldap.SCOPE_SUBTREE, "uid=%s" % raw_member, ("dn",)) - if len(user) == 0: - sys.stderr.write(raw_member + " doesn't exist, and won't be added to the group.\n") - return - if len(user) > 1: - sys.stderr.write(raw_member + " exist multiple times, this is so wrong, abandon all hope\n") - return - except Exception as e: - sys.stderr.write("Failed to search user in LDAP. Error: %s\n" % str(e)) - raise e - membertoadd = user[0][0] - # member expects DNs - if 'member' in NewPosixData.keys(): - if membertoadd in NewPosixData['member']: - sys.stderr.write(raw_member + " is already a member of the group, skipping.\n") - else: - NewPosixData['member'].append(membertoadd) - else: - NewPosixData['member'] = [membertoadd] - elif options.deleteMembers: - raw_members = options.deleteMembers.split(',') - for raw_member in raw_members: - membertoremove = 'uid=' + raw_member + ',ou=people,' + base - if 'member' in NewPosixData.keys(): - if membertoremove in NewPosixData['member']: - NewPosixData['member'].remove(membertoremove) - else: - sys.stderr.write(raw_member + " isn't a member of the group, skipping.\n") - else: - sys.stderr.write("This group contains no members.\n") - - if PosixData == NewPosixData: - sys.stderr.write("No changes to make; exiting.\n") - else: - modlist = ldap.modlist.modifyModlist(PosixData, NewPosixData) - ds.modify_s(dn, modlist) - except ldap.UNWILLING_TO_PERFORM, msg: - sys.stderr.write("LDAP was unwilling to modify the group. Error was: %s\n" % msg[0]["info"]) - ds.unbind() - sys.exit(1) - except ldap.NO_SUCH_OBJECT: - sys.stderr.write("The group you are trying to modify doesn't exist.\n") - ds.unbind() - sys.exit(1) - except ldap.TYPE_OR_VALUE_EXISTS: - sys.stderr.write("The gid given already exists.\n") - ds.unbind() - sys.exit(1) - except ldap.PROTOCOL_ERROR: - sys.stderr.write("There was an LDAP protocol error; see traceback.\n") - traceback.print_exc(file=sys.stderr) - ds.unbind() - sys.exit(1) - except Exception: - try: - sys.stderr.write("There was a general error, this is unexpected; see traceback.\n") - traceback.print_exc(file=sys.stderr) - ds.unbind() - except Exception: - sys.stderr.write("Also failed to unbind.\n") - traceback.print_exc(file=sys.stderr) - sys.exit(1) - - ds.unbind() - sys.exit(0) - -if __name__ == "__main__": - main() + with ldap3.Connection([ + ldap3.Server(s) for s in ldapconfig['servers']], + user=ldapconfig['user'], + auto_bind=True, + password=ldapconfig['password'] + ) as conn: + if args.action == 'adduser': + print(add_member(conn, ldapconfig['basedn'], args.group, args.user)) + elif args.action == 'removeuser': + print(remove_member(conn, ldapconfig['basedn'], args.group, args.user)) \ No newline at end of file -- To view, visit https://gerrit.wikimedia.org/r/301058 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ibc9e5bf28826804e90b9ae143bcdd4cf0020b11d Gerrit-PatchSet: 1 Gerrit-Project: operations/puppet Gerrit-Branch: production Gerrit-Owner: Yuvipanda <yuvipa...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits