add feature for deleting users and changing passwords with admin pass, many bug fixes, now it is fully tested
This commit is contained in:
@@ -8,4 +8,4 @@ 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.2.0
|
||||
Version: 1.3.0
|
||||
|
@@ -4,5 +4,3 @@ LDAPADMINNAME = cn=admin,dc=example,dc=org
|
||||
LDAPPASS = verysecr3t
|
||||
USERBASE = ou=Users,dc=example,dc=org
|
||||
CAPTCHA_PATH = /var/luser/luser/static/register/captcha_img/
|
||||
ALTUSERBASE =
|
||||
# ALTUSERBASE = ou=UsersAlt,dc=example,dc=org
|
||||
|
@@ -15,10 +15,39 @@ class LUSER():
|
||||
base := string base in LDAP system where users are made
|
||||
'''
|
||||
|
||||
def findlastlog(self):
|
||||
'''
|
||||
Return the largest uidNumber attribute of all users in base
|
||||
'''
|
||||
self.ldapconnection.search(search_base=self.logbase,search_filter=f'(objectClass=inetOrgPerson)', attributes=['uid'])
|
||||
|
||||
alllogs = self.ldapconnection.response
|
||||
|
||||
max = 0
|
||||
|
||||
for i in alllogs:
|
||||
i_log = i['attributes']['uid']
|
||||
if type(i_log) is list:
|
||||
i_log = i_log[0]
|
||||
if str(i_log) == 'total':
|
||||
continue
|
||||
if type(i_log) is str or type(i_log) is int:
|
||||
i_log = int(i_log)
|
||||
|
||||
if i_log > max:
|
||||
max = i_log
|
||||
|
||||
return max
|
||||
|
||||
def getlastlog(self)->int:
|
||||
self.ldapconnection.search(search_base=f'uid=total,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
|
||||
response = self.ldapconnection.response
|
||||
try:
|
||||
self.ldapconnection.search(search_base=f'uid=total,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
|
||||
response = self.ldapconnection.response
|
||||
except:
|
||||
self.setlastlog(0)
|
||||
|
||||
if response == []:
|
||||
self.setlastlog(0)
|
||||
response = 0
|
||||
else:
|
||||
response = int(response[0]['attributes']['uidNumber'])
|
||||
@@ -110,6 +139,7 @@ class LUSER():
|
||||
self.ldapconnection = Connection(ldapserver, admin_user, admin_pass, auto_bind=True)
|
||||
# uid and gid of most recently registered users
|
||||
lastuidfound = self.findlastuid()
|
||||
lastlogfound = self.findlastlog()
|
||||
else:
|
||||
self.ldapconnection = Connection(ldapserver, admin_user, admin_pass, auto_bind=False)
|
||||
|
||||
@@ -129,19 +159,22 @@ class LUSER():
|
||||
self.lastuid = lastuidfound
|
||||
self.lastgid = lastuidfound
|
||||
|
||||
self.lastlog = lastlogfound
|
||||
self.setlastlog(lastlogfound)
|
||||
|
||||
def prepare(self):
|
||||
'''
|
||||
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(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})
|
||||
|
||||
# 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})
|
||||
rcode3 = self.ldapconnection.add(self.logbase, ['top', 'organizationalUnit'], {'ou' : 'log'})
|
||||
|
||||
return rcode1 and rcode2 and rcode3
|
||||
|
||||
@@ -159,14 +192,13 @@ class LUSER():
|
||||
user := string containing username
|
||||
password := string containing user password
|
||||
'''
|
||||
|
||||
# Increase UID and GID counters
|
||||
self.lastuid += 1
|
||||
self.lastgid += 1
|
||||
|
||||
# Add user to base
|
||||
id = f"uid={user}"
|
||||
lastlog = self.getlastlog() + 1
|
||||
lastlog = self.lastlog + 1
|
||||
|
||||
# Object classes of a user entry
|
||||
objectClass = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
|
||||
@@ -180,14 +212,16 @@ class LUSER():
|
||||
|
||||
# Add new user to log
|
||||
attributes['description'] = 'ADD'
|
||||
attributes['uid'] = str(lastlog)
|
||||
|
||||
if rcode1:
|
||||
rcode2 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', objectClass, attributes)
|
||||
rcode2 = self.ldapconnection.add(f'uid={str(lastlog)},{self.logbase}', objectClass, attributes)
|
||||
else:
|
||||
return False
|
||||
|
||||
if rcode2:
|
||||
self.setlastlog(lastlog)
|
||||
self.lastlog=lastlog
|
||||
|
||||
# Return True only if both entries was successful
|
||||
return rcode1 and rcode2
|
||||
@@ -214,7 +248,9 @@ class LUSER():
|
||||
userdata = self.ldapconnection.response[0]
|
||||
userdata['attributes']['description'] = 'CHANGEPASS'
|
||||
|
||||
lastlog = self.getlastlog() + 1
|
||||
lastlog = self.lastlog + 1
|
||||
userdata['attributes']['uid'] = str(lastlog)
|
||||
|
||||
|
||||
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()])})
|
||||
@@ -224,6 +260,7 @@ class LUSER():
|
||||
|
||||
if rcode1:
|
||||
self.setlastlog(lastlog)
|
||||
self.lastlog = lastlog
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -246,7 +283,9 @@ class LUSER():
|
||||
userdata = self.ldapconnection.response[0]
|
||||
userdata['attributes']['description'] = 'DELETE'
|
||||
|
||||
lastlog = self.getlastlog() + 1
|
||||
lastlog = self.lastlog + 1
|
||||
userdata['attributes']['uid'] = str(lastlog)
|
||||
|
||||
|
||||
|
||||
rcode1 = self.ldapconnection.delete(f'uid={user},{self.base}')
|
||||
@@ -256,6 +295,7 @@ class LUSER():
|
||||
|
||||
if rcode2:
|
||||
self.setlastlog(lastlog)
|
||||
self.lastlog = lastlog
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
@@ -17,7 +17,6 @@ LDAPHOST = config.get('credentials', 'LDAPHOST')
|
||||
LDAPADMINNAME = config.get('credentials', 'LDAPADMINNAME')
|
||||
LDAPPASS = config.get('credentials', 'LDAPPASS')
|
||||
USERBASE = config.get('credentials', 'USERBASE')
|
||||
ALTUSERBASE = config.get('credentials', 'ALTUSERBASE')
|
||||
CAPTCHA_PATH = config.get('credentials', 'CAPTCHA_PATH')
|
||||
|
||||
@app.route('/account/changepassword/', methods=['POST', 'GET'])
|
||||
@@ -34,23 +33,22 @@ def changepassword():
|
||||
return 'Error: password is too short'
|
||||
|
||||
# Create a LUSER connection
|
||||
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE,ALTUSERBASE)
|
||||
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE)
|
||||
|
||||
# Retrive current password
|
||||
currentpassword = luser.getpassword(username)
|
||||
|
||||
if currentpassword == False:
|
||||
return 'User doesn't exist'
|
||||
return "User doesn't exist"
|
||||
|
||||
if ldap_salted_sha1.verify(oldpassword, currentpassword) == False and oldpassword != LDAPPASS:
|
||||
return 'Wrong username/password combination'
|
||||
|
||||
ldaphash = ldap_salted_sha1.hash(newpassword)
|
||||
althash = sha512_crypt.hash(newpassword)
|
||||
|
||||
# Try to change user password
|
||||
try:
|
||||
if luser.changepassword(username, ldaphash, althash) == True:
|
||||
if luser.changepassword(username, ldaphash) == True:
|
||||
return 'User password successfuly changed'
|
||||
else:
|
||||
return 'User password change failed'
|
||||
@@ -68,9 +66,9 @@ def unregister():
|
||||
password = request.form['password']
|
||||
|
||||
# Create a LUSER connection
|
||||
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE,ALTUSERBASE)
|
||||
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE)
|
||||
|
||||
if ldap_salted_sha1.verify(password, luser.getpassword(username)) == False:
|
||||
if ldap_salted_sha1.verify(password, luser.getpassword(username)) == False and password != LDAPPASS:
|
||||
return 'Wrong username/password combination'
|
||||
|
||||
# Try to delete user
|
||||
@@ -141,14 +139,13 @@ def register():
|
||||
return 'Error: username can only contain letters and numbers'
|
||||
|
||||
# Create a LUSER connection
|
||||
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE,ALTUSERBASE)
|
||||
luser = LUSER(LDAPHOST,LDAPADMINNAME,LDAPPASS,USERBASE)
|
||||
# Try to add user
|
||||
try:
|
||||
ldaphash = ldap_salted_sha1.hash(password)
|
||||
althash = sha512_crypt.hash(password)
|
||||
#smtpctlout=subprocess.run(["smtpctl","encrypt", password],text=True,stdout=subprocess.PIPE)
|
||||
#smtpdhash=smtpctlout.stdout[:-1]
|
||||
if luser.add(username,ldaphash,althash):
|
||||
if luser.add(username,ldaphash):
|
||||
return 'User successfuly registered'
|
||||
else:
|
||||
return 'User registration failed, username probably taken'
|
||||
|
Reference in New Issue
Block a user