From 96ff9242a3be08b961f9bc33c33dfd43cbfce47b Mon Sep 17 00:00:00 2001 From: fram3d Date: Thu, 8 Feb 2024 18:21:39 +0100 Subject: [PATCH] init --- models.py | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100755 models.py diff --git a/models.py b/models.py new file mode 100755 index 0000000..875f310 --- /dev/null +++ b/models.py @@ -0,0 +1,137 @@ +import ldap3 + +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 + self.admin_pass= admin_pass + 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(): + def __init__(self, ldap_server: ldapbind, log_server: ldapbind): + + self.ldap_server = ldap_server + self.log_server = log_server + + self.base = self.ldap_server.base + self.logbase = self.log_server.base + self.logconnection = self.log_server.conn + + self.ldapconnection = self.ldap_server.conn + self.logconnection = self.log_server.conn + + # How many changes we applied to the LDAP server + self.loaded = self.getloaded() + + # How many changes are recoreded in total + self.total = self.gettotal() + + 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 == []: + response = 0 + return int(response['attributes']['uidNumber']) + + 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 == []: + return self.logconnection.add(f'uid=total,{self.logbase}', OBJECTCLASSES, { 'uid' : 'total', 'uidNumber' : 0 }) + + return self.logconnection.modify(f'uid=total,{self.logbase}', {'uidNumber' : (ldap3.MODIFY_REPLACE, [newvalue])}) + + 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 == []: + response = 0 + return int(self.connection.response['attributes']['uidNumber']) + + 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 == []: + return self.logconnection.add(f'uid=loaded,{self.logbase}', OBJECTCLASSES, { 'uid' : 'loaded', 'uidNumber' : 0 }) + + return self.logconnection.modify(f'uid=loaded,{self.logbase}', {'uidNumber' : (ldap3.MODIFY_REPLACE, [newvalue])}) + + def refreshtotal(self): + self.settotal(self.findtotal()) + return self.gettotal() + + def findtotal(self): + for entry in range(self.gettotal(), MAXENTRIES): + 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() + + loaded = int(self.getloaded()) + 1 + total = int(self.gettotal()) + 1 + + 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) + return logconnection.response + + 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(): + def __init__(self, ldap_server: ldapbind): + self.ldap_server = ldap_server + self.branches = [] + + def add(self, log_server: logbranch): + self.branches.append(log_server) + + def remove(self, log_server: logbranch): + self.branches.remove(log_server) + + def sync(self): + for branch in self.branches: + branch.applylogs() +