LDAP-Konfiguration (inkl. base_dn, bind_dn, bind_password) */ private array $config; /** @var LdapConnectionHelper Zentrale Hilfsklasse für den Aufbau von LDAP-Verbindungen */ private LdapConnectionHelper $connectionHelper; /** * @param array $ldapConfig Teilbereich "ldap" aus der config.php */ public function __construct(array $ldapConfig) { // Vollständige LDAP-Konfiguration speichern. $this->config = $ldapConfig; // Gemeinsamen Verbindungs-Helper initialisieren. // Dieser kümmert sich um ldap_connect und die grundlegenden Optionen. $this->connectionHelper = new LdapConnectionHelper($ldapConfig); } /** * Stellt eine LDAP-Verbindung her und bindet sich mit dem technischen Konto. * * @return resource LDAP-Verbindungs-Handle * * @throws RuntimeException wenn Bind-Daten fehlen oder der Bind fehlschlägt */ private function connect() { // Technischen Bind-DN (Service-Account) aus der Konfiguration lesen. $bindDn = (string)($this->config['bind_dn'] ?? ''); $bindPassword = (string)($this->config['bind_password'] ?? ''); // Ohne Bind-DN oder Passwort kann kein technischer Bind durchgeführt werden. if ($bindDn === '' || $bindPassword === '') { throw new RuntimeException('LDAP-Binddaten für technisches Konto sind nicht konfiguriert.'); } // Verbindung über den zentralen Helper erstellen (Server, Port, Optionen). $connection = $this->connectionHelper->createConnection(); // Mit dem technischen Konto binden, um Lesezugriffe durchführen zu können. // Das @-Zeichen unterdrückt PHP-Warnings bei Fehlversuchen. if (@ldap_bind($connection, $bindDn, $bindPassword) !== true) { // Bei fehlgeschlagenem Bind Verbindung wieder schließen. ldap_unbind($connection); throw new RuntimeException('LDAP-Bind mit technischem Konto ist fehlgeschlagen.'); } // Erfolgreich gebundene Verbindung zurückgeben. return $connection; } /** * Liefert eine Liste von Benutzern aus dem AD. * * @return array> Liste von Benutzer-Datensätzen * [ * [ * 'samaccountname' => 'user1', * 'displayname' => 'User Eins', * 'mail' => 'user1@example.local', * ], * ... * ] * * @throws RuntimeException bei Konfigurations- oder Verbindungsproblemen */ public function getUsers(): array { // Base-DN ist der Startpunkt der Suche im Verzeichnisbaum (z. B. DC=...,DC=...). $baseDn = (string)($this->config['base_dn'] ?? ''); if ($baseDn === '') { throw new RuntimeException('LDAP base_dn für Benutzersuche ist nicht konfiguriert.'); } // Verbindung mit technischem Bind herstellen. $connection = $this->connect(); // Standard-Filter für Benutzer in AD: // - objectClass=user // - objectCategory=person $filter = '(&(objectClass=user)(objectCategory=person))'; // Nur relevante Attribute auslesen, um Datenmenge klein zu halten. $attributes = ['sAMAccountName', 'displayName', 'mail']; // LDAP-Suche unterhalb des Base-DN durchführen. $search = @ldap_search($connection, $baseDn, $filter, $attributes); if ($search === false) { // Bei einem Fehler die Verbindung schließen und Exception werfen. ldap_unbind($connection); throw new RuntimeException('LDAP-Suche nach Benutzern ist fehlgeschlagen.'); } // Suchergebnisse in ein PHP-Array umwandeln. $entries = ldap_get_entries($connection, $search); // Verbindung wieder schließen, da sie nicht mehr benötigt wird. ldap_unbind($connection); // Ergebnisliste für die View vorbereiten. $users = []; // Wenn die Struktur unerwartet ist, leere Liste zurückgeben. if (!is_array($entries) || !isset($entries['count'])) { return $users; } // Jeden einzelnen Eintrag aus dem Ergebnis verarbeiten. for ($i = 0; $i < $entries['count']; $i++) { $entry = $entries[$i]; // Attribute sind im Ergebnis verschachtelt, daher Zugriff über [...][0]. $users[] = [ 'samaccountname' => isset($entry['samaccountname'][0]) ? (string)$entry['samaccountname'][0] : '', 'displayname' => isset($entry['displayname'][0]) ? (string)$entry['displayname'][0] : '', 'mail' => isset($entry['mail'][0]) ? (string)$entry['mail'][0] : '', ]; } return $users; } /** * Liefert eine Liste von Gruppen aus dem AD. * * @return array> Liste von Gruppen-Datensätzen * * @throws RuntimeException bei Konfigurations- oder Verbindungsproblemen */ public function getGroups(): array { // Base-DN für die Gruppensuche aus der Konfiguration lesen. $baseDn = (string)($this->config['base_dn'] ?? ''); if ($baseDn === '') { throw new RuntimeException('LDAP base_dn für Gruppensuche ist nicht konfiguriert.'); } // Verbindung mit technischem Bind herstellen. $connection = $this->connect(); // Filter für Gruppenobjekte im AD. $filter = '(objectClass=group)'; // Attribute, die für die Darstellung relevant sind. $attributes = ['sAMAccountName', 'cn', 'description']; // LDAP-Suche ausführen. $search = @ldap_search($connection, $baseDn, $filter, $attributes); if ($search === false) { ldap_unbind($connection); throw new RuntimeException('LDAP-Suche nach Gruppen ist fehlgeschlagen.'); } // Ergebnisse holen. $entries = ldap_get_entries($connection, $search); // Verbindung schließen. ldap_unbind($connection); $groups = []; // Struktur prüfen, leere Liste zurückgeben, falls unerwartet. if (!is_array($entries) || !isset($entries['count'])) { return $groups; } // Alle Einträge in ein flacheres Array-Format transformieren. for ($i = 0; $i < $entries['count']; $i++) { $entry = $entries[$i]; $groups[] = [ 'samaccountname' => isset($entry['samaccountname'][0]) ? (string)$entry['samaccountname'][0] : '', 'cn' => isset($entry['cn'][0]) ? (string)$entry['cn'][0] : '', 'description' => isset($entry['description'][0]) ? (string)$entry['description'][0] : '', ]; } return $groups; } }