LDAP mit php alle Gruppen ausgeben

Hallo,
ich versuche mich nun schon seit 3 Wochen eigenständig in LDAP einzuarbeiten. Dabei habe ich mir zu Anfang vorgenommen „einfach“ mal alle Gruppen - mit Hilfe eines PHP-scriptes - auszugeben, in der meine Testperson Mitglied ist. Langfristig ist mein Ziel ein Login mit zwei verschiedenen Berechtigungsgruppen. Ich könnte wirklich zielführende konstruktive Hilfe brauchen oder ne Komplette Doku oder…oder. Bisher habe ich immer nur Ansätze gefunden/bekommen, die weit über meinen Wissenstand gehen.

Ich habe es selbst versucht, ich habe Dokumentationen gesucht, Bücher gewälzt, aber nichts auf die Reihe bekommen.
Hier mal mein Versuch bisher. Mir ist klar, dass der bisher nur zählt in wie vielen Gruppen der user Mitglied ist, aber ich komme da wirklich nicht weiter.

<?php
$ldapDN = 'Ca21er';
$ldapPass = 'EinPasswort';

$ldap_address = "ldap://entsprechende_url.de";
$ldap_port = 389;

$ldapConn =ldap_connect ($ldap_adress, $ldap_port) or die ("keine Serververbindung");

if($ldapConn){
ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapConn, LDAP_OPT_REFERRALS, 0);
$ldapBind = ldap_bind($ldapConn, "\\". $ldapDN, $ldapPass);

if($ldapBind){
echo "Bind erfolgreich <br>";

$dn = "OU=Schule, DC=Bildungsbehörde, DC=bw, DC=de";
$userDn = "CN=Erik\,Cartmen, OU=12.MA, OU=2, OU = Org.w9, OU = Schüler, OU = MZ03, OU=Schule, DC=Bildungsbehörde, DC=bw, DC=de))";

$filter ="(|sAMAccountName=$ldapDn*))"; 
#bei den Filtern bin ich mir extrem Unsicher, ich habe verschiedene probiert. der liefert mir wenigstens einen 1 -Wert. Alternativ hatte ich z.B.
//$filter="(&(objectCategory=user)(memberOf=OU=Orga.W10))
#der liefert mir einen 0 - Wert, was bedeuten wohl würde, dass Cartmen kein Mitglied der Gruppe ist

$attributes = array ("ou", "sAMAccountName");
#wenn ich das richtig verstehe sind die Attribute, dass was potentiell ausgegeben wird. Und da ich ja eigentlich alle Gruppen will in der er Mitglied ist habe ich OU gewählt und zum Angleich sAMAccountName. Liege ich damit richtig?

$sr = ldap_search($ldapConn,$dn,$filter,$attributes) or exit ("unable to search")

$info ldap_get_entries($ldapConn,$sr) or die("Error".ldap_error($ldapConn));

echo $info["count"]. "Einträge gefunden\n";
print_r($info);

for($i=0; $i<$info["count"] ; $i++)
{$ldap_username = $info[$i] ['sAMAccountName'][0];
}
var_dump($sr);
}else{echo"Bind fehlgeschlagen";}

}
ldap_close

Es würde mich freuen, wenn mir hier jemand weiterhelfen könnte;
v.a. interessiert mich auch, wie ich den $filter korrekt gestallte. Meine Varianten zeigten bisher immer keinen Eintrag, außer bei $filter ="(|sAMAccountName=$ldapDn*))";

Ich möchte meinen Versuch nur ungern aufgeben, nachdem ich schon so viel Zeit investiert habe mich in LDAP einzuarbeiten.

Vielen Dank für eure Hilfe
Milo

Hallo Milo,

mit PHP habe ich das zwar noch nicht probiert, aber vielleicht kann ich Dir beim LDAP-Teil weiterhelfen.

Ich würde Dir empfehlen, zuerst mit ldapsearch Deine Abfrage zu testen, und zwar von dem Rechner aus, auf dem der Webserver läuft, der Deinen PHP-Code ausführen soll. So kannst Du testen, ob überhaupt eine Abfrage möglich ist (da gibt es noch genügend Fallstricke) und auch, wie sie aussehen soll. Erst danach würde ich es mit PHP versuchen.

Hast Du denn eine LMN7? Dann probier doch mal folgende Abfrage:

ldapsearch -x -w "geheim123!" -H "ldap://10.0.0.1" -D "cn=global-binduser,ou=Management,ou=GLOBAL,dc=schule,dc=lan" -b "ou=teachers,ou=default-school,ou=schools,dc=schule,dc=lan" "(cn=zem)" memberOf

Das Passwort und die IP musst Du natürlich anpassen, auch die „dc=…“-Sachen. Der „zem“ ist bei meinem Beispiel ein Lehreraccount.

Zum Filter: Mit einem Filter selektierst Du Objekte des LDAP, also zum Beispiel einen bestimmten Lehrer – in meinem Beispiel den mit dem Login „zem“. Ohne den Filter würdest Du alle Lehrer ausgegeben bekommen.

In meinem Beispiel wird dann von diesem einen Lehrer nur das Attribut „memberOf“ ausgegeben. Wenn Du das weglässt, dann erhältst Du alle Informationen zu diesem LEhrer.

Vielleicht hilft Dir auch diese Seite weiter:

https://wiki.linuxmuster.net/community/anwenderwiki:scripting:ldapsearch

Beste Grüße

Jörg

Hallo Jörg,
Die generelle Idee über eine Kommandozeile zu gehen hatte ich schon, aber leider habe ich keine LMN7 :worried:.
Das macht die Sache nicht gerade einfacher, und nachinstallieren darf ich auf dem Rechner nichts.

Ich habe aber deinen Link genutzt um bei Hot examples mal nach Quellen mit php Lösungen zu suchen.
Da ich nichts zu meinem derzeitigen Problem gefunden habe bin ich einen Schritt weiter gegangen, denn mein endgültiges Ziel ist es ein Login zu schaffen, das zwischen Admin und user differenziert und diese dann an unterschiedliche Seiten weiter leitet.

Leider kann ich die Codes gar nicht nachvollziehen, die scheinen alle super komplex zu sein.

Hallo Milo,

folgendes Skript speichert alle Gruppen eines Users im Array $groups:

<?php

$ldap_server    = "ldaps://<UrlDesLdapServers>/";
$ldap_basedn    = "ou=schools,dc=linuxmuster,dc=lan";
$ldap_binduser  = 'cn=<BindUser>,ou=Management,ou=GLOBAL,dc=linuxmuster,dc=lan';
$ldap_bindpw    = '<BindPassword>';

$username = "<Kuerzel>";

// connect to ldap_server
if ($ldap_connection=@ldap_connect($ldap_server)) {
  // bind to ldap connection
  if (($ldap_bind=@ldap_bind($ldap_connection, $ldap_binduser, $ldap_bindpw)) == false) {
    echo "Cannot bind to '$ldap_server'";
    @ldap_close($ldap_connection);
    exit();
  }
  // search for user
  else if (($res_id = ldap_search($ldap_connection, $ldap_basedn, "cn=$username")) == false) {
    echo "No user found";
    @ldap_close($ldap_connection);
    exit();
  }
  else {
	  $user_entries = ldap_get_entries($ldap_connection, $res_id);
    $user_groups = $user_entries[0]["memberof"];
    $groups = array();
    foreach ($user_groups as $key => $group) {
      if ($key !== "count") {
        array_push($groups, strtok(substr($group, 3), ','));
      }
    }
    print_r($groups);
    @ldap_close($ldap_connection);
  }
}
else {
  echo "No connection to '$ldap_server'";
}

?>

Der print_r()-Befehl ist nur zur Kontrolle im Browser und sollte später entfernt werden.

Viele Grüße
Christoph

Hallo Milo,

Du kannst ldapsearch ja auch von einem anderen Rechner aus verwenden (wenn der LDAP-Server das zulässt).

Wo stockt es denn bei Dir genau – klappt denn das „ldap_bind“? Wenn ja, dann sollte der Rest nicht schwer sein.

Beste Grüße

Jörg

Danke euch für den großartigen Beistand.
Ich bin froh konstruktive Hilfe gefunden zu haben

Mal im Detail: ich versuche LDAP zu verstehen, da es mein endgültiges Ziel ist ein Login zu erstellen, in dem nach zwei Gruppen differenziert wird.
Dazu fand ich zwar Skripte online, aber die waren für Anfänger wie mich unverständlich.

Also war meine Idee mich ran zu tasten.
Erstmal schauen in welcher Gruppe sich ein User befindet.
Habe ich auch nicht hin bekommen.
Also weiter runter brechen:
In wie vielen Gruppen befindet sich ein User, und dieses Skript war das welches ich euch gepostet habe

Also der Bind ist gar kein Problem.
Den habe ich sofort hinbekommen.

Und mit dem Filter $filter ="(|sAMAccountName=$ldapDn*))" kommt zumindest heraus, dass da ein User existiert.
Aber der fragt ja praktisch nur danach, ob es einen User sAMAccountName gibt, der dem Loginnamen entspricht.
Ich wollte gerne wissen, ob $ldapDN = ‚Ca21er‘ Mitglied einer Gruppe ist. Wenn ich die Baumstruktur richtig verstehe müsste dass die Gruppe OU=12.MA sein. Aber

$filter="(&(objectCategory=user)(memberOf=OU=Orga.W10))
Liefert mir ein leeres array.

Wenn ich die Zugehörigkeit zu einer bestimmten Gruppe herausbekommen habe und ausgeben kann müsste ich das ganze rein theoretisch für mein Login-Script benutzen können.

Ich denke da an eine einfache if(User = Mitglied in Gruppe1){header=Formular für1} else-if(User = Mitglied in Gruppe2){Formular für 2} Form.

Danke Christoph, deinen Code teste ich gleich mal an.

Was denkt Ihr, bin ich mit meinem Vorgehen auf dem richtigen Weg?

Viele Grüße
Milo

Hallo Milo,

natürlich geht das. Mit meinem Code bekommst du ein Array, das alle Gruppen eines Users enthält. Mittels der PHP-Funktion in_array($group, $groups) kannst du nun schauen, ob die gewünschte Gruppe $group im Array $groups enthalten ist. Je nach Ergebnis kannst du nun fortfahren wie du möchtest. Beispiel:

$group1 = "teachers";
$group2 = "students";

if (in_array($group1, $groups) {
  ... // Code für User, der der Gruppe "teachers" angehört.
} elseif (in_array($group2, $groups) {
  ... // Code für User, der der Gruppe "students" angehört.
} else {
  ... // Code für User, der weder der einen noch der anderen Gruppe angehört.
}

Viele Grüße
Christoph

@Christoph
Ich kann Dir gar nicht sagen wie sehr es mich freut endlich mal ein konstruktives Forum gedunden zu haben
Da ich echt blutiger Anfänger bin muss noch ein paar dumme Fragen stellen:

  1. Wie kommt es, dass dein Code ohne Port arbeiten kann? Sucht LDAP sich dann automatisch einen Standart-Port?

  2. Sind die von mir gesetzten
    ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
    ldap_set_option($ldapConn, LDAP_OPT_REFERRALS, 0);
    generell überflüssig? In anderen Quellen wird da immer so viel Wert drauf gelegt.

  3. Ich versuche deinen Code nachzuvollziehen und hänge etwas an $ldap_binduser.
    Ist das mein $userDn?

Viele Grüße und Danke Dir
Milo

Hallo Milo,

  1. der Aufruf mit ldaps:// nutzt den Standardport 636. Du kannst natürlich auch ldap:// mit Standardport 389 verwenden, falls der Webserver intern läuft.
  2. Du kannst die Optionen natürlich setzen. In meinem Beispiel funktioniert es auch ohne, weshalb ich darauf verzichtet habe.
  3. $ldap_binduser ist der User, mit dem du den LDAP-Bind herstellst, also vermutlich global-binduser, wenn du nicht extra für deine Anwendung einen weiteren Binduser angelegt hast.

Viele Grüße
Christoph

Hallo Milo,

der „Bind-User“ ist irgendein Benutzer, der die gewünschte Information aus dem LDAP abfragen darf. Manche LDAP-Server erlauben anonyme Abfragen, aber normalerweise muss man einen Usernamen und ein Passwort angeben.

Du verwendest hier:

schon den User Ca21er, um den es später geht. Das geht natürlich, aber dann funktioniert Dein Skript nur für diesen einen User – genauer: für alle, deren Informationen Dein Ca21er auslesen darf. Außerdem musst Du das Passwort dieses Users in den Code einbauen (oder abfragen).

Besser wäre es, hier einen User zu verwenden, der den gesamten relevanten Teil des LDAP abfragen darf.

Ich würde Dir auch mal empfehlen, einen sehr allgemeinen Filter zu verwenden, z. B. „(cn=*)“, und Dir dann die gesamte Ausgabe anzusehen. So kannst Du die im LDAP hinterlegten Attribute erkennen, die sind nicht überall gleich. Bei uns (und darauf beziehen sich die Beispiele von Christoph) hat jeder User Attribute wie „memberOf=gruppe1“ – und zwar eines für jede Gruppe, in der er Mitglied ist. Es gibt aber auch LDAP-Bäume, da ist die Information, wer in welcher Gruppe ist, bei den Gruppen hinterlegt, z. B. gibt es bei der Gruppe ein Attribut „members=user1,user2,…“ – dann müsste Dein Code ganz anders aussehen. Wenn Du die Struktur des LDAP nicht kennst, dann ist es schwierig. Deshalb: Erst einmal so viel wie möglich abfragen.

Beste Grüße

Jörg

Hallo,
ich habe das ganze jetzt mal an meine Variablen angepasst.
Leider ohne größeren Erfolg. Zurückgegeben wird mir ein leeres Array [Array()].

Der Bind und die Suche funktionieren(also zumindest wird dort „etwas“ gesucht :grin: :

if($ldapConn = ldap_connect($ldap_adress,$ldap_port)){
echo"Cannot bind";
ldap_close($ldapConn);
}
else if(($sr =$ldapBind = ldap_bind($ldapConn, „\“. $ldapDN, „cn=*“))==false{
echo"No user found";
ldap_close($ldapConn);
}
else{
$user_entries = ldap_get_entries($ldapConn, $sr);
$user_groups = $user_entries[0][„memberof“];
$groups = array();
foreach ($user_groups as $key => $group) {
if ($key !== „count“) {
array_push($groups, strtok(substr($group, 3), ‚,‘));
}
}
print_r($groups);
ldap_close($ldapConn);
}
}

Habt ihr ne Ahnung wo mein Problem liegen kann. Ich habe auf einer Website gelesen, dass die primary Group nicht mit ausgegeben. Könnte das der Grund sein?

Viele Grüße
Milo

Hallo Milo,

wahrscheinlich ist bei dir das Attribut memberof nicht belegt. Ich hatte übersehen, dass du ja gar keinen linuxmuster-AD verwendest. Gib doch einfach mal per print_r($user_entries) alle Attribute und deren Belegung des ersten Users aus, auf den dein Filter zutrifft. Dann kannst du schauen, wo bei dir die Gruppen des Users vermerkt sind und memberof entsprechend durch dieses Attribut ersetzen.

Viele Grüße
Christoph

Hallo Cristoph,

ich weiß, langsam wird das peinlich aber ich muss nochmal nachfragen. Zudem habe ich in meinem letzten Posting einen Fehler entdeckt:
else if(($sr =$ldapBind = ldap_bind($ldapConn, „\“. $ldapDN, „cn=“))==false{
sollte natürlich
else if(($sr =ldap_search ($ldapConn,$dn, „cn=
“))==false
heißen.

Aber @Christoph
Also mit print_r($user_entries) und
else if(($sr =ldap_search ($ldapConn,$dn, „cn=*“))==false
bekomme ich ein Array mit allen Einträge mit ihren dn zurück.

Mit print_r($user_entries) und
else if(($sr =ldap_search ($ldapConn,$dn, „cn=$ldapDn“))==false
bekomme ich Array ([count]=>0) ausgegeben.

Mit print_r($groups) und
else if(($sr =ldap_search ($ldapConn,$dn, „cn=*“))==false
bekomme ich Array () ausgegeben.

Hilft das etwas bei der Problemanalyse?

Viele Grüße
Milo

Hallo,
ich lese gerade, die dn ist das value der memberof Attribut.
Dann bin ich mit
print_r($user_entries) und
else if(($sr =ldap_search ($ldapConn,$dn, „cn=*“))==false
doch schonmal ein kleinen Schritt näher?
Viele Grüße
Milo