This text is a work in progress—highly subject to change—and may not accurately describe any released version of the Apache™ Subversion® software. Bookmarking or otherwise referring others to this page is probably not such a smart idea. Please visit http://www.svnbook.com/ for stable versions of this book.

Contrôle d'accès basé sur les chemins

Apache et svnserve sont tous deux capables d'accorder ou de refuser l'accès aux utilisateurs. Généralement c'est géré globalement au niveau du dépôt : un utilisateur peut accéder (ou pas) au dépôt en lecture et il peut accéder (ou pas) au dépôt en écriture.

Il est pourtant aussi possible de définir des règles d'accès possédant une granularité plus fine. Un ensemble d'utilisateurs peut alors obtenir le droit d'écrire dans certains répertoires du dépôt mais pas dans d'autres ; parallèlement, un autre répertoire peut très bien ne pas être accessible en lecture pour la majorité des utilisateurs. Il est même possible de restreindre l'accès fichier par fichier.

Les deux types de serveurs utilisent un format de fichier commun pour décrire les règles d'accès basées sur les chemins. Dans cette section, nous allons expliquer ce format de fichier et comment configurer le serveur Subversion afin qu'il l'utilise pour gérer un contrôle d'accès basé sur les chemins.

Introduction au contrôle d'accès basé sur les chemins

Subversion permet le contrôle d'accès basé sur les chemins avec Apache via son module mod_authz_svn, qui doit être chargé en utilisant la directive LoadModule dans httpd.conf de la même manière que pour le chargement du module mod_dav_svn. Pour activer l'utilisation du module pour vos dépôts, vous devez ajouter les directives AuthzSVNAccessFile ou AuthzSVNReposRelativeAccessFile (toujours dans le fichier httpd.conf) en les faisant pointer vers votre propre fichier contenant les règles de contrôle d'accès (pour une explication détaillée, consultez la section intitulée « Contrôle d'accès par répertoire »).

Pour configurer le contrôle d'accès basé sur les chemins avec svnserve,faites simplement pointer la variable de configuration authz-db (qui se trouve dans le fichier svnserve.conf) vers votre fichier contenant les règles de contrôle d'accès.

Une fois que votre serveur sait où chercher les règles de contrôle d'accès, il est temps de définir ces règles.

La syntaxe du fichier est la même syntaxe que celle utilisée dans svnserve.conf et dans les fichiers de configuration. Les lignes commençant par un dièse (#) sont ignorées. Dans la forme la plus simple, chaque section désigne un dépôt et un chemin à l'intérieur de celui-ci. En d'autres termes, sauf pour quelques sections particulières, les noms de sections se présentent sous deux formes : soit nom-depot:chemin, soit [chemin] quand AuthzSVNAccessFile est utilisé. Si vous avez configuré un contrôle d'accès aux fichiers du dépôt via la directive AuthzSVNReposRelativeAccessFile, vous devriez toujours utiliser seulement la forme [path]. Les noms d'utilisateurs authentifiés sont les noms des options à l'intérieur de chaque section ; la valeur de chaque option décrit le niveau d'accès de cet utilisateur au chemin du dépôt : soit r (lecture seule), soit rw (lecture/écriture). Si l'utilisateur ne figure pas dans la section, l'accès n'est pas autorisé.

[Note] Note

Les chemins utilisés dans les sections du fichier de contrôle d'accès doivent être spécifiés en utilisant le « style interne » de Subversion, ce qui veut simplement dire qu'ils doivent être encodés en UTF-8 et utiliser comme séparateur de répertoires la barre oblique (/), même sur les systèmes Windows. Notez également que ces chemins ne doivent pas comporter de caractère « échappé » (tel qu'on les trouve par exemple dans l'encodage URI) — les espaces dans les noms de fichiers doivent être représentés telles quelles dans les noms de sections [nom-depot:chemin avec espaces]),

Voici un exemple simple pour montrer à quoi ressemble un fichier de configuration du contrôle d'accès où Sally possède des droits en lecture seule et Harry des droits en lecture/écriture pour le chemin /branches/calc/bug-142 (et tous ses enfants) dans le dépôt calc :

[calc:/branches/calc/bug-142]
harry = rw
sally = r
[Avertissement] Avertissement

Avant la version 1.7, Subversion ne distinguait pas la casse des caractères pour les noms de dépôts et de chemins dans le cadre du contrôle d'accès, il convertissait le tout en minuscules avant d'effectuer la confrontation avec le contenu du fichier de contrôle d'accès. Dorénavant, il est sensible à la casse. Si vous mettez à jour un serveur vers la version 1.7 à partir d'une version antérieure, passez en revue votre fichier de contrôle d'accès pour vérifier que la casse est correcte.

Le nom du dépôt tel qu'il est évalué par le sous-système de contrôle d'accès dérive directement du chemin du dépôt. La manière exacte dont se déroule cette évaluation diffère en fonction de la valeur de deux options. mod_dav_svn utilise seulement le nom du dépôt figurant dans l'URL de la racine du dépôt[71], alors que svnserve utilise l'ensemble du chemin relatif à partir de la racine du serveur (indiquée dans l'option --root (-r) de la ligne de commande) vers le dépôt.

[Avertissement] Avertissement

mod_dav_svn et svnserve évaluant le nom de dépôt de deux manières différentes, cela peut conduire à des problèmes lorsque les deux serveurs fonctionnent simultanément sur la machine. Naturellement, un administrateur préférerait faire pointer les deux configurations des serveurs sur le même fichier de contrôle d'accès. Cependant, afin que cela fonctionne, vous devez vous assurer que la partie du nom de dépôt qui figure dans le nom de section est compatible avec l'idée que se fait le serveur du nom de dépôt. Par exemple, en configurant la racine de svnserve pour qu'elle soit la même que la valeur de la directive SVNParentPath de mod_dav_svn, ou alors en utilisant un fichier de contrôle d'accès différent par dépôt afin que les noms de sections n'aient pas du tout besoin de faire référence au dépôt.

Si vous utilisez la directive SVNParentPath, il est important de spécifier les noms de dépôts dans vos sections. Si vous l'oubliez, à une section comme [/un/repertoire] correspondra le chemin /un/repertoire dans chaque dépôt. Cependant, si vous utilisez la directive SVNPath, il suffit d'indiquer les chemins dans vos sections (après tout, il n'y a qu'un seul dépôt).

Les droits sont hérités d'un répertoire parent dans le système de fichiers. Cela veut dire que vous pouvez spécifier un sous-répertoire avec des droits différents pour Sally. Si nous continuons avec l'exemple précédent, nous pouvons autoriser Sally à écrire vers un répertoire fils de la branche où elle ne possède que des droits de lecture :

[calc:/branches/calc/bug-142]
harry = rw
sally = r

# Sally peut écrire seulement dans le sous-répertoire "test"
[calc:/branches/calc/bogue-142/test]
sally = rw

Maintenant Sally peut écrire dans le sous-répertoire test de la branche, mais ne peut toujours que lire les autres parties. Harry, en attendant, continue à avoir les droits d'accès complets en lecture écriture sur toute la branche.

Il est aussi possible d'interdire explicitement l'accès à quelqu'un grâce aux règles d'héritage, en attribuant la valeur vide à un nom d'utilisateur :

[calc:/branches/calc/bogue-142]
harry = rw
sally = r

[calc:/branches/calc/bogue-142/secret]
harry =

Dans cet exemple, Harry a les droits de lecture/écriture sur l'arborescence bogue-142 toute entière, mais n'a absolument pas accès au répertoire secret contenu dans celle-ci.

[Astuce] Astuce

Ce qu'il faut retenir est que le chemin le plus spécifique est choisi en premier. Le serveur tente de trouver une correspondance avec le chemin lui-même, puis avec son chemin parent, puis avec le parent du parent, etc. Le résultat est que tout chemin spécifié dans le fichier des accès prendra le pas sur les droits hérités de ses répertoires parents.

De la même manière, les sections qui spécifient un nom de dépôt sont prioritaires sur celles qui n'en spécifient pas : si [calc:/un/chemin] et [/un/chemin] sont présents, le premier sera utilisé et le dernier ignoré pour calc.

Par défaut, personne n'a accès au dépôt. Cela signifie que si vous démarrez avec un fichier vide, vous voudrez probablement au moins donner les droits de lecture sur la racine du dépôt à tous les utilisateurs. Vous pouvez accomplir ceci en utilisant la variable astérisque (*), qui désigne « tous les utilisateurs » :

[/]
* = r

C'est une configuration très répandue ; notez qu'aucun nom de dépôt n'est mentionné dans le nom de la section. Ceci rend tous les dépôts accessibles en lecture à tous les utilisateurs. Une fois que tous les utilisateurs ont l'accès en lecture aux dépôts, vous pouvez accorder des droits d'écriture (rw) explicites à certains utilisateurs sur des sous-répertoires spécifiques à l'intérieur de dépôts spécifiques.

Notez que, bien que tous les exemples supra font référence à des répertoires, c'est simplement parce qu'il est plus commun de définir des droits d'accès sur des répertoires. Mais vous pouvez également restreindre les accès sur des fichiers.

 
[agenda:/projets/agenda/chef.ics]
harry = rw
sally = r

Contrôle d'accès par groupes

Le fichier des accès vous permet aussi de définir des groupes entiers d'utilisateurs, à la façon du fichier Unix /etc/group. Créez donc une section groups dans votre fichiers d'accès et décrivez vos groupes dans cette section : chaque nom de variable définit le nom d'un groupe et la valeur est une liste d'identifiants, séparés par des virgules, qui constituent les membres de ce groupe.

[groups]
developpeurs-calc = harry, sally, joe
developpeurs-paint = frank, sally, jane
tout-le-monde = harry, sally, joe, frank, sally, jane

Les droits d'accès peuvent être accordés aux groupes de la même façon qu'à de simples utilisateurs. Il faut juste les mettre en évidence par le préfixe « at » (@) :

[calc:/projets/calc]
@developpeurs-calc = rw

[paint:/projets/paint]
jane = r
@developpeurs-paint = rw

Un autre fait notable est que les droits définis pour les groupes ne sont pas écrasés par les droits individuels. En fait, c'est la combinaison de tous les droits qui s'applique. Dans l'exemple précédent, Jane est membre du groupe développeurs-paint, qui a les droits de lecture/écriture. Combiné avec la règle jane = r, cela donne toujours les droits de lecture/écriture à Jane. Les droits pour les membres d'un groupe ne peuvent être que étendus au delà des droits du groupe. Restreindre les droits d'utilisateurs qui font partie d'un groupe n'est pas possible.

Les groupes peuvent aussi contenir d'autres groupes :

[groups]
developpeurs-calc = harry, sally, joe
developpeurs-paint = frank, sally, jane
tout-le-monde = @developpeurs-calc, @developpeurs-paint

Alias

Certains systèmes d'authentification attendent et utilisent des noms d'utilisateurs relativement courts tels que ceux que nous avons décrits ici — harry, sally, joe, etc. Mais d'autres systèmes d'authentification, comme ceux qui utilisent des bases LDAP ou des certificats clients SSL, peuvent utiliser des noms d'utilisateurs beaucoup plus complexes. Par exemple, le nom d'utilisateur d'Harry dans un système protégé par LDAP pourrait très bien être : CN=Harold Hacker,OU=Engineers,DC=red-bean,DC=com. Avec des noms d'utilisateurs de ce type, le fichier des accès devient rapidement illisible, avec des noms d'utilisateurs longs ou obscurs qui peuvent facilement être mal orthographiés.

Heureusement, Subversion 1.5 a introduit les alias dans la syntaxe du fichier de contrôle d'accès. Vous n'avez ainsi à taper le nom d'utilisateur complexe entier qu'une seule fois, au sein d'un paragraphe qui lui attribue un alias bien plus digeste.

Les alias sont définis dans la section aliases du fichier de contrôle d'accès. Chaque nom de variable déclarée dans cette section définit un alias et la valeur de cette variable est l'identifiant réel Subversion qui est derrière l'alias.

[aliases]
harry = CN=Harold Hacker,OU=Engineers,DC=red-bean,DC=com
sally = CN=Sally Swatterbug,OU=Engineers,DC=red-bean,DC=com
joe = CN=Gerald I. Joseph,OU=Engineers,DC=red-bean,DC=com
…

Une fois défini votre ensemble d'alias, vous pouvez faire référence à ces utilisateurs en d'autres endroits du fichier par leurs alias, partout là où vous auriez sinon entré leur véritables noms d'utilisateurs. Il faut juste ajouter une esperluette (&) juste avant l'alias pour le distinguer des noms d'utilisateurs classiques :

[groups]
developpeurs-calc = &harry, &sally, &joe
developpeurs-paint = &frank, &sally, &jane
tout-le-monde = @developpeurs-calc, @developpeurs-paint

Vous pouvez aussi choisir d'utiliser des alias si les noms de vos utilisateurs changent souvent. Ainsi vous n'aurez que la table des alias à mettre à jour quand des modifications de noms d'utilisateurs auront lieu, au lieu d'avoir à effectuer des opérations de recherches-et-remplacements-globaux sur la totalité du fichier.

Fonctionnalités avancées de contrôle d'accès

À partir de Subversion 1.5, le fichier de contrôle d'accès reconnait aussi des mots-clés « magiques » afin de vous aider à créer des règles basées sur le statut d'authentification de l'utilisateurs. Ainsi le mot-clé $authenticated est utilisé pour désigner un utilisateur (quel qu'il soit) authentifié. Vous pouvez utiliser ce mot-clé à la place d'un identifiant, d'un alias ou d'un nom de groupe dans vos règles de contrôle d'accès. De la même manière, le mot-clé $anonymous désigne n'importe qui qui n'est pas authentifié.

[agenda:/projets/agenda]
$anonymous = r
$authenticated = rw

Un autre élément magique de la syntaxe des fichiers de contrôle d'accès est le caractère tilde (~) qui est un marqueur d'exclusion. Dans vos règles de contrôle d'accès, si vous préfixez un identifiant, un alias, un groupe ou un mot-clé d'authentification avec le caractère tilde, Subversion applique la règle aux utilisateurs qui ne vérifient pas la règle. Bien que inutilement complexe, le bloc suivant est équivalent à celui du précédent exemple :

 
[agenda:/projets/agenda]
~$authenticated = r
~$anonymous = rw

Un exemple moins simpliste pourrait ressembler à :

[groups]
developpeurs-calc = &harry, &sally, &joe
proprios-calc = &hewlett, &packard
calc = @developpeurs-calc, @proprios-calc

# tous les participants à calc ont les droits de lecture/écriture ...
[calc:/projets/calc]
@calc = rw

# ...mais seuls les propriétaires peuvent faire et modifier des étiquettes.
[calc:/projets/calc/tags]
~@proprios-calc = r

Embûches avec le contrôle d'accès

Si vous utilisez Apache en tant que serveur Subversion et que vous avez rendu certains sous-répertoires de votre dépôt inaccessibles en lecture à certains utilisateurs, vous devez être au courant d'un comportement potentiellement non-optimal de la commande svn checkout.

En fonction de la bibliothèque de communication HTTP que le client Subversion utilise, il envoie potentiellement une requête au serveur pour recevoir tout le contenu de l'extraction ou de la mise à jour dans une réponse unique (dont la taille peut être assez importante). Quand le serveur reçoit la requête, c'est la seule opportunité dont dispose Apache pour demander à l'utilisateur de s'authentifier. Ceci a des effets secondaires assez étonnants. Par exemple, si un certain sous-répertoire du dépôt n'est accessible en lecture qu'à l'utilisateur Sally et que l'utilisateur Harry extrait un répertoire parent, le client répondra à la demande d'authentification initiale en tant que Harry. Au fur et à mesure que le serveur génère la réponse, il n'a aucun moyen de renvoyer un défi d'authentification quand il atteint le sous-répertoire spécial ; ainsi le sous-répertoire tout entier est omis, plutôt que de demander à l'utilisateur de se ré-authentifier en tant que Sally le moment venu.

De même, si la racine du dépôt est accessible en lecture anonymement, l'extraction se fera entièrement sans authentification, omettant, encore une fois, le répertoire non-lisible, plutôt que d'envoyer une demande d'authentification au cours de l'opération[72].



[70] Un thème récurrent dans ce livre !

[71] N'importe quel nom de dépôt, lisible par un humain et configuré par la directive SVNReposName de httpd.conf est ignoré par le sous-système de contrôle d'accès. Vos sections du fichier de contrôle d'accès doivent faire référence aux dépôts par le chemin interne au serveur comme cela a été décrit précédemment.

[72] Pour plus d'informations sur ce comportement, lisez l'article de blog Authz and Anon Authn Agony sur https://subversion.apache.org/blog/2007-03-27-authz-and-anon-authn-agony.html (article en anglais).