Fixed typos, especially the wrong attribute in <form>
This commit is contained in:
parent
06249d530d
commit
2b566aeb8e
19 changed files with 327 additions and 85 deletions
240
nameko-func.py
240
nameko-func.py
|
|
@ -1,81 +1,303 @@
|
|||
from nameko.events import EventDispatcher, event_handler
|
||||
from nameko.rpc import rpc
|
||||
from configparser import ConfigParser
|
||||
import ldap3
|
||||
from ldap3 import Server, ServerPool, Connection, ObjectDef, AttrDef, Reader, Writer
|
||||
from datetime import datetime
|
||||
|
||||
# For testing
|
||||
from random import randint
|
||||
|
||||
# Read the config in the nameko.conf
|
||||
config = ConfigParser()
|
||||
config.read('nameko.conf')
|
||||
|
||||
# Sanity check for config
|
||||
try:
|
||||
mult_server = int(config['LDAP']['SERVERMULTIPLE'])
|
||||
# SERVERMULTIPLE is set to something not a number
|
||||
except:
|
||||
exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1")
|
||||
# less than one server is not a sensible option
|
||||
if mult_server < 1:
|
||||
exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1")
|
||||
|
||||
|
||||
# Function to setup the server or serverpool
|
||||
def ldapservers():
|
||||
# Just one server, no need for a pool
|
||||
if mult_server == 1:
|
||||
ldapserver = Server(config['LDAP']['LDAPSERVER1'])
|
||||
return ldapserver
|
||||
# Multiple servers, set up a pool
|
||||
else:
|
||||
ldapserver = ServerPool(None)
|
||||
for x in range(1, (mult_server+1)):
|
||||
ins = Server(config['LDAP']['LDAPSERVER' + str(x)])
|
||||
ldapserver.add(ins)
|
||||
return ldapserver
|
||||
|
||||
|
||||
# Since there's no reason why someone in ou=users shouldn't use the service,
|
||||
# here's the helper function to check whether an uid is in ou=customers or
|
||||
# ou=users
|
||||
# returns the full dn
|
||||
def user_or_customer(uid):
|
||||
server = ldapservers()
|
||||
conn = Connection(server)
|
||||
if conn.search('ou=customers,dc=ungleich,dc=ch', '(%s)' % uid):
|
||||
return '%s,ou=customers,dc=ungleich,dc=ch' % uid
|
||||
elif conn.search('ou=customers,dc=ungleich,dc=ch', '(%s)' % uid):
|
||||
return '%s,ou=customers,dc=ungleich,dc=ch' % uid
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# checks if a user already exists in the LDAP
|
||||
class UserLookUp(object):
|
||||
name = "userlookup"
|
||||
dispatch = EventDispatcher()
|
||||
|
||||
@rpc
|
||||
def lookup(self, user):
|
||||
# Setup the search parameter and connect to LDAP
|
||||
LDAP_UID = 'uid=%s' % user
|
||||
LDAP_USER_SEARCH = LDAP_UID + config['LDAP']['LDAPDATA']
|
||||
server = ldapservers()
|
||||
conn = Connection(server)
|
||||
conn.bind()
|
||||
# Search ou=users and ou=customers
|
||||
if conn.search('ou=customers,dc=ungleich,dc=ch', '(%s)' % LDAP_UID) or conn.search('ou=users,dc=ungleich,dc=ch', '(%s)' % LPAD_UID):
|
||||
# return conn.entries[0] for first search result since we can assume uid is unique
|
||||
self.dispatch('ldap', '%s [Info: UserLookUp] Searched for %s and found it: %s' % (datetime.now(), LDAP_UID, str(conn.entries[0])) )
|
||||
conn.unbind()
|
||||
# return True since the user is already in LDAP
|
||||
return True
|
||||
# User not in LDAP, so just close it down, write the log and return False
|
||||
else:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info: UserLookUp] Searched for %s and not found it.' % (datetime.now(), LDAP_UID) )
|
||||
return False
|
||||
|
||||
|
||||
# Create a user in the LDAP. Assumes the checks are already in place for existing users
|
||||
class CreateUser(object):
|
||||
name = "createuser"
|
||||
dispatch = EventDispatcher()
|
||||
|
||||
@rpc
|
||||
def create_user(self, user, password, firstname, lastname, email):
|
||||
return "To be done"
|
||||
|
||||
# Creates a user with some basic data
|
||||
server = ldapservers()
|
||||
conn = Connection(server, conf['LDAP']['LDAPMANAGER'], conf['LDAP']['LDAPMANAGERPASSWORD'])
|
||||
if not conn.bind():
|
||||
self.dispatch('ldap', '%s [Error CreateUser] Could not connect to LDAPserver' % datetime.now() )
|
||||
return "Could not connect to LDAP Server."
|
||||
# set objectClasses for the new user
|
||||
obj_new_user = ObjectDef(['inetOrgPerson', 'posixAccount', 'shadowAccount'], conn)
|
||||
w = Writer(conn, obj_new_user)
|
||||
# newly created users get put into ou=customers
|
||||
dn = 'uid=%s,ou=customers,dc=ungleich,dc=ch' % user
|
||||
w.new(dn)
|
||||
# Filling in some of the data
|
||||
# required attributes are sn, cn, homeDirectory, uid (already handled by dn), uidNumber, gidNumber
|
||||
w[0].givenName = firstname
|
||||
w[0].sn = lastname
|
||||
w[0].cn = firstname + " " + lastname
|
||||
w[0].mail = email
|
||||
w[0].userPassword = password
|
||||
w[0].homeDirectory = '/home/%s' % user
|
||||
# TODO: Learn how to get the last uidNumber and what gidNumber to use
|
||||
w[0].uidNumber = randint(1200,50000)
|
||||
w[0].gidNumber = randint(1200,50000)
|
||||
if not w.commit():
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error CreateUser] Could not write new user %s to LDAP DB' % (datetime.now(), dn) )
|
||||
return "Couldn't write data to the LDAP Server."
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info CreateUser] %s created.' % (datetime.now(), dn) )
|
||||
return True
|
||||
|
||||
# Returns some basic data from an user
|
||||
class GetUserData(object):
|
||||
name = "getuserdata"
|
||||
dispatch = EventDispatcher()
|
||||
|
||||
@rpc
|
||||
def get_data(self, user):
|
||||
return "To be done"
|
||||
# Setup the search parameter and connect to LDAP
|
||||
LDAP_UID = 'uid=%s' % user
|
||||
server = ldapservers()
|
||||
conn = Connection(server)
|
||||
if not conn.bind():
|
||||
self.dispatch('ldap', '%s [Error GetUserData] Could not connect to LDAP server.' % datetime.now() )
|
||||
return ("error", "Could not connect to LDAP server.", "", "")
|
||||
rdn = user_or_customer(LDAP_UID)
|
||||
if rdn == False:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info GetUserData] Could not find user %s' % (datetime.now(), LDAP_UID) )
|
||||
return ("error", "Could not find the user.", "", "")
|
||||
obj = ObjectDef(['inetOrgPerson', 'posixAccount', 'shadowAccount'], conn)
|
||||
# The Reader gets the data for the user
|
||||
r = Reader(conn, obj, rdn)
|
||||
r.search()
|
||||
# Since the DN is basically confirmed by user_or_customer() it shouldn't throw an exception, but better check
|
||||
try:
|
||||
x = r[0].sn
|
||||
except:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error GetUserData] Could not open Reader for %s' % (datetime.now(), rdn) )
|
||||
return ("error", "Could not read data for user.", "", "")
|
||||
# Putting the results into strings and then clean it up a bit if some attribute is not set in LDAP
|
||||
(firstname, lastname, email) = (str(r[0].givenName), str(r[0].sn), str(r[0].mail))
|
||||
if firstname == '[]':
|
||||
firstname = 'No firstname given'
|
||||
if lastname == '[]':
|
||||
lastname = 'No lastname given'
|
||||
if email == '[]':
|
||||
email = 'No email given'
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info GetUserData] Got data for %s Firstname: %s Lastname: %s Email: %s' % (datetime.now(), rdn, firstname, lastname, email) )
|
||||
return ("OK", firstname, lastname, email)
|
||||
|
||||
|
||||
|
||||
# change some (firstname, lastname, email) data for the user
|
||||
class ChangeUserData(object):
|
||||
name = "changeuserdata"
|
||||
dispatch = EventDispatcher()
|
||||
|
||||
@rpc
|
||||
def change_data(self, user, firstname, lastname, email):
|
||||
return "To be done"
|
||||
LDAP_UID = 'uid=%s' % user
|
||||
server = ldapservers()
|
||||
# Establish connection with a user who can change the data
|
||||
conn = Connection(server, conf['LDAP']['LDAPMANAGER'], conf['LDAP']['LDAPMANAGERPASSWORD'])
|
||||
if not conn.bind():
|
||||
self.dispatch('ldap', '%s [Error ChangeUserData] Could not connect to LDAP server.' % datetime.now() )
|
||||
return "Could not connect to LDAP server."
|
||||
# get the DN of the user
|
||||
rdn = user_or_customer(LDAP_UID)
|
||||
if rdn == False:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info ChangeUserData] User with %s not found.' % (datetime.now(), LDAP_UID) )
|
||||
return "Could not find user."
|
||||
# Set up a reader for the user
|
||||
obj = ObjectDef(['inetOrgPerson', 'posixAccount', 'shadowAccount'], conn)
|
||||
r = Reader(conn, obj, rdn)
|
||||
r.search()
|
||||
# Again, user_or_customer() should prevent it from throwing an exception because it's a confirmed user
|
||||
try:
|
||||
x = r[0].sn
|
||||
except:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error ChangeUserData] Could not open Reader for %s' % (datetime.now(), rdn) )
|
||||
return "Could not open the data of user."
|
||||
# Opens a Writer instance prefilled with the old data
|
||||
# We could check if something has changed, but since the form takes the old data as standard values, let's
|
||||
# just update the relevant attributes
|
||||
w = Writer.from_cursor(r)
|
||||
w[0].sn = lastname
|
||||
w[0].cn = firstname + " " + lastname
|
||||
w[0].givenName = firstname
|
||||
w[0].mail = email
|
||||
# check if the data is written
|
||||
if not w.commit():
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error ChangeUserData] Could not write changes for %s' % (datetime.now(), rdn) )
|
||||
return "Could not write changes for user."
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info ChangeUserData] Changed data for %s Firstname: %s Lastname: %s Email: %s' % (datetime.now(), rdn, firstname, lastname, email) )
|
||||
return True
|
||||
|
||||
|
||||
# Request a password reset
|
||||
# TODO: Set up a system for it
|
||||
# Basic idea: send email to customer with a confirmation request, set reply-to for something that handles it,
|
||||
class PasswordResetRequest(object):
|
||||
name = "passwordresetrequest"
|
||||
dispatch = EventDispatcher()
|
||||
|
||||
@rpc
|
||||
def send_request(self, user):
|
||||
# TODO: Find a good system for that
|
||||
return "To be done"
|
||||
|
||||
|
||||
# change the password for the user
|
||||
class ChangePassword(object):
|
||||
name = "changepassword"
|
||||
dispatch = EventDispatcher()
|
||||
|
||||
@rpc
|
||||
def change_password(self, user, oldpassword, newpassword):
|
||||
return "To be done"
|
||||
def change_password(self, user, newpassword):
|
||||
LDAP_UID = 'uid=%s'
|
||||
server = ldapservers()
|
||||
conn = Connection(server, conf['LDAP']['LDAPMANAGER'], conf['LDAP']['LDAPMANAGERPASSWORD'])
|
||||
if not conn.bind():
|
||||
self.dispatch('ldap', '%s [Error ChangePassword] Could not connect to LDAP server.' % datetime.now() )
|
||||
return "Could not connect to LDAP server."
|
||||
# check if uid=user is in either ou=customers or ou=users
|
||||
rdn = user_or_customer(LDAP_UID)
|
||||
if rdn == False:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error ChangePassword] Could not find user %s' % (datetime.now(), LDAP_UID) )
|
||||
return "Could not find the user."
|
||||
# Set up a Reader for the DN
|
||||
obj = ObjectDef(['inetOrgPerson', 'posixAccount', 'shadowAccount'], conn)
|
||||
r = Reader(conn, obj, rdn)
|
||||
r.search()
|
||||
# Shouldn't throw an exception, since the user is confirmed to be there
|
||||
try:
|
||||
x = r[0].sn
|
||||
except:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error ChangePassword] Could not open Reader for %s' % (datetime.now(), rdn) )
|
||||
return "Could not open the data for the user."
|
||||
# Set up the writer and overwrite the attribute with the new password
|
||||
w = Writer.from_cursor(r)
|
||||
w[0].userPassword = newpassword
|
||||
# Check to see if the change has gone through
|
||||
if not w.commit():
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error ChangePassword] Could not write data for %s' % (datetime.now(), rdn) )
|
||||
return "Could not write data for the user."
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info ChangePassword] Password changed for %s' % (datetime.now(), rdn) )
|
||||
return True
|
||||
|
||||
|
||||
# Deletes a user from LDAP
|
||||
class DeleteUser(object):
|
||||
name = "deleteuser"
|
||||
dispatch = EventDispatcher()
|
||||
|
||||
@rpc
|
||||
def delete_user(self, user):
|
||||
return "To be done"
|
||||
LDAP_UID = user
|
||||
server = ldapservers()
|
||||
conn = Connection(server, conf['LDAP']['LDAPMANAGER'], conf['LDAP']['LDAPMANAGERPASSWORD'])
|
||||
if not conn.bind():
|
||||
self.dispatch('ldap', '%s [Error DeleteUser] Could not connect to LDAP server.' % datetime.now() )
|
||||
return "Could not connect to LDAP server."
|
||||
# again, check whether the uid= is in ou=users or ou=customers
|
||||
dn = user_or_customer(LDAP_UID)
|
||||
if dn == False:
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error DeleteUser] Could not find the user %s' % (datetime.now(), LDAP_UID) )
|
||||
return "Could not find the user."
|
||||
# Check if the delete was successfull
|
||||
if not conn.delete(dn):
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Error DeleteUser] Could not delete %s' % (datetime.now(), dn) )
|
||||
return "Could not delete the user."
|
||||
conn.unbind()
|
||||
self.dispatch('ldap', '%s [Info DeleteUser] Deleted %s' % (datetime.now(), dn) )
|
||||
return True
|
||||
|
||||
|
||||
# the class to log all the dispatches
|
||||
# for now everything gets logged into the same logfile, but
|
||||
# I don't forsee that much traffic plus with timestamps and the class name
|
||||
# in the log should be readable
|
||||
class Log(object):
|
||||
name = "log"
|
||||
ldaplog = config['System']['LOGDIR'] + '/ldap.log'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue