IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Annuaires LDAP avec OpenLDAP

Annuaires LDAP avec OpenLDAP


précédentsommairesuivant

VI. Fonctionnement des permissions dans OpenLDAP

Dans ce chapitre nous nous attarderons sur le fonctionnement des permissions qui permettent de contrôler l'accès aux données des serveurs de la suite logicielle Openldap.

VI-A. Description de la syntaxe

VI-A-1. Description générale

Les permissions d'accès sont fournies au serveur slapd sous la forme d'une liste de clauses. La syntaxe de ces clauses est la suivante :

 
Sélectionnez
<clause d'accès> ::= access to <objet> [ by <sujet> <action> <contrôle> ]+

La définition de chacun de ces quatre composants est la suivante :

objet L'objet, ou bien la cible, désigne une entrée, un ensemble d'entrée ou un attribut de l'annuaire
sujet Décrit la ou les personnes à qui la clauses d'accès donne les droits. Il s'agit d'un ensemble de DNs
action Désigne le type d'accès est concédé: lecture, écriture, etc.
contrôle Indique le comportement du serveur après l'accès à la clause

Les informations les plus pertinentes sur la gestion des contrôle d'accès d'Openldap se trouvent dans la page manuel de slapd.access, et dans la FAQ d'Openldap.

VI-A-2. Description de la cible

VI-A-2-a. Syntaxe

La syntaxe de la cible est la suivante :

 
Sélectionnez
<objet> ::= * | [dn[.<dnstyle>]=<dnspec>] [filter=<ldapfilter>] [attrs=<attrlist>]

La cible peut donc être *, ce qui désigne toutes les entrées de l'annuaire. Elle peut sinon être désignée par son DN, par un filtre ou être une liste d'attributs. Il est possible de combiner toutes ces trois dernières cibles ensemble. Cela permet par exemple de cibler tous les attributs des entrées répondant à un filtre, dans une branche, ciblée par le DN.

VI-A-2-b. Le DN

La désignation du DN peut être donnée de cinq façons différentes :

  • De façon exacte. Il s'agit du comportement par défaut à partir de la version 2.2 de slapd. Il n'y a pas de dnstyle à fournir. Avec les versions précédentes, il est obligatoire de mettre un dnstyle ayant la valeur base ou bien exact qui est synonyme.
  • Désignation d'une sous branche. Si l'on veut cibler toutes les entrées sous une entrée précise, dnstyle doit contenir la valeur subtree ou sub synonyme du précédent.
  • Désignation d'un seul niveau. Si l'on ne veut cibler que les entrées immédiatement sous une entrée précise, dnstyle doit contenir la valeur one ou onelevel synonyme du précédent à partir de la version 2.2.
  • Désignation des enfants. Si l'on ne veut cibler que les enfants d'une entrée précise, en excluant l'entrée elle même, dnstyle doit contenir alors la valeur children.
  • Désignation par expression régulière. Il est possible de cibler des entrées par une expression régulière sur leur DN. dnstyle doit contenir alors la valeur regex. Il s'agit de la valeur par défaut sous Openldap 2.1.

VI-A-2-c. Les attributs

attrlist doit contenir une liste d'attributs, séparés par des virgules. Il existe deux attributs particuliers qui peuvent être inclus: entry et children. Le premier permet de cibler l'entrée elle même, le second ses enfants uniquement. Il est possible aussi de mettre des objectclass, ce qui est équivalent à mettre tous les attributs de l'objectclass en question.

L'accès à des entrées en tant que telle est nécessaire pour des opérations de création, d'effacement ou de renommage de l'entrée, mais aussi pour l'accès en écriture. Nous détaillerons ces cas dans des études de cas pratiques ci-après.

VI-A-3. Description du sujet

VI-A-3-a. La syntaxe

La définition complète de la clause sujet est la suivante :

 
Sélectionnez
*
anonymous
users
self
 
dn[.<dnstyle>[,<modifier>]]=<pattern>
dnattr=<attrname>
group[/<objectclass>[/<attrname>]]
     [.<style>]=<pattern>
peername[.<style>]=<pattern>
sockname[.<style>]=<pattern>
domain[.<domainstyle>[,<modifier>]]=<pattern>
sockurl[.<style>]=<pattern>
set[.<style>]=<pattern>
 
ssf=<n>
transport_ssf=<n>
tls_ssf=<n>
sasl_ssf=<n>
 
aci=<attrname>

Nous allons étudier qu'une partie de cette syntaxe, la plus significative et la plus utile.

VI-A-3-b. Désignation par catégorie du sujet

Le serveur slapd distingue quatre catégories différentes (mais non disjointes) d'utilisateurs, à qui il est possible de donner accès dans une clause, via les syntaxes suivantes dédiées au sujet :

* Désigne n'importe quel utilisateur, qu'il soit identifié ou pas.
anonymous Désigne un utilisateur non identifié.
users Désigne un utilisateur identifié.
self Désigne l'objet, c'est à dire l'utilisateur dont le DN est la cible.

VI-A-3-c. Désignation directe ou indirecte du sujet

La désignation directe du sujet se fait avec la syntaxe suivante :

 
Sélectionnez
dn[.<dnstyle>[,<modifier>]]=<pattern>

pattern est le DN de l'utilisateur qui sera sujet. Il est possible d'y associer un dnstyle, exactement comme dans la désignation de la cible. Dans le cas où ce dnstyle a pour valeur regex, il est possible de faire apparaître dans le pattern des sous chaînes de substitution, de la forme $i (où i est un chiffre entre 1 et 9). Chaque chaîne $i sera remplacée par la ième sous chaîne substituée de l'expression régulière de l'objet. Depuis la version 2.2 d'Openldap il existe un nouveau dnstyle qui est expand, qui permet d'utiliser ces chaînes de substitution de la cible, sans que le reste du pattern soit considéré comme une expression régulière.

Il existe une autre façon plus dynamique encore de désigner le sujet. Il est possible en effet de désigner le DN du sujet comme étant la valeur d'un attribut de la cible. La syntaxe suivante permet cela :

 
Sélectionnez
dnattr=<attrname>

attrname contient alors l'attribut dont la valeur désigne le sujet. Un exemple classique d'utilisation de cette syntaxe est la clause qui donne accès en écriture à un objet de type groupe au propriétaire du groupe. Le propriétaire étant un attribut de l'objet groupe.

VI-A-3-d. Désignation par un groupe du sujet

Il est possible de définir des objets de type groupe dans un annuaire. Ces objets possèdent un attribut, multivalué, contenant les DN des personnes appartenant au groupe. Dans les schémas fournis avec Openldap il existe deux classes de groupe: groupOfNames et groupOfUniqueNames, dont les attributs désignant les membres sont respectivement member et uniqueMember. Il est fort utile de savoir écrire des permissions concernant les membres d'un groupe. C'est ce que nous allons étudier maintenant.

La syntaxe pour que le sujet d'une clause soit les membres d'un groupe est la suivante :

 
Sélectionnez
group[/<objectclass>[/<attrname>]] [.<style>]=<pattern>

pattern est le nom du groupe. Par défaut les groupes doivent être de classe groupofnames, mais il est possible de changer cette classe en précisant l'objectclass. De même que l'attribut par défaut contenant les DNs sera member mais il est possible de le modifier en précisant l'attrname.

Il est possible de préciser un style, qui peut être base, exact (synonyme de base) ou regex. Dans ce dernier cas, il n'est pas possible d'utiliser des expressions régulières dans le pattern mais seulement des chaînes de substitutions.

VI-A-3-e. Désignation par les connexions réseau du sujet

Jusqu'à présent la désignation du sujet s'effectue à partir du contenu de l'annuaire. Dans cette partie nous allons désigner le sujet à partir d'informations concernant son accès physique au réseau.

Les syntaxes pour désigner ainsi le sujet sont les suivantes :

 
Sélectionnez
peername[.<style>]=<pattern>
sockname[.<style>]=<pattern>
domain[.<domainstyle>[,<modifier>]]=<pattern>
sockurl[.<style>]=<pattern>

Les définitions de ces clauses sont les suivantes :

peername Désigne l'extrémité distante de la connexion entre le serveur et le client. pattern est de la forme ip-address:port
sockname Désigne l'extrémité locale de la connexion entre le serveur et le client. pattern est de la même forme que celle décrite ci-dessus
domain Désigne le nom de la machine distante d'où est lancée la requête. Ce nom est récupéré par recherche DNS inversée, à condition que cette recherche, désactivée par défaut, soit activée dans le fichier de configuration de slapd. Les clauses désignant un sujet à l'aide du domain sont déconseillées, parce qu'il est très facile de falsifier son domaine. Il est possible d'utiliser un domainstyle avec la valeur subtree pour faire accepter des surdomaines
sockurl Désigne l'url contactée

style peut être base (ou son synonyme exact) ou bien regex pour pouvoir faire des substitutions, tout comme avec les groupes.

VI-A-3-f. Désignation par les ensembles du sujet

Les ensembles est l'un des moyens les plus pratique mais des moins connus pour préciser le sujet. Ils permettent de déterminer le sujet par rapport à la valeur de ses attributs, et éventuellement par rapport aussi à la valeur des attributs de l'objet.

La syntaxe est la suivante :

 
Sélectionnez
<set> :=        <base>
             | "(" <set> ")"
             | <set> <conj> <set>
             | <set> "/" <attribute> "*"
             | <set> "/" <attribute>
<base> :=       "this"
             | "user"
             | "[" <any text> "]"
<conj> :=       "&" | "|"
<attribute>> :=  any attribute name

Cette syntaxe définit des intersections (via le symbole &) et des réunions (via le symbole |) d'ensembles. Chaque ensemble est une ou plusieurs chaînes de caractères, qui peuvent être interprétées comme des DN lorsqu'elles sont suivies d'un /, dans une syntaxe de la forme <ensemble>/ attribut .

Dans ce cas un nouvel ensemble est construit, par la réunion des valeurs des attributs, pour chaque objet désigné par son DN dans l'ensemble initial. Il est possible de récupérer récursivement les valeurs de l'attribut par l'opérateur *.

Les valeurs des ensembles sont définies soit de façon absolues, par une chaîne fournies entre crochet ([ et ]), soit relativement à l'objet, désigné par this, soit à l'utilisateur, désigné par user.

L'accès est obtenu lorsque l'ensemble n'est pas vide.

Tous les utilisateur dont une valeur de l'attribut description est python :

 
Sélectionnez
user/description & [python]

Tous les utilisateur dont une valeur de l'attribut description est identique à une valeur de l'attribution description de la cible

 
Sélectionnez
user/description & this/description

Tous les utilisateur membre d'un groupe

 
Sélectionnez
[cn=dev,dc=ee,dc=fr]/uniquemember & user

Tous les utilisateur membre d'un groupe, ce groupe pouvant lui même contenir d'autres groupes

 
Sélectionnez
[cn=dev,dc=ee,dc=fr]/uniquemember*  & user

Tous les utilisateurs qui sont membres du groupes dont la valeur est contenu dans la cible

 
Sélectionnez
this/allowedgroups/uniquemember & user

Tous les utilisateurs qui sont membres du groupes dont la valeur est contenu dans la cible, ou bien, récursivement dans un groupe de ce groupe

 
Sélectionnez
this/allowedgroups/uniquemember* & user

Ces exemples montrent qu'il est possible d'utiliser la syntaxe des ensembles pour désigner des groupes. Ils montrent aussi que cette syntaxe est beaucoup plus forte que celle des groupes, puisqu'elle permet de faire des groupes récursifs.

VI-A-4. Description de l'action

Après avoir spécifier sur quel objet portait la clauses de sécurité, puis à qui elle donnait accès, il faut ensuite préciser sur quel est type d'accès, d'action, la permission est à accorder. Il existe deux méthodes pour définir l'action. La première consiste à fournir des types d'accès par groupe, les groupes ayant une relation d'inclusion entre eux. La deuxième méthode consiste à faire des accès élémentaires.

La syntaxe pour fournir une action est la suivante :

 
Sélectionnez
<access> ::= [self]{<level>|<priv>}
<level> ::= none | auth | compare | search | read | write
<priv> ::= {=|+|-}{w|r|s|c|x}+

La syntaxe level implémente la première méthode citée. Il existe six niveaux de permissions, de l'accès nul (none), le plus bas, à l'accès en écriture (write), le plus élevé. Chaque niveau incluant les niveaux inférieurs. Le deuxième niveau, auth permettant l'authentification.

À moins d'être dans le cas d'un annuaire en lecture seule pour tout le monde, la moindre des choses dans la mise en place d'un annuaire consiste à autoriser les utilisateurs à s'identifier. Pour cela, il est obligatoire d'avoir parmi les clauses d'accès une clause similaire à la suivante.

 
Sélectionnez
access to attribute=userPassword
        by anonymous auth
        by self write
        by * none break

La deuxième méthode pour désigner l'action consiste donc à donner, ou à retirer des accès élémentaires. La syntaxe priv permet cela. Les accès élémentaires sont définis par une des lettres x, c, s r ou w, ces lettres désignant respectivement l'accès en authentification, comparaison, recherche, lecture et écriture. Pour ajouter une accès élémentaire, il faut préfixer l'accès d'un +. Pour retirer il faut préfixer l'accès de -. Pour imposer un accès fixe, et ne pas tenir compte de ce qui a déjà été accordé, il faut préfixer d'un =.

En préfixant chacune de ces deux syntaxes d'un self, l'accès ne concernera que si l'utilisateur est désigné dans la cible. Un exemple d'utilisation de cette syntaxe est l'accès selfwrite accordé sur un objet de type groupe et qui permet à un utilisateur de ne modifier que la valeur attribut contenant son DN, pour se retirer du groupe par exemple.

VI-A-5. Description des contrôles

Les contrôles précisent le comportement que doit avoir le serveur slapd après avoir atteint une clause d'accès. Le comportement par défaut est de s'arrêter d'accorder les permissions obtenues lorsque la clause a été atteinte. Ceci est équivalent à écrire stop à la fin de la clause.
Les autres possibilités pour un contrôle sont break et continue. continue indique au serveur qu'il doit continuer à chercher d'autre sujet (et action), pour le même objet. break indique qu'il doit rechercher une autre cible.
Par défaut, chaque groupe de clauses pour un objet donné se termine implicitement par * none stop. Le serveur s'arrête donc et ne donne aucun droit.

VI-B. Cas pratiques

VI-B-1. Conseils généraux

Les expressions régulières doivent être utilisées uniquement quand cela est nécessaire. Quand on veut mettre en objet un sous arbre, on préférera utiliser le dnstyle, one, sub ou children en fonction du besoin.
Par ailleurs, pour éviter toute ambiguïté, il est préférable de toujours préciser les style et dnstyle plutôt que de s'appuyer sur les valeurs par défaut. Si vous connaissez par coeur toutes les style et dnstyle implicite, ce n'est pas forcément le cas de la personne qui relira le fichier de configuration après vous.
Le composant d'expression régulière (.)* est à éviter, parce qu'il peut correspondre à beaucoup trop de chose, y compris une chaîne vide. On lui préférera le composante (.)+, qui correspond à une chaîne d'au moins un caractère. On peut aussi parfois utiliser le composant [^,]+ qui correspond à une chaîne d'un au moins un caractère et ne contenant pas de virgule, ce qui permet d'isoler un niveau dans un DN.
De même l'on pensera à encadrer les expressions régulière d'un ^ et d'un $. Le premier correspond à un début de chaîne, le second à une fin de chaîne. Cela permet d'être certain que l'expression régulière ne répond pas à une surchaîne.

VI-B-1-a. Le piège des surchaînes

L'expression régulière

 
Sélectionnez
cn=[^,]+,ou=admin,dc=ee,dc=fr

répondra positivement au DN

 
Sélectionnez
cn=niakniak,ou=admin,dc=ee,dc=fr,cn=cracker,ou=users,dc=ee,dc=fr

Pour éviter ce détournement, il faut utiliser l'expression régulière suivante :

 
Sélectionnez
^cn=[^,]+,ou=admin,dc=ee,dc=fr$

, ou encore

 
Sélectionnez
^cn=([:alnum:]+),ou=admin,dc=ee,dc=fr$

À la fin du parcours de toutes les clauses, slapd affecte une permission par défaut. Cette permission par défaut est définie dans le fichier de configuration du serveur. Or la clause qui permet de définir ces permissions par défaut est devenu dépréciée dans la version 2.1. Cela signifie qu'elle sera supprimée des prochaines versions du logiciel. Il faut donc commencer à s'en passer et remplacer son usage par une clause de permission finale.

VI-B-2. Permission pour la création d'enfants

La clause :

 
Sélectionnez
access to dn.children="ou=contacts,dc=ee,dc=fr" 
       by dn="cn=intreenet,ou=apps-accounts,dc=ee,dc=fr" write

n'autorise pas la création d'enfants sous le noeud ou=contacts,dc=ee,dc=fr. Cette clause permet l'accès en écriture aux noeuds enfants, mais pour pouvoir créer des enfants, il faut rajouter une clause permettant de modifier aussi l'entrée ou=contacts,dc=ee,dc=fr

La clause :

 
Sélectionnez
access to dn="ou=contacts,dc=ee,dc=fr" attrs=children
       by dn="cn=intreenet,ou=apps-accounts,dc=ee,dc=fr" write

donne bien l'autorisation voulue, le droit d'écriture sur l'entrée ou=contacts,dc=ee,dc=fr, pour créer des enfants sous le noeud.

Les deux clauses sont donc nécessaires.

VI-B-3. Restriction pour la création d'enfant

Nous souhaitons maintenant permettre à un utilisateur donné (en réalité à une application) de créer, modifier et supprimer, mais uniquement des utilisateurs d'un type particulier (l'objectclass est fixé). Il faut modifier notre première clause pour y ajouter le filtre :

 
Sélectionnez
access to dn.children="ou=contacts,dc=ee,dc=fr" 
       filter=(objectclass=eeintreenetobject)
       by dn="cn=intreenet,ou=apps-accounts,dc=ee,dc=fr" write 
       by users read
       by * break

précédentsommairesuivant

Copyright (c) 2005, Michaël Parienti Maire. This work is licensed under the Creative Commons Attribution-Share Alike License. Modifications, reproductions, diffusions autorisées à condition de mentionner le nom de l'auteur original et de conserver les termes de cette licence Creative Commons.