Important: La plupart des explications qui suivent sont tirées de l'excellent cours de Ganaël LAPLANCHE.
Les caractéristiques et fonctionnalités de LDAP sont regroupées en quatre modèles :
Le modèle de nommage : définit comment l’information est stockée et organisée,
Le modèle fonctionnel : définit les services fournis par l’annuaire (recherche, ajout, etc.),
Le modèle d’information : définit le type d’informations stockées,
Le modèle de sécurité : définit les droits d’accès aux ressources.
LDAP est un protocole, ce qu’il signifie que son rôle est de présenter des informations. Un serveur LDAP agit en tant qu’intermédiaire entre une source de données et un client. Il fonctionne sur le port 389 par défaut.
Le modèle de nommage est la manière dont sont organisées les données dans l’annuaire.
Les données sont représentées sous forme d'arbre, couramment appelé Directory Information Tree (DIT). Chaque nœud, le Directory Entry Service (DES), représente une entrée. Ce format est conçu pour obtimiser la consultation des données, et non pas pour leur mise à jour.
Cette arborescence est liée au nommage de chaque élément : un élément marque son appartenance à l'élément supérieur en en reprenant le nom, qu'il complète par le sien.
Voici un exemple concret d'une représentation type (le rappel des entrées a été volontairement supprimé pour ne pas surcharger la figure) :
Une entrée peut soit être un élément d'organisation (typiquement une ou 'personnes'), soit un élément concret de cette organisation : un individu.
Voici un rappel des termes à connaître parfaitement :
Chaque élément est appelé une entrée (an entry). Une entrée peut être un branchement (un noeud, a node) ou un élément terminal (une feuille, a leaf).
Chaque élément possède un Distinguished Name (DN). Le DN est le nom complet de l’élément qui permet de le positionner dans l'arborescence. Il est unique dans l'annuaire.
e.g : "cn=ventes,ou=groups,dc=martymac,dc=com"
Chaque élément possède également un Relative Distinguished Name (RDN). Le RDN est la partie du DN de l’élément qui est relative au DN supérieur. Le RDN d'un élément ne permet pas de l'identifier de manière abolue dans l'annuaire.
e.g : "cn=ventes"
La racine est l'élément supérieur de tous les autres, c'est la base de l’arborescence. On l'appelle root en anglais, parfois on parle de "root DN".
e.g : "dc=martymac,dc=com"
Les DN de chaque entrées sont composés au moins d'un attribut de l'élément (par exemple "cn" ou "uid") et de sa valeur. Un attribut est l'une des caractéristiques de cet élément.
L'arbre (en exemple ci-dessus) se découpe ensuite en deux Organisational Units (ou) qui constituent deux branchements : "users" et "groups", dans lesquels nous trouvons ensuite les entrées feuilles de notre arbre : les utilisateurs et les groupes.
La RFC 2253 (rendue obsolète par la RFC 4514) normalise l’écriture des DN et conseille de ne pas ajouter d'espaces autour du signe "=", ni à la fin du DN. Les espaces sont autorisés par contre pour les valeurs des entrées. Il est aussi possible d'utiliser un "line-wrap" (saut de ligne) pour les DN très long mais à condition de découper après le caractère séparateur.
Exemples concrets possibles :
"CN=Kurt D. Zeilenga,OU=Engineering,L=Redwood Shores,
O=OpenLDAP Foundation,ST=California,C=US"
"cn=Ganael Laplanche,cn=ventes,ou=groups,dc=martymac,dc=com"
Il existe plusieurs types d'opération possibles applicables sur l'annuaire :
rechercher une entrée suivant certains critères,
s'authentifier,
ajouter une entrée,
supprimer une entrée,
(modifier une entrée),
renommer une entrée.
L'utilisation des ces actions nécessite certains outils.
La base est le DN à partir duquel nous allons agir. Pour une recherche, il s’agir du nœud à partir duquel est effectuée la recherche. Il peut s’agir de la racine de l’arbre pour une recherche sur la totalité de l’arbre.
e.g "dc=martymac,dc=com".
La portée (scope) définit la profondeur, le nombre de niveaux sur lesquels effectuer la recherche dans l'arbre des données. Il existe trois niveaux différents :
SUB : l'action est effectuée récursivement à partir de la base spécifiée sur la totalité de l’arborescence.
ONE : l'action est effectuée sur un seul niveau inférieur par rapport à la base spécifiée (les fils directs). Si l'on effectuait une recherche avec la portée ONE à partir de "dc=martymac,dc=com", nous pourrions trouver "ou=users,dc=martymac,dc=com" et "ou=groups,dc=martymac,dc=com".
BASE : l'action est effectuée uniquement sur la base spécifiée. Une recherche sur "dc=martymac,dc=com" avec la portée BASE renverrait cette entrée uniquement.
Un filtre va permettre d’effectuer des tests de correspondance lors d’une recherche. Il s’agit en quelques sortes du critère de la recherche.
Il existe quatre tests basiques, qui peuvent ensuite être combinés :
Le test d'égalité : X=Y
Le test d'infériorité : X<=Y
Le test de supériorité : X=>Y
Le test d’approximation : X∼=Y
Les autres opérateurs (<, >) ou des tests plus complexes peuvent être mis en place par combinaison, il faut alors utiliser les parenthèses ( ) et l'un des opérateurs suivants :
L'intersection (et) : &
L'union (ou) : |
La négation (non) : !
Ainsi, un test d'infériorité stricte donnerait : (&(X<=Y)( !(X=Y)))
Récemment est apparue une méthode concise et simplifiée pour interroger un annuaire LDAP. Il s'agit d'un format d’URL combinant toutes les notions étudiées. En une seule ligne, il est possible de spécifier tous les éléments de notre requête. Voici le format de cette URL (RFC 2255, rendue obsolète par la RFC 4516) :
ldap[s]://serveur[:port][/[base[?[attributs à afficher][?[portée][?[filtre][?extensions]]]]]]
L'exemple ci-dessous recherche tous les uid de notre arbre, à partir de la branche users :
ldap://localhost:389/ou=users,dc=martymac,dc=com?uid?sub
Un attribut est une valeur contenue dans une entrée.
Une entrée peut bien entendu contenir plusieurs attributs.
Voici un exemple de l'entrée LDAP d'un utilisateur POSIX :
dn: uid=martymac,ou=users,dc=martymac,dc=com objectClass: account objectClass: posixAccount cn: martymac uid: martymac uidNumber: 10001 gidNumber: 10001 homeDirectory: /home/martymac userPassword:: e0NSWVBUfWJjT29IUk5SbG1HbC4= loginShell: /bin/sh gecos: martymac description: martymac
Le format affiché est le format LDIF.
Ce paragraphe présente tous les attributs, un par ligne, que comprend notre entrée. Un attribut est séparé de sa valeur par " :". Suivant son type, un attribut peut avoir plusieurs valeurs : dans ce cas, il est dit "multivalué" et apparaît sur plusieurs lignes avec des valeurs différentes.
Nous pouvons observer ici des attributs nommés "dn", "objectClass", "cn", "uid", ...
L’attribut "dn" qui est indiqué en première ligne est le nom unique de notre entrée dans l'arbre dont nous avons parlé précédemment. Il constitue un attribut à part entière dans notre entrée. Il est composé du dn de l'entrée supérieure, ainsi que du rdn.
n.b: le rdn est défini par un ou plusieurs attributs de l'entrée (dans ce cas séparés par un +). Il est conseillé, pour une entrée de type posixAccount, d'utiliser les attributs uid ou cn (cf. RFC 2307). Nous avons choisi ici uid=martymac.
Sur un annuaire LDAP la racine est toujours composée des attributs "dc" (Domain Component) associés à chacune des parties du nom de domaine où est hébergé le serveur ("dc=martymac,dc=com" pour le domaine martymac.com).
Ceci est une convention. X500 préconisait les attributs "o", "l" et "c", mais LDAP a simplifié le procédé (cf. RFCs 2247, 4519, 4524).
L'attribut "ou" constitue une Organisational Unit, c’est à dire une unité organisationnelle : en quelque sorte un regroupement. Nous avons choisi d'en créer deux dans notre exemple : "users", qui accueillera nos utilisateurs et "groups", nos groupes. L'un des attributs le plus important est la classe d'objet (objectClass).
L'objectClass d’une entrée est un attribut qui permet de cataloguer cette entrée. Un objectClass définit un regroupement d'attributs obligatoires ou autorisés pour une entrée. Une entrée peut posséder un ou plusieurs objectClass. Ce sont ces objectClass qui définissent la présence de tous les autres attributs.
Ici, l’objectClass "posixAccount" rend obligatoires (MUST) les attributs cn, uid, uidNumber, gidNumber et homeDirectory. Il rend possible (MAY) l’utilisation des quatre autres attributs userPassword, loginShell, gecos et description.
Un annuaire LDAP a la capacité de charger en mémoire plusieurs schémas. À travers ces schémas, il est possible de définir de nouveaux attributs et de nouveaux objectClass. Cette souplesse permet de définir très finement ce qui sera stocké dans notre annuaire.
Concrètement, un schéma est un fichier qui décrit un à un les attributs disponibles (leur nom, leur type, etc...), ainsi que les objectClass qui y font appel. Au démarrage du serveur LDAP, le ou les fichiers de schéma spécifiés dans sa configuration seront chargés.
Dans notre exemple, l’objectClass posixAccount est défini dans le fichier nis.schema. Étudions une partie de ce fichier, livré avec OpenLDAP et situé dans /etc/ldap/schema :
#[...] attributetype ( 1.3.6.1.1.1.1.0 NAME ’uidNumber’ DESC ’An integer uniquely identifying a user in a domain’ EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE−VALUE ) #[...] objectclass( 1.3.6.1.1.1.2.0 NAME ’posixAccount’ SUP top AUXILIARY DESC ’Abstraction of an account with POSIX attributes’ MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description))
Le premier paragraphe définit l'un des attributs utilisés par le posixAccount : uidNumber.
Le second, l’objectClass posixAccount. Il est important de savoir :
À chaque définition correspond un OID (Object IDentifier), qui permet de rendre unique l’attribut spécifié. Ces OIDs sont déposés auprès de l'IANA et sont donc officiels.
Un attribut définit un type d’égalité à mettre en oeuvre lors d’une recherche (ici, intergerMatch) ainsi que le type de données qu’il contient (l’OID spécifié après SYNTAX).
Un objectClass définit les attributs que l’objet doit présenter (MUST) et ceux qu'il peut posséder (MAY).
Il est tout à fait possible de créer ses propres schémas mais il est préférable de réutiliser ceux déjà existant.
Les données contenues dans l’annuaire sont présentées dans un certain format : il s’agit du format LDIF (LDAP Data Interchange Format - RFC 2849).
Dans ce format, chaque entrée constitue un paragraphe, et, au sein de chaque paragraphe, chaque ligne constitue un attribut. Voici un exemple un peu plus complet, incluant le groupe de notre utilisateur :
#[...] dn: cn=utilisateurs,ou=groups,dc=martymac,dc=com objectClass: posixGroup cn: utilisateurs gidNumber: 10001 dn: uid=martymac,ou=users,dc=martymac,dc=com objectClass: account objectClass: posixAccount cn: martymac uid: martymac uidNumber: 10001 gidNumber: 10001 homeDirectory: /home/martymac userPassword:: e0NSWVBUfWJjT29IUk5SbG1HbC4= loginShell: /bin/sh gecos: martymac description: martymac #[...]
LDAP fournit plusieurs modèles de sécurité applicable.
L’une des opérations préalables à l’interrogation de l’annuaire est cette opération dite de "binding" (dans le cas d’une authentification simple). Le client envoie alors le DN d’un compte contenu dans l’annuaire lui-même, ainsi que le mot de passe associé. On pourra par la suite appliquer des droits particuliers sur ce compte en utilisant les ACLs.
Ceci correspond, si l’on fait le parallèle avec l’annuaire téléphonique, à la fonctionnalité de liste rouge, où certaines données ne sont pas accessibles à tout le monde.
Notez enfin qu’il est possible de se connecter de manière anonyme : le client envoie alors un DN vide au serveur LDAP.
Les ACLs (Access Control Lists) interviennent après la notion de binding. Il sera possible de donner des droits de lecture, d’écriture (ou d’autres droits divers) sur des branches particulières de l’annuaire au compte connecté.
Ceci permet de gérer finement les droits d’accès aux données. Nous verrons plus tard des exemples concrets d’ACLs.
Le chiffrement des communications, via SSL (Secure Socket Layer, ou TLS - Transport Layer Security) est également une méthode de protection de l’information. Il est possible, avec la plupart des annuaires existants, de chiffrer le canal de communication entre l’application cliente et l’annuaire. Ceci permet de garantir (un minimum) la confidentialité des données et d’éviter qu’un tiers n’écoute les communications sur le réseau.
SASL (Simple Authentication and Security Layer) est un mécanisme qui permet d’ajouter des méthodes d’authentification à des protocoles orientés connexion tels que LDAP ou IMAP. Il est défini dans la RFC 2222 ; l’implémentation la plus couramment utilisée est Cyrus-Sasl.
SASL donne la possibilité au client et au serveur de sélectionner quelle sera la méthode d’authentification utilisée. Ces méthodes sont extensibles via des plugins. Il permet également de mettre en place une couche de connexion sécurisée telle que SSL/TLS (sans rapport direct avec le chiffrement indépendant des connexions que nous avons cité ci-dessus).
Certains serveurs LDAP, dont OpenLDAP, permettent de manière native, la mise en place d’un annuaire répliqué (entièrement ou partiellement). Un annuaire dit "maître" envoie alors, par le biais du format LDIF, toutes les modifications effectuées sur un annuaire "esclave".
L'avantage d'utiliser cette technique est double :
permettre une meilleure montée en charge pour de gros annuaires : il est possible de rediriger le client vers l’un ou l’autre des annuaires répliqués,
disposer d’une copie conforme du premier annuaire, utile en cas de crash (attention, toute opération est reportée de l’annuaire maître vers l’esclave, donc ceci est non valable en cas de mauvaise manipulation).
Deux types de réplication existent :
le mode "maître-esclave", le plus courant : la réplication est unidirectionnelle, un annuaire maître envoie toutes les modifications à un annuaire esclave. Ceci n’autorise bien évidemment l’écriture que sur l’annuaire maître ; l’esclave est alors disponible uniquement en lecture.
le mode "maître-maître" : la réplication est bidirectionnelle, chaque annuaire peut être maître de l’autre. Ceci permet d’écrire indifféremment sur l’un ou l’autre des annuaires.
Sachez enfin qu’il est possible de chaîner les réplications pour obtenir plusieurs réplicats.
La distribution est un mécanisme qui va permettre de faire pointer un lien vers un autre annuaire pour une branche particulière. Ceci va permettre de déléguer la gestion de cette branche, un peu au sens DNS lorsqu’on délègue la gestion d’un domaine.
Ce mécanisme peut être représenté de la manière suivante, si l’on reprend l’exemple de notre domaine martymac.com :
Ici, l’annuaire 1 possède un referral pour la branche ou=groups. ce referral pointe vers l’annuaire 2. La gestion de cette branche est donc en quelques sortes "déléguée" à l’annuaire 2.
dn: ou=groups,dc=martymac,dc=com objectClass: referral ref: ldap://ldap2.martymac.com/ou=groups,dc=martymac,dc=com
n.b : Il existe également les "alias" qui sont des liens symboliques au sein du même annuaire. Cf. l’objectClass "alias".
OpenLDAP est un projet libre créé en 1998 par "Net Boolean". C'est l'implémentation libre la plus utilisée des annuaires LDAP.
Pour installer OpenLDAP, il suffit de récupérer deux paquets précompilé (slapd et ldap-utils, respectivement le serveur OpenLDAP et les utilitaires LDAP) via notre gestionnaire de paquets favori :
cvanvinc@pinson ~ $ sudo apt-get install slapd ldap-utils
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances
Lecture des informations d'état... Fait
[...]
La paquet slapd fournit un ensemble de binaires permettant d'interagir avec le serveur OpenLDAP :
slapd : le démon OpenLDAP,
slurpd : le démon de réplication,
slapindex : crée les index au sein de la base,
slapcat : effectue un dump (une copie intégrale) de la base,
slapadd : ajoute des entrées LDIF dans la base,
slappasswd : utilitaire de conversion de mots de passe,
slaptest : teste la validité du fichier de configuration slapd.conf,
slapdn : teste la conformité d'un DN donné en ligne de commande.
La paquet ldap-utils fournit également un ensemble de binaires utilisant le protocole LDAP :
ldapsearch : effectue une recherche au sein de l'annuaire,
ldapadd : ajoute une entrée,
ldapdelete : supprime une entrée,
ldapmodify : modifie une entrée (ajoute/supprime un attribut, ajoute/supprime une entrée, etc.),
ldapmodrdn : modifie le RDN d'une entrée (renomme une entrée),
ldappasswd : modifie le mot de passe d'une entrée LDAP,
ldapwhoami : affiche avec quel utilisateur le binding a eu lieu,
ldapcompare : permet de comparer l'attribut d’une entrée à une valeur spécifiée.
Le fichier de configuration de du serveur OpenLDAP (slapd) se situe dans le répertoire /etc/ldap.
Voici un exemple de configuration (/etc/ldap/slapd.conf) :
####################################################################### # Directives globales # Inclusion des schémas include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema # Où sera stocké le PID du demon pidfile /var/run/slapd/slapd.pid # Liste des arguments passés au démarrage du serveur argsfile /var/run/slapd.args # Niveau de log loglevel 0 # Emplacement des modules # Chargement du module BDB (Berkeley DB) modulepath /usr/lib/ldap moduleload back_bdb ##################################################################### # Déclaration des options pour le premier type de backend utilisé # Toutes les options s'y appliquent jusqu'à la prochaine directive # backend. #backend bdb ##################################################################### #backend <autre> ##################################################################### # Déclaration des options de la première "base", c'est à dire de la # première (et unique ici ) arborescence gerée par notre annuaire # Toutes les options s'y appliquent jusqu'à la prochaine directive # database. database bdb checkpoint 512 30 # La racine de notre arborescence suffix "dc=martymac,dc=com" # Le compte administrateur de notre arborescence et son mot de passe rootdn "cn=Manager,dc=martymac,dc=com" rootpw "secret" # Ou sont stockés les fichiers BDBs de notre arborescence directory "/var/lib/ldap" # Options d'index index objectClass eq # Sauvegarde de l'heure à laquelle est modifiée une entrée lastmod on # ACLs de notre première arborescence : # Une personne non authentifiée peut s'authentifier # Une personne authentifiée peut modifier son propre mot de passe # Les autres n'ont pas accès à l'attribut mot de passe access to attrs=userPassword by anonymous auth by self write by ∗ none # Tout le monde peut lire l'annuaire access to ∗ by ∗ read ####################################################################### # Autre arborescence # database <autre> # suffix "dc=debian,dc=org" #[...]
À l'intar de testparm pour Samba, OpenLDAP fournit également une commande, slaptest, qui vérifie la validité du fichier de configuration.
vanvincq@CP2L /etc/ldap $ sudo slaptest -f /etc/ldap/slapd.conf
config file testing succeeded
vanvincq@CP2L /etc/ldap $ sudo /etc/init.d/slapd restart
Stopping OpenLDAP: slapd.
Starting OpenLDAP: slapd.
Le fichier de configuration est subdivisé en trois sections importantes :
la section globale (début du fichier),
la section concernant les options de backends (débute par "backend"),
la section concernant les déclarations et les options des arborescences gérées (débute par "database").
L’inclusion des schémas est effectuée par la directive "include". Un schéma permet de définir les types de données contenus dans l'annuaire.
Par défaut, OpenLDAP fournit quelques schémas :
vanvincq@CP2L /etc/ldap $ ls /etc/ldap/schema/
collective.schema core.schema duaconf.schema inetorgperson.schema nis.ldif openldap.schema README
corba.schema cosine.ldif dyngroup.schema java.schema nis.schema pmi.schema
core.ldif cosine.schema inetorgperson.ldif misc.schema openldap.ldif ppolicy.schema
Tableau 3. Les niveaux de log disponibles.
Valeur | Fonction correspondante |
---|---|
1 | Appels de fonctions |
2 | Gestion des packets |
4 | Trace détaillée |
8 | Gestion des connexions |
16 | Affichage des packets envoyés et reçus |
32 | Gestion des filtres de recherche |
64 | Gestion du fichier de configuration |
128 | Gestion des ACLs |
256 | Affichage des connexions, opérations et résultats |
512 | Affichage des entrées retournées |
1024 | Affichage des communications avec les backends |
2048 | Parsing des entrées |
Ces niveaux sont cumulables, c’est à dire qu'un niveau 48 équivaut aux niveaux 16 et 32. Un niveau 0 équivaut à un log désactivé.
Les logs sont gérés par syslog, ce qui signifie que vous pourrez consulter les informations logguées dans le fichier /var/log/syslog.
Il existe différente sorte de Backend. Les plus couramment utilisés sont :
LDBM : ????????????
BDB (Berkekey DB) : recommandé car réputé plus robuste que LDBM.
Ces deux Backends sont des bases de données stockées dans des fichiers. Il en existe d'autres qui permettent de stocker les informations dans de véritables SGBD.
Une section de database représente la déclaration d'une arborescence. Ceci implique plusieurs paramètres, dont une racine, un compte administrateur, etc.
Les paramètres importants de cette sections sont :
La racine
Elle est spécifiée par la directive "suffix". La racine correspond souvent au FQDN (Fully Qualified Domain Name) de la machine associé aux attributs "dc".
suffix "dc=martymac,dc=com"
L'accès administrateur
Il est possible de déclarer un compte qui ne sera sujet à aucune limitation (un peu comme "root"). Ce compte peut correspondre ou non à une entrée dans l’annuaire. Il sera purement virtuel si aucun DN n'est effectivement stocké dans l’annuaire.
Ce compte particulier n’est pas soumis aux restrictions imposées par les ACLs (voir ci-dessous). Il est déclaré par la directive "rootdn". Son mot de passe est spécifié par la directive "rootpw".
n.b : attention, ne confondez pas "rootdn" et DN racine, qui correspond à la base de notre annuaire ! Ici le "rootdn" est bien le dn d’un utilisateur ayant les droits root...
Le mot de passe du rootdn peut être soit en clair soit un hash généré par la commande slappasswd. Nous pouvons générer ce hash de cette manière :
vanvincq@CP2L ~ $ sudo slappasswd -s "secret" -h {CRYPT}
{CRYPT}mpGWeJqRe8ka2
La valeur affichée est alors à copier-coller dans la valeur de la directive "rootpw" :
rootpw {CRYPT}mpGWeJqRe8ka2
Les index
Les index sont un moyen d’accélérer les recherches au sein de l’annuaire. Dans le fichier de configuration, il convient de préciser quels attributs seront le plus fréquemment utilisés pour les recherches et doivent donc être indexés. Ceci se fait par la directive "index" :
index objectClass eq
Ici, nous activons la gestion des index sur les objectClass, ce qui semble un minimum.
Chaque index est destiné à faciliter un type de recherche. Le type d'index à créer est ici "eq", ce qui signifie qu'il sera efficace pour une recherche faisant intervenir une égalité stricte de chaînes. Voici une liste des types d'index disponibles et leur type de recherche associé :
Tableau 4. Les niveaux de log disponibles.
Index | Type de recherche (filtre), exemple |
---|---|
eq | ’uid=martymac’, égalité stricte, pas d’utilisation de "wildcard" * (cf. sub) |
sub | ’uid=marty*’, utilisation d’un wildcard |
subinitial | optimisation de sub pour ’uid=marty*’, wildcard à la fin |
subfinal | optimisation de sub pour ’uid=*mac’, wildcard au début |
subany | optimisation de sub pour ’uid=*rtym*’, wilcard au début ou à la fin |
approx | ’uid =martymac’, recherche par approximation sonore |
pres | ’objectclass=posixAccount’, recherche de présence |
n.b : Le type de recherche effectué est déduit du filtre passé au client qui effectue cette recherche.
Un ou plusieurs types de recherches peuvent être spécifiés pour un ou plusieurs attributs à la fois. Dans ce cas, la virgule sépare les différents éléments. Exemple :
index uid,gecos,description eq,subinitial index uidNumber,gidNumber eq
Les index doivent être générés par l'administrateur pour être fonctionnels (commande "slapindex").
Les listes d'accès (ACLs)
Les ALCs permettent de définir finement les droits d'accès à l'annuaire. La syntaxe générale des ACLs est la suivante :
access to <quoi> [ by <qui> <acces > [ <contrôle> ] ]+
Dans l'exemple précédent, il y a deux ACLs :
access to attrs=userPassword by anonymous auth by self write by ∗ none access to ∗ by * read
La première concerne l’attribut userPassword :
on autorise l’accès aux personnes non authentifiées uniquement pour une authentification (by anonymous auth),
on autorise une personne authentifiée à modifier son propre mot de passe (by self write),
enfin, on refuse l’accès à cet attribut aux autres personnes.
La seconde ACL concerne toutes les informations contenues dans l’annuaire (*) :
on autorise tout le monde à les lire.
n.b : les ACls sont évaluées dans leur ordre d’apparition dans le fichier de configuration. OpenLDAP arrête leur évaluation lorsqu’il a trouvé une ACL faisant intervenir la cible recherchée. Les directives les plus générales doivent donc être situées après les directives s’appliquant à une cible particulière. C’est le cas ici avec l’ACL ciblant l’attribut userPassword, située avant celle ciblant toute information (*).
Pour plus de détails, il est utile de consulter la page man de "slapd.access".
Important : les commandes utilisées ici n’utilisent pas le protocole LDAP mais accèdent directement à la base de données sous-jacente (BDB dans notre cas). Il est donc impératif de toujours couper le serveur LDAP avant d’utiliser une commande slap(...), afin d’éviter un accès concurrent depuis le serveur lui-même, ce qui pourrait corrompre la base de données.
Pour arrêter le serveur :
vanvincq@CP2L ~ $ sudo /etc/init.d/slapd stop
Stopping OpenLDAP: slapd.
Le serveur est configuré pour qu’il utilise des index ; la première chose à effectuer avant de les utiliser est donc de les générer. Il faut en effet initialiser les index pour qu’OpenLDAP puisse ensuite les utiliser et les maintenir.
L’opération de génération n’est à effectuer qu’une seule fois et ceci se fait par le biais de la commande slapindex.
vanvincq@CP2L ~ $ sudo slapindex
WARNING!
Runnig as root!
There's a fair chance slapd will fail to start.
Check file permissions!
Slapcat est une commande très utile au quotidien. Elle effectue un "dump" de la base LDAP au format LDIF. Il est conseillé de l’utiliser régulièrement pour effectuer des sauvegardes d'annuaire.
Par défaut, slapcat affiche les informations sur la sortie standard, il faut donc la rediriger vers un fichier pour obtenir notre sauvegarde :
vanvincq@CP2L ~ $ sudo slapcat > sauvegarde.ldif
vanvincq@CP2L ~ $ cat sauvegarde.ldif
dn: dc=nodomain
objectClass: top
objectClass: dcObject
objectClass: organization
o: nodomain
dc: nodomain
structuralObjectClass: organization
entryUUID: 12da0472-0ee9-1031-8578-ff7c8d5f3ae5
creatorsName: cn=admin,dc=nodomain
createTimestamp: 20120330191954Z
entryCSN: 20120330191954.026871Z#000000#000#000000
modifiersName: cn=admin,dc=nodomain
modifyTimestamp: 20120330191954Z
dn: cn=admin,dc=nodomain
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9SjVnR2NwZTJNci9HaDNrYkVXdFF3aWJMblJLYXprVDc=
structuralObjectClass: organizationalRole
entryUUID: 12da6c78-0ee9-1031-8579-ff7c8d5f3ae5
creatorsName: cn=admin,dc=nodomain
createTimestamp: 20120330191954Z
entryCSN: 20120330191954.029543Z#000000#000#000000
modifiersName: cn=admin,dc=nodomain
modifyTimestamp: 20120330191954Z
Slapadd est l’inverse de slapcat. Cette commande permet de peupler notre annuaire en utilisant un fichier LDIF. Elle est typiquement utilisée pour restaurer une sauvegarde effectuée avec slapcat :
vanvincq@CP2L ~ $ sudo slapadd < sauvegarde.ldif
=> hdb_tool_entry_put: id2entry_add failed: DB_KEYEXIST: Key/data pair already exists (-30995)
=> hdb_tool_entry_put: txn_aborted! DB_KEYEXIST: Key/data pair already exists (-30995)
slapadd: could not add entry dn="dc=nodomain" (line=1): txn_aborted! DB_KEYEXIST: Key/data pair already exists (-30995)
_######## 44.12% eta none elapsed none spd 4.6 k/s
Closing DB...
L’arrêt et le démarrage du serveur LDAP se font par le biais du script /etc/init.d/slapd :
vanvincq@CP2L ~ $ sudo /etc/init.d/slapd start
Starting OpenLDAP: slapd.
À la différence des outils slap, les outils ldap utilisent le protocole LDAP, il peuvent donc être mis en oeuvre depuis n’importe quelle machine disposant d’un accès réseau au serveur LDAP. Ils utilisent le format LDIF pour échanger des informations avec le serveur.
Pour ajouter une entrée dans l’annuaire, il faut utiliser la commande ldapadd.
Synopsis simplifié :
ldapadd -W -D <binddn> -x -H ldap://<serveur> -f <fichier.ldif>
L’option "-W" active la demande de mot de passe pour s’authentifier en tant que <binddn>. L’option "-x" permet de ne pas utiliser SASL pour l’authentification. Enfin, le fichier LDIF source doit contenir une (ou plusieurs) entrée(s) à insérer et l’intégralité de ses (leurs) attributs.
Exemple de fichier LDIF à insérer :
dn: uid=dupont , ou=users , dc=martymac , dc=com objectClass: account objectClass: posixAccount cn: dupont uid: dupont uidNumber: 10001 gidNumber: 1024 homeDirectory: /home/dupont userPassword:: e0NSWVBUfXZKblR0TjVSaXQ0Tmc= loginShell: /bin/sh gecos: dupont description: dupont
Insertion de l'entrée
vanvincq@CP2L ~/Bureau $ ldapadd -W -D "cn=Manager,dc=martymac,dc=com" -x -H ldap://localhost -f fichier.ldif
Enter LDAP Password:
ldap_bind: Invalid credentials (49)
L'entrée est insérée depuis le serveur même (localhost) à partir du compte "Manager" déclaré dans le fichier de configuration. Cette commande ne fonctionnera pas si vous n’avez pas initialisé l’annuaire avec les entrées de base qui ont été vues auparavant : ou=users et dc=martymac,dc=com. Voyons comment créer ces entrées basiques.
L’initialisation de l’annuaire n’est qu’un ajout massif de plusieurs entrées. Cet ajout massif peut se faire par le biais de slapadd si on posséde déjà un dump de l’annuaire et si on se situe sur le serveur. À distance, il faut se servir de la commande ldapadd. Il suffit de lui fournir un fichier LDIF contenant plusieurs entrées qui seront ajoutées dans le même ordre avec lequel elles apparaissent dans le fichier.
Ce fichier va donc tout d’abord contenir l’entrée de la racine, qui est nécessaire, puis chacune des "ou" qui ont été vues en exemple. Enfin, les feuilles seront constituées d’utilisateurs et de groupes.
Fichier LDIF à insérer :
dn: dc=martymac,dc=com objectClass: dcObject objectClass: organization dc: martymac o: martymac description: martymac dn: ou=users,dc=martymac,dc=com objectClass: top objectClass: organizationalUnit ou: users dn: ou=groups , dc=martymac , dc=com objectClass: top objectClass: organizationalUnit ou: groups dn: cn=utilisateurs,ou=groups,dc=martymac,dc=com objectClass: posixGroup cn: utilisateurs gidNumber: 2000 dn: uid=garfield,ou=users,dc=martymac,dc=com objectClass: account objectClass: posixAccount cn: garfield uid: garfield uidNumber: 10001 gidNumber: 2000 homeDirectory: /home/garfield userPassword:: e0NSWVBUfWRhSDJadHI4dElnZFE= loginShell: /bin/sh gecos: garfield description: garfield dn: uid=odie,ou=users,dc=martymac,dc=com objectClass: account objectClass: posixAccount cn: odie uid: odie uidNumber: 10002 gidNumber: 2000 homeDirectory: /home/odie userPassword:: e0NSWVBUfTQzZXltaHBSUzBqQVk= loginShell: /bin/sh gecos: odie description: odie
Le fichier ci-dessus comprends :
l’entrée de la racine (indispensable)
l’entrée des deux ou : users et groups
un groupe : utilisateurs
deux utilisateurs : garfield et odie appartenant au groupe utilisateurs (attr. gidNumber)
Voici un schéma représentant cette arboresence :
Avant de pouvoir insérer cette arborescence, une réorganisation s'impose. En effet, actuellement mon fichier de configuration /etc/ldap/slapd.conf n'est pas pris en compte. Je propose que nous repartions du bon pied.
Tout d'abord, on s'assure que la configuration actuelle du fichier /etc/ldap/slapd.conf est correcte et fonctionne :
vanvincq@CP2L /etc/ldap $ sudo slaptest -f slapd.conf
config file testing succeeded
On arrête le daemon afin de pouvoir tranquillement effectuer les modifications :
vanvincq@CP2L /etc/ldap $ sudo /etc/init.d/slapd stop
Stopping OpenLDAP: slapd.
Maintenant, il faut éditer et ajouter au fichier /etc/ldap/slapd.conf les lignes suivantes :
# before the first database definition database config # NOTE: the suffix is hardcoded as cn=config and # MUST not have a suffix directive # normal rules apply - rootdn can be anything you want # but MUST be under cn=config rootdn "cn=admin,cn=config" # use any of the supported password formats e.g. {SSHA} etc # or plaintext as shown rootpw config
Au cas où, faisons une sauvegarde du précédent répertoire slapd.d puis créons le notre :
vanvincq@CP2L /etc/ldap $ sudo mv slapd.d/ slapd.d.bak
vanvincq@CP2L /etc/ldap $ sudo mkdir slapd.d
vanvincq@CP2L /etc/ldap $ sudo chown openldap:openldap slapd.d
vanvincq@CP2L /etc/ldap $ ls -l
total 24
-rw-r--r-- 1 root root 245 22 nov. 2010 ldap.conf
drwxr-xr-x 2 root root 4096 15 juin 2011 sasl2
drwxr-xr-x 2 root root 4096 5 avril 23:23 schema
-rw-r--r-- 1 root root 2525 9 avril 18:02 slapd.conf
drwxr-xr-x 2 openldap openldap 4096 9 avril 18:05 slapd.d
drwxr-xr-x 3 openldap openldap 4096 5 avril 23:23 slapd.d.bak
Maintenant, il faut convertir le fichier de configuration actuel au format de la nouvelle version de OpenLDAP, tout en prenant soin de changer également les droits :
vanvincq@CP2L /etc/ldap $ sudo slaptest -f slapd.conf -F slapd.d config file testing succeeded vanvincq@CP2L /etc/ldap $ sudo chown -R openldap:openldap slapd.d/* vanvincq@CP2L /etc/ldap $ ls -l slapd.d total 8 drwxr-x--- 3 openldap openldap 4096 9 avril 18:11 cn=config -rw------- 1 openldap openldap 927 9 avril 18:11 cn=config.ldif
Bon, rien ne marche... .... .. .. . ... Essayons un dpkg-reconfigure alors.
vanvincq@CP2L /etc/ldap $ sudo dpkg-reconfigure slapd
vanvincq@CP2L /etc/ldap $ sudo ldapsearch -x
# extended LDIF
#
# LDAPv3
# base <> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# search result
search: 2
result: 32 No such object
# numResponses: 1
Alors là, c'est le passage bizarre. Pourquoi n'ai-je rien ? En comparant un peu avec les autres journaux, je suis la même procédure mais rien n'y fait.
A REFAIRE !