PHP - Connexion à un annuaire LDAP

Décembre 2016

Introduction à LDAP

PHP permet la connexion et l'envoi de requêtes sur un annuaire LDAP, c'est-à-dire un serveur permettant de stocker des informations de manière hiérarchique.

Un serveur LDAP est conçu pour être capable de gérer les opérations suivantes :

  • établir la connexion avec l'annuaire
  • rechercher des entrées
  • comparer des entrées
  • ajouter des entrées
  • modifier des entrées
  • supprimer des entrées
  • annuler ou abandonner une opération
  • fermer la connexion avec l'annuaire


Ainsi PHP fournit un ensemble de fonctions (pour peu que le module LDAP soit installé)
permettant de réaliser ces opérations. Ces fonctions seront explicitées au long de l'article.



Avant de commencer, il faut installer le module LDAP pour le langage PHP. Ce module ajoute un certain nombre de fonctions qui débutent par « ldap_ » et qui permettent d'interfacer le serveur. En effet, par défaut, PHP n'est pas livré avec le support LDAP. Si vous n'installez pas le module et que vous tentez d'utiliser les commandes concernant LDAP, vous obtiendrez le message d'erreur suivant :

Fatal error: Call to unsupported or undefined function ldap_connect()
inrpm -ivh /home/httpd/html/ldap/consulte.php on line x


Il est possible de se procurer ces bibliothèques sur le serveur de l'Université du Michigan (ldap-3.3 package) ou chez Netscape (Netscape Directory SDK).

Séquence d'interrogation avec LDAP

L'interrogation d'un serveur LDAP avec PHP se fait selon une séquence simple,
nécessitant un nombre peu élevé de fonctions spécialisées. La séquence basique est la suivante :

  • Etablissement de la connexion avec le serveur LDAP
  • Liaison et authentification sur le serveur (appelé bind en anglais)
  • Recherche d'une entrée (ou bien une autre opération)
  • Exploitation des résultats (uniquement dans le cas d'une recherche)
  • Fermeture de la connexion

Connexion au serveur LDAP

Avant de pouvoir interroger le serveur LDAP, il est essentiel d'initier la connexion.
Pour cela l'interpréteur PHP a besoin de connaître quelques renseignements
relatifs à l'annuaire :

  • L'adresse du serveur
  • Le port sur lequel le serveur fonctionne
  • La racine de l'annuaire
  • Le login de l'utilisateur (généralement root) ainsi que son mot de passe



<?
// Fichier de configuration pour l'interface PHP
// de notre annuaire LDAP
$server = "localhost";

$port = "389";

$racine = "o=commentcamarche, c=fr";

$rootdn = "cn=ldap_admin, o=commentcamarche, c=fr";

$rootpw = "secret";

?>


On définit donc cinq variables pour caractériser le serveur LDAP :
le nom du serveur, le port (389 par défaut), la racine supérieure de l'arborescence, la chaîne de connexion pour l'administrateur ainsi que son mot de passe.


La première fonction à utiliser est la fonction ldap_connect() permettant d'établir
une liaison avec le serveur. Sa syntaxe est la suivante :

int ldap_connect ([string hostname [, int port]])


Cette fonction admet en paramètre le nom du serveur (éventuellement le port. Par défaut le port est 389). En cas d'échec cette fonction retourne 0 sinon elle retourne un entier permettant d'identifier le serveur et nécessaire dans les fonctions suivantes.


Voici un exemple de connexion au serveur :

<?
echo "Connexion...<br>";

$ds=ldap_connect($server);

?>


Toutefois cette opération n'est pas suffisante pour pouvoir exécuter des opérations sur le serveur LDAP. En effet, il est nécessaire d'initier la liaison (en anglais to bind) avec le serveur LDAP à l'aide de la fonction ldap_bind() dont la syntaxe est la suivante :

int ldap_bind (int identifiant [, string bind_rdn [, string bind_password]])


Cette fonction attend en paramètre l'identifiant du serveur retourné ainsi qu'éventuellement le Nom distingué relatif de l'utilisateur (RDN - Relative Distinguished Name) et son mot de passe. Si l'utilisateur et le mot de passe ne sont pas précisés, la connexion se fait de manière anonyme.


La déconnexion du serveur LDAP se fait tout naturellement par la fonction ldap_close() avec la syntaxe suivante :

int ldap_close (int identifiant)


Cette fonction est similaire à la fonction ldap_unbind().

Voici un exemple complet de connexion et de déconnexion à un serveur LDAP :

<?
// Fichier de configuration pour l'interface PHP
// de notre annuaire LDAP
$server = "localhost";

$port = "389";

$racine = "o=commentcamarche, c=fr";

$rootdn = "cn=ldap_admin, o=commentcamarche, c=fr";

$rootpw = "secret";

echo "Connexion...<br>";

$ds=ldap_connect($server);

if ($ds==1)
{
// on s'authentifie en tant que super-utilisateur, ici, ldap_admin
$r=ldap_bind($ds,$rootdn,$rootpw);

// Ici les opérations à effectuer
echo "Déconnexion...<br>";

ldap_close($ds);

}
else {
echo "Impossible de se connecter au serveur LDAP";

}
?>

Exécution des opérations


Ajouter une entrée avec ldap_add()

La fonction ldap_add() permet d'ajouter des entrées à un annuaire LDAP
auquel on s'est préalablement connecté (et lié). Voici sa syntaxe :

int ldap_add (int identifiant, string dn, array entry)


La fonction ldap_add() admet en paramètre l'identifiant du serveur LDAP retourné par la fonction

ldap_connect() ainsi que le nom distingué de l'entrée (c'est-à-dire son emplacement dans l'annuaire) et un tableau contenant l'ensemble des valeurs des attributs de l'entrée.


Lorsqu'un attribut est multivalué (c'est-à-dire lorsqu'un attribut est lui-même composé de plusieurs valeurs), celles-ci sont indexées dans une case du tableau (les indices du tableau commencent à 0). Dans l'exemple ci-dessous par exemple, l'attribut "mail" possède plusieurs valeurs :

<?php
$ds=ldap_connect($server); // On suppose que le serveur LDAP est sur cet hote
if ($ds) {
$r=ldap_bind($ds,$rootdn,$rootpw);

// preparation des données
$entry["cn"]="Pillou";

$entry["sn"]="Jean-Francois";

$entry["mail"][0]="webmaster@commentcamarche.net";

$entry["mail"][1]="Jeff@commentcamarche.net";

$entry["objectclass"]="person";

// Ajout des données dans l'annuaire
$r=ldap_add($ds, "cn=Jean-Francois Pillou, o=commentcamarche, c=fr", $entry);

ldap_close($ds);

} else {
echo "Connexion au serveur LDAP impossible";

}

?>

Comparer une entrée avec ldap_compare()

La fonction ldap_compare() permet de comparer la valeur d'un attribut d'une entrée de l'annuaire LDAP, auquel on s'est préalablement connecté (et lié), à une valeur passée en paramètre. Voici la syntaxe de la fonction ldap_compare() :

int ldap_compare (int identifiant, string dn, string attribut, string valeur)


La fonction ldap_compare() admet en paramètre l'identifiant du serveur LDAP retourné par la fonction

ldap_connect(), le nom distingué de l'entrée (c'est-à-dire son emplacement dans l'annuaire) ainsi que le nom de l'attribut de l'entrée et la valeur à laquelle on veut comparer sa valeur dans l'annuaire.


En cas d'erreur, la fonction ldap_compare() renvoie la valeur -1, en cas de réussite elle renvoie TRUE, enfin dans le cas contraire elle renvoie FALSE.


L'exemple suivant (largement inspiré de celui de www.php.net) montre comment comparer un mot de passe avec celui stocké dans l'annuaire pour un utilisateur donné :

<?php
$ds=ldap_connect($server);

if ($ds) {
$r=ldap_bind($ds,$rootdn,$rootpw);

// preparation des données
$dn="cn=Pillou Jean-Francois, o=commentcamarche,c=fr";

$valeur="MonMot2Passe";

$attribut="password";

// Comparaison du mot de passe à celui dans l'annuaire
$resultat=ldap_compare($ds, $dn, $attribut, $valeur);

if ($resultat == -1) {
echo "Erreur:".ldap_error($ds);

}
elseif ($resultat == TRUE) {
echo "Le mot de passe est correct";

}
else ($resultat == FALSE) {
echo "Le mot de passe est erronné...";

}
ldap_close($ds);

} else {
echo "Connexion au serveur LDAP impossible";

}

?>





Notez l'utilisation de la fonction ldap_error() sur laquelle nous reviendrons
ultérieurement pour afficher les détails de l'erreur !

Supprimer une entrée avec ldap_delete()

La fonction ldap_delete() permet de supprimer des entrées d'un annuaire LDAP. Voici sa syntaxe :

int ldap_delete (int identifiant, string dn)


La fonction ldap_delete() admet uniquement deux paramètres :
  • l'identifiant du serveur LDAP retourné par la fonction


ldap_connect()
  • le nom distingué de l'entrée à supprimer.


Une fois de plus, cette fonction renvoie TRUE en cas de réussite,

FALSE en cas d'échec.


L'exemple suivant illustre la suppression d'un élément de l'annuaire :

<?php
$ds=ldap_connect($server); // On suppose que le serveur LDAP est sur cet hote
if ($ds) {
$r=ldap_bind($ds,$rootdn,$rootpw);

// preparation des données
$dn="Pillou Jean-Francois,o=commentcamarche,c=fr";

// Supression de l'entrée de l'annuaire
$r=ldap_delete($ds, $dn);

ldap_close($ds);

} else {
echo "Connexion au serveur LDAP impossible";

}

?>

Modifier une entrée avec ldap_modify()

La fonction ldap_modify() permet de modifier une entrée de l'annuaire LDAP. Sa syntaxe est la même que celle de la fonction ldap_add() :

int ldap_modify (int identifiant, string dn, array entry)


La fonction ldap_modify() admet en paramètre l'identifiant du serveur LDAP retourné par la fonction

ldap_connect() ainsi que le nom distingué de l'entrée (c'est-à-dire son emplacement dans l'annuaire) et un tableau contenant l'ensemble des valeurs des attributs de l'entrée à modifier.


Lorsqu'un attribut est multivalué (c'est-à-dire lorsqu'un attribut est lui-même composé de plusieurs valeurs), celles-ci sont indexées dans une case du tableau (les indices du tableau commencent à 0). Dans l'exemple ci-dessous par exemple, l'attribut
"mail" possède plusieurs valeurs :

<?php
$ds=ldap_connect($server); // On suppose que le serveur LDAP est sur cet hote
if ($ds) {
$r=ldap_bind($ds,$rootdn,$rootpw);

// preparation des données
$entry["cn"]="Pillou";

$entry["sn"]="Jean-Francois";

$entry["mail"][0]="webmaster@commentcamarche.net";

$entry["mail"][1]="Jeff@commentcamarche.net";

$entry["objectclass"]="person";

// Ajout des données dans l'annuaire
$r=ldap_modify($ds, "cn=Jean-Francois Pillou, o=commentcamarche, c=fr", $entry);

ldap_close($ds);

} else {
echo "Connexion au serveur LDAP impossible";

}

?>

Rechercher une entrée avec ldap_search()

La recherche d'entrée dans l'annuaire est sans aucun doute la fonction la plus utile
parmi les fonctions LDAP de PHP¨car un annuaire est prévu pour être plus souvent
sollicité en lecture (recherche) qu'en écriture (ajout/suppression/modification).


La fonction ldap_search() permet de rechercher une ou plusieurs entrées de l'annuaire LDAP à l'aide du DN de base, c'est-à-dire le niveau de l'annuaire à partir duquel la recherche est effectuée, ainsi qu'un filtre représentant le type de recherche que l'on désire effectuer. Sa syntaxe est la suivante :

int ldap_search (int identifiant, string base_dn,
string filter [, array attributs [, int attrsonly [,
int sizelimit [, int timelimit [, int deref]]]]])


La fonction ldap_search() admet en paramètre l'identifiant du serveur LDAP retourné par la fonction

ldap_connect() ainsi que le nom distingué du dossier de base (c'est-à-dire celui à partir duquel la recherche doit s'effectuer) et le filtre de la recherche. La fonction ldap_search() est par défaut configurée avec l'option de récursivité LDAP_SCOPE_SUBTREE ce qui signifie que la recherche se fait dans toutes les branches filles du dossier de base.


Le paramètre attributs permet de restreindre les attributs et les valeurs retournées, c'est-à-dire qu'il s'agit d'un tableau contenant le nom des attributs (chaînes de caractères) des attributs que l'on désire utiliser. Par défaut l'intégralité des attributs des entrées est renvoyée par le serveur, ce qui peut donner un nombre de données très important.

Le paramètre attrsonly permet de demander à l'annuaire de retourner uniquement les types d'attributs et non leurs valeurs lorsqu'il vaut 1. Par défaut (ou lorsque ce paramètre vaut 0) les types des attributs ainsi que leurs valeurs sont retournés par le serveur.

Le sixième paramètre sizelimit comme son nom l'indique permet de limiter le nombre maximum de résultat retourné par l'annuaire afin de réduire le volume des données retournées. Il faut noter que si le serveur est configuré pour retourner moins de résultats, une valeur supérieure de l'attribut ne permettra pas de dépasser la valeur inscrite dans la configuration du serveur. La valeur 0 indique qu'aucune limite autre que celle imposée par le serveur n'est définie.

Le septième paramètre timelimit permet de limiter le temps maximal de la recherche pris par le serveur. Il faut noter que si le serveur est configuré pour retourner moins de résultats, une valeur supérieure de l'attribut ne permettra pas de dépasser la valeur inscrite dans la configuration du serveur. La valeur 0 indique qu'aucune limite autre que celle imposée par le serveur n'est définie.

Enfin le huitième paramètre deref permet d'indiquer selon sa valeur la façon de procéder avec les alias lors de la recherche. Les valeurs possibles de ce paramètre sont les suivantes :

  • LDAP_DEREF_NEVER : les alias ne sont jamais déréférencés. Il s'agit de la valeur par défaut.
  • LDAP_DEREF_SEARCHING : les alias sont déréférencés uniquement pendant la recherche et non pendant leur localisation.
  • LDAP_DEREF_FINDING : les alias sont déréférencés uniquement pendant leur localisation et non lors de la recherche.
  • LDAP_DEREF_ALWAYS : les alias sont toujours déréférencés.


L'exemple suivant permet de connaître le nombre de résultats retournés pour une recherche d'une personne dont le nom ou le prenom commence par la chaîne $person passée en paramètre :

<?php
$ds=ldap_connect($server); // On suppose que le serveur LDAP est sur cet hote
if ($ds) {
$r=ldap_bind($ds,$rootdn,$rootpw);

$dn = "o=commentcamarche, c=fr";

$filtre="(|(sn=$person*)(cn=$person*))";

$restriction = array( "cn", "sn", "mail");

$sr=ldap_search($ds, $dn, $filtre, $restriction);

$info = ldap_get_entries($ds, $sr);

print $info["count"]." enregistrements trouves

";

ldap_close($ds);

} else {
echo "Connexion au serveur LDAP impossible";

}

?>





Toutefois, une fois l'opération de recherche effectuée, il s'agit d'exploiter les résultats obtenus. Ainsi, la majeure partie des fonctions LDAP ont pour but le traitement des résultats de la recherche.

Dans l'exemple ci-dessus, la fonction ldap_get_entries() permet de récupérer des informations sur les entrées retournées par la fonction ldap_search().

Traitement des résultats

De nombreuses fonctions LDAP permettent d'exploiter les résultats renvoyés
par la fonction ldap_search(). Ces fonctions ont un nom commençant généralement par

ldap_get_ suivi du nom de l'élément à récupérer :

  • ldap_get_dn() permet de récupérer le DN de l'entrée
  • ldap_get_entries() permet de récupérer l'ensemble des entrées
  • ldap_get_option() permet de récupérer la valeur d'une option
  • ldap_get_values() permet de récupérer toutes les valeurs d'une entrée
  • ldap_get_values_len() permet de récupérer les valeurs binaires d'une entrée
  • ldap_count_entries() permet de récupérer le nombre d'entrées retournées par la fonction de recherche

Récupérer le nombre d'entrées retournées

La fonction ldap_count_entries() permet de connaître le nombre d'entrées retournées par la fonction ldap_search(). Sa syntaxe est la suivante :

int ldap_count_entries (int link_identifier, int result_identifier)


La fonction ldap_count_entries() admet en paramètre l'identifiant du serveur LDAP retourné par la fonction ldap_connect() ainsi que l'identifiant du résultat retourné par la fonction ldap_search() et retourne un entier représentant le nombre d'entrées stockées dans le résultat de la recherche.

Voici un exemple d'utilisation :

<?php
$ds=ldap_connect($server); // On suppose que le serveur LDAP est sur cet hote
if ($ds) {
$r=ldap_bind($ds,$rootdn,$rootpw);

$dn = "o=commentcamarche, c=fr";

$filtre="(|(sn=$person*)(cn=$person*))";

$restriction = array( "cn", "sn", "mail");

$sr=ldap_search($ds, $dn, $filtre, $restriction);

$nombre = ldap_count_entries($ds, $sr);

print $nombre." enregistrements trouves

";

ldap_close($ds);

} else {
echo "Connexion au serveur LDAP impossible";

}

?>


Récupérer les entrées retournées

La fonction ldap_get_entries() permet de récupérer l'ensemble des entrées retournées par la fonction ldap_search() ainsi que de lire les attributs associés et leur(s) valeur(s).

Sa syntaxe est la suivante :

array ldap_get_entries (int link_identifier, int result_identifier)


La fonction ldap_get_entries() admet en paramètre l'identifiant du serveur LDAP retourné par la fonction

ldap_connect() ainsi que l'identifiant du résultat retourné par la fonction ldap_search() et retourne un tableau multidimensionnel contenant le résultat de la recherche, c'est-à-dire le DN et le nom de l'entrée ainsi que la ou les valeurs de chacune d'entre-elles.


La structure du tableau retourné (on supposera qu'il se trouve dans la variable $entrees) est la suivante :

  • $entrees["count"] : nombre d'entrées dans le résultat
  • $entrees[0] : détail de la première entrée
  • $entrees[i]["dn"] : DN de la ième entrée
  • $entrees[i]["count"] : nombre d'attributs de la ième entrée
  • $entrees[i][j] : valeur du jème attribut de la ième entrée
  • $entrees[i]["attribut"] : valeur de l'attribut nommé "attribut" de la ième entrée (pour un attribut multivalué)
  • $entrees[i]["attribut"]["count"] : Nombre de valeurs du jème attribut de la ième entrée (pour un attribut multivalué)
  • $entrees[i]["attribut"][j] : Jème valeur de l'attribut nommé "attribut" de la ième entrée (pour un attribut multivalué)


Les noms des attributs dans le tableau associatif sont en minuscules, ainsi l'attribut givenName devra être écrit givenname (par exemple $entrees[i]["givenname"])

Voici un exemple d'utilisation :

<?php
$ds=ldap_connect($server); // On suppose que le serveur LDAP est sur cet hote
if ($ds) {
$r=ldap_bind($ds,$rootdn,$rootpw);

$dn = "o=commentcamarche, c=fr";

$filtre="(|(sn=$person*)(cn=$person*))";

$restriction = array( "cn", "sn", "mail");

$sr = ldap_search($ds, $dn, $filter);

echo "Le nombre d'entrées retourné est de ".ldap_count_entries($ds,$sr)."<br>";

echo "Récupération des entrées ...";

$info = ldap_get_entries($ds, $sr);

echo "Affichage des données des ".$info["count"]. " entrées trouvées :";

for ($i=0; $i<$info["count"]; $i++)
{
echo "<p align="justify">";

echo "Le dn (Distinguished Name) est: ". $info[$i]["dn"] ."<br>";

echo "Nom (sn) : ". $info[$i]["sn"][0] . "<br>";

echo "Prénom (cn) : ". $info[$i]["cn"][0] . "<br>";

for($j=0;$j<$info[$i]["mail"]["count"];$j++) {
echo "Email numéro $j: ". $info[$i][ "mail"][$j] ."<br>";

}
}
echo "<p> ... Fermeture de la connexion";

ldap_close($ds);

} else {
echo "Connexion au serveur LDAP impossible";

}

?>





Notez que pour récupérer uniquement le nombre de résultats total, il est préférable d'utiliser la fonction ldap_count_entries() que de passer par la fonction ldap_get_entries() puis $entrees["count"]

Plus d'informations

  • Pour plus d'informations sur LDAP, reportez-vous à la section consacrée à ce sujet
  • Pour plus d'informations sur l'interfaçage d'un annuaire LDAP, reportez-vous au site de référence PHP.net
  • PhpLdapAdmin, une application en PHP permettant de gérer votre annuaire LDAP



Article écrit par Jean-François Pillou


A voir également :

Ce document intitulé «  PHP - Connexion à un annuaire LDAP  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.