[spip-dev] Fonctionnalité LDAP avec AD : création de doublons

Bonjour,

Après une absence de plusieurs années (mais personne ne doit s'en souvenir ^^'), je suis de retour sur les listes de diffusion de SPIP :wink:

J'aimerais utiliser les fonctionnalités de liaison de SPIP avec un annuaire LDAP. Et dans mon cas, cet annuaire c'est AD...

En fouillant un peu sur le site, j'ai vu que d'autres personnes avaient essayé, et s'étaient heurtées à des problèmes, notamment des problèmes de création de doublons d'utilisateurs, le champ 'login' n'étant pas renseigné.

J'ai essayé de regarder d'où cela venait, et j'ai trouvé le problème qui se pose sur mon environnement (avec SPIP 2.0.6) : la ligne 84 du fichier ecrire\auth\ldap.php ne génère pas d'erreur même si le champ 'uid' n'existe pas dans l'AD
******************** ligne 84 ********************
// Lire les infos sur l'uid de l'utilisateur depuis LDAP
$result = @ldap_read($ldap_link, $dn, "objectClass=*", array("uid", "cn", "mail", "description"));

Sylvain Jorge do marco a écrit :

Bonjour,

Après une absence de plusieurs années (mais personne ne doit s'en souvenir ^^'), je suis de retour sur les listes de diffusion de SPIP :wink:

J'aimerais utiliser les fonctionnalités de liaison de SPIP avec un annuaire LDAP. Et dans mon cas, cet annuaire c'est AD...

En fouillant un peu sur le site, j'ai vu que d'autres personnes avaient essayé, et s'étaient heurtées à des problèmes, notamment des problèmes de création de doublons d'utilisateurs, le champ 'login' n'étant pas renseigné.

J'ai essayé de regarder d'où cela venait, et j'ai trouvé le problème qui se pose sur mon environnement (avec SPIP 2.0.6) : la ligne 84 du fichier ecrire\auth\ldap.php ne génère pas d'erreur même si le champ 'uid' n'existe pas dans l'AD
******************** ligne 84 ********************
// Lire les infos sur l'uid de l'utilisateur depuis LDAP
$result = @ldap_read($ldap_link, $dn, "objectClass=*", array("uid", "cn", "mail", "description"));
**************************************************

Du coup, on ne passe pas dans la partie qui récupère le samaccountname (et le login reste donc vide).

Pour résoudre ce problème, j'ai modifié cette ligne 84 en ajoutant la récupération du samaccountname s'il existe :
******************** ligne 84 ********************
// Lire les infos sur l'uid de l'utilisateur depuis LDAP
$result = @ldap_read($ldap_link, $dn, "objectClass=*", array("uid", "samaccountname", "cn", "mail", "description"));
**************************************************

Et dans l'initialisation de la variable $login ligne 102, j'ai ajouté un test pour utiliser le samaccountname, en remplaçant :
**************************************************
if (!$login) $login = $val[$uid][0];
**************************************************
par :
**************************************************
if (!$login) $login = $val['uid'][0];
// Si ça ne marche pas, essayer avec le samaccountname
if (!$login) $login = $val['samaccountname'][0];
**************************************************

Je suppose cependant que si le code était conçu comme ça, c'est que dans certains contextes la fonction ldap_read renvoie une erreur si un des attributs demandés n'existe pas. Je propose donc au final le code suivant (en plus de la modification de récupération des données de l'auteur ci-dessus), qui devrait résoudre le problème sans entrainer de régression :
**************************************************
// Lire les infos sur l'utilisateur depuis LDAP
$result = @ldap_read($ldap_link, $dn, 'objectClass=*', array('uid', 'samaccountname', 'cn', 'mail', 'description'));
       // Si ça ne marche pas, essayer avec l'uid uniquement
if (!$result) {
    $result = @ldap_read($ldap_link, $dn, 'objectClass=*', array('uid', 'cn', 'mail', 'description'));
}

// Si ça ne marche pas, essayer avec le samaccountname uniquement
if (!$result) {
    $result = @ldap_read($ldap_link, $dn, 'objectClass=*', array('samaccountname', 'cn', 'mail', 'description'));
}
**************************************************

Qu'en pensez-vous ?

Sylvain

ce qui serait vraiment intéressant ce serait de modifier la mise en oeuvre du LDAP qui soit vraiment un choix du webmestre et non pas la recherche aléatoire d'un champ de login via un script.
quitte a proposer des valeurs par défaut comme le fait glpi
j'avais proposé une modification en ce sens il y a quelque temps.

si on veut s'orienter vers un allégement de spip et une sortie de cette fonctionnalité du core ( tendance spip 2.1) la mise en plugin s'impose.

Merci pour vos suggestions.
http://trac.rezo.net/trac/spip/changeset/13862
devrait résoudre les problèmes.

Committo,Ergo:Sum

Bonjour,

Committo,Ergo:sum a écrit :

J'aimerais utiliser les fonctionnalités de liaison de SPIP avec un annuaire LDAP. Et dans mon cas, cet annuaire c'est AD...

En fouillant un peu sur le site, j'ai vu que d'autres personnes avaient essayé, et s'étaient heurtées à des problèmes, notamment des problèmes de création de doublons d'utilisateurs, le champ 'login' n'étant pas renseigné.

(...)

Merci pour vos suggestions.
http://trac.rezo.net/trac/spip/changeset/13862
devrait résoudre les problèmes.

Qui, du coup, résout un peu http://trac.rezo.net/trac/spip/ticket/1721 aussi. 'Un peu': spip stocke bien le login entré (i.e. respecte la casse des caractères), et créé un nouvel utilisateur le cas échéant ; on se retrouve avec des doublons sur les emails et les noms, mais plus sur les login ; je ne sais pas trop si cela va être clair du côté des utilisateurs (qui peuvent s'identifier pour d'autres services sans que la casse soit prise en compte).

Oui mais en fait ça n'a jamais été très clair ça, même hors LDAP.
Il est possible en SPIP de donner à un auteur un mail d'un autre auteur, tandis que le formulaire d'inscription refuse d'envoyer de nouveaux identifiants à un adresse mail déjà utilisée.

Committo,Ergo:Sum

En effet, ça corrige bien le problème rapporté.

Le login n'étant plus passé en minuscules, il est en effet enregistré tel quel dans la base, mais ça n'entraine pas pour autant de doublons dans mes essais (avec mes installations, les requêtes mysql sont insensibles à la casse, que ce soit sous windows ou linux).

Pour continuer à travailler en attendant une correction, j'avais mis en place mes modifs dans un plugin (mon premier !) comme suggéré par lara. J'en avais profité pour ajouter la recherche dans plusieurs OU. Est-ce que cette modification peut vous intéresser (auquel cas il faudrait aussi se pencher sur les formulaires d'install) ?

Sylvain

Committo,Ergo:sum a écrit :

Faire l'un sans l'autre me semble étrange. Mets ton plugin sur la zone qu'on puisse voir de quoi il retourne.

Committo,Ergo:Sum

Je ne suis pas sûr que ça vaille encore le coup de le mettre sur spip-zone... C'est pour l'instant un peu de la bidouille XD

Ce plugin est simplement la réécriture de auth_ldap()...
Dans la fonction auth_ldap_search(), pour permettre de rechercher dans plusieurs OU j'ai simplement supprimé "$ldap_base = $ldap['base'];" et ajouté :
if (is_array($ldap['base']))
    $ldap_bases = $ldap['base'];
else
    $ldap_bases = array($ldap['base']);

puis j'ai mis la recherche pour retrouver le DN et la tentative pour deviner le DN dans des boucles foreach ($ldap_bases as $ldap_base)

Rien de plus...

Et plutôt que me pencher sur les formulaires d'install, dans la config du ldap, j'ai fait de "$GLOBALS['ldap_base']" un tableau avec la liste de mes OU...

On pourrait même sans trop changer l'install mettre une chaîne avec un caractère séparateur à définir dans $GLOBALS['ldap_base'], puis utiliser un simple explode pour retrouver les différentes OU dans auth_ldap_search()...

Si tu penses tout de même que publier ce "plugin" a un intérêt, je le ferai sans problème :wink:

J'avais également une autre modification en tête qui ne demanderait qu'à modifier l'install et le fichier config : la possibilité de définir plusieurs serveurs LDAP (dans mon cas, j'ai 3 serveurs AD : le serveur principal, un serveur de secours et un serveur distant. Les 3 sont bien sûr synchronisés...).

Sylvain

Emmanuel Saint-James a écrit :

Ah je vois, c'est une bonne idée. Vu les caractères spéciaux de LDAP et l'autorisation d'espace, je propose le | comme séparateur de DN (plus exactement la Regexp "\s*|\s*" pour améliorer la lisibilité).
ok ?

Committo,Ergo:Sum

Moi, ça me convient...

Sylvain

Committo,Ergo:sum a écrit :