diff --git a/bin/showgroup.py b/bin/showgroup.py index c74c8b848a0acd4a4f321d788dc887355fb9ee7e..266ebeae99269e2f3cb1e9842ccd1e03a88b1681 100755 --- a/bin/showgroup.py +++ b/bin/showgroup.py @@ -5,10 +5,8 @@ import argparse import collections import lib_path import lib -import tabulate import dphysldap - OPTS = collections.OrderedDict() OPTS['access'] = 'accessRight' OPTS['blocked'] = 'blocked' @@ -18,56 +16,49 @@ OPTS['mail'] = 'mail' OPTS['telephone'] = 'telephoneNumber' -def main(): +def get_args(opts=dict()): parser = argparse.ArgumentParser( - add_help=False, description='Show group members') - parser.add_argument('group', help='The group name (cn)') - for k, v in OPTS.items(): + add_help=False, description='Show groups or group members') + parser.add_argument('group', help='The group name (cn), or wildcards') + for k, v in opts.items(): parser.add_argument('-' + k[:1], '--' + k, dest=k, action='store_const', const=True, - help='Show ' + v + ' column') + help='Show ' + v) parser.add_argument('--help', action='help', help='Show this help message and exit') - arg = vars(parser.parse_args()) - - ldap = dphysldap.Ldap() + return vars(parser.parse_args()) - group_query = 'cn: {0}'.format(arg['group']) - group_attrs = ['cn', 'gidNumber', 'memberUid'] - groups = ldap.get_groups(query=group_query, attributes=group_attrs) - if len(groups) != 1: - sys.exit('error: number of groups matched: {0}'.format(len(groups))) - group = groups[0] +def main(): + args = get_args(OPTS) - if 'memberUid' not in group: - sys.exit('error: empty group') - members = group['memberUid'] - user_query = 'uid:' + ';'.join(members) - user_attrs = ['uid', 'uidNumber', 'gecos'] + ldap = dphysldap.Ldap() - for k, v in OPTS.items(): - if arg[k]: - user_attrs.append(v) + groups = dphysldap.Groups(ldap, ['cn', 'gidNumber', 'memberUid']) + groups.search(args['group']) - users = ldap.get_users(query=user_query, attributes=user_attrs) + if not groups: + sys.exit('No groups found.') - if not users: - sys.exit('error: no users found') + if len(groups) != 1: + #groups.sort('cn') + print(groups) - cn = group['cn'] - gid = group['gidNumber'] - print('Members of {} ({}):'.format(cn, gid)) + else: + group = groups[0] + cn = group['cn'] + gid = group['gidNumber'] + members = group['memberUid'] - table = list() + print('Members of {} ({}):'.format(cn, gid)) - for u in users: - row = list() - for attr in user_attrs: - row.append(u[attr]) - table.append(row) + attrs = ['uid', 'uidNumber', 'gecos'] + attrs.extend([v for k, v in OPTS.items() if args[k]]) - print(tabulate.tabulate(table, tablefmt='simple', headers=user_attrs)) + users = dphysldap.Users(ldap, attrs) + users.search(';'.join(members)) + #users.sort('uid') + print(users) if __name__ == "__main__": diff --git a/bin/showuser.py b/bin/showuser.py new file mode 100755 index 0000000000000000000000000000000000000000..758cc29caa278d2639332920fb3a34c9749d211f --- /dev/null +++ b/bin/showuser.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +import sys +import argparse +import collections +import lib_path +import lib +import dphysldap + +OPTS = collections.OrderedDict() +OPTS['access'] = 'accessRight' +OPTS['blocked'] = 'blocked' +OPTS['home'] = 'homeDirectory' +OPTS['shell'] = 'loginShell' +OPTS['mail'] = 'mail' +OPTS['telephone'] = 'telephoneNumber' +OPTS['gid'] = 'gidNumber' +OPTS['cn'] = 'cn' +OPTS['language'] = 'language' + + +def get_args(opts=dict()): + parser = argparse.ArgumentParser( + add_help=False, description='Show user(s)') + parser.add_argument('user', help='The user name (uid), or wildcards') + for k, v in opts.items(): + parser.add_argument('-' + k[:1], '--' + k, dest=k, + action='store_const', const=True, + help='Show ' + v) + parser.add_argument('--help', action='help', + help='Show this help message and exit') + return vars(parser.parse_args()) + + +def main(): + args = get_args(OPTS) + + ldap = dphysldap.Ldap() + + attrs = ['uid', 'uidNumber', 'gecos'] + attrs.extend([v for k, v in OPTS.items() if args[k]]) + + users = dphysldap.Users(ldap, attrs) + users.search(args['user']) + #users.sort('uid') + + if not users: + sys.exit('No userss found.') + + if len(users) != 1: + print(users) + + else: + user = users[0] + for attr in attrs: + print(': '.join([attr, str(user[attr])])) + + +if __name__ == "__main__": + main() diff --git a/lib/isg/dphysldap.py b/lib/isg/dphysldap.py index cc3f8483890427d2a58815a8bb2ed3915d37f983..d8407187a3cafcb92ace83cacaaf1e7aef2b9ddf 100644 --- a/lib/isg/dphysldap.py +++ b/lib/isg/dphysldap.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 import ssl -from collections.abc import Mapping +import collections import lib_path import lib import ldap3 +import tabulate +FMT = 'simple' SERVERS = ['phd-aa1.ethz.ch', 'phd-aa2.ethz.ch', 'phd-aa3.ethz.ch'] BASE = 'dc=phys,dc=ethz,dc=ch' CA_CERTS = '/etc/ssl/certs/ca-certificates.crt' @@ -28,7 +30,7 @@ class AttributeValue(list): return delimit.join([str(e) for e in self]) -class Entry(Mapping): +class Entry(collections.abc.Mapping): """ Abstraction class for LDAP Entry imitating dict """ @@ -49,6 +51,12 @@ class Entry(Mapping): def __len__(self): return len(self._storage) + + def __str__(self): + """ + Modifies the "informal" string value of str(x) or print(x) + """ + return '\n'.join([': '.join([k, str(v)]) for k, v in self.items() if v]) class Ldap(object): @@ -78,7 +86,7 @@ class Ldap(object): self.connection.start_tls() self.connection.bind() self.user_classes = ['posixAccount', 'dphysUser', 'inetOrgPerson', 'shadowAccount'] - self.group_classes = ['posixGroup'] + self.group_classes = ['posixGroup', 'dphysGroup'] self.obj_user = None self.obj_group = None @@ -105,3 +113,75 @@ class Ldap(object): if not self.obj_group: self.obj_group = ldap3.ObjectDef(self.group_classes, self.connection) return self.get_entries(self.obj_group, query=query, attributes=attributes) + + +class Groups(list): + """ + Abstraction class for Groups imitating list + """ + def __init__(self, ldap, attrs, *args): + list.__init__(self, *args) + self._ldap = ldap + self._attrs = attrs + + def __str__(self): + """ + Modifies the "informal" string value of str(x) or print(x) + to return groups in tabulated form + """ + headers = self._attrs + table = [[g[h] for h in headers] for g in self] + return tabulate.tabulate(table, tablefmt=FMT, headers=headers) + + #def sort(self, attr): + # self = sorted(self, key=lambda k: k[attr]) + + def search(self, cn): + """ + Search example: `cn`, `cn*`, `*cn*`, `cn1;cn2` + """ + query = 'cn: {0}'.format(cn) + self.clear() + self.extend(self._ldap.get_groups(query=query, attributes=self._attrs)) + + def members(self, index=None): + """ + Returns list of members + """ + if index == None: + members = set() + for group in self: + members.add(group['memberUid']) + return list(members) + else: + return self[index]['memberUid'] + + +class Users(list): + """ + Abstraction class for Users imitating list + """ + def __init__(self, ldap, attrs, *args): + list.__init__(self, *args) + self._ldap = ldap + self._attrs = attrs + + def __str__(self): + """ + Modifies the "informal" string value of str(x) or print(x) + to return users in tabulated form + """ + headers = self._attrs + table = [[u[h] for h in headers] for u in self] + return tabulate.tabulate(table, tablefmt=FMT, headers=self._attrs) + + #def sort(self, attr): + # self = sorted(self, key=lambda d: d[attr].__str__()) + + def search(self, uid): + """ + Search example: `uid`, `uid*`, `*uid*`, `uid1;uid2` + """ + query = 'uid: {0}'.format(uid) + self.clear() + self.extend(self._ldap.get_users(query=query, attributes=self._attrs))