Fixed typos, especially the wrong attribute in <form>

This commit is contained in:
downhill 2018-10-14 17:48:11 +02:00
parent 06249d530d
commit 2b566aeb8e
19 changed files with 327 additions and 85 deletions

View File

@ -45,6 +45,16 @@ AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(
# LDAP config end # 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, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -71,6 +81,7 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'dal',
] ]
MIDDLEWARE = [ MIDDLEWARE = [

View File

@ -9,6 +9,6 @@
<li> Email: {{email}} </li> <li> Email: {{email}} </li>
</ul> </ul>
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>

View File

@ -2,12 +2,12 @@
<h2> Changing the password for {{user}} </h2> <h2> Changing the password for {{user}} </h2>
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>
<br><br> <br><br>
To change the password for {{user}}, please supply To change the password for {{user}}, please supply
<form action={% url 'change_password' %} type="post"> <form action={% url 'change_password' %} method="post">
{% csrf_token %} {% csrf_token %}
<br>The old password:<br> <br>The old password:<br>
<input type="password" name="oldpassword" id="oldpassword"> <input type="password" name="oldpassword" id="oldpassword">

View File

@ -2,11 +2,11 @@
<h2> Changing user data for {{user}} </h2> <h2> Changing user data for {{user}} </h2>
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>
<br><br> <br><br>
<form action={% url 'change_data' %} type="post"> <form action={% url 'change_data' %} method="post">
{% csrf_token %} {% csrf_token %}
<br>Firstname:<br> <br>Firstname:<br>
<input type="text" name="firstname" id="firstname" value="{{firstname}}"> <input type="text" name="firstname" id="firstname" value="{{firstname}}">

View File

@ -2,12 +2,12 @@
<h2> Deleting an Account </h2> <h2> Deleting an Account </h2>
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>
<br><br> <br><br>
To delete an account, please type the username and password below: To delete an account, please type the username and password below:
<form action={% url 'account_delete' %} type="post"> <form action={% url 'account_delete' %} method="post">
<br><br>Username:<br> <br><br>Username:<br>
<input type="text" name="username" id="username"> <input type="text" name="username" id="username">
<br><br>Password:<br> <br><br>Password:<br>

View File

@ -2,6 +2,6 @@
<h2> The user {{user}} was deleted from our system. </h2> <h2> The user {{user}} was deleted from our system. </h2>
<br> <br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>

View File

@ -6,10 +6,10 @@ While trying to {{service}}, an error was encountered: {{error}}
<br><br> <br><br>
You can try to: You can try to:
<br> <br>
<form action={% url urlname %} type="get"> <form action={% url urlname %} method="get">
<input type="submit" value="Go back and try again"> <input type="submit" value="Go back and try again">
</form> </form>
<br>or<br> <br>or<br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Go to the indexpage"> <input type="submit" value="Go to the indexpage">
</form> </form>

View File

@ -3,7 +3,8 @@
<h2> Welcome to the ungleich user service </h2> <h2> Welcome to the ungleich user service </h2>
<br><br> <br><br>
If you want to use the user service, you will need an account on our system. If you already have one, please login below: If you want to use the user service, you will need an account on our system. If you already have one, please login below:
<form action={% url 'index' %} type="post"> <form action={% url 'index' %} method="post">
{% csrf_token %}
<br><br>Username:<br> <br><br>Username:<br>
<input type="text" name="username" id="username"> <input type="text" name="username" id="username">
<br><br>Password:<br> <br><br>Password:<br>
@ -12,10 +13,10 @@ If you want to use the user service, you will need an account on our system. If
<input type="submit" value="Submit"> <input type="submit" value="Submit">
</form> </form>
<br><br>If you have an account, but forgot your password, please visit our password reset page: <br><br>If you have an account, but forgot your password, please visit our password reset page:
<form action={% url 'reset_password' %} type="get"> <form action={% url 'reset_password' %} method="get">
<input type="submit" value="Password reset"> <input type="submit" value="Password reset">
</form> </form>
<br><br>If you don't have an account, please register yourself with us: <br><br>If you don't have an account, please register yourself with us:
<form action={% url 'register' %} type="get"> <form action={% url 'register' %} method="get">
<input type="submit" value="Register an user"> <input type="submit" value="Register an user">
</form> </form>

View File

@ -2,10 +2,10 @@
<h2> Sorry, but your login has failed </h2> <h2> Sorry, but your login has failed </h2>
<br><br>This service runs for our LDAP users, so maybe you don't already have an LDAP account with us? If so, please register one. <br><br>This service runs for our LDAP users, so maybe you don't already have an LDAP account with us? If so, please register one.
<form action={% url 'register' %} type="get"> <form action={% url 'register' %} method="get">
<input type="submit" value="Register an user"> <input type="submit" value="Register an user">
</form> </form>
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>

View File

@ -2,6 +2,6 @@
<h2> You must be logged in to access this page </h2> <h2> You must be logged in to access this page </h2>
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>

View File

@ -2,13 +2,13 @@
<h2> Register an user at ungleich </h2> <h2> Register an user at ungleich </h2>
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>
<br><br> <br><br>
To register yourself an user, please fill out the fields below: To register yourself an user, please fill out the fields below:
<br> <br>
<form action={% url 'register' %} type="post"> <form action={% url 'register' %} method="post">
{% csrf_token %} {% csrf_token %}
<br>Username (alphanumeric):<br> <br>Username (alphanumeric):<br>
<input type="text" name="username" id="username"> <input type="text" name="username" id="username">

View File

@ -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 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. temporary password. Please remember to change it immediately after logging in.
<br> <br>
<form action={% url 'reset_password' %} type="post"> <form action={% url 'reset_password' %} method="post">
{% csrf_token %} {% csrf_token %}
Username:<br> Username:<br>
<input type="text" name="user" id="user"> <input type="text" name="user" id="user">

View File

@ -4,6 +4,6 @@
<br><br> <br><br>
You will shortly get the confirmation email at {{email}} to confirm that you wish to reset the password for {{user}}. You will shortly get the confirmation email at {{email}} to confirm that you wish to reset the password for {{user}}.
<br><br> <br><br>
<form action={% url 'index' %} type="get"> <form action={% url 'index' %} method="get">
<input type="submit" value="Back to indexpage"> <input type="submit" value="Back to indexpage">
</form> </form>

View File

@ -4,18 +4,18 @@
<br><br> <br><br>
You have the following options: You have the following options:
<br> <br>
<form action={% url 'change_data' %} type="get"> <form action={% url 'change_data' %} method="get">
<input type="submit" value="Change your userdata"> <input type="submit" value="Change your userdata">
</form> </form>
<br> <br>
<form action={% url 'change_password' %} type="get"> <form action={% url 'change_password' %} method="get">
<input type="submit" value="Change your password"> <input type="submit" value="Change your password">
</form> </form>
<br> <br>
<form action={% url 'reset_password' %} type="get"> <form action={% url 'reset_password' %} method="get">
<input type="submit" value="Reset your password"> <input type="submit" value="Reset your password">
</form> </form>
<br> <br>
<form action={% url 'account_delete' %} type="get"> <form action={% url 'account_delete' %} method="get">
<input type="submit" value="Delete your account"> <input type="submit" value="Delete your account">
</form> </form>

View File

@ -18,14 +18,14 @@ from django.urls import path
from django.conf.urls import url from django.conf.urls import url
from django.contrib import admin from django.contrib import admin
from .views import Register, ChangeData, ResetPassword, DeleteAccount, Index from .views import Register, ChangeData, ChangePassword, ResetPassword, DeleteAccount, Index
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), # path('admin/', admin.site.urls),
path('register/', Register.as_view(), name="register"), path('register/', Register.as_view(), name="register"),
path('changedata/', ChangeData.as_view(), name="change_data"), path('changedata/', ChangeData.as_view(), name="change_data"),
path('resetpassword/', ResetPassword.as_view(), name="reset_password"), path('resetpassword/', ResetPassword.as_view(), name="reset_password"),
path('changepassword/', ChangePassword.as_view(), name="change_password"), path('changepassword/', ChangePassword.as_view(), name="change_password"),
path('deleteaccount/', DeleteAccount.as_view(), name="account_delete"), path('deleteaccount/', DeleteAccount.as_view(), name="account_delete"),
path('/', Index.as_view(), name="index") path('index/', Index.as_view(), name="index"),
] ]

View File

@ -3,21 +3,16 @@ from django.views.generic import View
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.http import HttpResponse, HttpResponseRedirect 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.urls import reverse_lazy
from django_nameko import get_pool
# Check to see if the username is already taken # Check to see if the username is already taken
# Helper function, not to be set up as a view # Helper function, not to be set up as a view
# First checks the DB, since ldap parks users there # Check the LDAP if the user exists
# After that, check LDAP directly if the user just never
# logged in
def check_user_exists(username): def check_user_exists(username):
if User.objects.filter(username=username).exists(): with get_pool().next() as rpc:
return True return rpc.userlookup.lookup(username)
# TODO: Needs to look up the LDAP
else return False
# The index page # The index page
# If there's a session open, it will give the user the options he/she/it can do, if not, # 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 # check if the supplied passwords match
if password1 != password2: if password1 != password2:
return render(request, 'registererror.html', { 'urlname': urlname, 'service': service, 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') email = request.POST.get('email')
# Is the emailaddress valid? # 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.' } ) return render(request, 'registererror.html', { 'urlname': urlname, 'service': service, 'error': 'The supplied email address is invalid.' } )
firstname = request.POST.get('firstname') firstname = request.POST.get('firstname')
lastname = request.POST.get('lastname') 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.' } ) return render(request, 'registererror.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter your firstname and lastname.' } )
# throw it to nameko to create the user # throw it to nameko to create the user
if self.create_user(username, password1, firstname, lastname, email): with get_pool().next() as rpc:
return render(request, 'usercreated.html', { 'user': username } ) result = rpc.createuser.create_user(username, password1, firstname, lastname, email)
return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown error while creating the user.' } ) 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 # Change user data for logged in users
class ChangeData(View): class ChangeData(View):
# provide the form for the change request # provide the form for the change request
def get(self, request): def get(self, request):
urlname = 'change_data'
service = 'get default data for logged in user'
if not request.user.is_authenticated: if not request.user.is_authenticated:
return render(request, 'mustbeloggedin.html') return render(request, 'mustbeloggedin.html')
user = request.user user = request.user
login(request, user) login(request, user)
# get basic data (firstname, lastname, email) # 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 # 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 # get the change request
def post(self, 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.' } ) return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter a lastname.' } )
elif email == "": elif email == "":
return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter an 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.' } ) return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'The supplied email address is invalid.' } )
# Trying to change the data # 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, '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 # Resets the password for a user
# Will need to send a confirmation email to the user and we will need a backend # 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: if password1 != password2:
return render(request, 'error.html', { 'urlname': urlname, 'service': service, return render(request, 'error.html', { 'urlname': urlname, 'service': service,
'error': 'Please check if you typed the same password both times for the new password' } ) '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 # 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 } ) return render(request, 'changedpassword.html', { 'user': user } )
# Password not changed, instead got some kind of error
else: else:
return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown error while changing the password!' } ) return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } )
# Changes the password for the supplied user
def change_password(self, user, oldpassword, password):
#TODO: write nameko function to change a password
return True
# Deletes an account
class DeleteAccount(View): class DeleteAccount(View):
# Show the basic form for deleting an account
def get(self, request): def get(self, request):
return render(request, 'deleteaccount.html') return render(request, 'deleteaccount.html')
# Reads the filled out form
def post(self, request): def post(self, request):
# Variables for error page # Variables for error page
urlname = 'account_delete' urlname = 'account_delete'
@ -242,11 +246,13 @@ class DeleteAccount(View):
return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Wrong password for user.' } ) return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Wrong password for user.' } )
# Try to delete the 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, '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

View File

@ -1,81 +1,303 @@
from nameko.events import EventDispatcher, event_handler from nameko.events import EventDispatcher, event_handler
from nameko.rpc import rpc from nameko.rpc import rpc
from configparser import ConfigParser 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 = ConfigParser()
config.read('nameko.conf') config.read('nameko.conf')
# Sanity check for config
try: try:
mult_server = int(config['LDAP']['SERVERMULTIPLE']) mult_server = int(config['LDAP']['SERVERMULTIPLE'])
# SERVERMULTIPLE is set to something not a number
except: except:
exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1") exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1")
# less than one server is not a sensible option
if mult_server < 1: if mult_server < 1:
exit("[LDAP] SERVERMULTIPLE has to be an integer >= 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): class UserLookUp(object):
name = "userlookup" name = "userlookup"
dispatch = EventDispatcher() dispatch = EventDispatcher()
@rpc @rpc
def lookup(self, user): def lookup(self, user):
# Setup the search parameter and connect to LDAP
LDAP_UID = 'uid=%s' % user 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): class CreateUser(object):
name = "createuser" name = "createuser"
dispatch = EventDispatcher() dispatch = EventDispatcher()
@rpc @rpc
def create_user(self, user, password, firstname, lastname, email): 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): class GetUserData(object):
name = "getuserdata" name = "getuserdata"
dispatch = EventDispatcher() dispatch = EventDispatcher()
@rpc @rpc
def get_data(self, user): 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): class ChangeUserData(object):
name = "changeuserdata" name = "changeuserdata"
dispatch = EventDispatcher() dispatch = EventDispatcher()
@rpc @rpc
def change_data(self, user, firstname, lastname, email): 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): class PasswordResetRequest(object):
name = "passwordresetrequest" name = "passwordresetrequest"
dispatch = EventDispatcher() dispatch = EventDispatcher()
@rpc @rpc
def send_request(self, user): def send_request(self, user):
# TODO: Find a good system for that
return "To be done" return "To be done"
# change the password for the user
class ChangePassword(object): class ChangePassword(object):
name = "changepassword" name = "changepassword"
dispatch = EventDispatcher() dispatch = EventDispatcher()
@rpc @rpc
def change_password(self, user, oldpassword, newpassword): def change_password(self, user, newpassword):
return "To be done" 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): class DeleteUser(object):
name = "deleteuser" name = "deleteuser"
dispatch = EventDispatcher() dispatch = EventDispatcher()
@rpc @rpc
def delete_user(self, user): 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): class Log(object):
name = "log" name = "log"
ldaplog = config['System']['LOGDIR'] + '/ldap.log' ldaplog = config['System']['LOGDIR'] + '/ldap.log'

View File

@ -10,4 +10,5 @@ SERVERMULTIPLE = 1
LDAPSERVER1 = localhost LDAPSERVER1 = localhost
LDAPDATA = ,ou=customers,dc=foo,dc=bar LDAPMANAGER = cn=manager,dc=ungleich,dc=ch
LDAPMANAGERPASSWORD = foobar

View File

@ -2,3 +2,4 @@ django>=2.1.2
django-auth-ldap>=1.7.0 django-auth-ldap>=1.7.0
nameko>=2.11.0 nameko>=2.11.0
ldap3>=2.5.1 ldap3>=2.5.1
django-nameko>=0.1