diff --git a/dal/dal/settings.py b/dal/dal/settings.py index d3cf036..0dfd7c7 100644 --- a/dal/dal/settings.py +++ b/dal/dal/settings.py @@ -45,6 +45,16 @@ AUTH_LDAP_USER_SEARCH = LDAPSearchUnion( # LDAP config end +# Django nameko config + +# Where's the Rabbitmq at +NAMEKO_CONFIG = { + 'AMQP_URI': 'amqp://guest:guest@127.0.0.1' + } + +# Standard pool size +NAMEKO_POOL_SIZE = 4 + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -71,6 +81,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'dal', ] MIDDLEWARE = [ diff --git a/dal/dal/templates/changeddata.html b/dal/dal/templates/changeddata.html index 864b1b1..4fbbff4 100644 --- a/dal/dal/templates/changeddata.html +++ b/dal/dal/templates/changeddata.html @@ -9,6 +9,6 @@
  • Email: {{email}}


  • -
    +
    diff --git a/dal/dal/templates/changepassword.html b/dal/dal/templates/changepassword.html index b8afd14..ea21d5e 100644 --- a/dal/dal/templates/changepassword.html +++ b/dal/dal/templates/changepassword.html @@ -2,12 +2,12 @@

    Changing the password for {{user}}



    -
    +


    To change the password for {{user}}, please supply -
    + {% csrf_token %}
    The old password:
    diff --git a/dal/dal/templates/changeuserdata.html b/dal/dal/templates/changeuserdata.html index 9293b66..c5201d1 100644 --- a/dal/dal/templates/changeuserdata.html +++ b/dal/dal/templates/changeuserdata.html @@ -2,11 +2,11 @@

    Changing user data for {{user}}



    - +


    -
    + {% csrf_token %}
    Firstname:
    diff --git a/dal/dal/templates/deleteaccount.html b/dal/dal/templates/deleteaccount.html index d7bec78..bcc340b 100644 --- a/dal/dal/templates/deleteaccount.html +++ b/dal/dal/templates/deleteaccount.html @@ -2,12 +2,12 @@

    Deleting an Account



    - +


    To delete an account, please type the username and password below: -
    +

    Username:


    Password:
    diff --git a/dal/dal/templates/deleteduser.html b/dal/dal/templates/deleteduser.html index 4e3751d..3076386 100644 --- a/dal/dal/templates/deleteduser.html +++ b/dal/dal/templates/deleteduser.html @@ -2,6 +2,6 @@

    The user {{user}} was deleted from our system.


    - +
    diff --git a/dal/dal/templates/error.html b/dal/dal/templates/error.html index b13c1c8..0001244 100644 --- a/dal/dal/templates/error.html +++ b/dal/dal/templates/error.html @@ -6,10 +6,10 @@ While trying to {{service}}, an error was encountered: {{error}}

    You can try to:
    -
    +

    or
    -
    +
    diff --git a/dal/dal/templates/landing.html b/dal/dal/templates/landing.html index f6dfb0d..ce4108b 100644 --- a/dal/dal/templates/landing.html +++ b/dal/dal/templates/landing.html @@ -3,7 +3,8 @@

    Welcome to the ungleich user service



    If you want to use the user service, you will need an account on our system. If you already have one, please login below: -
    + + {% csrf_token %}

    Username:


    Password:
    @@ -12,10 +13,10 @@ If you want to use the user service, you will need an account on our system. If


    If you have an account, but forgot your password, please visit our password reset page: -
    +


    If you don't have an account, please register yourself with us: -
    +
    diff --git a/dal/dal/templates/loginfailed.html b/dal/dal/templates/loginfailed.html index 5bd0e4a..9dcf74f 100644 --- a/dal/dal/templates/loginfailed.html +++ b/dal/dal/templates/loginfailed.html @@ -2,10 +2,10 @@

    Sorry, but your login has failed



    This service runs for our LDAP users, so maybe you don't already have an LDAP account with us? If so, please register one. -
    +


    -
    +
    diff --git a/dal/dal/templates/mustbeloggedin.html b/dal/dal/templates/mustbeloggedin.html index 031fbf3..d70cd21 100644 --- a/dal/dal/templates/mustbeloggedin.html +++ b/dal/dal/templates/mustbeloggedin.html @@ -2,6 +2,6 @@

    You must be logged in to access this page



    -
    +
    diff --git a/dal/dal/templates/registeruser.html b/dal/dal/templates/registeruser.html index 6412db1..17d1683 100644 --- a/dal/dal/templates/registeruser.html +++ b/dal/dal/templates/registeruser.html @@ -2,13 +2,13 @@

    Register an user at ungleich



    -
    +


    To register yourself an user, please fill out the fields below:
    -
    + {% csrf_token %}
    Username (alphanumeric):
    diff --git a/dal/dal/templates/resetpassword.html b/dal/dal/templates/resetpassword.html index 4d4c080..06ba5a9 100644 --- a/dal/dal/templates/resetpassword.html +++ b/dal/dal/templates/resetpassword.html @@ -5,7 +5,7 @@ To reset your password, please enter your username below. You will get an email asking you to confirm this and after confirmation an email with your temporary password. Please remember to change it immediately after logging in.
    - + {% csrf_token %} Username:
    diff --git a/dal/dal/templates/send_resetrequest.html b/dal/dal/templates/send_resetrequest.html index 7da946d..c03ab7d 100644 --- a/dal/dal/templates/send_resetrequest.html +++ b/dal/dal/templates/send_resetrequest.html @@ -4,6 +4,6 @@

    You will shortly get the confirmation email at {{email}} to confirm that you wish to reset the password for {{user}}.

    - +
    diff --git a/dal/dal/templates/useroptions.html b/dal/dal/templates/useroptions.html index 4ce5597..ec60fc6 100644 --- a/dal/dal/templates/useroptions.html +++ b/dal/dal/templates/useroptions.html @@ -4,18 +4,18 @@

    You have the following options:
    -
    +

    -
    +

    -
    +

    -
    +
    diff --git a/dal/dal/urls.py b/dal/dal/urls.py index c6d57da..efdb67c 100644 --- a/dal/dal/urls.py +++ b/dal/dal/urls.py @@ -18,14 +18,14 @@ from django.urls import path from django.conf.urls import url from django.contrib import admin -from .views import Register, ChangeData, ResetPassword, DeleteAccount, Index +from .views import Register, ChangeData, ChangePassword, ResetPassword, DeleteAccount, Index urlpatterns = [ - path('admin/', admin.site.urls), +# path('admin/', admin.site.urls), path('register/', Register.as_view(), name="register"), path('changedata/', ChangeData.as_view(), name="change_data"), path('resetpassword/', ResetPassword.as_view(), name="reset_password"), path('changepassword/', ChangePassword.as_view(), name="change_password"), path('deleteaccount/', DeleteAccount.as_view(), name="account_delete"), - path('/', Index.as_view(), name="index") + path('index/', Index.as_view(), name="index"), ] diff --git a/dal/dal/views.py b/dal/dal/views.py index 45e74e4..1c1edf2 100644 --- a/dal/dal/views.py +++ b/dal/dal/views.py @@ -3,21 +3,16 @@ from django.views.generic import View from django.contrib.auth import authenticate, login from django.contrib.auth.models import User from django.http import HttpResponse, HttpResponseRedirect -from django.core.validators import email_re +from django.core.validators import validate_email, ValidationError from django.urls import reverse_lazy - +from django_nameko import get_pool # Check to see if the username is already taken # Helper function, not to be set up as a view -# First checks the DB, since ldap parks users there -# After that, check LDAP directly if the user just never -# logged in +# Check the LDAP if the user exists def check_user_exists(username): - if User.objects.filter(username=username).exists(): - return True - # TODO: Needs to look up the LDAP - else return False - + with get_pool().next() as rpc: + return rpc.userlookup.lookup(username) # The index page # If there's a session open, it will give the user the options he/she/it can do, if not, @@ -72,40 +67,50 @@ class Register(View): # check if the supplied passwords match if password1 != password2: return render(request, 'registererror.html', { 'urlname': urlname, 'service': service, - 'error': 'Your passwords didn\'t match. Please supply the same password twice.' } ) + 'error': 'Your passwords did not match. Please supply the same password twice.' } ) email = request.POST.get('email') # Is the emailaddress valid? - if not email_re.match(email): + try: + validate_email(email) + except ValidationError: return render(request, 'registererror.html', { 'urlname': urlname, 'service': service, 'error': 'The supplied email address is invalid.' } ) + firstname = request.POST.get('firstname') lastname = request.POST.get('lastname') - if firstname == "" or not firstname or lastname == "" or not lastname + if firstname == "" or not firstname or lastname == "" or not lastname: return render(request, 'registererror.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter your firstname and lastname.' } ) # throw it to nameko to create the user - if self.create_user(username, password1, firstname, lastname, email): - return render(request, 'usercreated.html', { 'user': username } ) - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown error while creating the user.' } ) + with get_pool().next() as rpc: + result = rpc.createuser.create_user(username, password1, firstname, lastname, email) + if result == True: + return render(request, 'usercreated.html', { 'user': username } ) + else: + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } ) - def create_user(self, username, password, firstname, lastname, email): - #TODO: write nameko function to create a user - return True - # Change user data for logged in users class ChangeData(View): - + + # provide the form for the change request def get(self, request): + urlname = 'change_data' + service = 'get default data for logged in user' if not request.user.is_authenticated: return render(request, 'mustbeloggedin.html') user = request.user login(request, user) # get basic data (firstname, lastname, email) - (firstname, lastname, email) = self.get_data(user) + with get_pool().next() as rpc: + (state, firstname, lastname, email) = rpc.getuserdata.get_data(user) + # If it throws an error, the errormessage gets put into firstname.. not great naming, but works best this way + if state == "error": + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': firstname } ) # The template puts the old data as standard in the fields - return render(request, 'changeuserdata.html', { 'user': user, 'firstname': firstname, 'lastname': lastname, 'email': email } ) + else: + return render(request, 'changeuserdata.html', { 'user': user, 'firstname': firstname, 'lastname': lastname, 'email': email } ) # get the change request def post(self, request): @@ -128,20 +133,20 @@ class ChangeData(View): return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter a lastname.' } ) elif email == "": return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter an email.' } ) - elif not email_re.match(email): + try: + validate_email(email) + except ValidationError: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'The supplied email address is invalid.' } ) # Trying to change the data - if self.change_data(firstname, lastname, email): + with get_pool().next() as rpc: + result = rpc.changeuserdata.change_data(user, firstname, lastname, email) + # Data change worked + if result == True: return render(request, 'changeddata.html', { 'user': user, 'firstname': firstname, 'lastname': lastname, 'email': email } ) - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'An unknown error occurred.' } ) + # Data change did not work, display error + else: + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } ) - # TODO: call nameko to get basic data from user - def get_data(self, user): - return ("a", "b", "c") - - # TODO: call nameko to change user data and think about return value - def change_data(self, firstname, lastname, email): - return True # Resets the password for a user # Will need to send a confirmation email to the user and we will need a backend @@ -205,26 +210,25 @@ class ChangePassword(View): if password1 != password2: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please check if you typed the same password both times for the new password' } ) - + with get_pool().next() as rpc: # Trying to change the password - if self.change_password(user, oldpassword, password1): + result = rpc.changepassword.change_password(user, password1) + # Password was changed + if result == True: return render(request, 'changedpassword.html', { 'user': user } ) + # Password not changed, instead got some kind of error else: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown error while changing the password!' } ) - - - # Changes the password for the supplied user - def change_password(self, user, oldpassword, password): - #TODO: write nameko function to change a password - return True - + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } ) +# Deletes an account class DeleteAccount(View): + # Show the basic form for deleting an account def get(self, request): return render(request, 'deleteaccount.html') + # Reads the filled out form def post(self, request): # Variables for error page urlname = 'account_delete' @@ -242,11 +246,13 @@ class DeleteAccount(View): return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Wrong password for user.' } ) # Try to delete the user - if self.delete_user(username): + with get_pool().next() as rpc: + result = rpc.deleteuser.delete_user(user) + # User deleted + if result == True: return render(request, 'deleteduser.html', { 'user': username } ) - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown error while trying to delete the user.' } ) + # User not deleted, got some kind of error + else: + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } ) - def delete_user(self, username): - #TODO: nameko call to delete the user - return True diff --git a/nameko-func.py b/nameko-func.py index 6a4925b..da1e445 100644 --- a/nameko-func.py +++ b/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' diff --git a/nameko.conf b/nameko.conf index f35b263..67c7576 100644 --- a/nameko.conf +++ b/nameko.conf @@ -10,4 +10,5 @@ SERVERMULTIPLE = 1 LDAPSERVER1 = localhost -LDAPDATA = ,ou=customers,dc=foo,dc=bar +LDAPMANAGER = cn=manager,dc=ungleich,dc=ch +LDAPMANAGERPASSWORD = foobar diff --git a/requirements.txt b/requirements.txt index be5535b..6c3c085 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ django>=2.1.2 django-auth-ldap>=1.7.0 nameko>=2.11.0 ldap3>=2.5.1 +django-nameko>=0.1