fix bugs
This commit is contained in:
parent
e6fdb916bf
commit
67f3fefae5
@ -1,10 +1,12 @@
|
|||||||
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/
|
||||||
@ -16,5 +18,3 @@ 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/
|
|
||||||
|
@ -8,4 +8,4 @@ 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.7
|
Version: 1.0.8
|
||||||
|
144
luser/models.py
144
luser/models.py
@ -1,3 +1,4 @@
|
|||||||
|
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
|
||||||
|
|
||||||
@ -9,9 +10,30 @@ 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['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
|
||||||
|
|
||||||
|
if response == []:
|
||||||
|
self.ldapconnection.add(f'uid=total,{self.logbase}', OBJECTCLASSES, { 'uid' : 'total', 'uidNumber' : 0 })
|
||||||
|
|
||||||
|
self.ldapconnection.modify(f'uid=total,{self.logbase}', {'uidNumber' : (ldap3.MODIFY_REPLACE, [newvalue])})
|
||||||
|
|
||||||
|
return self.ldapconnection.response
|
||||||
|
|
||||||
def findlastuid(self):
|
def findlastuid(self):
|
||||||
'''
|
'''
|
||||||
@ -33,16 +55,12 @@ class LUSER():
|
|||||||
|
|
||||||
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 = ''
|
||||||
@ -73,15 +91,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
|
||||||
@ -92,6 +108,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
|
||||||
@ -99,31 +124,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):
|
||||||
'''
|
'''
|
||||||
@ -133,12 +148,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
|
||||||
@ -154,16 +168,17 @@ 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(self.logbase, 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
|
# Add new user to log
|
||||||
if self.alt:
|
attributes['description'] = 'ADD'
|
||||||
rcode2 = self.ldapconnection.add(f'{id},{self.basealt}', objectClass, attributesalt)
|
lastlog = self.getlastlog() + 1
|
||||||
else:
|
|
||||||
rcode2 = True
|
rcode2 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', objectClass, attributes)
|
||||||
|
|
||||||
|
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
|
||||||
@ -174,29 +189,34 @@ class LUSER():
|
|||||||
|
|
||||||
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 = self.ldapconnection.modify(f'uid={user},{self.base}', {'shadowLastChange' : (MODIFY_REPLACE,[self.lastpwchangenow()])})
|
chlastchangebool = False
|
||||||
|
|
||||||
# If alternative base is set modify user password/hash with althash, if not, pretend change was successful
|
USERATTRIBUTES=['cn' , 'sn', 'givenName', 'uid', 'uidNumber' , 'gidNumber', 'homeDirectory', 'loginShell', 'gecos' , 'shadowLastChange', 'shadowMax', 'userPassword', 'mail']
|
||||||
if self.alt:
|
|
||||||
chlastchangeboolalt = self.ldapconnection.modify(f'uid={user},{self.base}', {'shadowLastChange' : (MODIFY_REPLACE, [self.lastpwchangenow()])})
|
OBJECTCLASSES = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
|
||||||
else:
|
|
||||||
chlastchangeboolalt = True
|
self.ldapconnection.search(search_base=f'uid=username,{self.base}',search_filter='(objectClass=person)', attributes=USERATTRIBUTES)
|
||||||
|
|
||||||
|
userdata = self.ldapconnection.response[0]
|
||||||
|
userdata['attributes']['description'] = 'CHANGEPASS'
|
||||||
|
|
||||||
|
lastlog = self.getlastlog() + 1
|
||||||
|
|
||||||
|
rcode1 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', OBJECTCLASSES, userdata['attributes'])
|
||||||
|
|
||||||
|
if rcode1:
|
||||||
|
self.setlastlog(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()])})
|
||||||
|
|
||||||
# Return True only if changing of both password and time of last password change was successful
|
# Return True only if changing of both password and time of last password change was successful
|
||||||
return chpassbool and chpassboolalt and chlastchangebool and chlastchangeboolalt
|
return chpassbool and chlastchangebool
|
||||||
|
|
||||||
def delete(self, user):
|
def delete(self, user):
|
||||||
'''
|
'''
|
||||||
@ -205,15 +225,23 @@ class LUSER():
|
|||||||
user := string containing username
|
user := string containing username
|
||||||
'''
|
'''
|
||||||
|
|
||||||
rcode1 = self.ldapconnection.delete(f'uid={user},{self.base}')
|
USERATTRIBUTES=['cn' , 'sn', 'givenName', 'uid', 'uidNumber' , 'gidNumber', 'homeDirectory', 'loginShell', 'gecos' , 'shadowLastChange', 'shadowMax', 'userPassword', 'mail']
|
||||||
|
|
||||||
# If alternative base is set delete user from alternative base, if not, pretend deletion was successful
|
OBJECTCLASSES = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
|
||||||
if self.alt:
|
|
||||||
rcode2 = self.ldapconnection.delete(f'uid={user},{self.basealt}')
|
self.ldapconnection.search(search_base=f'uid={user},{self.base}',search_filter='(objectClass=person)', attributes=USERATTRIBUTES)
|
||||||
else:
|
|
||||||
rcode2 = True
|
userdata = self.ldapconnection.response[0]
|
||||||
|
userdata['attributes']['description'] = 'DELETE'
|
||||||
|
|
||||||
|
lastlog = self.getlastlog() + 1
|
||||||
|
|
||||||
|
rcode1 = self.ldapconnection.add(f'uid={lastlog},{self.logbase}', OBJECTCLASSES, userdata['attributes'])
|
||||||
|
|
||||||
|
if rcode1:
|
||||||
|
self.setlastlog(lastlog)
|
||||||
|
rcode2 = self.ldapconnection.delete(f'uid={user},{self.base}')
|
||||||
|
|
||||||
# Return True only if deletion from both bases was successful
|
|
||||||
return rcode1 and rcode2
|
return rcode1 and rcode2
|
||||||
|
|
||||||
def getpassword(self, user):
|
def getpassword(self, user):
|
||||||
|
Loading…
Reference in New Issue
Block a user