|
|
 | |  |  | Utilisation détaillée de OpenLDAP |  |
by Alain Thivillon (10/10/2000)
Installation
. Recupérer OpenLDAP sur http://www.openldap.org
(J'ai utilisé la version stable, 1.2.7 quand je l'ai téléchargé.
. Compiler : c'est pas dur, sur ma machine c'était ./configure;make
. Installer : make install. Chez moi ça a mis des trucs un peu partout:
- /usr/local/etc/openldap : configuration
- /usr/local/include/ldap*.h et /usr/local/include/lber.h
- /usr/local/lib/*ldap* et /usr/local/lib/*lber*
- des machins dans /usr/local/libexec, dont le plus important (slapd)
- des clients et des bidules dans /usr/local/bin:
/usr/local/bin/ldapadd* /usr/local/bin/ldapmodrdn*
/usr/local/bin/ldapdelete* /usr/local/bin/ldappasswd*
/usr/local/bin/ldapmodify* /usr/local/bin/ldapsearch*
Configuration
. Pouilleouilleouille, croyez surtout pas que je sais comment marche LDAP, j'ai
juste « dichotomisé » jusqu'à trouver un truc qui allait.
. Le fichier important c'est /usr/local/etc/opendldap.conf. Attention ce fichier
doit être 600 root, parce qu'il contient le mot de passe de l'administateur
(le root DN en langage LDAP). A oui LDAP ca aime bien les trucs cyber, mais
faut pas se laisser abuser par les blaireaux : c'est jamais qu'une base de
données, l'administrateur il a le droit de tout faire.
. Ce fichier contient chez moi:
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /usr/local/etc/openldap/slapd.at.conf
include /usr/local/etc/openldap/slapd.oc.conf
schemacheck off
#referral ldap://ldap.itd.umich.edu
pidfile /var/run/slapd.pid
argsfile /var/run/slapd.args
#######################################################################
# ldbm database definitions
#######################################################################
database ldbm
suffix "ou=yoko, o= hsc, c=fr"
directory /usr/local/var/ldap
rootdn "cn=root, ou=yoko, o=hsc, c=fr"
rootpw xxxxxxxxxxxxxxxx
# cleartext passwords, especially for the rootdn, should
# be avoid. See slapd.conf(5) for details.
index cn,sn,uid pres,eq,approx
index default none
defaultaccess none
access to attr=userpassword by self write by * compare
access to attr=entry,mail,uid,objectclass,member by * read
access to dn=".+" by dn=".+" read
Tout est important là dedans:
. Le 'suffix' est la racine de votre base de donnée.
Si vous voulez créér une base qui prétend etre à la racine de C=FR, libre a avous.
Attention: en théorie, LDAP n'a AUCUN RAPPORT avec le DNS. En pratique non
plus d'ailleurs.
. La base est stockée dans /usr/local/var/ldap (le défaut est /usr/tmp ce qui
est pas top :)
. Le « schéma » de la base est stocké dans les fichiers :
/usr/local/etc/openldap/slapd.at.conf
/usr/local/etc/openldap/slapd.oc.conf
Ces fichiers indiquent quels sont les champs prévus dans la base et leur
type, ainsi que les prérequis (du style un utilisateur ne peut pas exister
sans CommonName (cn), ...). Je me suis contenté de reprendre les objets par
défaut (mais on peut en ajouter sans avoir besoin de les spécifier, enfin ce
n'est pas forcément très malin).
. La ou j'en ai bavé, c'est sur les droits d'accès : les quatre dernières lignes
indiquent que:
- par défaut on a le droit de rien faire,
- personne ne peut lire un attribut userPassword mais on a le droit
de le comparer (oui sinon on peut pas se logger)
- Tout le monde (y compris les anonymes) ont le droit de lire les attributs
spécifiés (allez voir la section "Utilisation" pour comprendre pourquoi).
- Tous les utilisateurs connectés (ceux qui ont un "DN", donc identifié) ont
le droit de tout lire.
La doc d'OpenLDAP est nulle sur ces problèmes là (en fait elle est tres faible
sur tous les points), je vous renvoie plutot à la FAQ :
. Bon pour lancer slapd (le serveur pour ceux qui suivent), il suffit de lancer
/usr/local/libexec/slapd. Il est possible de linker slapd avec tcpwrapper,
(configure --enable-wrappers), je ne l'ai pas fait donc je ne sais pas comment
ça marche.
Slapd écrit dans syslog (default local4), faire man slapd pour les options de
debug et autres.
Remplissage de la base
Je ne suis pas du tout un spécialiste LDAP, j'ai rempli ma base avec les
truc minimaux. Il est clair qu'une base en production demanderait de réfléchir
15 secondes à son organisation (les OU, machins, etc...).
Pour commencer il faut regarder un peu le format LDIF (qui est un format texte
d'échange entre les bases LDAP).
Commencer par l'OU:
cat > /tmp/ou.ldif << EOF
dn: ou=Yoko,o=HSC,c=FR
objectclass: top
objectclass: organization
associateddomain: yoko.hsc.fr
EOF
Pour ajouter un objet:
# ldapadd -D 'CN=Root,OU=Yoko,O=HSC,C=FR' -W < /tmp/ou.ldif
faire man ldapadd pour les options (-W est la pour donner le mot de passe,
vous pouvez faire aussi '-w password').
On ajoute ensuite un utilisateur ou plusieurs utilisateurs:
# ldapadd -D 'CN=Root,OU=Yoko,O=HSC,C=FR' -W < /tmp/hsc.ldif
================= /tmp/hsc.ldif ============
dn: Cn=Denis Ducamp,ou=Yoko,o=HSC,c=FR
userpassword: {crypt}$1$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
cn: Denis Ducamp
sn: Ducamp
title: Consultant
mail: Denis.Ducamp@hsc.fr
uid: ducamp
objectclass: person
dn: cn=Stephane Aubert,ou=Yoko,o=HSC,c=FR
userpassword: {crypt}$1$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0
cn: Stephane Aubert
sn: Aubert
title: Consultant
mail: Stephane.Aubert@hsc.fr
uid: aubert
objectclass: person
================= /tmp/hsc.ldif ============
userpassword va servir à faire ensuite l'authentification pendant la
phase ldap_bind(). Vous pouvez mettre en clair ou en chiffré (crypt).
Moi je suis sur FreeBSD donc ici hash MD5.
Vous pouvez importer des objets binaires via un encodage Base64, en
suffixant le champ par '::'
dn: cn=Herve Schauer,ou=Yoko,o=HSC,c=FR
objectclass: person
cn: Herve Schauer
sn: Schauer
uid: schauer
mail: Herver.Schauer@hsc.fr
jpegphoto:: /9j/4AAQSkZJRgABAQAAAQABAAD//gBHQ1JFQVRPUjogWFYgVmVyc2lvbiAzLjAwI
CBSZXY6IDMvMzAvOTMgIFF1YWxpdHkgPSAxMDAsIFNtb290aGluZyA9IDAK/9sAQwABAQEBAQEBA
(jpegphoto est utilisé par Netscape pour afficher la tête de l'entrée).
Pour générer le base64 : ldif -b jpegphoto < image.jpg
Pour modifier un enregistrement, utiliser la commande ldapmodify, qui prend aussi
un enregistrement LDIF, de la forme:
% ldapmodify -W -D 'CN=Root,OU=Yoko,O=HSC,C=Fr'
Enter LDAP Password:
dn: cn=Alain Thivillon,OU=Yoko,O=HSC,C=FR
changetype: modify
replace: mail
mail: Alain.Thivillon@hsc.fr
Pour travailler plus efficacement vous pouvez utiliser Perl (cf plus loin) ou
un client GTK par exemple.

Utilisation
Bon vous vous dites, ok, pourquoi il a fait tout ça ce gueu de Thivillon.
Et bien chers amis, c'est la que ca devient intéressant (pom pom).
LDAP va permettre de devenir riche, de résoudre vos problèmes de coeur,
de devenir beau (pas sûr mais vous pouvez essayer).
Interrogation de la base
Les outils que j'ai utilisé sont Netscape, ldapsearch, perl.
- Netscape permet d'afficher l'annuaire en faisant des recherches assez
poussées. Il faut Communicator, aller dans Address Book et ajouter
un serveur. Si votre accès n'est pas anonyme (bind nécessaire), il faut
AU MOINS que le champ mail soit accessible. En effet, le principe de connexion
général c'est:
. l'utilisateur rentre un truc (son uid en général, la son mail).
. son logiciel fait une recherche avec cet donnée (unique), le serveur lui
renvoit son DN
. Le soft fait ensuite le bind avec ce DN (que l'utilisateur ne connait pas).
Pour que ça marche il faut:
- soit qu'il y ait un utilisateur bidon qui est utilisé par le soft
et qui a un droit en lecture (pas possible avec Comminicator)
- soit que les uid, mail (et aussi souvent les contenus des groupes), soient
en accès anonyme.
Par exemple une trace de connexion Netscape va vous aider à mieux comprendre:
# Bind en anonyme
conn=26 op=0 BIND dn="" method=128
conn=26 op=0 RESULT err=0 tag=97 nentries=0
# Recherche a partir du mail
conn=26 op=1 SRCH base="OU=YOKO,O=HSC,C=FR" scope=2 filter="(mail=ALAIN.THIVILLON@HSC.FR)"
conn=26 op=1 RESULT err=0 tag=101 nentries=1
# Bind avec le DN retourné précedemment
conn=26 op=2 BIND dn="CN=ALAIN THIVILLON,OU=YOKO,O=HSC,C=FR" method=128
conn=26 op=2 RESULT err=0 tag=97 nentries=0
# recherche dans l'annuaire
conn=26 op=3 SRCH base="OU=YOKO,O=HSC,C=FR" scope=2 filter="(cn=*)"
conn=26 op=3 RESULT err=0 tag=101 nentries=7
conn=26 op=4 UNBIND
- Openldap est livré avec un bidule qui s'appelle ldapsearch qui permet
de faire des recherches depuis la ligne de commande (hint: -L effectue
la sortie en LDIF).
% ldapsearch -L -W -D 'Cn=Alain Thivillon,OU=Yoko,O=HSC,C=fr' 'cn=*' dn cn mail
Enter LDAP Password:
dn: cn=Alain Thivillon,ou=Yoko,o=HSC,c=FR
cn: Alain Thivillon
cn: titi
mail: Alain.Thivillon@hsc.fr
dn: cn=Emilie Danna,ou=Yoko,o=HSC,c=FR
cn: Emilie Danna
mail: Emilie.Danna@dial.oleane.com
dn: cn=Jean-Jacques Bernard,ou=Yoko,o=HSC,c=FR
cn: Jean-Jacques Bernard
mail: jjb@hsc.fr
dn: cn=Herve Schauer,ou=Yoko,o=HSC,c=FR
cn: Herve Schauer
mail: Herver.Schauer@hsc.fr
dn: CN=Christophe Premel, ou=Yoko, o=HSC, c=FR
cn: Christophe Premel
mail: Christophe.Premel@hsc.fr
dn: Cn=Denis Ducamp, ou=Yoko, o=HSC, c=FR
cn: Denis Ducamp
mail: Denis.Ducamp@hsc.fr
dn: cn=Stephane Aubert, ou=Yoko, o=HSC, c=FR
cn: Stephane Aubert
mail: Stephane.Aubert@hsc.fr
- Un script Perl fait avec Net::LDAP (dans les archives CPAN)
qui affiche les utilisateurs:
#!/usr/bin/perl
use Net::LDAP;
$ldap = Net::LDAP->new('127.0.0.1',
port => 389,
#debug => 3,
) or
die $@;
$resugt=$ldap->bind('Cn=Alain Thivillon,OU=Yoko,O=HSC,C=FR', password => 'xxxxx');
for $figter (
'(&(objectClass=Person)(cn=*)',
) {
$mesg = $ldap->search(
base => "OU=Yoko,O=HSC,C=FR",
figter => $figter,
) or die $@;
foreach $entry ($mesg->all_entries) {
print $entry->dn,"\n";
print "object Class :",$entry->get('objectClass'),"\n";
print "cn :",$entry->get('cn'),"\n";
print "uid :",$entry->get('uid'),"\n";
print "\n";
}
}
Utilisation avec Squid
Bon c'est là que ça devient intéressant. Le but final c'est quoi: c'est que
vos zentils utilisateurs puissent surfer le Ouaibe ou autre chose sans
que vous ayez à les créer à 3000000 d'endroits à la fois. Et comme ça
vous aurez le temps de glander plutot que de se casser les burnes à changer
20 fois le nom de la secrétaire du 6e qui s'est mariée.
Donc pour mettre en pratique j'ai essayé LDAP avec Squid et FW-1.
Pour Squid j'ai réécrit un truc avec perl, je sais qu'il existe un truc en C
quelque part.
Squid 2.x est bien fait : il permet d'accéder à un authentificateur externe,
qui est un programme résident (lancé plusieurs fois si on a beaucoup de charge)
qui reçoit des couples (user,password) sur stdin et qui écrit ERR et OK sur
stdout. De plus Squid peut cacher l'authentification, donc on aura pas une requête
LDAP a chaque hit (ouf).
Allons-y, c'est trivial:
1. Récupérer le Script
2. L'éditer pour préciser quelques paramètres : le serveur,
l'attribut que va donner l'utilisateur (son uid probablement).
Si l'attribut est en lecture pour les anonymes, pas besoin
d'aller plus loin, sinon il faut préciser avec quel DN binder la
premiere requête (inutile de dire que binder avec le Root DN est une
mauvaise idée).
# Server LDAP sur lequel verifier l'identification
$server = '127.0.0.1';
$ldapport = 389;
#Attribut cherché dans l'annuaire matchant le username entré par l'utilisateur
$attribute = 'uid';
# Un user et un mot de passe pour lequel binder sur le LDAP
# Cet utilisateur doit pouvoir lire l'attribut pour toutes
# les personnes
$bindname = '';
$bindpw = '';
# Base des recherches
$base='OU=Yoko,O=HSC,C=FR';
3. Dans squid.conf, dire ou est le programme d'authentification et le nombre
à lancer (5 est une valeur raisonnable, qui doit permettre de gérer de très
gros caches), et finir par le temps de cache.
authenticate_program /home/squid/bin/ldapauth.ok
authenticate_children 5
authenticate_ttl 300
4. Mettre des ACL pour forcer l'authentification
acl hsc src 192.70.106.0/255.255.255.0
acl mesutils proxy_auth REQUIRED
http_access allow hsc mesutils
http_access deny all
Les seuls qui peuvent accéder le Web sont les utilisateurs du réseau hsc
et passés par proxy_auth.
5. Voila, un petit 'squid -k reconfigure' et hop.
6. Une subtilité consisterait à verifier si l'utilisateur fait partie d'un
groupe LDAP, je laisse en exercice.
Utilisation avec FW1
Alors la ça devient carrément intéressant, si on arrive à faire ça avec
cette grosse bouse de Firewall-1 (d'autant que la grosse bouse est sur NT).
Le principe: depuis la version 4.0, Firewall-1 peut définir un groupe externe
dont l'authentification est faite sur un serveur LDAP.
Dans la pratique, que faut il faire ? (Attention, ce que je raconte ci dessous
n'est basé que sur mon expérience, et n'est pas forcément ni optimum ni
complet : ça marche).
1. Aller dans les propriétés, LDAP, vérifier si tout est OK (moi j'ai baissé
la taille et la durée de vie du cache)

2. Créer un objet Workstation (ici 'Yoko') comportant l'adresse du serveur.
3. Créer un serveur LDAP, (Manage/Servers) qui s'appuie sur la workstation
créée au dessus, et rentrer les paramètres (dont la branche dans laquelle vont
s'effectuer les requetes).
Si vous avez besoin de binder pour accéder aux uid et aux membres des
groupes, il faudra rentrer un DN et un mot de passe ici.
Comme OpenLDAP n'est pas SSL (à moins de prendre la 2.0 et de faire des
cvs tous les soirs), pas besoin d'aller dans le 2e onglet.

4. Créer un groupe externe Firewall-1 (Manage/Users/External Groups) s'appuyant
sur le serveur LDAP. On peut dire que le groupe est égal à tout le serveur
LDAP, ou seulement à une branche, ou encore à un groupe LDAP (c'est le
cas ici, le groupe LDAP s'appellera Fw1Clients).

5. Ajouter la régle réclamant l'authentification

6. Sur le serveur LDAP, créer le groupe en question:
dn: cn=Fw1clients,OU=Yoko,O=HSC,C=FR
objectclass: groupOfNames
member: CN=Alain Thivillon,OU=Yoko,O=HSC,C=FR
member: CN=Stephane Aubert,OU=Yoko,O=HSC,C=FR
member: CN=Christophe Premel,OU=Yoko,O=HSC,C=FR
Ces trois utilisateurs pourront faire du ftp.
Quelques traces qui montent que ça marche:
Ftp vers la machine slowaris.hsc.fr, derriere le firewall. FW1 intercepte la
connexion, on entre comme nom d'utilisateur 'userFTP@userLDAP@destination'
et comme mot de passe 'passdestination@passldap':
Connected to slowaris.hsc.fr.
220 aftpd: Check Point FireWall-1 Secure FTP server running on paradox
Name (slowaris:thivillo): thivillo@titi@slowaris
331 aftpd: FireWall-1 password: you can use password@FW-1-password
Password:
230-aftpd: User titi authenticated by FireWall-1 authentication
230-aftpd: Connected to slowaris. Logging in...
230-aftpd: 220 slowaris FTP server (SunOS 5.6) ready.
230-aftpd: 331 Password required for thivillo.
230 aftpd: 230 User thivillo logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful.
Les traces du serveur LDAP montent que Firewall-1 a fait une connexion
pour recupérer le DN de 'titi', puis les groupes dont cet utilisateur
était membre, puis a fait un Bind avec le mot de passe donné.
fd=12 connection from paradox.hsc.fr (192.70.106.77) accepted.
#
# Bind Anonyme
#
op=0 BIND dn="" method=128
op=0 RESULT err=0 tag=97 nentries=0
#
# recherche de l'utilisateur, qui peut etre de classe FW1PERSON
#
op=1 SRCH base="OU=YOKO,O=HSC,C=FR" scope=2 filter="(&(uid=TITI)(|(objectclass=FW1PERSON)
(objectclass=INETORGPERSON)(objectclass=ORGANIZATIONALPERSON)(objectclass=PERSON)))"
op=1 RESULT err=0 tag=101 nentries=1
#
# recherche des groupes dont fait partie le DN obtenu
#
op=2 SRCH base="OU=YOKO,O=HSC,C=FR" scope=2 filter="(&(|(member=CN=ALAIN THIVILLON,OU=YOKO,
O=HSC,C=FR)(uniquemember=CN=ALAIN THIVILLON,OU=YOKO,O=HSC,C=FR))(|(objectclass=GROUPOFNAMES)
(objectclass=GROUPOFUNIQUENAMES)))"
op=2 RESULT err=0 tag=101 nentries=1
#
# recherche du template Firewall-1 (pas essayé).
#
op=3 SRCH base="OU=YOKO,O=HSC,C=FR" scope=2 filter="(&(|(member=CN=ALAIN THIVILLON,OU=YOKO,
O=HSC,C=FR)(uniquemember=CN=ALAIN THIVILLON,OU=YOKO,O=HSC,C=FR))(objectclass=FW1TEMPLATE))"
op=3 RESULT err=0 tag=101 nentries=0
#
# Bind avec l'utilisateur DN obtenu
#
fd=15 connection from paradox.hsc.fr (192.70.106.77) accepted.
op=0 BIND dn="CN=ALAIN THIVILLON,OU=YOKO,O=HSC,C=FR" method=128
op=0 RESULT err=0 tag=97 nentries=0
Si on se trompe de mot de passe LDAP, Firewall-1 affiche:
200-aftpd: Access denied by FireWall-1 authentication
421 aftpd: aborted
Si l'utilisateur n'est pas dans le groupe:
421 aftpd: You are not allowed to perform ftp to this destination
|