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) | ||||
|  | ||||
| @@ -127,21 +157,24 @@ class LUSER(): | ||||
|             self.lastgid = lastUID | ||||
|         else: | ||||
|             self.lastuid = lastuidfound  | ||||
|             self.lastgid = 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