Compare commits
12 Commits
7435588363
...
master
Author | SHA1 | Date | |
---|---|---|---|
0cdde03725
|
|||
2b8c5ea453
|
|||
3818419cae
|
|||
09c22b23a7
|
|||
6251e610e8
|
|||
67f3fefae5
|
|||
e6fdb916bf
|
|||
1da508d0d6
|
|||
7f1ab45d53
|
|||
b33110f8f4
|
|||
718cdf6c89
|
|||
ae167a764e
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
__pycache__
|
||||
luser/__pycache__
|
||||
luser.deb
|
||||
build-deb/luser/var/
|
||||
|
@@ -1,17 +1,20 @@
|
||||
all: man deb
|
||||
|
||||
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
|
||||
cp man/luser.1 luser/usr/share/man/man1/
|
||||
gzip -f luser/usr/share/man/man1/luser.1
|
||||
deb: man ../requirments.txt ../run.py ../luser ../LICENSE
|
||||
mkdir -p luser/var/luser/luser
|
||||
cp -r ../luser/* luser/var/luser/luser/
|
||||
cp ../run.py luser/var/luser/
|
||||
cp ../LICENSE luser/var/luser/
|
||||
chmod -w luser/DEBIAN/*
|
||||
chmod +w luser/DEBIAN/control
|
||||
dpkg-deb --build luser
|
||||
chmod +w luser/DEBIAN/*
|
||||
clean:
|
||||
rm -f luser.deb
|
||||
rm -f man/luser.1
|
||||
rm -rf luser/var
|
||||
mkdir -p luser/var/luser/luser
|
||||
mkdir -p luser/usr/share/man/man1/
|
||||
|
@@ -4,8 +4,8 @@ Priority: optional
|
||||
Architecture: all
|
||||
Essential: no
|
||||
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
|
||||
Maintainer: fram3d <fram3d@dmz.rs>
|
||||
Description: Web app that allows users to add,remove and change passwords in LDAP system
|
||||
Version: 1.0.0
|
||||
Version: 1.1.0
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
/usr/bin/systemctl enable luser.service
|
||||
/sbin/service luser start
|
||||
cp /tmp/oldluserconfig.ini /var/luser/luser/config.ini
|
||||
rm /tmp/oldluserconfig.ini
|
||||
if [ -f /tmp/oldluserconfig.ini ] ; then
|
||||
cp /tmp/oldluserconfig.ini /var/luser/luser/config.ini
|
||||
rm /tmp/oldluserconfig.ini
|
||||
fi
|
||||
|
@@ -1,2 +1,4 @@
|
||||
#!/bin/sh
|
||||
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini
|
||||
#!/bin/bash
|
||||
if [ -f /var/luser/luser/config.ini ] ; then
|
||||
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini
|
||||
fi
|
||||
|
@@ -1,4 +1,6 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
/sbin/service luser stop
|
||||
/usr/bin/systemdctl disable luser.service
|
||||
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini
|
||||
/usr/bin/systemctl disable luser.service
|
||||
if [ -f /var/luser/luser/config.ini ] ; then
|
||||
cp /var/luser/luser/config.ini /tmp/oldluserconfig.ini
|
||||
fi
|
||||
|
@@ -5,7 +5,7 @@ After=network.target nss-lookup.target
|
||||
|
||||
[Service]
|
||||
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]
|
||||
WantedBy=multi-user.target
|
||||
|
100
build-deb/luser/usr/local/bin/captcha.sh
Executable file
100
build-deb/luser/usr/local/bin/captcha.sh
Executable 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:-
|
@@ -1,5 +1,5 @@
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__, static_url_path='/account/static')
|
||||
|
||||
from luser import routes
|
||||
|
@@ -3,6 +3,6 @@ LDAPHOST = ldap.example.org
|
||||
LDAPADMINNAME = cn=admin,dc=example,dc=org
|
||||
LDAPPASS = verysecr3t
|
||||
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 = ou=UsersAlt,dc=example,dc=org
|
||||
|
176
luser/models.py
176
luser/models.py
@@ -1,6 +1,10 @@
|
||||
import ldap3
|
||||
from ldap3 import Server,Connection,ALL,MODIFY_REPLACE
|
||||
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 that represents secure connection to LDAP server
|
||||
@@ -9,9 +13,32 @@ class LUSER():
|
||||
admin_user := string DN of LDAP admin user
|
||||
admin_pass := string password of LDAP admin user
|
||||
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):
|
||||
'''
|
||||
@@ -25,21 +52,20 @@ class LUSER():
|
||||
|
||||
for i in alluids:
|
||||
i_uid = i['attributes']['uidNumber']
|
||||
if i_uid > max:
|
||||
max = i_uid
|
||||
if type(i_uid) is str or type(i_uid) is int:
|
||||
i_uid = int(i_uid)
|
||||
|
||||
if i_uid > max:
|
||||
max = i_uid
|
||||
|
||||
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
|
||||
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
|
||||
if basealt == '':
|
||||
baselist = self.base.split(",")
|
||||
else:
|
||||
baselist = self.basealt.split(",")
|
||||
baselist = self.base.split(",")
|
||||
|
||||
organization = ''
|
||||
dc = ''
|
||||
@@ -70,15 +96,13 @@ class LUSER():
|
||||
|
||||
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.admin_user = admin_user
|
||||
self.admin_pass = admin_pass
|
||||
self.base = base
|
||||
self.basealt = basealt
|
||||
self.organization, self.dc, self.dcfull, self.domain = self.expandbase()
|
||||
self.organizationalt, self.dcalt, self.dcfullalt, self.domainalt = self.expandbase(self.basealt)
|
||||
self.alt = True
|
||||
self.logbase = f'ou=log,{self.dcfull}'
|
||||
self.autoconnect = autoconnect
|
||||
ldapserver = Server(ldap_host, use_ssl=True)
|
||||
lastuidfound = 0
|
||||
@@ -89,6 +113,15 @@ class LUSER():
|
||||
else:
|
||||
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:
|
||||
self.lastuid = lastUID
|
||||
self.lastgid = lastUID
|
||||
@@ -96,31 +129,21 @@ class LUSER():
|
||||
self.lastuid = lastuidfound
|
||||
self.lastgid = lastuidfound
|
||||
|
||||
|
||||
# Set alt boolean to false if basealt not set
|
||||
if basealt == '':
|
||||
self.alt = False
|
||||
|
||||
def prepare(self):
|
||||
'''
|
||||
Create base on LDAP host
|
||||
'''
|
||||
# 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
|
||||
|
||||
rcode2 = self.ldapconnection.add(self.base, ['top', 'organizationalUnit'], {'ou' : self.organization})
|
||||
|
||||
# Add dcobject and organizational units as above for base alt
|
||||
rcode3 = True
|
||||
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})
|
||||
# Create organizational units for log on LDAP server and store boolean indicating it's success
|
||||
rcode3 = self.ldapconnection.add(self.logbase, ['top', 'organizationalUnit'], {'ou' : self.organization})
|
||||
|
||||
return rcode1 and rcode2 and rcode3 and rcode4
|
||||
return rcode1 and rcode2 and rcode3
|
||||
|
||||
def lastpwchangenow(self):
|
||||
'''
|
||||
@@ -130,12 +153,11 @@ class LUSER():
|
||||
|
||||
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
|
||||
user := string containing username
|
||||
password := string containing user password
|
||||
althash := string containing user password/hash for the alternative base
|
||||
'''
|
||||
|
||||
# Increase UID and GID counters
|
||||
@@ -144,6 +166,7 @@ class LUSER():
|
||||
|
||||
# Add user to base
|
||||
id = f"uid={user}"
|
||||
lastlog = self.getlastlog() + 1
|
||||
|
||||
# Object classes of a user entry
|
||||
objectClass = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
|
||||
@@ -151,49 +174,61 @@ class LUSER():
|
||||
# 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}' }
|
||||
|
||||
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
|
||||
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:
|
||||
rcode2 = self.ldapconnection.add(f'{id},{self.basealt}', objectClass, attributesalt)
|
||||
|
||||
# Add new user to log
|
||||
attributes['description'] = 'ADD'
|
||||
|
||||
if rcode1:
|
||||
rcode2 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', objectClass, attributes)
|
||||
else:
|
||||
rcode2 = True
|
||||
return False
|
||||
|
||||
if rcode2:
|
||||
self.setlastlog(lastlog)
|
||||
|
||||
# Return True only if both entries was successful
|
||||
return rcode1 and rcode2
|
||||
|
||||
def changepassword(self, user, newpass, althash=''):
|
||||
def changepassword(self, user, newpass):
|
||||
'''
|
||||
Change password of user to newpass
|
||||
|
||||
user := string containing username
|
||||
newpass := string containing new password
|
||||
althash := string containing password/hash for alternative base
|
||||
'''
|
||||
|
||||
# This variable holds boolean indicating successful change of user password
|
||||
chpassbool = self.ldapconnection.modify(f'uid={user},{self.base}', {'userPassword': (MODIFY_REPLACE,[newpass])})
|
||||
|
||||
# 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
|
||||
chpassbool = False
|
||||
|
||||
# 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()])})
|
||||
|
||||
# If alternative base is set modify user password/hash with althash, if not, pretend change was successful
|
||||
if self.alt:
|
||||
chlastchangeboolalt = self.ldapconnection.modify(f'uid={user},{self.base}', {'shadowLastChange' : (MODIFY_REPLACE, [self.lastpwchangenow()])})
|
||||
else:
|
||||
chlastchangeboolalt = True
|
||||
if chpassbool and chlastchangebool:
|
||||
rcode1 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', OBJECTCLASSES, userdata['attributes'])
|
||||
|
||||
# Return True only if changing of both password and time of last password change was successful
|
||||
return chpassbool and chpassboolalt and chlastchangebool and chlastchangeboolalt
|
||||
if rcode1:
|
||||
self.setlastlog(lastlog)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def delete(self, user):
|
||||
'''
|
||||
@@ -202,16 +237,30 @@ class LUSER():
|
||||
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}')
|
||||
|
||||
# If alternative base is set delete user from alternative base, if not, pretend deletion was successful
|
||||
if self.alt:
|
||||
rcode2 = self.ldapconnection.delete(f'uid={user},{self.basealt}')
|
||||
else:
|
||||
rcode2 = True
|
||||
if rcode1:
|
||||
rcode2 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', OBJECTCLASSES, userdata['attributes'])
|
||||
|
||||
# Return True only if deletion from both bases was successful
|
||||
return rcode1 and rcode2
|
||||
if rcode2:
|
||||
self.setlastlog(lastlog)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
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'])
|
||||
|
||||
# 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
|
||||
|
@@ -118,7 +118,7 @@ def register():
|
||||
if len(password) < 8:
|
||||
return 'Error: password is too short'
|
||||
|
||||
# Check lenght of password
|
||||
# Check if passwords matches
|
||||
if password != confirmpassword:
|
||||
return 'Error: passwords do not match'
|
||||
|
||||
@@ -126,6 +126,14 @@ def register():
|
||||
if username.islower() == False:
|
||||
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
|
||||
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE,ALTUSERBASE)
|
||||
# Try to add user
|
||||
|
@@ -17,11 +17,11 @@
|
||||
<input type="text" name="username" id="username" placeholder="username" required>
|
||||
<label for="password">password</label>
|
||||
<input type="password" name="password" id="password" placeholder="password" required>
|
||||
<label for="confirmpassword">password</label>
|
||||
<input type="confirmpassword" name="confirmpassword" id="confirmpassword" placeholder="confirmpassword" required>
|
||||
<label for="confirmpassword">confirmpassword</label>
|
||||
<input type="password" name="confirmpassword" id="confirmpassword" placeholder="confirmpassword" required>
|
||||
<p>password must be at least 8 characters long<p>
|
||||
<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>
|
||||
<label for="captcha answer">captcha answer</label>
|
||||
<input type="text" name="captchaa" id="captchaa" placeholder="captcha answer" required>
|
||||
|
@@ -1,2 +1,3 @@
|
||||
ldap3
|
||||
flask
|
||||
passlib
|
||||
|
Reference in New Issue
Block a user