Compare commits

..

12 Commits

Author SHA1 Message Date
0cdde03725 add pychache in luser dir to gitignore and passlib to requirements.txt 2024-04-10 14:10:19 +02:00
2b8c5ea453 fix log numbering 2024-04-05 15:48:10 +02:00
3818419cae change version in deb 2024-03-28 19:28:15 +01:00
09c22b23a7 fix all new ldapsync issues 2024-03-28 19:25:56 +01:00
6251e610e8 bug fixes 2024-03-28 18:55:48 +01:00
67f3fefae5 fix bugs 2024-03-28 17:54:13 +01:00
e6fdb916bf santize user input and ldap records 2024-01-05 06:46:34 +01:00
1da508d0d6 add integrity checks for user input 2024-01-04 08:22:17 +01:00
7f1ab45d53 fix static path 2023-12-28 04:53:46 +01:00
b33110f8f4 fix instalation 2023-12-27 17:46:22 +01:00
718cdf6c89 fix confrim password registration form to hide password 2023-11-17 16:58:59 +01:00
ae167a764e change label in html for confirm password 2023-11-01 17:28:54 +01:00
14 changed files with 253 additions and 80 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
__pycache__ __pycache__
luser/__pycache__
luser.deb luser.deb
build-deb/luser/var/ build-deb/luser/var/

View File

@@ -1,17 +1,20 @@
all: man deb all: man deb
man: man/luser.1.md man: man/luser.1.md
mkdir -p luser/usr/share/man/man1/
pandoc man/luser.1.md -f markdown+hard_line_breaks -s -t man -o man/luser.1 pandoc man/luser.1.md -f markdown+hard_line_breaks -s -t man -o man/luser.1
cp man/luser.1 luser/usr/share/man/man1/ cp man/luser.1 luser/usr/share/man/man1/
gzip -f luser/usr/share/man/man1/luser.1 gzip -f luser/usr/share/man/man1/luser.1
deb: man ../requirments.txt ../run.py ../luser ../LICENSE deb: man ../requirments.txt ../run.py ../luser ../LICENSE
mkdir -p luser/var/luser/luser
cp -r ../luser/* luser/var/luser/luser/ cp -r ../luser/* luser/var/luser/luser/
cp ../run.py luser/var/luser/ cp ../run.py luser/var/luser/
cp ../LICENSE luser/var/luser/ cp ../LICENSE luser/var/luser/
chmod -w luser/DEBIAN/*
chmod +w luser/DEBIAN/control
dpkg-deb --build luser dpkg-deb --build luser
chmod +w luser/DEBIAN/*
clean: clean:
rm -f luser.deb rm -f luser.deb
rm -f man/luser.1 rm -f man/luser.1
rm -rf luser/var rm -rf luser/var
mkdir -p luser/var/luser/luser
mkdir -p luser/usr/share/man/man1/

View File

@@ -4,8 +4,8 @@ Priority: optional
Architecture: all Architecture: all
Essential: no Essential: no
Installed-Size: 2000 Installed-Size: 2000
Depends: python3-flask, python3-ldap3, gunicorn Depends: python3-flask, python3-ldap3, gunicorn, imagemagick, python3-passlib
Homepage: https://gitea.dmz.rs/fram3d/luser Homepage: https://gitea.dmz.rs/fram3d/luser
Maintainer: fram3d <fram3d@dmz.rs> Maintainer: fram3d <fram3d@dmz.rs>
Description: Web app that allows users to add,remove and change passwords in LDAP system Description: Web app that allows users to add,remove and change passwords in LDAP system
Version: 1.0.0 Version: 1.1.0

View File

@@ -1,5 +1,7 @@
#!/bin/sh #!/bin/bash
/usr/bin/systemctl enable luser.service /usr/bin/systemctl enable luser.service
/sbin/service luser start /sbin/service luser start
cp /tmp/oldluserconfig.ini /var/luser/luser/config.ini if [ -f /tmp/oldluserconfig.ini ] ; then
rm /tmp/oldluserconfig.ini cp /tmp/oldluserconfig.ini /var/luser/luser/config.ini
rm /tmp/oldluserconfig.ini
fi

View File

@@ -1,2 +1,4 @@
#!/bin/sh #!/bin/bash
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini if [ -f /var/luser/luser/config.ini ] ; then
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini
fi

View File

@@ -1,4 +1,6 @@
#!/bin/sh #!/bin/bash
/sbin/service luser stop /sbin/service luser stop
/usr/bin/systemdctl disable luser.service /usr/bin/systemctl disable luser.service
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini if [ -f /var/luser/luser/config.ini ] ; then
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini
fi

View File

@@ -5,7 +5,7 @@ After=network.target nss-lookup.target
[Service] [Service]
WorkingDirectory=/var/luser/ WorkingDirectory=/var/luser/
ExecStart=/usr/bin/gunicorn --workers 3 --bind 127.0.0.1:5000 run:app ExecStart=/usr/bin/gunicorn --workers 3 --bind 0.0.0.0:80 run:app
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@@ -0,0 +1,100 @@
#!/bin/sh
# This script is an example captcha script.
# It takes the text to recognize in the captcha image as a parameter.
# It return the image binary as a result. ejabberd support PNG, JPEG and GIF.
# The whole idea of the captcha script is to let server admins adapt it to
# their own needs. The goal is to be able to make the captcha generation as
# unique as possible, to make the captcha challenge difficult to bypass by
# a bot.
# Server admins are thus supposed to write and use their own captcha generators.
# This script relies on ImageMagick.
# It is NOT compliant with ImageMagick forks like GraphicsMagick.
INPUT=$1
if test -n ${BASH_VERSION:-''} ; then
get_random ()
{
R=$RANDOM
}
else
for n in `od -A n -t u2 -N 48 /dev/urandom`; do RL="$RL$n "; done
get_random ()
{
R=${RL%% *}
RL=${RL#* }
}
fi
get_random
WAVE1_AMPLITUDE=$((2 + $R % 5))
get_random
WAVE1_LENGTH=$((50 + $R % 25))
get_random
WAVE2_AMPLITUDE=$((2 + $R % 5))
get_random
WAVE2_LENGTH=$((50 + $R % 25))
get_random
WAVE3_AMPLITUDE=$((2 + $R % 5))
get_random
WAVE3_LENGTH=$((50 + $R % 25))
get_random
W1_LINE_START_Y=$((10 + $R % 40))
get_random
W1_LINE_STOP_Y=$((10 + $R % 40))
get_random
W2_LINE_START_Y=$((10 + $R % 40))
get_random
W2_LINE_STOP_Y=$((10 + $R % 40))
get_random
W3_LINE_START_Y=$((10 + $R % 40))
get_random
W3_LINE_STOP_Y=$((10 + $R % 40))
get_random
B1_LINE_START_Y=$(($R % 40))
get_random
B1_LINE_STOP_Y=$(($R % 40))
get_random
B2_LINE_START_Y=$(($R % 40))
get_random
B2_LINE_STOP_Y=$(($R % 40))
#B3_LINE_START_Y=$(($R % 40))
#B3_LINE_STOP_Y=$(($R % 40))
get_random
B1_LINE_START_X=$(($R % 20))
get_random
B1_LINE_STOP_X=$((100 + $R % 40))
get_random
B2_LINE_START_X=$(($R % 20))
get_random
B2_LINE_STOP_X=$((100 + $R % 40))
#B3_LINE_START_X=$(($R % 20))
#B3_LINE_STOP_X=$((100 + $R % 40))
get_random
ROLL_X=$(($R % 40))
convert -size 180x60 xc:none -pointsize 40 \
\( -clone 0 -fill white \
-stroke black -strokewidth 4 -annotate +0+40 "$INPUT" \
-stroke white -strokewidth 2 -annotate +0+40 "$INPUT" \
-roll +$ROLL_X+0 \
-wave "$WAVE1_AMPLITUDE"x"$WAVE1_LENGTH" \
-roll -$ROLL_X+0 \) \
\( -clone 0 -stroke black \
-strokewidth 1 -draw \
"line $B1_LINE_START_X,$B1_LINE_START_Y $B1_LINE_STOP_X,$B1_LINE_STOP_Y" \
-strokewidth 1 -draw \
"line $B2_LINE_START_X,$B2_LINE_START_Y $B2_LINE_STOP_X,$B2_LINE_STOP_Y" \
-wave "$WAVE2_AMPLITUDE"x"$WAVE2_LENGTH" \) \
\( -clone 0 -stroke white \
-strokewidth 2 -draw "line 0,$W1_LINE_START_Y 140,$W1_LINE_STOP_Y" \
-strokewidth 2 -draw "line 0,$W2_LINE_START_Y 140,$W2_LINE_STOP_Y" \
-strokewidth 2 -draw "line 0,$W3_LINE_START_Y 140,$W3_LINE_STOP_Y" \
-wave "$WAVE3_AMPLITUDE"x"$WAVE3_LENGTH" \) \
-flatten -crop 140x60 +repage -quality 90 -depth 8 png:-

View File

@@ -1,5 +1,5 @@
from flask import Flask from flask import Flask
app = Flask(__name__) app = Flask(__name__, static_url_path='/account/static')
from luser import routes from luser import routes

View File

@@ -3,6 +3,6 @@ LDAPHOST = ldap.example.org
LDAPADMINNAME = cn=admin,dc=example,dc=org LDAPADMINNAME = cn=admin,dc=example,dc=org
LDAPPASS = verysecr3t LDAPPASS = verysecr3t
USERBASE = ou=Users,dc=example,dc=org USERBASE = ou=Users,dc=example,dc=org
CAPTCHA_PATH = /var/luser/luser/static/account/register/captcha_img/ CAPTCHA_PATH = /var/luser/luser/static/register/captcha_img/
ALTUSERBASE = ALTUSERBASE =
# ALTUSERBASE = ou=UsersAlt,dc=example,dc=org # ALTUSERBASE = ou=UsersAlt,dc=example,dc=org

View File

@@ -1,6 +1,10 @@
import ldap3
from ldap3 import Server,Connection,ALL,MODIFY_REPLACE from ldap3 import Server,Connection,ALL,MODIFY_REPLACE
from datetime import datetime from datetime import datetime
OBJECTCLASSES = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
USERATTRIBUTES = ['cn' , 'sn', 'givenName', 'uid', 'uidNumber' , 'gidNumber', 'homeDirectory', 'loginShell', 'gecos' , 'shadowLastChange', 'shadowMax', 'userPassword', 'mail', 'description']
class LUSER(): class LUSER():
''' '''
Class that represents secure connection to LDAP server Class that represents secure connection to LDAP server
@@ -9,9 +13,32 @@ class LUSER():
admin_user := string DN of LDAP admin user admin_user := string DN of LDAP admin user
admin_pass := string password of LDAP admin user admin_pass := string password of LDAP admin user
base := string base in LDAP system where users are made base := string base in LDAP system where users are made
basealt := string base in LDAP system where users are made with password hashes generated for openalt
''' '''
def getlastlog(self)->int:
self.ldapconnection.search(search_base=f'uid=total,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
response = self.ldapconnection.response
if response == []:
response = 0
else:
response = int(response[0]['attributes']['uidNumber'])
return response
def setlastlog(self, newvalue: int):
newvalue = int(newvalue)
# Check if total record already present
self.ldapconnection.search(search_base=f'uid=total,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
response = self.ldapconnection.response
attributes = {'cn' : 'total', 'sn' : 'total', 'givenName' : 'total', 'uid' : 'total', 'uidNumber' : newvalue, 'gidNumber' : newvalue, 'homeDirectory' : f'/home/total', 'loginShell' : '/usr/bin/git-shell', 'gecos' : 'SystemUser', 'shadowLastChange' : self.lastpwchangenow(), 'shadowMax' : '45', 'userPassword' : 'total', 'mail' : f'total@{self.domain}' }
if response == []:
self.ldapconnection.add(f'uid=total,{self.logbase}', OBJECTCLASSES, attributes)
else:
self.ldapconnection.modify(f'uid=total,{self.logbase}', {'uidNumber' : (ldap3.MODIFY_REPLACE, [newvalue])})
return self.ldapconnection.response
def findlastuid(self): def findlastuid(self):
''' '''
@@ -25,21 +52,20 @@ class LUSER():
for i in alluids: for i in alluids:
i_uid = i['attributes']['uidNumber'] i_uid = i['attributes']['uidNumber']
if i_uid > max: if type(i_uid) is str or type(i_uid) is int:
max = i_uid i_uid = int(i_uid)
if i_uid > max:
max = i_uid
return max return max
def expandbase(self, basealt = ''): def expandbase(self):
''' '''
Extract orgnaization, name of dc object and full domain part with all dc values from base Extract orgnaization, name of dc object and full domain part with all dc values from base
basealt := string base in LDAP system where users are made, if not set the function uses base specified on creation of LUSER instance (self.base)
''' '''
# Split base string with commas to find values of organization and dc # Split base string with commas to find values of organization and dc
if basealt == '': baselist = self.base.split(",")
baselist = self.base.split(",")
else:
baselist = self.basealt.split(",")
organization = '' organization = ''
dc = '' dc = ''
@@ -70,15 +96,13 @@ class LUSER():
return organization, dc, dcfull, domain return organization, dc, dcfull, domain
def __init__(self, ldap_host, admin_user, admin_pass, base, basealt='', autoconnect=True, lastUID = 1000): def __init__(self, ldap_host, admin_user, admin_pass, base, autoconnect=True, lastUID = 1000):
self.ldap_host = ldap_host self.ldap_host = ldap_host
self.admin_user = admin_user self.admin_user = admin_user
self.admin_pass = admin_pass self.admin_pass = admin_pass
self.base = base self.base = base
self.basealt = basealt
self.organization, self.dc, self.dcfull, self.domain = self.expandbase() self.organization, self.dc, self.dcfull, self.domain = self.expandbase()
self.organizationalt, self.dcalt, self.dcfullalt, self.domainalt = self.expandbase(self.basealt) self.logbase = f'ou=log,{self.dcfull}'
self.alt = True
self.autoconnect = autoconnect self.autoconnect = autoconnect
ldapserver = Server(ldap_host, use_ssl=True) ldapserver = Server(ldap_host, use_ssl=True)
lastuidfound = 0 lastuidfound = 0
@@ -89,6 +113,15 @@ class LUSER():
else: else:
self.ldapconnection = Connection(ldapserver, admin_user, admin_pass, auto_bind=False) self.ldapconnection = Connection(ldapserver, admin_user, admin_pass, auto_bind=False)
# Check if base and log base is created
self.ldapconnection.search(search_base=f'{self.base}',search_filter='(objectClass=organizationalUnit)', attributes=['ou'])
if self.ldapconnection.response == []:
self.prepare()
self.ldapconnection.search(search_base=f'{self.logbase}',search_filter='(objectClass=organizationalUnit)', attributes=['ou'])
if self.ldapconnection.response == []:
self.prepare()
if lastuidfound == 0: if lastuidfound == 0:
self.lastuid = lastUID self.lastuid = lastUID
self.lastgid = lastUID self.lastgid = lastUID
@@ -96,31 +129,21 @@ class LUSER():
self.lastuid = lastuidfound self.lastuid = lastuidfound
self.lastgid = lastuidfound self.lastgid = lastuidfound
# Set alt boolean to false if basealt not set
if basealt == '':
self.alt = False
def prepare(self): def prepare(self):
''' '''
Create base on LDAP host Create base on LDAP host
''' '''
# Create dcObject on LDAP server and store boolean indicating it's success # Create dcObject on LDAP server and store boolean indicating it's success
rcode1 = self.ldapconnection.add(f'dc={self.dcfull}', ['dcObject', 'organization'], {'o' : self.dc, 'dc' : self.dc}) rcode1 = self.ldapconnection.add(self.dcfull, ['dcObject', 'organization'], {'o' : self.dc, 'dc' : self.dc})
# Create organizational units on LDAP server and store boolean indicating it's success # Create organizational units on LDAP server and store boolean indicating it's success
rcode2 = self.ldapconnection.add(self.base, ['top', 'organizationalUnit'], {'ou' : self.organization}) rcode2 = self.ldapconnection.add(self.base, ['top', 'organizationalUnit'], {'ou' : self.organization})
# Add dcobject and organizational units as above for base alt # Create organizational units for log on LDAP server and store boolean indicating it's success
rcode3 = True rcode3 = self.ldapconnection.add(self.logbase, ['top', 'organizationalUnit'], {'ou' : self.organization})
rcode4 = True
if self.alt:
rcode3 = self.ldapconnection.add(f'dc={self.dcfull}', ['dcObject', 'organization'], {'o' : self.dc, 'dc' : self.dc})
rcode4 = self.ldapconnection.add(self.base, ['top', 'organizationalUnit'], {'ou' : self.organization})
return rcode1 and rcode2 and rcode3 and rcode4 return rcode1 and rcode2 and rcode3
def lastpwchangenow(self): def lastpwchangenow(self):
''' '''
@@ -130,12 +153,11 @@ class LUSER():
return str((datetime.utcnow() - datetime(1970,1,1)).days) return str((datetime.utcnow() - datetime(1970,1,1)).days)
def add(self, user, password, althash=""): def add(self, user, password):
''' '''
Add a user to base in LDAP with user and pass as credentials Add a user to base in LDAP with user and pass as credentials
user := string containing username user := string containing username
password := string containing user password password := string containing user password
althash := string containing user password/hash for the alternative base
''' '''
# Increase UID and GID counters # Increase UID and GID counters
@@ -144,6 +166,7 @@ class LUSER():
# Add user to base # Add user to base
id = f"uid={user}" id = f"uid={user}"
lastlog = self.getlastlog() + 1
# Object classes of a user entry # Object classes of a user entry
objectClass = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount'] objectClass = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
@@ -151,49 +174,61 @@ class LUSER():
# Attributes for a user entry # Attributes for a user entry
attributes = {'cn' : user, 'sn' : user, 'givenName' : user, 'uid' : user, 'uidNumber' : self.lastuid, 'gidNumber' : self.lastgid, 'homeDirectory' : f'/home/{user}', 'loginShell' : '/usr/bin/git-shell', 'gecos' : 'SystemUser', 'shadowLastChange' : self.lastpwchangenow(), 'shadowMax' : '45', 'userPassword' : password, 'mail' : f'{user}@{self.domain}' } attributes = {'cn' : user, 'sn' : user, 'givenName' : user, 'uid' : user, 'uidNumber' : self.lastuid, 'gidNumber' : self.lastgid, 'homeDirectory' : f'/home/{user}', 'loginShell' : '/usr/bin/git-shell', 'gecos' : 'SystemUser', 'shadowLastChange' : self.lastpwchangenow(), 'shadowMax' : '45', 'userPassword' : password, 'mail' : f'{user}@{self.domain}' }
attributesalt = {'cn' : user, 'sn' : user, 'givenName' : user, 'uid' : user, 'uidNumber' : self.lastuid, 'gidNumber' : self.lastgid, 'homeDirectory' : f'/home/{user}', 'loginShell' : '/usr//bin/git-shell', 'gecos' : 'SystemUser', 'shadowLastChange' : self.lastpwchangenow(), 'shadowMax' : '45', 'userPassword' : althash, 'mail' : f'{user}@{self.domainalt}'}
# Return boolean value of new user entry # Return boolean value of new user entry
rcode1 = self.ldapconnection.add(f'{id},{self.base}', objectClass, attributes) rcode1 = self.ldapconnection.add(f'uid={user},{self.base}', objectClass, attributes)
# If alternative base is set add the same user to the alternative base as well, if not act as if it was success
if self.alt: # Add new user to log
rcode2 = self.ldapconnection.add(f'{id},{self.basealt}', objectClass, attributesalt) attributes['description'] = 'ADD'
if rcode1:
rcode2 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', objectClass, attributes)
else: else:
rcode2 = True return False
if rcode2:
self.setlastlog(lastlog)
# Return True only if both entries was successful # Return True only if both entries was successful
return rcode1 and rcode2 return rcode1 and rcode2
def changepassword(self, user, newpass, althash=''): def changepassword(self, user, newpass):
''' '''
Change password of user to newpass Change password of user to newpass
user := string containing username user := string containing username
newpass := string containing new password newpass := string containing new password
althash := string containing password/hash for alternative base
''' '''
# This variable holds boolean indicating successful change of user password # This variable holds boolean indicating successful change of user password
chpassbool = self.ldapconnection.modify(f'uid={user},{self.base}', {'userPassword': (MODIFY_REPLACE,[newpass])}) chpassbool = False
# If alternative base is set modify user password/hash with althash, if not, pretend change was successful
if self.alt:
chpassboolalt = self.ldapconnection.modify(f'uid={user},{self.basealt}', {'userPassword': (MODIFY_REPLACE,[althash])})
else:
chpassboolalt = True
# This variable holds boolean indicating successful change of shadowLastChange value to current time # This variable holds boolean indicating successful change of shadowLastChange value to current time
chlastchangebool = False
USERATTRIBUTES=['cn' , 'sn', 'givenName', 'uid', 'uidNumber' , 'gidNumber', 'homeDirectory', 'loginShell', 'gecos' , 'shadowLastChange', 'shadowMax', 'userPassword', 'mail']
OBJECTCLASSES = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
self.ldapconnection.search(search_base=f'uid={user},{self.base}',search_filter='(objectClass=person)', attributes=USERATTRIBUTES)
userdata = self.ldapconnection.response[0]
userdata['attributes']['description'] = 'CHANGEPASS'
lastlog = self.getlastlog() + 1
chpassbool = self.ldapconnection.modify(f'uid={user},{self.base}', {'userPassword': (MODIFY_REPLACE,[newpass])})
chlastchangebool = self.ldapconnection.modify(f'uid={user},{self.base}', {'shadowLastChange' : (MODIFY_REPLACE,[self.lastpwchangenow()])}) chlastchangebool = self.ldapconnection.modify(f'uid={user},{self.base}', {'shadowLastChange' : (MODIFY_REPLACE,[self.lastpwchangenow()])})
# If alternative base is set modify user password/hash with althash, if not, pretend change was successful if chpassbool and chlastchangebool:
if self.alt: rcode1 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', OBJECTCLASSES, userdata['attributes'])
chlastchangeboolalt = self.ldapconnection.modify(f'uid={user},{self.base}', {'shadowLastChange' : (MODIFY_REPLACE, [self.lastpwchangenow()])})
else:
chlastchangeboolalt = True
# Return True only if changing of both password and time of last password change was successful if rcode1:
return chpassbool and chpassboolalt and chlastchangebool and chlastchangeboolalt self.setlastlog(lastlog)
return True
else:
return False
else:
return False
def delete(self, user): def delete(self, user):
''' '''
@@ -202,16 +237,30 @@ class LUSER():
user := string containing username user := string containing username
''' '''
USERATTRIBUTES=['cn' , 'sn', 'givenName', 'uid', 'uidNumber' , 'gidNumber', 'homeDirectory', 'loginShell', 'gecos' , 'shadowLastChange', 'shadowMax', 'userPassword', 'mail']
OBJECTCLASSES = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
self.ldapconnection.search(search_base=f'uid={user},{self.base}',search_filter='(objectClass=person)', attributes=USERATTRIBUTES)
userdata = self.ldapconnection.response[0]
userdata['attributes']['description'] = 'DELETE'
lastlog = self.getlastlog() + 1
rcode1 = self.ldapconnection.delete(f'uid={user},{self.base}') rcode1 = self.ldapconnection.delete(f'uid={user},{self.base}')
# If alternative base is set delete user from alternative base, if not, pretend deletion was successful if rcode1:
if self.alt: rcode2 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', OBJECTCLASSES, userdata['attributes'])
rcode2 = self.ldapconnection.delete(f'uid={user},{self.basealt}')
else:
rcode2 = True
# Return True only if deletion from both bases was successful if rcode2:
return rcode1 and rcode2 self.setlastlog(lastlog)
return True
else:
return False
else:
return False
def getpassword(self, user): def getpassword(self, user):
''' '''
@@ -224,4 +273,9 @@ class LUSER():
self.ldapconnection.search(search_base=self.base,search_filter=f'(&(objectClass=inetOrgPerson)(uid={user}))', attributes=['userPassword']) self.ldapconnection.search(search_base=self.base,search_filter=f'(&(objectClass=inetOrgPerson)(uid={user}))', attributes=['userPassword'])
# Return userPassword attribute from the response # Return userPassword attribute from the response
return self.ldapconnection.response[0]['attributes']['userPassword'][0].decode('utf-8') userpass = self.ldapconnection.response[0]['attributes']['userPassword'][0]
if type(userpass) is bytes:
userpass = userpass.decode('utf-8')
return userpass

View File

@@ -118,7 +118,7 @@ def register():
if len(password) < 8: if len(password) < 8:
return 'Error: password is too short' return 'Error: password is too short'
# Check lenght of password # Check if passwords matches
if password != confirmpassword: if password != confirmpassword:
return 'Error: passwords do not match' return 'Error: passwords do not match'
@@ -126,6 +126,14 @@ def register():
if username.islower() == False: if username.islower() == False:
return 'Error: uppercase characters in username are not allowed' return 'Error: uppercase characters in username are not allowed'
# Check lenght of username
if len(username) < 1 or len(username) > 30:
return 'Error: username has to be between 1 and 30 characters long'
# Check if username is alphanumeric
if not username.isalnum():
return 'Error: username can only contain letters and numbers'
# Create a LUSER connection # Create a LUSER connection
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE,ALTUSERBASE) luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE,ALTUSERBASE)
# Try to add user # Try to add user

View File

@@ -17,11 +17,11 @@
<input type="text" name="username" id="username" placeholder="username" required> <input type="text" name="username" id="username" placeholder="username" required>
<label for="password">password</label> <label for="password">password</label>
<input type="password" name="password" id="password" placeholder="password" required> <input type="password" name="password" id="password" placeholder="password" required>
<label for="confirmpassword">password</label> <label for="confirmpassword">confirmpassword</label>
<input type="confirmpassword" name="confirmpassword" id="confirmpassword" placeholder="confirmpassword" required> <input type="password" name="confirmpassword" id="confirmpassword" placeholder="confirmpassword" required>
<p>password must be at least 8 characters long<p> <p>password must be at least 8 characters long<p>
<br> <br>
<img src=/account/register/captcha_img/{{ imgsrc }} alt="{{ captchahash }}" style="width:200;margin:auto;"> <img src=/account/static/register/captcha_img/{{ imgsrc }} alt="{{ captchahash }}" style="width:200;margin:auto;">
<p> <p>
<label for="captcha answer">captcha answer</label> <label for="captcha answer">captcha answer</label>
<input type="text" name="captchaa" id="captchaa" placeholder="captcha answer" required> <input type="text" name="captchaa" id="captchaa" placeholder="captcha answer" required>

View File

@@ -1,2 +1,3 @@
ldap3 ldap3
flask flask
passlib