Configuration générale des ACL
Le système d’ACL fourni par OpenLDAP est assez simple dans sa syntaxe, car il se résume aux questions suivantes : Qui a accès à quoi et pour quoi faire  ?
Et sa syntaxe de configuration est la suivante :
<access directive> ::= access to <what> 
[by <who> [<access>] [<control>] ]+ 
<what> ::= * | 
[dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>] 
[filter=<ldapfilter>] [attrs=<attrlist>] 
<basic-style> ::= regex | exact 
<scope-style> ::= base | one | subtree | children 
<attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> ,  
<attrlist> 
<attr> ::= <attrname> | entry | children 
<who> ::= * | [anonymous | users | self 
| dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>] 
[dnattr=<attrname>] 
[group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>] 
[peername[.<basic-style>]=<regex>] 
[sockname[.<basic-style>]=<regex>] 
[domain[.<basic-style>]=<regex>] 
[sockurl[.<basic-style>]=<regex>] 
[set=<setspec>] 
[aci=<attrname>] 
<access> ::= [self]{<level>|<priv>} 
<level> ::= none | disclose | auth | compare | search | read | write 
| manage 
<priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+ 
<control> ::= [stop | continue | break]
À première vue, la configuration d’une ACL paraît bien compliquée. Les sections suivantes tâcheront de donner une explication pour chacune de ces syntaxes.
1. Les entrées ciblées (à quoi  ?)
Le "à quoi" fait référence aux entrées (et/ou aux attributs) auxquelles les ACL vont s’appliquer et sont généralement sélectionnées de trois façons : l’annuaire entier, par DN ou par filtre.
Voici la syntaxe utilisée :
<what> ::= * | 
[dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>] 
[filter=<ldapfilter>] [attrs=<attrlist>] 
<basic-style> ::= regex | exact 
<scope-style> ::= base | one | subtree | children 
<attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist> 
<attr> ::= <attrname> | entry | children
Avec :
	•	* : permet de sélectionner toutes les entrées de l’annuaire.
	•	dn [. <Basic-style>] = <regex> : permet de sélectionner des entrées à partir du résultat d’une expression régulière utilisée sur une entrée cible. 
	•	dn. <Scope-style> = <DN> : permet de sélectionner des entrées à partir d’une entrée cible et selon une portée parmi base, one, subtree ou children.
Voyons maintenant quelques exemples de configuration au travers des entrées ci-dessous :
Numéro	Entrée (dn)	
1	dc=exemple,dc=com	
2	cn=linux,ou=binds,dc=exemple,dc=com	
3	ou=utilisateurs,dc=exemple,dc=com	
4	uid=user1,ou=utilisateurs,dc=exemple,dc=com	
5	uid=user2,ou=utilisateurs,dc=exemple,dc=com	
6	ou=manager,ou=utilisateurs,dc=exemple,dc=com	
7	cn=gtoggsint,ou=groups,dc=exemple,dc=com	
Des ACL sont ensuite appliquées à chacune des entrées :
Configuration des ACL pour les entrées ciblées	Résultat	
*	1,2,3,4,5,6 et 7	
dn.base="ou=utilisateurs,dc=exemple,dc=com"	3	
dn.one="ou=utilisateurs,dc=exemple,dc=com"	4 et 5	
dn.subtree="ou=utilisateurs,dc=exemple,dc=com"	3, 4, 5 et 6	
dn.children="ou=utilisateurs,dc=exemple,dc=com"	4, 5 et 6	
 	 	
¬
À noter la particularité des portées nommées one et children qui ne retournent pas dans leurs résultats l’entrée de base fournie dans la configuration.
Une fois les entrées sélectionnées par rapport à leurs positions dans l’annuaire, il est possible d’affiner la sélection pour chaque entrée à l’aide de filtres et/ou du nom de l’attribut (ou des attributs).
¬
À noter que l’on pourrait également effectuer notre sélection basée uniquement sur les résultats du filtre en parcourant dans ce cas la totalité de l’annuaire. 
La ligne suivante permettra par exemple de sélectionner toutes les entrées de l’annuaire possédant la classe d’objet person :
to filter=(objectClass=person)
Il est également possible d’appliquer ce filtre seulement à une partie de l’annuaire, comme dans l’exemple suivant, où la configuration sélectionnera toutes les entrées contenant la classe d’objet person depuis la branche ou=utilisateurs,dc=exemple,dc=com :
to dn.subtree="ou=utilisateurs,dc=exemple,dc=com" 
filter=(objectClass=person)
Si les entrées possédant l’attribut description sont recherchées, alors il faudrait taper la configuration suivante :
to dn.subtree="ou=utilisateurs,dc=exemple,dc=com" 
filter=(objectClass=person) attr=description
2. Les entrées accréditées (qui a accès  ?)
Le « qui » désigne les utilisateurs gratifiés de droits (ou d’aucuns) sur une ou plusieurs entrées et peut prendre les valeurs principalement utilisées suivantes :
*	Désigne n’importe quel utilisateur connecté, y compris une connexion anonyme.	
anonymous	Désigne les utilisateurs non authentifiés.	
users	Désigne les utilisateurs authentifiés.	
self	Désigne le DN de l’utilisateur actuellement connecté, en supposant qu’il ait été précédemment authentifié avec succès par une requête de "Bind".	
dn[.<basic-style>]=<regex>	Désigne le DN du ou des utilisateurs trouvé(s) par une expression régulière.	
dn.<scope-style>=<DN>	Désigne le DN de ou des utilisateurs trouvé(s) dans la portée définie.	
¬
Se rappeler que le nom de connexion utilisé pour spécifier un utilisateur pour l’authentification prend la forme d’un DN (par exemple, dn : uid=userA,ou=utilisateur,dc=entreprise,dc=com) ou un identifiant SASL (dn: uid=jerry,cn=gssapi,cn=auth). La valeur self est utilisée comme raccourci pour le DN de l’utilisateur authentifié de la session en cours. Les exemples plus loin dans ce chapitre permettront d’aider à clarifier ce concept.
3. Les droits accordés (pour faire quoi  ?)
Le « pour faire quoi » désigne la notion de niveau de permission ou, en d’autres termes, d’actions autorisées (ou pas) sur une entrée.
Le tableau ci-dessous résume les différents niveaux de permissions :
Niveau d’accès	Permission accordée	
écrire	Permet de modifier la valeur des attributs.
Par exemple, changez ce numéro de téléphone pour 12-34-56-78-90.	
lire	Permet la lecture de la valeur des attributs.
Par exemple, montrez-moi toutes les entrées avec un numéro de téléphone à 123*.	
chercher	Permet d’appliquer des filtres de recherche de la valeur des attributs.
Par exemple, y a-t-il des entrées avec un numéro de téléphone commançant par 123*?	
comparer	Permet de comparer la valeur des attributs.
Par exemple, votre numéro de téléphone est bien le 12-34-56-78-90.	
authentifier	Permet les opérations de "bind" (authentifier). Cela nécessite que le client envoie un nom d’utilisateur sous la forme d’un DN et d’un certain type d’informations.	
aucun	Pas d’accès.	
¬
À noter que les niveaux supérieurs possèdent toutes les permissions des niveaux inférieurs. Par exemple, le niveau de permission "comparer" implique la possession de la permission "authentifier", de même que le niveau de permission "écrire" implique l’accès à tous les autres niveaux de permissions : "lecture, rechercher, comparer et authentifier".
4. Évaluation des droits
Les ACL s’appliquent de manière globale ou/et par DIT (ou backend). Si des ACL sont configurées au niveau du DIT, alors ce sont celles-ci qui seront analysées en premier. Dans le cas contraire, ce seront les ACL globales qui seront appliquées.
Cependant, il faut savoir que la notion d’ACL par défaut existe. En effet, si des ACL sont configurées au niveau d’un DIT, alors la dernière ACL complétant la liste sera : access to * by * none qui signifie que si l’opération effectuée ne correspond à aucune des ACL alors elle sera rejetée, cette dernière refusant l’accès à tout le monde sur toutes les entrées et les attributs de l’annuaire.
Et si aucune ACL n’est configurée au niveau du DIT, alors ce sont les ACL globales qui seront appliquées. Dans ce cas, l’ACL par défaut est : access to * by * read qui signifie d’autoriser la lecture sur toutes les entrées et attributs par tout le monde.
Un autre point important concernant l’application des ACL : la façon dont elles seront appliquées si plusieurs d’entre elles concernent l’opération réalisée. Il faut savoir que dans ce cas l’ordre a son importance puisque c’est la première ACL concordante qui sera appliquée et les prochaines seront tout simplement écartées.
Cela se traduit donc ainsi : dès que le serveur OpenLDAP au travers de son processus "slapd" reçoit une opération à traiter, il va tout d’abord se focaliser sur l’entrée cible "what" pour y déterminer le DIT à utiliser. S’il trouve des ACL pour cet annuaire, il commencera par analyser la toute première règle à la recherche d’une correspondance avec la requête reçue. Si l’opération est concernée par l’ACL, le serveur OpenLDAP ne poursuivra pas avec les suivantes, mais continuera son analyse en regardant cette fois-ci le champ "who". Là encore, si l’ACL possède plusieurs valeurs (cas plus rare), l’analyse du serveur OpenLDAP procédera aussi de la même façon en sélectionnant la première règle qui correspondra. Enfin, si les permissions demandées par l’opération sont inférieures ou égales aux autorisations accordées par l’ACL, alors elle sera acceptée, sinon, elle sera refusée.
¬
Ainsi, en termes de stratégie de sécurité, cela signifie que les ACL les plus restrictives devront être listées en premier et les moins restrictives en dernier.
5. Exemples de configuration d’ACL
Dans cette section seront abordés de nombreux exemples qui permettront de comprendre plus facilement les différentes syntaxes vues précédemment.
L’ACL suivante autorise un accès en lecture à tous les utilisateurs de liaison à la totalité de l’annuaire (c’est-à-dire tous les attributs) :
access to * by * read
L’exemple suivant autorise l’accès à l’attribut userPassword à tous les utilisateurs de l’annuaire, mais seulement à des fins d’authentification. Les utilisateurs ne peuvent donc pas comparer, chercher, lire ou modifier cet attribut.
access to attrs=userPassword 
     by * auth
En revanche, l’ACL ci-dessous permet à un utilisateur (une fois authentifié) de modifier son propre mot de passe dans l’annuaire OpenLDAP (avec l’utilisation de la valeur self) et autorise toute personne à utiliser des mots de passe à des fins d’authentification.
access to attrs=userPassword 
     by self write 
     by * auth
L’exemple suivant va permettre de montrer l’importance de définir les ACL dans le bon ordre, sans quoi l’effet peut produire le contraire de celui souhaité.
En effet, avec les directives ci-dessous, les opérations de recherche à partir de la sous-branche ou=utilisateur,dc=exemple,dc=com sont autorisés à tous les utilisateurs de l’annuaire, alors que depuis les sous-branches de l’entrée dc=exemple,dc=com, ces mêmes utilisateurs ne disposeront que du droit de "lecture" seulement :
access to dn.children="ou=utilisateur,dc=exemple,dc=com" 
by * search 
 
access to dn.children="dc=exemple,dc=com" 
by * read
En revanche, si les directives sont disposées comme ci-dessous :
access to dn.children="dc=exemple,dc=com" 
by * read 
 
access to dn.children="ou=utilisateur,dc=exemple,dc=com" 
by * search
alors, tous les utilisateurs de l’annuaire ne possèderont que l’autorisation de "lecture" depuis les sous-branches de l’entrée dc=exemple,dc=com, sans possibilité d’effectuer des recherches à partir des sous-branches de l’entrée ou=utilisateur,dc=exemple,dc=com. Ce comportement met ainsi en lumière le fonctionnement de l’application des ACL respectueux de l’ordre défini pour chacune de ces règles.
Voici un prochain exemple permettant de mettre en lumière la règle implicite "access to * by * none" ou "by * none" qui fait suite à la définition d’une ACL.
Ainsi, en remplaçant le caractère par le terme users dans la directive précédente, cela implique que tous les autres utilisateurs (donc les anonymes) n’auront aucun droit sur toutes les sous-branches de ou=utilisateur,dc=exemple,dc=com par l’application implicite de "by * none" :
access to dn.children="ou=utilisateur,dc=exemple,dc=com" 
by users read [by * none ]
De même, la règle ACL implicite "access to * by * none" viendra se positionner en toute fin des ACL afin de bloquer l’accès aux autres entrées de l’annuaire :
access to dn.one="ou=utilisateur,dc=exemple,dc=com" 
by users read 
[by * none ] 
[access to * by * none]
En revanche, dans le cas où aucune ACL ne serait appliquée à un annuaire (ou DIT) comme dc=exemple,dc=com, alors la directive globale par défaut "access to * by * read" serait appliquée et autoriserait donc quiconque à lire la totalité de l’annuaire.
Et pour finir, voici un exemple de configuration d’ACL afin de remplir les objectifs ci-dessous :
	•	Les comptes d’utilisateurs administratifs sont situés sous le DN : ou=admins,ou =utilisateur,dc=exemple,dc=com
	•	Les comptes d’utilisateurs normaux sont situés sous le DN : ou=utilisateur,dc=exemple,dc=com
	•	Les utilisateurs normaux ne devraient pas pouvoir accéder aux mots de passe des autres utilisateurs.
	•	Un utilisateur doit pouvoir modifier son mot de passe.
	•	Les utilisateurs administratifs devraient pouvoir modifier le mot de passe de n’importe quel utilisateur.
La configuration sera donc la suivante et sera appliquée au niveau du DIT dc=exemple,dc=com pour les sous-entrées de ou=utilisateur,dc=exemple,dc=com.
Exemple
access to dn.children="ou=utilisateur,dc=exemple,dc=com" 
  attrs=userPassword 
  by self write 
  by dn.children="ou=admins,ou=utilisateur,dc=exemple,dc=com" write 
  by * auth