""" 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(): """ 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) 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, "") return (status, user_dn) def unbind(self) -> bool: """ Unbinds and disconnect from the server. 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: """ 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: print(f"[++] Changed password of user {user_dn}") else: print( f"[!!] Could not change password of user {user_dn}: " f"{self.link.last_error}") return status