lgit/models.py

186 lines
7.6 KiB
Python
Raw Normal View History

2024-02-08 17:21:39 +00:00
import ldap3
2024-03-01 09:07:39 +00:00
import random
2024-02-08 17:21:39 +00:00
MAXENTRIES = 1000000
OBJECTCLASSES = ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'shadowAccount']
USERATTRIBUTES = ['cn' , 'sn', 'givenName', 'uid', 'uidNumber' , 'gidNumber', 'homeDirectory', 'loginShell', 'gecos' , 'shadowLastChange', 'shadowMax', 'userPassword', 'mail', 'description']
class ldapbind():
def __init__(self, ldap_host: str, admin_user: str, admin_pass: str, base: str):
self.ldap_host = ldap_host
self.admin_user = admin_user
2024-03-01 09:07:39 +00:00
self.admin_pass = admin_pass
2024-02-08 17:21:39 +00:00
self.base = base
ldapserver = ldap3.Server(self.ldap_host,use_ssl=True)
self.conn = ldap3.Connection(ldapserver, admin_user, admin_pass, auto_bind=True)
class logbranch():
2024-03-01 09:07:39 +00:00
def __init__(self, ldap_server: ldapbind, log_server: ldapbind = None):
2024-02-08 17:21:39 +00:00
self.ldap_server = ldap_server
self.log_server = log_server
2024-03-01 09:07:39 +00:00
if self.log_server == None:
dc = ldap_server.base.split(',')
self.dc = ','.join(dc[1:])
self.log_server = ldapbind(ldap_server.ldap_host, ldap_server.admin_user, ldap_server.admin_pass, f'ou=log,{self.dc}')
2024-02-08 17:21:39 +00:00
self.base = self.ldap_server.base
self.logbase = self.log_server.base
self.ldapconnection = self.ldap_server.conn
self.logconnection = self.log_server.conn
2024-03-01 09:07:39 +00:00
# Unique id of the log branch
self.id = self.getid()
2024-02-08 17:21:39 +00:00
# How many changes we applied to the LDAP server
self.loaded = self.getloaded()
# How many changes are recoreded in total
self.total = self.gettotal()
2024-03-01 09:07:39 +00:00
def getid(self)->int:
self.logconnection.search(search_base=f'uid=id,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
response = self.logconnection.response
if response == []:
id = random.randint(10**12, 10**13-1)
self.logconnection.add(f'uid=id,{self.logbase}', OBJECTCLASSES, { 'uid' : 'id', 'uidNumber' : id })
return id
return int(response[0]['attributes']['uidNumber'])
2024-02-08 17:21:39 +00:00
def gettotal(self)->int:
self.logconnection.search(search_base=f'uid=total,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
response = self.logconnection.response
if response == []:
2024-03-01 09:07:39 +00:00
settotal(0)
return 0
return int(response[0]['attributes']['uidNumber'])
2024-02-08 17:21:39 +00:00
def settotal(self, newvalue: int):
newvalue = int(newvalue)
# Check if total record already present
self.logconnection.search(search_base=f'uid=total,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
response = self.logconnection.response
if response == []:
2024-03-01 09:07:39 +00:00
self.logconnection.add(f'uid=total,{self.logbase}', OBJECTCLASSES, { 'uid' : 'total', 'uidNumber' : 0 })
2024-02-08 17:21:39 +00:00
2024-03-01 09:07:39 +00:00
self.logconnection.modify(f'uid=total,{self.logbase}', {'uidNumber' : (ldap3.MODIFY_REPLACE, [newvalue])})
return self.logconnection.response
2024-02-08 17:21:39 +00:00
def getloaded(self):
self.connection.search(search_base=f'uid=loaded,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
response = self.logconnection.response
if response == []:
2024-03-01 09:07:39 +00:00
setloaded(0)
return 0
return int(self.connection.response[0]['attributes']['uidNumber'])
2024-02-08 17:21:39 +00:00
def setloaded(self, newvalue: int):
newvalue = int(newvalue)
# Check if loaded record already present
self.logconnection.search(search_base=f'uid=loaded,{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
response = self.logconnection.response
if response == []:
2024-03-01 09:07:39 +00:00
self.logconnection.add(f'uid=loaded,{self.logbase}', OBJECTCLASSES, { 'uid' : 'loaded', 'uidNumber' : 0 })
2024-02-08 17:21:39 +00:00
2024-03-01 09:07:39 +00:00
self.logconnection.modify(f'uid=loaded,{self.logbase}', {'uidNumber' : (ldap3.MODIFY_REPLACE, [newvalue])})
return self.logconnection.response
2024-02-08 17:21:39 +00:00
def refreshtotal(self):
self.settotal(self.findtotal())
return self.gettotal()
def findtotal(self):
2024-03-01 09:07:39 +00:00
for entry in range(self.gettotal() + 1, MAXENTRIES):
2024-02-08 17:21:39 +00:00
self.logconnection.search(search_base=f'uid={entry},{self.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
if self.logconnection.response == []:
return entry - 1
def applylogs(self):
self.refreshtotal()
2024-03-01 09:07:39 +00:00
loaded = self.getloaded() + 1
total = self.gettotal() + 1
2024-02-08 17:21:39 +00:00
for log_number in range(loaded, total):
self.setlog(log_number)
return total - loaded
def applylog(self, log_number: int):
log = self.getlog(log_number)
return self.setlog(self, log)
def getlog(self, log_number: int):
self.logconnection.search(search_base=f'uid={log_number},{self.logbase}',search_filter = '(objectClass=person)', attributes = USERATTRIBUTES)
2024-03-01 09:07:39 +00:00
return logconnection.response[0]
2024-02-08 17:21:39 +00:00
def setlog(self, log_number: int):
log = self.getlog(log_number)
attributes = log['attributes']['description']
uid = attributes['uid']
action = attributes['description']
attributes['description'] = ''
if action == 'ADD':
self.ldapconnection.add(f'uid={uid},{self.base}', OBJECTCLASSES, attributes)
elif action == 'DELETE':
self.ldapconnection.delete(f'uid={uid},{self.base}')
elif action == 'CHANGEPASS':
self.ldapconnection.modify(f'uid={uid},{self.base}', {'userPassword': (MODIFY_REPLACE,attributes['userPassword'])})
else:
return f'Error: Unrecognized action in log entry: {action}'
self.setloaded( self.getloaded() + 1 )
return ldapconnection.response
class logtree():
2024-03-01 09:07:39 +00:00
def __init__(self):
2024-02-08 17:21:39 +00:00
self.branches = []
def add(self, log_server: logbranch):
2024-03-01 09:07:39 +00:00
# Find ID of new branch
id = log_server.logconnection.search(search_base=f'{log_server.logbase}',search_filter='(objectClass=person)', attributes=['uidNumber'])
remotebranches = []
for branch in self.branches:
# Create base for log copies of the new log branch to all existing ones
branch.ldapconnection.search(search_base=f'ou=ldapsync{id},{branch.dc}',search_filter='(objectClass=organizationalUnit)', attributes=['ou'])
if branch.ldapconnection.response == []:
branch.ldapconnection.add(f'ou=ldapsync{id},{branch.dc}', ['top', 'organizationalUnit'], {'ou' : id})
remotebranch = logbranch(branch.log_server)
remotebranch.logbase = f'ou=ldapsync{id},{branch.dc}'
remotebranches.append(remotebranch)
branchdata = {'local' : log_server , 'remote' : remotebranches}
self.branches.append(branchdata)
2024-02-08 17:21:39 +00:00
def remove(self, log_server: logbranch):
2024-03-01 09:07:39 +00:00
for branch in self.branches:
if branch['local'] == log_server:
self.branches.remove(branch)
def push(self):
for branch in self.branches:
localtotal = branch.gettotal()
for remotebranch in branch['remote']:
remotetotal = remotebranch.gettotal()
for log in range(remotetotal + 1, localtotal + 1):
locallog = branch['local'].getlog(log)
remotebranch.logconnection.add(f'uid={log},{remotebranch.logbase}', OBJECTCLASSES, locallog['attributes'])
2024-02-08 17:21:39 +00:00
def sync(self):
2024-03-01 09:07:39 +00:00
self.push()
2024-02-08 17:21:39 +00:00
for branch in self.branches:
2024-03-01 09:07:39 +00:00
branch['local'].applylogs()
for localbranch in branch['remote']:
localbranch.applylogs()
2024-02-08 17:21:39 +00:00