refactored ldapuserdir code after splitting from sigateway project
This commit is contained in:
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
*~
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
sdist
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
298
bin/ldapuserdir-ctl
Executable file
298
bin/ldapuserdir-ctl
Executable file
@@ -0,0 +1,298 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import logging
|
||||
from ldapuserdir import LdapUserDir
|
||||
import ldap
|
||||
import sys
|
||||
import os
|
||||
from optparse import OptionParser
|
||||
import ConfigParser
|
||||
import getpass
|
||||
|
||||
def read_cfg(filename):
|
||||
cfg = ConfigParser.ConfigParser()
|
||||
|
||||
try:
|
||||
mylogger.debug('reading config from %s' % filename)
|
||||
cfg.read(filename)
|
||||
config = {
|
||||
'serverurl' : cfg.get('Ldap','serverurl'),
|
||||
'user_ou' : cfg.get('Ldap','user_ou'),
|
||||
'group_ou' : cfg.get('Ldap','group_ou'),
|
||||
'default_user_dn' : cfg.get('Ldap','default_user_dn'),
|
||||
'default_user_pw' : cfg.get('Ldap','default_user_pw'),
|
||||
}
|
||||
except Exception, err:
|
||||
sys.stderr.write("Error in reading configuration from %s\n" % filename)
|
||||
sys.stderr.write(str(err)+'\n')
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
config['default_group_filter'] = cfg.get('Ldap','default_group_filter')
|
||||
except:
|
||||
config['default_group_filter'] = '*'
|
||||
|
||||
return config
|
||||
|
||||
#Defaults
|
||||
|
||||
cfgfile_loc = [os.path.expanduser('~/.ldapuserdir-ctl.cfg'),
|
||||
'/etc/ldapuserdir-ctl.cfg']
|
||||
config = {
|
||||
'serverurl' : 'ldaps://xyzdir.example.com:636',
|
||||
'user_ou' : 'OU=Users,DC=example.com,DC=ch',
|
||||
'group_ou' : 'OU=Groups,DC=example.com,DC=ch',
|
||||
'default_user_dn' : 'CN=minpriv_user,OU=Services,DC=example.com,DC=ch',
|
||||
'default_user_pw' : 'dummypwd',
|
||||
'default_group_filter' : 'svc-ra*'
|
||||
}
|
||||
|
||||
flag_needprivileges = False
|
||||
userfilter = '-'
|
||||
|
||||
user_pw = ''
|
||||
mode = 'list'
|
||||
|
||||
mylogger = logging.getLogger(os.path.basename(sys.argv[0]))
|
||||
mylogger.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter('%(name)s %(levelname)s: %(message)s')
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.WARNING)
|
||||
ch.setFormatter(formatter)
|
||||
mylogger.addHandler(ch)
|
||||
|
||||
################################################
|
||||
# OPTION PARSING
|
||||
usage = """usage %prog [options] groupname [usernames]
|
||||
|
||||
Used to inspect or change members of a group in Active Directory
|
||||
User names can be given as full distinguished names or just as
|
||||
the short names (in that case they will be extended by the
|
||||
standard OU extension)
|
||||
|
||||
Examples:
|
||||
List group members
|
||||
%prog svc_ra_x06sa
|
||||
%prog 'svc_ra_*'
|
||||
|
||||
Get group memberships for user mueller
|
||||
%prog -g mueller
|
||||
|
||||
Add/delete users to/from a group (requires access rights!)
|
||||
%prog -a svc_ra_x06sa user1 user2 user3
|
||||
%prog -d svc_ra_x06sa user1 user2
|
||||
|
||||
List users matching a pattern
|
||||
%prog -u 'mueller*'
|
||||
|
||||
The configuration is read from a configuration file (default
|
||||
locations: """
|
||||
usage += ", ".join(cfgfile_loc) + ')\n'
|
||||
usage += """Configuration file example:
|
||||
|
||||
[Ldap]
|
||||
# URL for contacting the LDAP server
|
||||
serverurl = ldaps://d.psi.ch:636
|
||||
# base ldap path under which all users are found
|
||||
user_ou = OU=Users,OU=PSI,DC=d,DC=psi,DC=ch
|
||||
# base ldap path under which groups are found
|
||||
group_ou = ou=Groups,ou=PSI,dc=d,dc=psi,dc=ch
|
||||
# minimally privileged Ldap user and password for running normal
|
||||
# lookup queries
|
||||
default_user_dn = CN=linux_ldap,OU=Services,OU=IT,DC=d,DC=psi,DC=ch
|
||||
default_user_pw = TBVsK5zOfqMyxVmXco7y
|
||||
# Optional:
|
||||
# default filter to be used for group searches
|
||||
default_group_filter = svc-ra*
|
||||
|
||||
"""
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option('-a',
|
||||
action = 'store_true',
|
||||
dest = 'flag_add',
|
||||
help = 'add group members',
|
||||
)
|
||||
parser.add_option('-d',
|
||||
action = 'store_true',
|
||||
dest = 'flag_del',
|
||||
help = 'delete group members',
|
||||
)
|
||||
parser.add_option('-c',
|
||||
action = 'store',
|
||||
dest = 'cfgfile',
|
||||
help = 'path of a config file',
|
||||
default = ''
|
||||
)
|
||||
parser.add_option('-u',
|
||||
action = 'store',
|
||||
dest = 'userfilter',
|
||||
help = 'list all matching ldap users that have defined unix mappings',
|
||||
)
|
||||
parser.add_option('--debug',
|
||||
action = 'store_true',
|
||||
dest = 'flag_debug',
|
||||
help = 'debug mode: log messages at debug level',
|
||||
)
|
||||
parser.add_option('-D',
|
||||
action = 'store',
|
||||
dest = 'user_dn',
|
||||
help = 'DN or CN of ldap user for binding to the AD server (%s)' % config['default_user_dn'],
|
||||
default = None
|
||||
)
|
||||
parser.add_option('-f',
|
||||
action = 'store',
|
||||
dest = 'pwfile',
|
||||
help = 'path to password file (without this pwd will be prompted for)',
|
||||
default = ''
|
||||
)
|
||||
parser.add_option('-g',
|
||||
action = 'store',
|
||||
dest = 'user_to_group',
|
||||
help = 'get group memberships for this user',
|
||||
default = ''
|
||||
)
|
||||
parser.add_option('-v',
|
||||
action = 'store_true',
|
||||
dest = 'flag_verbose',
|
||||
help = 'use more verbose output',
|
||||
default = False
|
||||
)
|
||||
parser.add_option('--user-ou',
|
||||
action = 'store',
|
||||
dest = 'user_ou',
|
||||
help = 'default OU for users (%s)' % config['user_ou'],
|
||||
default = None
|
||||
)
|
||||
parser.add_option('--group-ou',
|
||||
action = 'store',
|
||||
dest = 'group_ou',
|
||||
help = 'default OU for groups (%s)' % config['group_ou'],
|
||||
default = None
|
||||
)
|
||||
parser.add_option('--no-msSFU',
|
||||
action = 'store_true',
|
||||
dest = 'flag_nosfu',
|
||||
help = 'do not restrict to entries with unix (msSFU) mappings',
|
||||
default = False
|
||||
)
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
group = None
|
||||
usernames = []
|
||||
if len(args) > 0:
|
||||
group = args.pop(0)
|
||||
usernames = args
|
||||
|
||||
if options.flag_debug:
|
||||
ch.setLevel(logging.DEBUG)
|
||||
|
||||
cfgfile = None
|
||||
if(options.cfgfile != ''):
|
||||
cfgfile = options.cfgfile
|
||||
else:
|
||||
for tmp in cfgfile_loc:
|
||||
if os.path.exists(tmp):
|
||||
cfgfile = tmp
|
||||
|
||||
if cfgfile == None:
|
||||
sys.stderr.write('Error: You must provide a config file (default locations '
|
||||
+ ', '.join(cfgfile_loc) + ' or explicitely)\n')
|
||||
sys.exit(1)
|
||||
|
||||
config = read_cfg(cfgfile)
|
||||
|
||||
user_dn = config['default_user_dn']
|
||||
if options.user_dn:
|
||||
config['user_dn'] = options.user_dn
|
||||
if options.group_ou:
|
||||
config['group_ou'] = options.group_ou
|
||||
if options.user_ou:
|
||||
config['user_ou'] = options.user_ou
|
||||
|
||||
flag_verbose = options.flag_verbose
|
||||
flag_sfu = not options.flag_nosfu
|
||||
userfilter = options.userfilter
|
||||
|
||||
if options.flag_del:
|
||||
mode = 'del'
|
||||
flag_needprivileges = True
|
||||
if options.flag_add:
|
||||
mode = 'add'
|
||||
flag_needprivileges = True
|
||||
if userfilter:
|
||||
mode = 'userlist'
|
||||
if options.user_to_group:
|
||||
mode = "user_to_group"
|
||||
user_to_group = options.user_to_group
|
||||
|
||||
if (mode == 'add' or mode == 'del') and len(usernames) == 0:
|
||||
sys.stderr.write("Error: Not enough arguments\n")
|
||||
sys.exit(1)
|
||||
|
||||
if ',' not in user_dn:
|
||||
user_dn = 'CN=' + user_dn + ',' + user_ou
|
||||
|
||||
if flag_needprivileges and user_dn == config['default_user_dn']:
|
||||
try:
|
||||
l_unpriv = LdapUserDir(config['serverurl'],
|
||||
config['default_user_dn'],
|
||||
config['default_user_pw'],
|
||||
user_ou = config['user_ou'],
|
||||
logger = mylogger)
|
||||
user_dn = l_unpriv.systemuser2dn(os.getlogin())
|
||||
if user_dn == '':
|
||||
sys.stderr.write('Error: Need priviledged user and cannot map your system user "%s" to LDAP DN for binding (you may want to use explicit -D user_dn option?)' % os.getlogin() )
|
||||
sys.exit(1)
|
||||
except ldap.LDAPError, e:
|
||||
sys.stderr.write('LDAP error: %s\n' % str(e))
|
||||
sys.exit(1)
|
||||
|
||||
if user_dn == config['default_user_dn']:
|
||||
user_pw = config['default_user_pw']
|
||||
|
||||
if options.pwfile != '':
|
||||
pwf = open(options.pwfile)
|
||||
user_pw = pwf.readline().rstrip('\n')
|
||||
|
||||
if user_pw == '':
|
||||
user_pw = getpass.getpass()
|
||||
if user_pw == '':
|
||||
sys.stderr.write('Error: No empty passwd allowed\n')
|
||||
# Note: AD accepts empty passwds, but will give anonymous access
|
||||
# So, we want to catch that case
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
l = LdapUserDir(config['serverurl'],
|
||||
user_dn,
|
||||
user_pw,
|
||||
config['group_ou'],
|
||||
config['user_ou'],
|
||||
sfu = flag_sfu,
|
||||
logger=mylogger)
|
||||
|
||||
if mode == 'list':
|
||||
sfilter = config['default_group_filter']
|
||||
if group:
|
||||
sfilter = group
|
||||
l.list_groups(sfilter)
|
||||
elif mode == 'userlist':
|
||||
l.list_users_etcpwd(userfilter, verbose = flag_verbose)
|
||||
elif mode == 'user_to_group':
|
||||
sys.stdout.write("\n".join(l.get_groups_for_user(user_to_group))
|
||||
+ "\n")
|
||||
elif mode == 'add':
|
||||
l.add_groupmembers(group, usernames)
|
||||
elif mode == 'del':
|
||||
l.del_groupmembers(group, usernames)
|
||||
except ldap.INVALID_CREDENTIALS, e:
|
||||
sys.exit(1)
|
||||
except ldap.LDAPError, e:
|
||||
sys.stderr.write('Unhandled LDAP error: %s\n' % str(e))
|
||||
sys.exit(1)
|
||||
except:
|
||||
sys.stderr.write('Unhandled Exception!!!!!!!!\n')
|
||||
raise
|
||||
|
||||
sys.exit(0)
|
||||
18
etc/ldapuserdir-ctl.cfg
Normal file
18
etc/ldapuserdir-ctl.cfg
Normal file
@@ -0,0 +1,18 @@
|
||||
[Ldap]
|
||||
# URL for contacting the LDAP server
|
||||
serverurl = ldaps://d.psi.ch:636
|
||||
|
||||
# base ldap path under which all users are found
|
||||
user_ou = OU=Users,OU=PSI,DC=d,DC=psi,DC=ch
|
||||
|
||||
# base ldap path under which groups are found
|
||||
group_ou = ou=Groups,ou=PSI,dc=d,dc=psi,dc=ch
|
||||
|
||||
# minimally privileged Ldap user and password for running normal
|
||||
# lookup queries
|
||||
default_user_dn = CN=linux_ldap,OU=Services,OU=IT,DC=d,DC=psi,DC=ch
|
||||
default_user_pw = secret_pwd
|
||||
|
||||
# Optional
|
||||
# default filter to be used for group searches
|
||||
default_group_filter = svc-ra*
|
||||
1
ldapuserdir/__init__.py
Normal file
1
ldapuserdir/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from ldapuserdir import LdapUserDir
|
||||
267
ldapuserdir/ldapuserdir.py
Normal file
267
ldapuserdir/ldapuserdir.py
Normal file
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env python
|
||||
######################################################################
|
||||
# Tool for modifying group memberships in AD
|
||||
#
|
||||
# Author: Derek Feichtinger <derek.feichtinger@psi.ch>
|
||||
#
|
||||
# Version info: $Id: ldapgroupmng.py 65 2012-09-25 15:35:38Z feichtinger $
|
||||
######################################################################
|
||||
|
||||
""" This module provides the LdapUserDir class. It is used to interact
|
||||
with an LDAP based user directory service
|
||||
"""
|
||||
|
||||
import ldap
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import logging
|
||||
|
||||
##############################################################
|
||||
# definitions of the search strings
|
||||
|
||||
# restrict to entries with msSFU mappings
|
||||
searches_mssfu= dict({
|
||||
'get_users' : '(&(objectClass=user)(!(objectClass=computer))(msSFU30UidNumber=*)(msSFU30HomeDirectory=*)(cn=%s))',
|
||||
'systemuser2dn' : '(&(objectClass=user)(!(objectClass=computer))(msSFU30UidNumber=*)(msSFU30HomeDirectory=*)(cn=%s))',
|
||||
'get_groups_struct' : '(&(objectClass=Group)(msSFU30GidNumber=*)(cn=%s))',
|
||||
'get_groups_for_user' : '(&(objectClass=Group)(msSFU30GidNumber=*)(cn=%s)(member=%s))'})
|
||||
|
||||
# allow entries without msSFU mappings
|
||||
searches_nomssfu= dict({
|
||||
'get_users' : '(&(objectClass=user)(!(objectClass=computer))(cn=%s))',
|
||||
'systemuser2dn' : '(&(objectClass=user)(!(objectClass=computer))(msSFU30UidNumber=*)(msSFU30HomeDirectory=*)(cn=%s))',
|
||||
'get_groups_struct' : '(&(objectClass=Group)(cn=%s))',
|
||||
'get_groups_for_user' : '(&(objectClass=Group)(cn=%s)(member=%s))'})
|
||||
##############################################################
|
||||
|
||||
class LdapUserDir(object):
|
||||
""" A class to interact with a LDAP based user and group directory
|
||||
"""
|
||||
def __init__(self,
|
||||
serverurl,
|
||||
user_dn,
|
||||
user_pw,
|
||||
group_ou = 'ou=example.com',
|
||||
user_ou = 'ou=example.com',
|
||||
sfu = True,
|
||||
logger = None):
|
||||
self.serverurl = serverurl
|
||||
self.group_ou = group_ou
|
||||
self.user_ou = user_ou
|
||||
|
||||
# whether to only search for entries with msSFU mappings
|
||||
# i.e. with existing unix attributes
|
||||
if sfu:
|
||||
self.searches = searches_mssfu
|
||||
else:
|
||||
self.searches = searches_nomssfu
|
||||
|
||||
|
||||
if logger == None:
|
||||
self.logger = logging.getLogger('LdapUserDir')
|
||||
self.logger.setLevel(logging.WARNING)
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
ch = logging.StreamHandler()
|
||||
|
||||
ch.setFormatter(formatter)
|
||||
ch.setLevel(logging.DEBUG)
|
||||
self.logger.addHandler(ch)
|
||||
else:
|
||||
self.logger = logger
|
||||
|
||||
self._ldap = ldap.initialize(self.serverurl, trace_level=0,
|
||||
trace_file=sys.stderr)
|
||||
self.logger.debug('binding to: %s\n' % serverurl)
|
||||
self.logger.debug('binding as user: %s\n' % user_dn)
|
||||
try:
|
||||
self._ldap.bind_s(user_dn, user_pw)
|
||||
except ldap.INVALID_CREDENTIALS, e:
|
||||
self.logger.error('Authentication failure for dn:"%s"\n' % user_dn)
|
||||
raise
|
||||
# need to clean that later
|
||||
except ldap.LDAPError, e:
|
||||
raise
|
||||
|
||||
def get_users(self, filter='*', ou=None):
|
||||
"""get the names of all users from the directory service
|
||||
@param filter A filter expression used for the cn part of the ldap dn
|
||||
@param ou The organisational unit to be used in the ldap search
|
||||
@returns A dictionary of the matching users { dn1:list1, ... }
|
||||
"""
|
||||
if ou == None:
|
||||
user_ou = self.user_ou
|
||||
#try:
|
||||
r = self._ldap.search_s(user_ou, ldap.SCOPE_SUBTREE,
|
||||
self.searches['get_users'] % filter)
|
||||
#except ldap.LDAPError, e:
|
||||
# print e
|
||||
# return
|
||||
return r
|
||||
|
||||
def list_users_etcpwd(self, filter='*', ou=None, verbose = False):
|
||||
"""Print '/etc/pwd' format like information about matching users
|
||||
@param filter A filter expression used for the cn part of the ldap dn
|
||||
@param ou The organisational unit to be used in the ldap search
|
||||
"""
|
||||
r = self.get_users(filter, ou)
|
||||
for dn, entry in r:
|
||||
# MUST fields
|
||||
try:
|
||||
print ':'.join([entry['cn'][0], entry['msSFU30UidNumber'][0],
|
||||
'IGNORE',
|
||||
entry['msSFU30GidNumber'][0],
|
||||
entry['displayName'][0],
|
||||
entry['msSFU30HomeDirectory'][0],
|
||||
entry['msSFU30LoginShell'][0],
|
||||
]),
|
||||
except KeyError:
|
||||
print ':'.join([entry['cn'][0],"","",entry['displayName'][0],
|
||||
"",""])
|
||||
|
||||
if verbose:
|
||||
for k in ['description', 'mail', 'mobile']:
|
||||
print '[%s:]' % (k,) ,
|
||||
if k in entry:
|
||||
print entry[k][0],
|
||||
else:
|
||||
print 'N.A.',
|
||||
print
|
||||
|
||||
def systemuser2dn(self, uname):
|
||||
"""Converts a user's system username to the dn of the ldap directory
|
||||
by performing a search on ldap
|
||||
@param uname The system username
|
||||
@returns The DN of the user or '' if no matching record was found
|
||||
|
||||
@exception may throw an ldap.LDAPError exception
|
||||
"""
|
||||
#try:
|
||||
srch = self.searches['systemuser2dn'] % uname
|
||||
self.logger.debug('systemuser2dn: %s' % srch)
|
||||
r = self._ldap.search_s(self.user_ou, ldap.SCOPE_SUBTREE, srch)
|
||||
#except ldap.LDAPError, e:
|
||||
# print e
|
||||
if len(r) == 0:
|
||||
return ''
|
||||
self.logger.debug('systemuser2dn: dn = %s' % r[0][0])
|
||||
return r[0][0]
|
||||
|
||||
def get_groups_struct(self, gfilter='*', ou = None):
|
||||
"""searches for groups
|
||||
returns the full ldap search result structure for the search
|
||||
with the optional filter applied to the cn field
|
||||
@param filter A filter expression used for the cn part of the ldap dn
|
||||
@param ou The organisational unit to be used in the ldap search
|
||||
@returns A dictionary of the matching groups { dn1:list1, ... }
|
||||
"""
|
||||
if ou == None:
|
||||
group_ou = self.group_ou
|
||||
#try:
|
||||
srch = self.searches['get_groups_struct'] % gfilter
|
||||
self.logger.debug('get_groups_struct: %s' % srch)
|
||||
r = self._ldap.search_s(group_ou, ldap.SCOPE_SUBTREE, srch)
|
||||
#except ldap.LDAPError, e:
|
||||
# print e
|
||||
return r
|
||||
|
||||
def get_groups_for_user(self, user, gfilter='*', ou=None, returndn = False):
|
||||
"""Get groups for a particular user from LDAP.
|
||||
The function will try to determine whether it receives a DN or
|
||||
a system username that needs to be converted to a DN first.
|
||||
@param user The user's DN or system name
|
||||
@param gfilter A filter expression used for the cn part of the ldap dn
|
||||
@param ou The organisational unit to be used in the ldap search
|
||||
@param returndn If set True the function will return DN, otherwise CN
|
||||
@returns list of group names
|
||||
"""
|
||||
if ou == None:
|
||||
group_ou = self.group_ou
|
||||
if not ',' in user:
|
||||
dnname = self.systemuser2dn(user)
|
||||
else:
|
||||
dnname = user
|
||||
|
||||
srch = self.searches['get_groups_for_user'] % (gfilter, dnname)
|
||||
|
||||
self.logger.debug('get_groups_for_user: %s' % srch)
|
||||
r = self._ldap.search_s(group_ou, ldap.SCOPE_SUBTREE, srch)
|
||||
|
||||
reslist = []
|
||||
for dn, entry in r:
|
||||
reslist.append(dn)
|
||||
|
||||
if returndn:
|
||||
return reslist
|
||||
|
||||
cnlist = []
|
||||
reg = re.compile(r'^CN=([^,]+),')
|
||||
for dn in reslist:
|
||||
m = reg.match(dn)
|
||||
if m:
|
||||
cnlist.append(m.group(1))
|
||||
else:
|
||||
raise RuntimeError("Could not match CN in DN (%s)" % dn)
|
||||
|
||||
return cnlist
|
||||
|
||||
def list_groups(self, filter = '*', ou = None):
|
||||
"""Prints a list of groups from the LDAP directory
|
||||
@param filter A filter expression used for the cn part of the ldap dn
|
||||
@param ou The organisational unit to be used in the ldap search
|
||||
"""
|
||||
r = self.get_groups_struct(filter, ou)
|
||||
if len(r) == 0:
|
||||
sys.stderr.write("Error: no groups found (filter: %s)\n" % filter)
|
||||
return 0
|
||||
|
||||
for dn, entry in r:
|
||||
print entry['cn'][0]
|
||||
if 'member' in entry:
|
||||
for cn in entry['member']:
|
||||
print ' member: ', cn
|
||||
|
||||
def _mod_groupmembers(self, ldapmode, dngroup, usernames):
|
||||
"""modifies members of an LDAP group entry
|
||||
@param ldapmode Either ldap.MOD_ADD, or ldap.MOD_DELETE
|
||||
@param dngroup DN of the group
|
||||
@param usernames List of usernames (system names or DNs)
|
||||
"""
|
||||
if not ',' in dngroup:
|
||||
dngroup = ''.join(['cn=', dngroup, ',', self.group_ou])
|
||||
dnlist = []
|
||||
for name in usernames:
|
||||
if not ',' in name:
|
||||
dnname = self.systemuser2dn(name)
|
||||
if dnname == '':
|
||||
raise RuntimeError('Error: No such ldap user: %s' % name)
|
||||
dnlist.append(dnname)
|
||||
else:
|
||||
dnlist.append(name)
|
||||
mod_attrs = [(ldapmode, 'member', dnlist)]
|
||||
try:
|
||||
self._ldap.modify_s(dngroup, mod_attrs)
|
||||
except ldap.ALREADY_EXISTS, e:
|
||||
self.logger.error('Entry already exists in group %s' % dngroup)
|
||||
raise
|
||||
except ldap.LDAPError, e:
|
||||
self.logger.error('ERROR modifying LDAP: group: %s; user list: %s\n'
|
||||
% (dngroup, dnlist))
|
||||
raise
|
||||
|
||||
def add_groupmembers(self, group, usernames):
|
||||
"""Adds users to an LDAP group
|
||||
@param dngroup DN of the group
|
||||
@param usernames List of usernames (system names or DNs)
|
||||
"""
|
||||
self._mod_groupmembers(ldap.MOD_ADD, group, usernames)
|
||||
|
||||
def del_groupmembers(self, group, usernames):
|
||||
"""Deletes users from an LDAP group
|
||||
@param dngroup DN of the group
|
||||
@param usernames List of usernames (system names or DNs)
|
||||
"""
|
||||
self._mod_groupmembers(ldap.MOD_DELETE, group, usernames)
|
||||
|
||||
def __del__(self):
|
||||
self._ldap.unbind()
|
||||
1
ldapuserdir/version.py
Normal file
1
ldapuserdir/version.py
Normal file
@@ -0,0 +1 @@
|
||||
__version__ = "0.1"
|
||||
31
setup.py
Normal file
31
setup.py
Normal file
@@ -0,0 +1,31 @@
|
||||
#from setuptools import setup, find_packages
|
||||
#from distutils.core import setup
|
||||
|
||||
# we use the distribute framework that has a backward compatible invocation
|
||||
# to the setuptools
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
# we get the package version from inside our package, since we then
|
||||
# can use it also from within the package
|
||||
execfile('ldapuserdir/version.py')
|
||||
|
||||
setup(
|
||||
name = "ldapuserdir",
|
||||
version = __version__,
|
||||
description = "Client for interacting with a LDAP user/group directory service",
|
||||
long_description = "Client for listing user and group information and"
|
||||
+ " for managing group memberships",
|
||||
author = "Derek Feichtinger",
|
||||
author_email = "derek.feichtinger@psi.ch",
|
||||
license = "GPL",
|
||||
# url =
|
||||
#packages = find_packages('sigateway'),
|
||||
packages = ['ldapuserdir'],
|
||||
scripts = ['bin/ldapuserdir-ctl'],
|
||||
|
||||
# following format is (targetdir,[list of files])
|
||||
data_files = [('etc',['etc/ldapuserdir-ctl.cfg'])],
|
||||
|
||||
install_requires = ['python-ldap']
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user