PgSQL to LDAP transition - Phase 1: Added LDAP support for member data.
This is the first major update for the PgSQL to LDAP transition. We will be deprecating the members table in PostgreSQL and moving that information into the LDAP directory. With this commit, all newly created members will have their attributes added to LDAP in addition to the members table in the database. The database is still used as the canonical source of this information: the information in LDAP is kept up-to-date but almost never referenced.
This commit is contained in:
parent
a8268ce266
commit
7b81a13f78
|
@ -190,8 +190,15 @@ def create(username, name, minimum_id, maximum_id, home, password=None, descript
|
||||||
|
|
||||||
### User creation ###
|
### User creation ###
|
||||||
|
|
||||||
# create the LDAP entry
|
if not ldap_connection.user_lookup(username):
|
||||||
ldap_connection.user_add(username, name, userid, gid, home, shell, gecos, description)
|
|
||||||
|
# create the LDAP entry
|
||||||
|
ldap_connection.account_add(username, name, userid, gid, home, shell, gecos, description)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
# add the required attribute to the LDAP entry
|
||||||
|
ldap_connection.member_add_account(username, userid, gid, home, shell, gecos)
|
||||||
|
|
||||||
# create a user group if no other group was specified
|
# create a user group if no other group was specified
|
||||||
if not group:
|
if not group:
|
||||||
|
@ -257,7 +264,7 @@ def status(username):
|
||||||
Returns: a boolean 2-tuple (exists, has_password)
|
Returns: a boolean 2-tuple (exists, has_password)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ldap_state = ldap_connection.user_lookup(username)
|
ldap_state = ldap_connection.account_lookup(username)
|
||||||
krb_state = krb_connection.get_principal(username)
|
krb_state = krb_connection.get_principal(username)
|
||||||
return (ldap_state is not None, krb_state is not None)
|
return (ldap_state is not None, krb_state is not None)
|
||||||
|
|
||||||
|
@ -786,7 +793,7 @@ def check_name_usage(name):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# see if user exists in LDAP
|
# see if user exists in LDAP
|
||||||
if ldap_connection.user_lookup(name):
|
if ldap_connection.account_lookup(name):
|
||||||
raise NameConflict(name, "account", "LDAP")
|
raise NameConflict(name, "account", "LDAP")
|
||||||
|
|
||||||
# see if group exists in LDAP
|
# see if group exists in LDAP
|
||||||
|
@ -818,7 +825,7 @@ def check_account_status(username, require_ldap=True, require_krb=False):
|
||||||
|
|
||||||
if not connected():
|
if not connected():
|
||||||
raise AccountException("Not connected to LDAP and Kerberos")
|
raise AccountException("Not connected to LDAP and Kerberos")
|
||||||
if require_ldap and not ldap_connection.user_lookup(username):
|
if require_ldap and not ldap_connection.account_lookup(username):
|
||||||
raise NoSuchAccount(username, "LDAP")
|
raise NoSuchAccount(username, "LDAP")
|
||||||
if require_krb and not krb_connection.get_principal(username):
|
if require_krb and not krb_connection.get_principal(username):
|
||||||
raise NoSuchAccount(username, "KRB")
|
raise NoSuchAccount(username, "KRB")
|
||||||
|
|
|
@ -11,8 +11,9 @@ must also be moved into this module.
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
from csc.adm import terms
|
from csc.adm import terms
|
||||||
from csc.backends import db
|
from csc.backends import db, ldapi
|
||||||
from csc.common import conf
|
from csc.common import conf
|
||||||
|
from csc.common.excep import InvalidArgument
|
||||||
|
|
||||||
|
|
||||||
### Configuration ###
|
### Configuration ###
|
||||||
|
@ -25,7 +26,8 @@ def load_configuration():
|
||||||
"""Load Members Configuration"""
|
"""Load Members Configuration"""
|
||||||
|
|
||||||
string_fields = [ 'studentid_regex', 'realname_regex', 'server',
|
string_fields = [ 'studentid_regex', 'realname_regex', 'server',
|
||||||
'database', 'user', 'password' ]
|
'database', 'user', 'password', 'server_url', 'users_base',
|
||||||
|
'groups_base', 'admin_bind_dn', 'admin_bind_pw' ]
|
||||||
|
|
||||||
# read configuration file
|
# read configuration file
|
||||||
cfg_tmp = conf.read(CONFIG_FILE)
|
cfg_tmp = conf.read(CONFIG_FILE)
|
||||||
|
@ -86,41 +88,46 @@ class NoSuchMember(MemberException):
|
||||||
### Connection Management ###
|
### Connection Management ###
|
||||||
|
|
||||||
# global database connection
|
# global database connection
|
||||||
connection = db.DBConnection()
|
db_connection = db.DBConnection()
|
||||||
|
|
||||||
|
# global directory connection
|
||||||
|
ldap_connection = ldapi.LDAPConnection()
|
||||||
|
|
||||||
def connect():
|
def connect():
|
||||||
"""Connect to PostgreSQL."""
|
"""Connect to PostgreSQL."""
|
||||||
|
|
||||||
load_configuration()
|
load_configuration()
|
||||||
connection.connect(cfg['server'], cfg['database'])
|
db_connection.connect(cfg['server'], cfg['database'])
|
||||||
|
ldap_connection.connect(cfg['server_url'], cfg['admin_bind_dn'], cfg['admin_bind_pw'], cfg['users_base'], cfg['groups_base'])
|
||||||
|
|
||||||
|
|
||||||
def disconnect():
|
def disconnect():
|
||||||
"""Disconnect from PostgreSQL."""
|
"""Disconnect from PostgreSQL."""
|
||||||
|
|
||||||
connection.disconnect()
|
db_connection.disconnect()
|
||||||
|
ldap_connection.disconnect()
|
||||||
|
|
||||||
|
|
||||||
def connected():
|
def connected():
|
||||||
"""Determine whether the connection has been established."""
|
"""Determine whether the db_connection has been established."""
|
||||||
|
|
||||||
return connection.connected()
|
return db_connection.connected() and ldap_connection.connected()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Member Table ###
|
### Member Table ###
|
||||||
|
|
||||||
def new(realname, studentid=None, program=None, mtype='user', userid=None):
|
def new(uid, realname, studentid=None, program=None, mtype='user'):
|
||||||
"""
|
"""
|
||||||
Registers a new CSC member. The member is added to the members table
|
Registers a new CSC member. The member is added to the members table
|
||||||
and registered for the current term.
|
and registered for the current term.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
uid - the initial user id
|
||||||
realname - the full real name of the member
|
realname - the full real name of the member
|
||||||
studentid - the student id number of the member
|
studentid - the student id number of the member
|
||||||
program - the program of study of the member
|
program - the program of study of the member
|
||||||
mtype - a string describing the type of member ('user', 'club')
|
mtype - a string describing the type of member ('user', 'club')
|
||||||
userid - the initial user id
|
|
||||||
|
|
||||||
Returns: the memberid of the new member
|
Returns: the memberid of the new member
|
||||||
|
|
||||||
|
@ -135,7 +142,7 @@ def new(realname, studentid=None, program=None, mtype='user', userid=None):
|
||||||
# blank attributes should be NULL
|
# blank attributes should be NULL
|
||||||
if studentid == '': studentid = None
|
if studentid == '': studentid = None
|
||||||
if program == '': program = None
|
if program == '': program = None
|
||||||
if userid == '': userid = None
|
if uid == '': uid = None
|
||||||
if mtype == '': mtype = None
|
if mtype == '': mtype = None
|
||||||
|
|
||||||
# check the student id format
|
# check the student id format
|
||||||
|
@ -147,18 +154,33 @@ def new(realname, studentid=None, program=None, mtype='user', userid=None):
|
||||||
raise InvalidRealName(realname)
|
raise InvalidRealName(realname)
|
||||||
|
|
||||||
# check for duplicate student id
|
# check for duplicate student id
|
||||||
member = connection.select_member_by_studentid(studentid)
|
member = db_connection.select_member_by_studentid(studentid) or \
|
||||||
|
ldap_connection.member_search_studentid(studentid)
|
||||||
if member:
|
if member:
|
||||||
raise DuplicateStudentID(studentid)
|
raise DuplicateStudentID(studentid)
|
||||||
|
|
||||||
# add the member
|
# check for duplicate userid
|
||||||
memberid = connection.insert_member(realname, studentid, program)
|
member = db_connection.select_member_by_userid(uid) or \
|
||||||
|
ldap_connection.user_lookup(uid)
|
||||||
|
if member:
|
||||||
|
raise InvalidArgument("uid", uid, "duplicate uid")
|
||||||
|
|
||||||
# register them for this term
|
# add the member to the database
|
||||||
connection.insert_term(memberid, terms.current())
|
memberid = db_connection.insert_member(realname, studentid, program, userid=uid)
|
||||||
|
|
||||||
# commit the transaction
|
# add the member to the directory
|
||||||
connection.commit()
|
ldap_connection.member_add(uid, realname, studentid, program)
|
||||||
|
|
||||||
|
# register them for this term in the database
|
||||||
|
db_connection.insert_term(memberid, terms.current())
|
||||||
|
|
||||||
|
# register them for this term in the directory
|
||||||
|
member = ldap_connection.member_lookup(uid)
|
||||||
|
member['term'] = [ terms.current() ]
|
||||||
|
ldap_connection.user_modify(uid, member)
|
||||||
|
|
||||||
|
# commit the database transaction
|
||||||
|
db_connection.commit()
|
||||||
|
|
||||||
return memberid
|
return memberid
|
||||||
|
|
||||||
|
@ -177,7 +199,7 @@ def get(memberid):
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return connection.select_member_by_id(memberid)
|
return db_connection.select_member_by_id(memberid)
|
||||||
|
|
||||||
|
|
||||||
def get_userid(userid):
|
def get_userid(userid):
|
||||||
|
@ -197,7 +219,7 @@ def get_userid(userid):
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return connection.select_member_by_userid(userid)
|
return db_connection.select_member_by_userid(userid)
|
||||||
|
|
||||||
|
|
||||||
def get_studentid(studentid):
|
def get_studentid(studentid):
|
||||||
|
@ -217,7 +239,7 @@ def get_studentid(studentid):
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return connection.select_member_by_studentid(studentid)
|
return db_connection.select_member_by_studentid(studentid)
|
||||||
|
|
||||||
|
|
||||||
def list_term(term):
|
def list_term(term):
|
||||||
|
@ -237,7 +259,7 @@ def list_term(term):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# retrieve a list of memberids in term
|
# retrieve a list of memberids in term
|
||||||
memberlist = connection.select_members_by_term(term)
|
memberlist = db_connection.select_members_by_term(term)
|
||||||
|
|
||||||
return memberlist.values()
|
return memberlist.values()
|
||||||
|
|
||||||
|
@ -259,7 +281,7 @@ def list_name(name):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# retrieve a list of memberids matching name
|
# retrieve a list of memberids matching name
|
||||||
memberlist = connection.select_members_by_name(name)
|
memberlist = db_connection.select_members_by_name(name)
|
||||||
|
|
||||||
return memberlist.values()
|
return memberlist.values()
|
||||||
|
|
||||||
|
@ -272,7 +294,7 @@ def list_all():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# retrieve a list of members
|
# retrieve a list of members
|
||||||
memberlist = connection.select_all_members()
|
memberlist = db_connection.select_all_members()
|
||||||
|
|
||||||
return memberlist.values()
|
return memberlist.values()
|
||||||
|
|
||||||
|
@ -292,18 +314,23 @@ def delete(memberid):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# save member data
|
# save member data
|
||||||
member = connection.select_member_by_id(memberid)
|
member = db_connection.select_member_by_id(memberid)
|
||||||
|
|
||||||
# bail if not found
|
# bail if not found
|
||||||
if not member:
|
if not member:
|
||||||
raise NoSuchMember(memberid)
|
raise NoSuchMember(memberid)
|
||||||
|
|
||||||
term_list = connection.select_terms(memberid)
|
term_list = db_connection.select_terms(memberid)
|
||||||
|
|
||||||
# remove data from the db
|
# remove data from the db
|
||||||
connection.delete_term_all(memberid)
|
db_connection.delete_term_all(memberid)
|
||||||
connection.delete_member(memberid)
|
db_connection.delete_member(memberid)
|
||||||
connection.commit()
|
db_connection.commit()
|
||||||
|
|
||||||
|
# remove data from the directory
|
||||||
|
if member and member['userid']:
|
||||||
|
uid = member['userid']
|
||||||
|
ldap_connection.user_delete(uid)
|
||||||
|
|
||||||
return (member, term_list)
|
return (member, term_list)
|
||||||
|
|
||||||
|
@ -334,7 +361,7 @@ def update(member):
|
||||||
raise InvalidStudentID(studentid)
|
raise InvalidStudentID(studentid)
|
||||||
|
|
||||||
# check for duplicate student id
|
# check for duplicate student id
|
||||||
dupmember = connection.select_member_by_studentid(studentid)
|
dupmember = db_connection.select_member_by_studentid(studentid)
|
||||||
if dupmember:
|
if dupmember:
|
||||||
raise DuplicateStudentID(studentid)
|
raise DuplicateStudentID(studentid)
|
||||||
|
|
||||||
|
@ -348,10 +375,10 @@ def update(member):
|
||||||
raise NoSuchMember(memberid)
|
raise NoSuchMember(memberid)
|
||||||
|
|
||||||
# do the update
|
# do the update
|
||||||
connection.update_member(member)
|
db_connection.update_member(member)
|
||||||
|
|
||||||
# commit the transaction
|
# commit the transaction
|
||||||
connection.commit()
|
db_connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -376,6 +403,14 @@ def register(memberid, term_list):
|
||||||
if type(term_list) in (str, unicode):
|
if type(term_list) in (str, unicode):
|
||||||
term_list = [ term_list ]
|
term_list = [ term_list ]
|
||||||
|
|
||||||
|
ldap_member = None
|
||||||
|
db_member = get(memberid)
|
||||||
|
if db_member['userid']:
|
||||||
|
uid = db_member['userid']
|
||||||
|
ldap_member = ldap_connection.member_lookup(uid)
|
||||||
|
if ldap_member and 'term' not in ldap_member:
|
||||||
|
ldap_member['term'] = []
|
||||||
|
|
||||||
for term in term_list:
|
for term in term_list:
|
||||||
|
|
||||||
# check term syntax
|
# check term syntax
|
||||||
|
@ -383,9 +418,16 @@ def register(memberid, term_list):
|
||||||
raise InvalidTerm(term)
|
raise InvalidTerm(term)
|
||||||
|
|
||||||
# add term to database
|
# add term to database
|
||||||
connection.insert_term(memberid, term)
|
db_connection.insert_term(memberid, term)
|
||||||
|
|
||||||
connection.commit()
|
# add the term to the directory
|
||||||
|
if ldap_member:
|
||||||
|
ldap_member['term'].append(term)
|
||||||
|
|
||||||
|
if ldap_member:
|
||||||
|
ldap_connection.user_modify(uid, ldap_member)
|
||||||
|
|
||||||
|
db_connection.commit()
|
||||||
|
|
||||||
|
|
||||||
def registered(memberid, term):
|
def registered(memberid, term):
|
||||||
|
@ -402,7 +444,7 @@ def registered(memberid, term):
|
||||||
Example: registered(3349, "f2006") -> True
|
Example: registered(3349, "f2006") -> True
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return connection.select_term(memberid, term) is not None
|
return db_connection.select_term(memberid, term) is not None
|
||||||
|
|
||||||
|
|
||||||
def member_terms(memberid):
|
def member_terms(memberid):
|
||||||
|
@ -418,7 +460,7 @@ def member_terms(memberid):
|
||||||
Example: registered(0) -> 's1993'
|
Example: registered(0) -> 's1993'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
terms_list = connection.select_terms(memberid)
|
terms_list = db_connection.select_terms(memberid)
|
||||||
terms_list.sort(terms.compare)
|
terms_list.sort(terms.compare)
|
||||||
return terms_list
|
return terms_list
|
||||||
|
|
||||||
|
@ -432,18 +474,19 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
# t=test m=member s=student u=updated
|
# t=test m=member s=student u=updated
|
||||||
tmname = 'Test Member'
|
tmname = 'Test Member'
|
||||||
|
tmuid = 'testmember'
|
||||||
tmprogram = 'Metaphysics'
|
tmprogram = 'Metaphysics'
|
||||||
tmsid = '00000000'
|
tmsid = '00000000'
|
||||||
tm2name = 'Test Member 2'
|
tm2name = 'Test Member 2'
|
||||||
|
tm2uid = 'testmember2'
|
||||||
tm2sid = '00000001'
|
tm2sid = '00000001'
|
||||||
tm2uname = 'Test Member II'
|
tm2uname = 'Test Member II'
|
||||||
tm2usid = '00000002'
|
tm2usid = '00000002'
|
||||||
tm2uprogram = 'Pseudoscience'
|
tm2uprogram = 'Pseudoscience'
|
||||||
tm2uuserid = 'testmember'
|
|
||||||
|
|
||||||
tmdict = {'name': tmname, 'userid': None, 'program': tmprogram, 'type': 'user', 'studentid': tmsid }
|
tmdict = {'name': tmname, 'userid': tmuid, 'program': tmprogram, 'type': 'user', 'studentid': tmsid }
|
||||||
tm2dict = {'name': tm2name, 'userid': None, 'program': None, 'type': 'user', 'studentid': tm2sid }
|
tm2dict = {'name': tm2name, 'userid': tm2uid, 'program': None, 'type': 'user', 'studentid': tm2sid }
|
||||||
tm2udict = {'name': tm2uname, 'userid': tm2uuserid, 'program': tm2uprogram, 'type': 'user', 'studentid': tm2usid }
|
tm2udict = {'name': tm2uname, 'userid': tm2uid, 'program': tm2uprogram, 'type': 'user', 'studentid': tm2usid }
|
||||||
|
|
||||||
thisterm = terms.current()
|
thisterm = terms.current()
|
||||||
nextterm = terms.next(thisterm)
|
nextterm = terms.next(thisterm)
|
||||||
|
@ -464,8 +507,8 @@ if __name__ == '__main__':
|
||||||
if dmid: delete(dmid['memberid'])
|
if dmid: delete(dmid['memberid'])
|
||||||
|
|
||||||
test(new)
|
test(new)
|
||||||
tmid = new(tmname, tmsid, tmprogram)
|
tmid = new(tmuid, tmname, tmsid, tmprogram)
|
||||||
tm2id = new(tm2name, tm2sid)
|
tm2id = new(tm2uid, tm2name, tm2sid)
|
||||||
success()
|
success()
|
||||||
|
|
||||||
tmdict['memberid'] = tmid
|
tmdict['memberid'] = tmid
|
||||||
|
@ -495,7 +538,7 @@ if __name__ == '__main__':
|
||||||
success()
|
success()
|
||||||
|
|
||||||
test(register)
|
test(register)
|
||||||
register(tmid, terms.next(terms.current()))
|
register(tmid, nextterm)
|
||||||
assert_equal(True, registered(tmid, nextterm))
|
assert_equal(True, registered(tmid, nextterm))
|
||||||
success()
|
success()
|
||||||
|
|
||||||
|
@ -517,7 +560,7 @@ if __name__ == '__main__':
|
||||||
success()
|
success()
|
||||||
|
|
||||||
test(get_userid)
|
test(get_userid)
|
||||||
assert_equal(tm2udict, get_userid(tm2uuserid))
|
assert_equal(tm2udict, get_userid(tm2uid))
|
||||||
success()
|
success()
|
||||||
|
|
||||||
test(get_studentid)
|
test(get_studentid)
|
||||||
|
|
|
@ -12,6 +12,7 @@ This frontend is poorly documented, deprecated, and undoubtedly full of bugs.
|
||||||
import curses.ascii, re, os
|
import curses.ascii, re, os
|
||||||
from helpers import menu, inputbox, msgbox, reset
|
from helpers import menu, inputbox, msgbox, reset
|
||||||
from csc.adm import accounts, members, terms
|
from csc.adm import accounts, members, terms
|
||||||
|
from csc.common.excep import InvalidArgument
|
||||||
|
|
||||||
# color of the ceo border
|
# color of the ceo border
|
||||||
BORDER_COLOR = curses.COLOR_RED
|
BORDER_COLOR = curses.COLOR_RED
|
||||||
|
@ -20,7 +21,7 @@ BORDER_COLOR = curses.COLOR_RED
|
||||||
def action_new_member(wnd):
|
def action_new_member(wnd):
|
||||||
"""Interactively add a new member."""
|
"""Interactively add a new member."""
|
||||||
|
|
||||||
studentid, program = None, ''
|
userid, studentid, program = '', None, ''
|
||||||
|
|
||||||
# read the name
|
# read the name
|
||||||
prompt = " Name: "
|
prompt = " Name: "
|
||||||
|
@ -50,12 +51,21 @@ def action_new_member(wnd):
|
||||||
if program is None or program.lower() == 'exit':
|
if program is None or program.lower() == 'exit':
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# read user id
|
||||||
|
prompt = "Userid:"
|
||||||
|
while userid == '':
|
||||||
|
userid = inputbox(wnd, prompt, 18)
|
||||||
|
|
||||||
|
# user abort
|
||||||
|
if userid is None or userid.lower() == 'exit':
|
||||||
|
return False
|
||||||
|
|
||||||
# connect the members module to its backend if necessary
|
# connect the members module to its backend if necessary
|
||||||
if not members.connected(): members.connect()
|
if not members.connected(): members.connect()
|
||||||
|
|
||||||
# attempt to create the member
|
# attempt to create the member
|
||||||
try:
|
try:
|
||||||
memberid = members.new(realname, studentid, program)
|
memberid = members.new(userid, realname, studentid, program)
|
||||||
|
|
||||||
msgbox(wnd, "Success! Your memberid is %s. You are now registered\n"
|
msgbox(wnd, "Success! Your memberid is %s. You are now registered\n"
|
||||||
% memberid + "for the " + terms.current() + " term.")
|
% memberid + "for the " + terms.current() + " term.")
|
||||||
|
@ -69,6 +79,12 @@ def action_new_member(wnd):
|
||||||
except members.InvalidRealName:
|
except members.InvalidRealName:
|
||||||
msgbox(wnd, 'Invalid real name: "%s"' % realname)
|
msgbox(wnd, 'Invalid real name: "%s"' % realname)
|
||||||
return False
|
return False
|
||||||
|
except InvalidArgument, e:
|
||||||
|
if e.argname == 'uid' and e.explanation == 'duplicate uid':
|
||||||
|
msgbox(wnd, 'A member with this user ID exists.')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def action_term_register(wnd):
|
def action_term_register(wnd):
|
||||||
|
@ -196,7 +212,7 @@ def repair_account(wnd, memberid, userid):
|
||||||
password = input_password(wnd)
|
password = input_password(wnd)
|
||||||
accounts.create_member(userid, password, member['name'], memberid)
|
accounts.create_member(userid, password, member['name'], memberid)
|
||||||
msgbox(wnd, "Account created (where the hell did it go, anyway?)\n"
|
msgbox(wnd, "Account created (where the hell did it go, anyway?)\n"
|
||||||
"If you're homedir still exists, it will not be inaccessible to you,\n"
|
"If your homedir still exists, it will not be inaccessible to you,\n"
|
||||||
"please contact systems-committee@csclub.uwaterloo.ca to get this resolved.\n")
|
"please contact systems-committee@csclub.uwaterloo.ca to get this resolved.\n")
|
||||||
|
|
||||||
elif not haspw:
|
elif not haspw:
|
||||||
|
@ -267,7 +283,8 @@ def action_create_account(wnd):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# member already has an account?
|
# member already has an account?
|
||||||
if member['userid']:
|
if not accounts.connected(): accounts.connect()
|
||||||
|
if member['userid'] and accounts.status(member['userid'])[0]:
|
||||||
|
|
||||||
userid = member['userid']
|
userid = member['userid']
|
||||||
msgbox(wnd, "Member " + str(memberid) + " already has an account: " + member['userid'] + "\n"
|
msgbox(wnd, "Member " + str(memberid) + " already has an account: " + member['userid'] + "\n"
|
||||||
|
@ -278,6 +295,9 @@ def action_create_account(wnd):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if member['userid']:
|
||||||
|
userid = member['userid']
|
||||||
|
|
||||||
# read user id
|
# read user id
|
||||||
prompt = "Userid:"
|
prompt = "Userid:"
|
||||||
while userid == '':
|
while userid == '':
|
||||||
|
|
|
@ -98,7 +98,7 @@ class LDAPConnection(object):
|
||||||
|
|
||||||
### Helper Methods ###
|
### Helper Methods ###
|
||||||
|
|
||||||
def lookup(self, dn):
|
def lookup(self, dn, objectClass=None):
|
||||||
"""
|
"""
|
||||||
Helper method to retrieve the attributes of an entry.
|
Helper method to retrieve the attributes of an entry.
|
||||||
|
|
||||||
|
@ -113,7 +113,11 @@ class LDAPConnection(object):
|
||||||
|
|
||||||
# search for the specified dn
|
# search for the specified dn
|
||||||
try:
|
try:
|
||||||
matches = self.ldap.search_s(dn, ldap.SCOPE_BASE)
|
if objectClass:
|
||||||
|
search_filter = '(objectClass=%s)' % self.escape(objectClass)
|
||||||
|
matches = self.ldap.search_s(dn, ldap.SCOPE_BASE, search_filter)
|
||||||
|
else:
|
||||||
|
matches = self.ldap.search_s(dn, ldap.SCOPE_BASE)
|
||||||
except ldap.NO_SUCH_OBJECT:
|
except ldap.NO_SUCH_OBJECT:
|
||||||
return None
|
return None
|
||||||
except ldap.LDAPError, e:
|
except ldap.LDAPError, e:
|
||||||
|
@ -123,148 +127,60 @@ class LDAPConnection(object):
|
||||||
if len(matches) > 1:
|
if len(matches) > 1:
|
||||||
raise LDAPException("duplicate dn in ldap: " + dn)
|
raise LDAPException("duplicate dn in ldap: " + dn)
|
||||||
|
|
||||||
|
# dn was found, but didn't match the objectClass filter
|
||||||
|
elif len(matches) < 1:
|
||||||
|
return None
|
||||||
|
|
||||||
# return the attributes of the single successful match
|
# return the attributes of the single successful match
|
||||||
else:
|
match = matches[0]
|
||||||
match = matches[0]
|
match_dn, match_attributes = match
|
||||||
match_dn, match_attributes = match
|
return match_attributes
|
||||||
return match_attributes
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### User-related Methods ###
|
### User-related Methods ###
|
||||||
|
|
||||||
def user_lookup(self, uid):
|
def user_lookup(self, uid, objectClass=None):
|
||||||
"""
|
"""
|
||||||
Retrieve the attributes of a user.
|
Retrieve the attributes of a user.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
uid - the UNIX username to look up
|
uid - the uid to look up
|
||||||
|
|
||||||
Returns: attributes of user with uid
|
Returns: attributes of user with uid
|
||||||
|
|
||||||
Example: connection.user_lookup('mspang') ->
|
|
||||||
{ 'uid': 'mspang', 'uidNumber': 21292 ...}
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dn = 'uid=' + uid + ',' + self.user_base
|
dn = 'uid=' + uid + ',' + self.user_base
|
||||||
return self.lookup(dn)
|
return self.lookup(dn, objectClass)
|
||||||
|
|
||||||
|
|
||||||
def user_search(self, search_filter):
|
def user_search(self, search_filter, params):
|
||||||
"""
|
"""
|
||||||
Helper for user searches.
|
Search for users with a filter.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
search_filter - LDAP filter string to match users against
|
search_filter - LDAP filter string to match users against
|
||||||
|
|
||||||
Returns: the list of uids matched (usernames)
|
Returns: a dictionary mapping uids to attributes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not self.connected(): raise LDAPException("Not connected!")
|
if not self.connected(): raise LDAPException("Not connected!")
|
||||||
|
|
||||||
|
search_filter = search_filter % tuple(self.escape(x) for x in params)
|
||||||
|
|
||||||
# search for entries that match the filter
|
# search for entries that match the filter
|
||||||
try:
|
try:
|
||||||
matches = self.ldap.search_s(self.user_base, ldap.SCOPE_SUBTREE, search_filter)
|
matches = self.ldap.search_s(self.user_base, ldap.SCOPE_SUBTREE, search_filter)
|
||||||
except ldap.LDAPError, e:
|
except ldap.LDAPError, e:
|
||||||
raise LDAPException("user search failed: %s" % e)
|
raise LDAPException("user search failed: %s" % e)
|
||||||
|
|
||||||
# list for uids found
|
results = {}
|
||||||
uids = []
|
|
||||||
|
|
||||||
for match in matches:
|
for match in matches:
|
||||||
dn, attributes = match
|
dn, attrs = match
|
||||||
|
uid = attrs['uid'][0]
|
||||||
|
results[uid] = attrs
|
||||||
|
|
||||||
# uid is a required attribute of posixAccount
|
return results
|
||||||
if not attributes.has_key('uid'):
|
|
||||||
raise LDAPException(dn + ' (posixAccount) has no uid')
|
|
||||||
|
|
||||||
# do not handle the case of multiple usernames in one entry (yet)
|
|
||||||
elif len(attributes['uid']) > 1:
|
|
||||||
raise LDAPException(dn + ' (posixAccount) has multiple uids')
|
|
||||||
|
|
||||||
# append the sole uid of this match to the list
|
|
||||||
uids.append( attributes['uid'][0] )
|
|
||||||
|
|
||||||
return uids
|
|
||||||
|
|
||||||
|
|
||||||
def user_search_id(self, uidNumber):
|
|
||||||
"""
|
|
||||||
Retrieves a list of users with a certain UNIX uid number.
|
|
||||||
|
|
||||||
LDAP (or passwd for that matter) does not enforce any
|
|
||||||
restriction on the number of accounts that can have
|
|
||||||
a certain UID. Therefore this method returns a list of matches.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
uidNumber - the user id of the accounts desired
|
|
||||||
|
|
||||||
Returns: the list of uids matched (usernames)
|
|
||||||
|
|
||||||
Example: connection.user_search_id(21292) -> ['mspang']
|
|
||||||
"""
|
|
||||||
|
|
||||||
# search for posixAccount entries with the specified uidNumber
|
|
||||||
search_filter = '(&(objectClass=posixAccount)(uidNumber=%d))' % uidNumber
|
|
||||||
return self.user_search(search_filter)
|
|
||||||
|
|
||||||
|
|
||||||
def user_search_gid(self, gidNumber):
|
|
||||||
"""
|
|
||||||
Retrieves a list of users with a certain UNIX gid
|
|
||||||
number (search by default group).
|
|
||||||
|
|
||||||
Returns: the list of uids matched (usernames)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# search for posixAccount entries with the specified gidNumber
|
|
||||||
search_filter = '(&(objectClass=posixAccount)(gidNumber=%d))' % gidNumber
|
|
||||||
return self.user_search(search_filter)
|
|
||||||
|
|
||||||
|
|
||||||
def user_add(self, uid, cn, uidNumber, gidNumber, homeDirectory, loginShell=None, gecos=None, description=None):
|
|
||||||
"""
|
|
||||||
Adds a user to the directory.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
uid - the UNIX username for the account
|
|
||||||
cn - the real name of the member
|
|
||||||
uidNumber - the UNIX user id number
|
|
||||||
gidNumber - the UNIX group id number (default group)
|
|
||||||
homeDirectory - home directory for the user
|
|
||||||
loginShell - login shell for the user
|
|
||||||
gecos - comment field (usually stores name etc)
|
|
||||||
description - description field (optional and unimportant)
|
|
||||||
|
|
||||||
Example: connection.user_add('mspang', 'Michael Spang',
|
|
||||||
21292, 100, '/users/mspang', '/bin/bash',
|
|
||||||
'Michael Spang,,,')
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not self.connected(): raise LDAPException("Not connected!")
|
|
||||||
|
|
||||||
dn = 'uid=' + uid + ',' + self.user_base
|
|
||||||
attrs = {
|
|
||||||
'objectClass': [ 'top', 'account', 'posixAccount', 'shadowAccount' ],
|
|
||||||
'uid': [ uid ],
|
|
||||||
'cn': [ cn ],
|
|
||||||
'loginShell': [ loginShell ],
|
|
||||||
'uidNumber': [ str(uidNumber) ],
|
|
||||||
'gidNumber': [ str(gidNumber) ],
|
|
||||||
'homeDirectory': [ homeDirectory ],
|
|
||||||
'gecos': [ gecos ],
|
|
||||||
}
|
|
||||||
|
|
||||||
if loginShell:
|
|
||||||
attrs['loginShell'] = loginShell
|
|
||||||
if description:
|
|
||||||
attrs['description'] = [ description ]
|
|
||||||
|
|
||||||
try:
|
|
||||||
modlist = ldap.modlist.addModlist(attrs)
|
|
||||||
self.ldap.add_s(dn, modlist)
|
|
||||||
except ldap.LDAPError, e:
|
|
||||||
raise LDAPException("unable to add: %s" % e)
|
|
||||||
|
|
||||||
|
|
||||||
def user_modify(self, uid, attrs):
|
def user_modify(self, uid, attrs):
|
||||||
|
@ -281,8 +197,6 @@ class LDAPConnection(object):
|
||||||
connection.user_modify('mspang', user)
|
connection.user_modify('mspang', user)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not self.connected(): raise LDAPException("Not connected!")
|
|
||||||
|
|
||||||
# distinguished name of the entry to modify
|
# distinguished name of the entry to modify
|
||||||
dn = 'uid=' + uid + ',' + self.user_base
|
dn = 'uid=' + uid + ',' + self.user_base
|
||||||
|
|
||||||
|
@ -308,8 +222,6 @@ class LDAPConnection(object):
|
||||||
Example: connection.user_delete('mspang')
|
Example: connection.user_delete('mspang')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not self.connected(): raise LDAPException("Not connected!")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dn = 'uid=' + uid + ',' + self.user_base
|
dn = 'uid=' + uid + ',' + self.user_base
|
||||||
self.ldap.delete_s(dn)
|
self.ldap.delete_s(dn)
|
||||||
|
@ -318,6 +230,116 @@ class LDAPConnection(object):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Account-related Methods ###
|
||||||
|
|
||||||
|
def account_lookup(self, uid):
|
||||||
|
"""
|
||||||
|
Retrieve the attributes of an account.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
uid - the uid to look up
|
||||||
|
|
||||||
|
Returns: attributes of user with uid
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.user_lookup(uid, 'posixAccount')
|
||||||
|
|
||||||
|
|
||||||
|
def account_search_id(self, uidNumber):
|
||||||
|
"""
|
||||||
|
Retrieves a list of accounts with a certain UNIX uid number.
|
||||||
|
|
||||||
|
LDAP (or passwd for that matter) does not enforce any restriction on
|
||||||
|
the number of accounts that can have a certain UID number. Therefore
|
||||||
|
this method returns a list of matches.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
uidNumber - the user id of the accounts desired
|
||||||
|
|
||||||
|
Returns: a dictionary mapping uids to attributes
|
||||||
|
|
||||||
|
Example: connection.account_search_id(21292) -> {'mspang': { ... }}
|
||||||
|
"""
|
||||||
|
|
||||||
|
search_filter = '(&(objectClass=posixAccount)(uidNumber=%s))'
|
||||||
|
return self.user_search(search_filter, [ uidNumber ])
|
||||||
|
|
||||||
|
|
||||||
|
def account_search_gid(self, gidNumber):
|
||||||
|
"""
|
||||||
|
Retrieves a list of accounts with a certain UNIX gid
|
||||||
|
number (search by default group).
|
||||||
|
|
||||||
|
Returns: a dictionary mapping uids to attributes
|
||||||
|
"""
|
||||||
|
|
||||||
|
search_filter = '(&(objectClass=posixAccount)(gidNumber=%s))'
|
||||||
|
return self.user_search(search_filter, [ gidNumber ])
|
||||||
|
|
||||||
|
|
||||||
|
def account_add(self, uid, cn, uidNumber, gidNumber, homeDirectory, loginShell=None, gecos=None, description=None, update=False):
|
||||||
|
"""
|
||||||
|
Adds a user account to the directory.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
uid - the UNIX username for the account
|
||||||
|
cn - the real name of the member
|
||||||
|
uidNumber - the UNIX user id number
|
||||||
|
gidNumber - the UNIX group id number (default group)
|
||||||
|
homeDirectory - home directory for the user
|
||||||
|
loginShell - login shell for the user
|
||||||
|
gecos - comment field (usually stores name etc)
|
||||||
|
description - description field (optional and unimportant)
|
||||||
|
update - if True, will update existing entries
|
||||||
|
|
||||||
|
Example: connection.user_add('mspang', 'Michael Spang',
|
||||||
|
21292, 100, '/users/mspang', '/bin/bash',
|
||||||
|
'Michael Spang,,,')
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self.connected(): raise LDAPException("Not connected!")
|
||||||
|
|
||||||
|
dn = 'uid=' + uid + ',' + self.user_base
|
||||||
|
attrs = {
|
||||||
|
'objectClass': [ 'top', 'account', 'posixAccount', 'shadowAccount' ],
|
||||||
|
'uid': [ uid ],
|
||||||
|
'cn': [ cn ],
|
||||||
|
'loginShell': [ loginShell ],
|
||||||
|
'uidNumber': [ str(uidNumber) ],
|
||||||
|
'gidNumber': [ str(gidNumber) ],
|
||||||
|
'homeDirectory': [ homeDirectory ],
|
||||||
|
'gecos': [ gecos ],
|
||||||
|
}
|
||||||
|
|
||||||
|
if loginShell:
|
||||||
|
attrs['loginShell'] = [ loginShell ]
|
||||||
|
if description:
|
||||||
|
attrs['description'] = [ description ]
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
old_entry = self.user_lookup(uid)
|
||||||
|
if old_entry and 'posixAccount' not in old_entry['objectClass'] and update:
|
||||||
|
|
||||||
|
attrs.update(old_entry)
|
||||||
|
attrs['objectClass'] = list(attrs['objectClass'])
|
||||||
|
attrs['objectClass'].append('posixAccount')
|
||||||
|
if not 'shadowAccount' in attrs['objectClass']:
|
||||||
|
attrs['objectClass'].append('shadowAccount')
|
||||||
|
|
||||||
|
modlist = ldap.modlist.modifyModlist(old_entry, attrs)
|
||||||
|
self.ldap.modify_s(dn, modlist)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
modlist = ldap.modlist.addModlist(attrs)
|
||||||
|
self.ldap.add_s(dn, modlist)
|
||||||
|
|
||||||
|
except ldap.LDAPError, e:
|
||||||
|
raise LDAPException("unable to add: %s" % e)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Group-related Methods ###
|
### Group-related Methods ###
|
||||||
|
|
||||||
def group_lookup(self, cn):
|
def group_lookup(self, cn):
|
||||||
|
@ -355,27 +377,19 @@ class LDAPConnection(object):
|
||||||
try:
|
try:
|
||||||
search_filter = '(&(objectClass=posixGroup)(gidNumber=%d))' % gidNumber
|
search_filter = '(&(objectClass=posixGroup)(gidNumber=%d))' % gidNumber
|
||||||
matches = self.ldap.search_s(self.group_base, ldap.SCOPE_SUBTREE, search_filter)
|
matches = self.ldap.search_s(self.group_base, ldap.SCOPE_SUBTREE, search_filter)
|
||||||
except ldap.LDAPError,e :
|
except ldap.LDAPError, e:
|
||||||
raise LDAPException("group search failed: %s" % e)
|
raise LDAPException("group search failed: %s" % e)
|
||||||
|
|
||||||
# list for groups found
|
# list for groups found
|
||||||
group_cns = []
|
group_cns = []
|
||||||
|
|
||||||
|
results = {}
|
||||||
for match in matches:
|
for match in matches:
|
||||||
dn, attributes = match
|
dn, attrs = match
|
||||||
|
uid = attrs['cn'][0]
|
||||||
|
results[uid] = attrs
|
||||||
|
|
||||||
# cn is a required attribute of posixGroup
|
return results
|
||||||
if not attributes.has_key('cn'):
|
|
||||||
raise LDAPException(dn + ' (posixGroup) has no cn')
|
|
||||||
|
|
||||||
# do not handle the case of multiple cns for one group (yet)
|
|
||||||
elif len(attributes['cn']) > 1:
|
|
||||||
raise LDAPException(dn + ' (posixGroup) has multiple cns')
|
|
||||||
|
|
||||||
# append the sole uid of this match to the list
|
|
||||||
group_cns.append( attributes['cn'][0] )
|
|
||||||
|
|
||||||
return group_cns
|
|
||||||
|
|
||||||
|
|
||||||
def group_add(self, cn, gidNumber, description=None):
|
def group_add(self, cn, gidNumber, description=None):
|
||||||
|
@ -457,8 +471,129 @@ class LDAPConnection(object):
|
||||||
raise LDAPException("unable to delete group: %s" % e)
|
raise LDAPException("unable to delete group: %s" % e)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Member-related Methods ###
|
||||||
|
|
||||||
|
def member_lookup(self, uid):
|
||||||
|
"""
|
||||||
|
Retrieve the attributes of a member. This method will only return
|
||||||
|
results that have the objectClass 'member'.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
uid - the username to look up
|
||||||
|
|
||||||
|
Returns: attributes of member with uid
|
||||||
|
|
||||||
|
Example: connection.member_lookup('mspang') ->
|
||||||
|
{ 'uid': 'mspang', 'uidNumber': 21292 ...}
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self.connected(): raise LDAPException("Not connected!")
|
||||||
|
|
||||||
|
dn = 'uid=' + uid + ',' + self.user_base
|
||||||
|
return self.lookup(dn, 'member')
|
||||||
|
|
||||||
|
|
||||||
|
def member_search_studentid(self, studentid):
|
||||||
|
"""
|
||||||
|
Retrieves a list of members with a certain studentid.
|
||||||
|
|
||||||
|
Returns: a dictionary mapping uids to attributes
|
||||||
|
"""
|
||||||
|
|
||||||
|
search_filter = '(&(objectClass=member)(studentid=%s))'
|
||||||
|
return self.user_search(search_filter, [ studentid ] )
|
||||||
|
|
||||||
|
|
||||||
|
def member_search_name(self, name):
|
||||||
|
"""
|
||||||
|
Retrieves a list of members with the specified name (fuzzy).
|
||||||
|
|
||||||
|
Returns: a dictionary mapping uids to attributes
|
||||||
|
"""
|
||||||
|
|
||||||
|
search_filter = '(&(objectClass=member)(cn~=%s))'
|
||||||
|
return self.user_search(search_filter, [ name ] )
|
||||||
|
|
||||||
|
|
||||||
|
def member_search_term(self, term):
|
||||||
|
"""
|
||||||
|
Retrieves a list of members who were registered in a certain term.
|
||||||
|
|
||||||
|
Returns: a dictionary mapping uids to attributes
|
||||||
|
"""
|
||||||
|
|
||||||
|
search_filter = '(&(objectClass=member)(term=%s))'
|
||||||
|
return self.user_search(search_filter, [ term ])
|
||||||
|
|
||||||
|
|
||||||
|
def member_search_program(self, program):
|
||||||
|
"""
|
||||||
|
Retrieves a list of members in a certain program (fuzzy).
|
||||||
|
|
||||||
|
Returns: a dictionary mapping uids to attributes
|
||||||
|
"""
|
||||||
|
|
||||||
|
search_filter = '(&(objectClass=member)(program~=%s))'
|
||||||
|
return self.user_search(search_filter, [ program ])
|
||||||
|
|
||||||
|
|
||||||
|
def member_add(self, uid, cn, studentid, program=None, description=None):
|
||||||
|
"""
|
||||||
|
Adds a member to the directory.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
uid - the UNIX username for the member
|
||||||
|
cn - the real name of the member
|
||||||
|
studentid - the member's student ID number
|
||||||
|
program - the member's program of study
|
||||||
|
description - a description for the entry
|
||||||
|
"""
|
||||||
|
|
||||||
|
dn = 'uid=' + uid + ',' + self.user_base
|
||||||
|
attrs = {
|
||||||
|
'objectClass': [ 'top', 'account', 'member' ],
|
||||||
|
'uid': [ uid ],
|
||||||
|
'cn': [ cn ],
|
||||||
|
'studentid': [ studentid ],
|
||||||
|
}
|
||||||
|
|
||||||
|
if program:
|
||||||
|
attrs['program'] = [ program ]
|
||||||
|
if description:
|
||||||
|
attrs['description'] = [ description ]
|
||||||
|
|
||||||
|
try:
|
||||||
|
modlist = ldap.modlist.addModlist(attrs)
|
||||||
|
self.ldap.add_s(dn, modlist)
|
||||||
|
except ldap.LDAPError, e:
|
||||||
|
raise LDAPException("unable to add: %s" % e)
|
||||||
|
|
||||||
|
|
||||||
|
def member_add_account(self, uid, uidNumber, gidNumber, homeDirectory, loginShell=None, gecos=None):
|
||||||
|
"""
|
||||||
|
Adds login privileges to a member.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.account_add(uid, None, uidNumber, gidNumber, homeDirectory, loginShell, gecos, None, True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Miscellaneous Methods ###
|
### Miscellaneous Methods ###
|
||||||
|
|
||||||
|
def escape(self, value):
|
||||||
|
"""
|
||||||
|
Escapes special characters in a value so that it may be safely inserted
|
||||||
|
into an LDAP search filter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
value = str(value)
|
||||||
|
value = value.replace('\\', '\\5c').replace('*', '\\2a')
|
||||||
|
value = value.replace('(', '\\28').replace(')', '\\29')
|
||||||
|
value = value.replace('\x00', '\\00')
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def used_uids(self, minimum=None, maximum=None):
|
def used_uids(self, minimum=None, maximum=None):
|
||||||
"""
|
"""
|
||||||
Compiles a list of used UIDs in a range.
|
Compiles a list of used UIDs in a range.
|
||||||
|
@ -543,9 +678,17 @@ if __name__ == '__main__':
|
||||||
tushell = '/bin/false'
|
tushell = '/bin/false'
|
||||||
tugecos = 'Test User,,,'
|
tugecos = 'Test User,,,'
|
||||||
tgname = 'testgroup'
|
tgname = 'testgroup'
|
||||||
|
tmname = 'testmember'
|
||||||
|
tmrname = 'Test Member'
|
||||||
|
tmstudentid = '99999999'
|
||||||
|
tmprogram = 'UBW'
|
||||||
|
tmdesc = 'Test Description'
|
||||||
cushell = '/bin/true'
|
cushell = '/bin/true'
|
||||||
cuhome = '/home/changed'
|
cuhome = '/home/changed'
|
||||||
curname = 'Test Modified User'
|
curname = 'Test Modified User'
|
||||||
|
cmhome = '/home/testmember'
|
||||||
|
cmshell = '/bin/false'
|
||||||
|
cmgecos = 'Test Member,,,'
|
||||||
|
|
||||||
test(LDAPConnection)
|
test(LDAPConnection)
|
||||||
connection = LDAPConnection()
|
connection = LDAPConnection()
|
||||||
|
@ -563,6 +706,7 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection.user_delete(tuname)
|
connection.user_delete(tuname)
|
||||||
|
connection.user_delete(tmname)
|
||||||
connection.group_delete(tgname)
|
connection.group_delete(tgname)
|
||||||
except LDAPException:
|
except LDAPException:
|
||||||
pass
|
pass
|
||||||
|
@ -596,8 +740,20 @@ if __name__ == '__main__':
|
||||||
'cn': [ turname ]
|
'cn': [ turname ]
|
||||||
}
|
}
|
||||||
|
|
||||||
test(LDAPConnection.user_add)
|
test(LDAPConnection.account_add)
|
||||||
connection.user_add(tuname, turname, tuuid, tugid, tuhome, tushell, tugecos)
|
connection.account_add(tuname, turname, tuuid, tugid, tuhome, tushell, tugecos)
|
||||||
|
success()
|
||||||
|
|
||||||
|
emdata = {
|
||||||
|
'uid': [ tmname ],
|
||||||
|
'cn': [ tmrname ],
|
||||||
|
'studentid': [ tmstudentid ],
|
||||||
|
'program': [ tmprogram ],
|
||||||
|
'description': [ tmdesc ],
|
||||||
|
}
|
||||||
|
|
||||||
|
test(LDAPConnection.member_add)
|
||||||
|
connection.member_add(tmname, tmrname, tmstudentid, tmprogram, tmdesc)
|
||||||
success()
|
success()
|
||||||
|
|
||||||
tggid = unusedids.pop()
|
tggid = unusedids.pop()
|
||||||
|
@ -610,41 +766,95 @@ if __name__ == '__main__':
|
||||||
connection.group_add(tgname, tggid)
|
connection.group_add(tgname, tggid)
|
||||||
success()
|
success()
|
||||||
|
|
||||||
|
test(LDAPConnection.account_lookup)
|
||||||
|
udata = connection.account_lookup(tuname)
|
||||||
|
if udata: del udata['objectClass']
|
||||||
|
assert_equal(eudata, udata)
|
||||||
|
success()
|
||||||
|
|
||||||
|
test(LDAPConnection.member_lookup)
|
||||||
|
mdata = connection.member_lookup(tmname)
|
||||||
|
if mdata: del mdata['objectClass']
|
||||||
|
assert_equal(emdata, mdata)
|
||||||
|
success()
|
||||||
|
|
||||||
test(LDAPConnection.user_lookup)
|
test(LDAPConnection.user_lookup)
|
||||||
udata = connection.user_lookup(tuname)
|
udata = connection.user_lookup(tuname)
|
||||||
del udata['objectClass']
|
mdata = connection.user_lookup(tmname)
|
||||||
|
if udata: del udata['objectClass']
|
||||||
|
if mdata: del mdata['objectClass']
|
||||||
assert_equal(eudata, udata)
|
assert_equal(eudata, udata)
|
||||||
|
assert_equal(emdata, mdata)
|
||||||
success()
|
success()
|
||||||
|
|
||||||
test(LDAPConnection.group_lookup)
|
test(LDAPConnection.group_lookup)
|
||||||
gdata = connection.group_lookup(tgname)
|
gdata = connection.group_lookup(tgname)
|
||||||
del gdata['objectClass']
|
if gdata: del gdata['objectClass']
|
||||||
assert_equal(egdata, gdata)
|
assert_equal(egdata, gdata)
|
||||||
success()
|
success()
|
||||||
|
|
||||||
test(LDAPConnection.user_search_id)
|
test(LDAPConnection.account_search_id)
|
||||||
eulist = [ tuname ]
|
eulist = [ tuname ]
|
||||||
ulist = connection.user_search_id(tuuid)
|
ulist = connection.account_search_id(tuuid).keys()
|
||||||
assert_equal(eulist, ulist)
|
assert_equal(eulist, ulist)
|
||||||
success()
|
success()
|
||||||
|
|
||||||
test(LDAPConnection.user_search_gid)
|
test(LDAPConnection.account_search_gid)
|
||||||
ulist = connection.user_search_gid(tugid)
|
ulist = connection.account_search_gid(tugid)
|
||||||
if tuname not in ulist:
|
if tuname not in ulist:
|
||||||
fail("(%s) not in (%s)" % (tuname, ulist))
|
fail("%s not in %s" % (tuname, ulist))
|
||||||
success()
|
success()
|
||||||
|
|
||||||
ecudata = connection.user_lookup(tuname)
|
test(LDAPConnection.member_search_studentid)
|
||||||
|
mlist = connection.member_search_studentid(tmstudentid).keys()
|
||||||
|
emlist = [ tmname ]
|
||||||
|
assert_equal(emlist, mlist)
|
||||||
|
success()
|
||||||
|
|
||||||
|
test(LDAPConnection.member_search_name)
|
||||||
|
mlist = connection.member_search_name(tmrname)
|
||||||
|
if tmname not in mlist:
|
||||||
|
fail("%s not in %s" % (tmname, mlist))
|
||||||
|
success()
|
||||||
|
|
||||||
|
test(LDAPConnection.member_search_program)
|
||||||
|
mlist = connection.member_search_program(tmprogram)
|
||||||
|
if tmname not in mlist:
|
||||||
|
fail("%s not in %s" % (tmname, mlist))
|
||||||
|
success()
|
||||||
|
|
||||||
|
test(LDAPConnection.group_search_id)
|
||||||
|
glist = connection.group_search_id(tggid).keys()
|
||||||
|
eglist = [ tgname ]
|
||||||
|
assert_equal(eglist, glist)
|
||||||
|
success()
|
||||||
|
|
||||||
|
ecudata = connection.account_lookup(tuname)
|
||||||
ecudata['loginShell'] = [ cushell ]
|
ecudata['loginShell'] = [ cushell ]
|
||||||
ecudata['homeDirectory'] = [ cuhome ]
|
ecudata['homeDirectory'] = [ cuhome ]
|
||||||
ecudata['cn'] = [ curname ]
|
ecudata['cn'] = [ curname ]
|
||||||
|
|
||||||
test(LDAPConnection.user_modify)
|
test(LDAPConnection.user_modify)
|
||||||
connection.user_modify(tuname, ecudata)
|
connection.user_modify(tuname, ecudata)
|
||||||
cudata = connection.user_lookup(tuname)
|
cudata = connection.account_lookup(tuname)
|
||||||
assert_equal(ecudata, cudata)
|
assert_equal(ecudata, cudata)
|
||||||
success()
|
success()
|
||||||
|
|
||||||
|
tmuid = unusedids.pop()
|
||||||
|
tmgid = unusedids.pop()
|
||||||
|
emadata = emdata.copy()
|
||||||
|
emadata.update({
|
||||||
|
'loginShell': [ cmshell ],
|
||||||
|
'uidNumber': [ str(tmuid) ],
|
||||||
|
'gidNumber': [ str(tmgid) ],
|
||||||
|
'gecos': [ cmgecos ],
|
||||||
|
'homeDirectory': [ cmhome ],
|
||||||
|
})
|
||||||
|
|
||||||
|
test(LDAPConnection.member_add_account)
|
||||||
|
connection.member_add_account(tmname, tmuid, tmuid, cmhome, cmshell, cmgecos)
|
||||||
|
success()
|
||||||
|
|
||||||
ecgdata = connection.group_lookup(tgname)
|
ecgdata = connection.group_lookup(tgname)
|
||||||
ecgdata['memberUid'] = [ tuname ]
|
ecgdata['memberUid'] = [ tuname ]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue