LDAP et PHP

LDAP est un annuaire (Lightweigth Directory Acces Protocol) qui permet une authentification sécurisée, (moins que Kerberos, ou autre) mais facile d’utilisation. Active Directory (que je nommerais désormais « AD ») utilise un annuaire LDAP pour permettre aux utilisateurs de se connecter sur un réseau. Et les comptes sont utilisables ensuite pour une grande variété d’utilisation (droits, connexions spéciales,etc …).

Ici je vais vous faire part de la page d’authentification que j’ai créée pour permettre aux utilisateurs de se connecter sur site intranet hebergé sur un apache sous Linux. Sur cet Apache est installé OpenLDAP, une extension permettant de se connecter à une base LDAP depuis cette machine vers une autre. Donc ma page .php utilise cette extension pour se connecter sur mon PDC et aller lire les informations de mon annuaire LDAP.

En fonction de l’unité d’organisation (ou « groupe ») auquel appartient l’utilisateur, il aura accès, ou non, à des liens de téléchargement.

Concrètement, voici les étapes à réaliser :

  1. Se connecter à une base LDAP
  2. Définir deux options LDAP obligatoire lorsque qu’on est en  relation avec un AD
  3. Se lier à un compte existant (n’importe lequel, ca sera notre compte de recherche) pour effectuer une recherche sur notre base (en fait,on peut se connecter en anonyme par défaut, mais nous n’aurons aucun droit en lecture, donc ce n’est pas conseillé)
  4. Effectuer la recherche (pour un AD, les utilisateurs se connectent avec l’attribut « samaccountname » en tant que login) pour le champ samaccountname, et on cherche à récupérer son nom complet « cn » pour pouvoir vérifier le couple login/mot de passe. Note : la fonction de connexion LDAP en php utilise le champ « cn » au lieu de « samaccountname » pour identifier les utilisateurs.
  5. Logiquement on trouve un utilisateur, on se déconnecte du compte de recherche.
  6. Puis on essaye de le connecter avec son « cn » et le mot de passe qu’il a entré dans le formulaire préalablement.
  7. Et enfin, grâce à des manipulations de chaîne on récupère l’OU (unité d’organisation en anglais = organisational unit) final duquel fait partie l’utilisateur. (exemple : l’utilisateur m.dupont fait partie du groupe informatique, et le chemin de son CN stocké est : CN=Maxime MD. Dupont, OU=INFORMATIQUE, DN=entreprise, DN=local. Je récupère juste « INFORMATIQUE », ce qui m’intéresse pour identifier le groupe de travail de l’utilisateur.
  8. Puis, on charge une liste depuis une base de donnée, de téléchargements, infos etc ce que vous voulez, en fonction de son appartenance à un groupe (OU).

Bon comme ça, le programme à l’air chargé, mais je vous ai mâché le travail, et je vais vous montrer le code que j’ai écrit pour cela :

if (isset($_POST['login']) && isset($_POST['password'])) 
{
	if(!empty($_POST['password'])) // sinon, le mode connexion anonyme est accepté
	{
		// On récupère le login et le pass
		$user=htmlspecialchars($_POST['login']);
		$passwd=htmlspecialchars($_POST['password']);
		

		//$user = str_replace('.',' ',$user);
		// Le nom de domaine facon : DC=DOMAIN,DC=LOCAL
		$ldap_base = 'dc=domain,dc=local';
		// Le nom de domaine facon : DOMAIN.LOCAL
		$ldap_server = 'domain.local';
		// Le port pour la connexion LDAP (par defaut 389)
		$ldap_port = '389';
		// Login/mdp utilisateurs par defaut à utiliser pour chercher les entrées des OU
		$user_default="cn=Robot User,ou=INFORMATIQUE ,ou=Entreprise,ou=Postes et Utilisateurs,".$ldap_base; 
		$pwd_user_default="pwd";
		
		// Création de la variable "$connexion_serveur" ou l'on indique les informations pour interroger la base
		$connexion_serveur = @ldap_connect($ldap_server, $ldap_port) or die("Impossible de se connecter au serveur LDAP");
		
		// On définit ici la version LDAP (OBLIGATOIRE!!!)
		ldap_set_option($connexion_serveur, LDAP_OPT_PROTOCOL_VERSION, 3);
		ldap_set_option($connexion_serveur, LDAP_OPT_REFERRALS, 0);	// Pour liaison avec l'AD
		error_reporting(E_ALL ^ E_NOTICE);   //Supprime des messages inutiles 

		if($connexion_user=@ldap_bind($connexion_serveur, $user_default, $pwd_user_default)) 
		//ldap_bind($connexion_serveur);	// Connexion anonyme (aucun droit en lecture, donc NON)
		{
			//echo "Test debug 1: On cherche : ".htmlspecialchars($user)."<br><br>";
			$searchFor=$user;               // On veut chercher l'utilisateur qui vient de se logger
			$searchField="samaccountname";	// Par rapport au champ "samaccountname"
			$searchName="name";
			
			$trouver_champs = array("distinguishedname","cn");
			$filtre="($searchField=$searchFor)"; //      $filtre = "ou=*"
			$sr=ldap_search($connexion_serveur, $ldap_base, $filtre, $trouver_champs);	//On cherche les champs de $trouver_champs, avec le filtrage $filtre.
			
			$info = ldap_get_entries($connexion_serveur, $sr);	// On récupère les entrées dans $info
			  
			$user_found =0;

			for($i=0; $i < $info["count"]; $i++) // On les stockes dans des variables indépendantes
			{
				$user_ou=$info[$i]["distinguishedname"][0];
				$user_cn=$info[$i]["cn"][0];
				$user_found = $i+1; // si =1, l'utilisateur à été trouvé, si =0, il n'éxiste pas dans la base LDAP
			}
			$i=0;
			// ici on va chercher recursivement de quel groupes définis fait partie l'user
			if($user_found==1)
			{
				$connexion = connexion_bdd();
				$user_group=array();
				$groups_bdd = $connexion->query("SELECT * FROM organisational_unit");
				while($row = $groups_bdd->fetch())
				{
					if(checkGroupEx($connexion_serveur, $user_ou , getDN($connexion_serveur, $row['nom'], $ldap_base)))
					{
						$user_group[$i]= $row['nom'];
						$i++;
					}	
				}
				$groups_bdd->closeCursor();
				if(empty($user_group[0])) $user_group[0]=" Aucun";
			}
			
			ldap_unbind($connexion_serveur);	// On se déconnecte
		} else {
			echo "Erreur lors de la tentative de liaison avec LDAP";
		} 
		if($user_found == 1)
		{
				// définir ici les comptes admin du site
				$liste_administrateurs=array("Administrateur", "toto");
				//Puis on se reconnecte avec cette fois le couple login/mdp saisis
				$connexion_serveur = @ldap_connect($ldap_server, $ldap_port) or die("Impossible de se connecter au serveur LDAP");	
				
				if($connexion_user=@ldap_bind($connexion_serveur, $user_ou, $passwd))	//on se lie
				{
					$_SESSION['login'] = htmlspecialchars($_POST['login']);
					$_SESSION['password'] = htmlspecialchars($_POST['password']);
					$_SESSION['admin']=0;	// on est pas admin
					$_SESSION['nom'] = $user_cn;	// nom d'user
					$_SESSION['ou_finale']= split_strings($user_ou, 1);	// l'OU dans lequel se situe l'user
					$_SESSION['user_group'] = $user_group;	// les groupes de l'user (GR_ et _USER)
					$_SESSION['download'] = 1;	//permet affichage bouton download dans menu
					
					foreach($liste_administrateurs as $c_row)
					{
						if($user_cn = $c_row)
						{
							$_SESSION['admin']=1;	//si on est admin	
						}
					}

					ldap_unbind($connexion_serveur);	// on se déconnecte
					/* on redirige sur l'index */
					echo "<script language=javascript>";
					echo "self.location.href='index.php'";
					echo "</script>";
				} else { // dans le cas ou le nom d'utilisateur est bon mais pas le mdp
					echo "<script language=javascript>";
					echo "alert('Votre login ou mot de passe est invalide !');";
					echo "self.location.href='index.php'";
					echo "</script>";
					
				}
		} else { // dans le cas ou le nom d'utilisateurs n'existe pas
			echo "<script language=javascript>";
			echo "alert('Votre login ou mot de passe est invalide !');";
			echo "self.location.href='index.php'";
			echo "</script>";		
		}
	} else { // dans le cas ou on ne rentre pas de mot de passe
		echo "<script language=javascript>";
		echo "alert('Entrez un mot de passe !');";
		echo "self.location.href='index.php'";
		echo "</script>";
	}
}

 Note : Vous pouvez afficher le code source pour une meilleure visibilité en passant la souris sur le code et en cliquant sur l’icône « View source ».

Je vais expliquer ici quelques points clés, la connexion se fait grâce à cette ligne :

$connexion_serveur = @ldap_connect($ldap_server, $ldap_port) or die("Impossible de se connecter au serveur LDAP");

Les deux options à définir pour intéragir avec un AD sont celles-ci :

ldap_set_option($connexion_serveur, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($connexion_serveur, LDAP_OPT_REFERRALS, 0);

On se lie (connecte) à un compte :

$connexion_user=@ldap_bind($connexion_serveur, $user_default, $pwd_user_default)

Avec cette ligne on va chercher dans l’annuaire LDAP des entrées :

$sr=ldap_search($connexion_serveur, $ldap_base, $filtre, $trouver_champs);

Avec :

  • $connexion_serveur, « linstance » de connexion renvoyée par le ldap_connect,
  • $ldap_base correspond à votre domaine sous cette forme : « dc=entreprise, dc=local » pour un domaine en entreprise.local,
  • $filtre contient le champ pour lequel faire la recherche, ici on recherche pour le champ « samaccountname » et pour l’utilisateur « $user« , envoyé en POST,
  • $trouver_champs est simplement la liste des champs qu’on doit récupérer pour notre/nos entrées trouvées, pour moi, les champs « cn » et « distinguishedname » m’intéressait. ( bien que cn soit récupérer par défaut, sans que on l’ajoute dans $trouver_champs)

 

 

Laisser un commentaire