From c51403ed2d26c153eae06e65c7008261b6e7c8b2 Mon Sep 17 00:00:00 2001 From: Alexandre CHAZAL Date: Mon, 6 Dec 2021 19:33:43 +0100 Subject: [PATCH] fix(ldap_client): added docstrings, re-indented correctly, moved Client class's parameters to a Dataclass --- app/ldap_client.py | 130 +++++++++++++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 40 deletions(-) diff --git a/app/ldap_client.py b/app/ldap_client.py index 976c67a..fc38758 100644 --- a/app/ldap_client.py +++ b/app/ldap_client.py @@ -1,60 +1,110 @@ -import ldap3 +""" +Module used to connect to the target LDAP server +""" from typing import Tuple +from dataclasses import dataclass +import ldap3 + + +@dataclass +class ClientParams: + """ + Parameters for the Client class + """ + address: str + base_dn: str + port: int = 389 + tls: bool = False + primary_attribute: str = "uid" + class Client(): - def __init__(self, address: str, port: int, base_dn: str, primary_attribute: str = "uid", tls: bool = False): - self.server = ldap3.Server(host=address, port=port, use_ssl=tls) - self.base_dn = base_dn - self.address = address - self.port = port - self.tls = tls - self.primary_attribute = primary_attribute + """ + Class that represents a connection to an LDAP server. + + Attributes: + server (ldap3.Connection): An ldap3.Server object + base_dn (str): The target base DN + address (str): The target server's address + port (int): The target server's port + tls (bool): A boolean to indicate TLS usage + primary_attribute (str): The clients' LDAP primary attributes + link (ldap3.Connection): Represents the current link status + """ + def __init__(self, params: ClientParams): + self.server = ldap3.Server( + host=params.address, + port=params.port, + use_ssl=params.tls) + self.base_dn = params.base_dn + self.address = params.address + self.port = params.port + self.tls = params.tls + self.primary_attribute = params.primary_attribute + self.link = None def bind(self, user: str, bind_passwd: str) -> Tuple[bool, str]: + """ + Binds to the target server. + + Args: + user (str): The target username + bind_passwd (str): The target user's password + + Returns: + (bool, str): (True, "") if the bind was successful + (False, "") if it wasn't. + """ user_dn = f"{self.primary_attribute}={user},{self.base_dn}" - self.link = ldap3.Connection(self.server, user=user_dn, password=bind_passwd) + self.link = ldap3.Connection(self.server, + user=user_dn, + password=bind_passwd) - try: - status = self.link.bind() - except Exception as _: - status = False + status = self.link.bind() + if status is False: + print(f"[!!] Could not bind {user_dn} to the LDAP directory: " + f"{self.link.last_error}") + return (False, "") - if status == False: - print(f"[!!] Could not bind {user_dn} to the LDAP directory: {self.link.last_error}") - return (status, "") - return (status, user_dn) def unbind(self) -> bool: - if self.link.bound != True: - return False - - try: - self.link.unbind() - except Exception as e: - pass + """ + Unbinds and disconnect from the server. - return True + Returns: + bool: True if the operation was successful, False if it wasn't. + """ + if self.link.bound is False: + return False + + return self.link.unbind() def change_pwd(self, user_dn: str, new_password: str) -> bool: - if self.link.bound == False: + """ + Changes a specific user's DN. + + Args: + user_dn (str): The target user's DN + new_password (str): The wanted password + + Returns: + bool: True if the operation was successful, False if it wasn't. + """ + if self.link.bound is False: print("[!!] Can't change the password: not bound to the server") return False - - status = self.link.modify(user_dn, {'userPassword': [(ldap3.MODIFY_REPLACE, [new_password])]}) - if status == True: + + status = self.link.modify( + user_dn, { + 'userPassword': [ + (ldap3.MODIFY_REPLACE, [new_password])]}) + if status: print(f"[++] Changed password of user {user_dn}") - else: - print(f"[!!] Could not change password of user {user_dn}: {self.link.last_error}") + else: + print( + f"[!!] Could not change password of user {user_dn}: " + f"{self.link.last_error}") return status - -if __name__ == "__main__": - client = Client("dc01.lan.alxczl.fr", 636, "cn=users,cn=accounts,dc=lan,dc=alxczl,dc=fr", True) - client_dn = "uid=alexandre,cn=users,cn=accounts,dc=lan,dc=alxczl,dc=fr" - res = client.bind(client_dn, "Getshrektm8") - if res[0] == False: - print(client.link.result["description"]) - - #client.link.unbind() \ No newline at end of file