Active Directory LDAP client
| 16 | |
| 17 | |
| 18 | class ADClient: |
| 19 | """Active Directory LDAP client""" |
| 20 | |
| 21 | def __init__(self, dc_host, domain, username, password): |
| 22 | self.dc_host = dc_host |
| 23 | self.domain = domain |
| 24 | self.username = username |
| 25 | self.password = password |
| 26 | self.connection = None |
| 27 | |
| 28 | def connect(self): |
| 29 | """Connect to Domain Controller using LDAP""" |
| 30 | try: |
| 31 | # Create server object |
| 32 | server = Server(self.dc_host, get_info=ALL) |
| 33 | |
| 34 | # Create connection with NTLM authentication |
| 35 | user_dn = f"{self.domain}\\{self.username}" |
| 36 | self.connection = Connection( |
| 37 | server, |
| 38 | user=user_dn, |
| 39 | password=self.password, |
| 40 | authentication=NTLM, |
| 41 | auto_bind=True |
| 42 | ) |
| 43 | |
| 44 | logger.info(f"Successfully connected to DC: {self.dc_host}") |
| 45 | return True |
| 46 | |
| 47 | except LDAPException as e: |
| 48 | logger.error(f"LDAP connection failed: {e}") |
| 49 | return False |
| 50 | except Exception as e: |
| 51 | logger.error(f"Connection error: {e}") |
| 52 | return False |
| 53 | |
| 54 | def disconnect(self): |
| 55 | """Close LDAP connection""" |
| 56 | if self.connection: |
| 57 | self.connection.unbind() |
| 58 | self.connection = None |
| 59 | |
| 60 | def query_computers(self): |
| 61 | """Query all computer objects from Active Directory""" |
| 62 | if not self.connection: |
| 63 | raise Exception("Not connected to AD. Call connect() first.") |
| 64 | |
| 65 | try: |
| 66 | # Convert domain to DN format (e.g., company.local -> DC=company,DC=local) |
| 67 | domain_dn = ','.join([f"DC={part}" for part in self.domain.split('.')]) |
| 68 | |
| 69 | # Search for computer objects |
| 70 | search_base = domain_dn |
| 71 | search_filter = '(objectClass=computer)' |
| 72 | |
| 73 | self.connection.search(search_base, search_filter, attributes=LDAP_COMPUTER_ATTRIBUTES) |
| 74 | |
| 75 | computers = [] |