Gestion d'accès - Policies¶
Résumé¶
La gestion d'accès s'appuie sur des policies. Le modèle s'inspire du modèle de gestion d'accès d'AWS (avec toutefois ne nombreux écarts sur lesquels nous reviendrons plus tard) ainsi que certains concepts en place sur cerbos.
Une policy (littéralement une politique) est un regroupement de règles qui décrivent une autorisation ou un refus en fonction
- du sujet (user, rôle, groupe),
- du contexte (modèle, dossier, groupe, tuple, champ),
- des permissions désirées (access, read, write),
- des actions désirées (read, open, delete, save, etc.),
- des transitions d'état souhaitées
- des opérations souhaitées
- de conditions
Les règles en question sont appelées statements. Ce sont elles qui implémentent la logique d'autorisation (allow) ou de refus (deny). Il est aussi possible que le statement ne fournisse pas de réponse (none). Cela arrive si les critères de décision (sujet, contexte, permissions demandées, actions demandées ou conditions) ne s'appliquent pas.
Lorsqu'une policy est évaluée, toutes les règles qui la composent sont évaluées. La policy accorde une autorisation lorsqu'au moins un des statements accorde une autorisation et pour autant qu'aucun statement n'indique un refus. La policy refuse donc une autorisation dès qu'une règle signale un refus. Dans les autres cas, c'est-à-dire lorsqu'aucune règle ne s'applique au contexte, la policy ne donne pas d'avis et c'est à l'application de décider si cela doit être interprété comme une autorisation ou un refus.
Sur une application utilisant les policies, la gestion des accès fonctionne sur le principe du refus implicite. Cela signifie que l'accès à une ressource ou une action est systématiquement refusé tant qu'il n'y a pas de policy qui l'autorise. À noter qu'à niveau de priorité égal, un refus explicite peut également annuler une autorisation accordée au préalable. Cela signifie que si une policy accorde une autorisation mais qu'une autre de même priorité la refuse, c'est cette dernière qui l'emporte. La hiérarchie entre les policies est établie selon deux axes (structure ou priorité). Ces aspects sont décrits plus bas dans ce document.
Sur une application n'utilisant pas de policies, les accès sont autorisés à tous les utilisateurs.
Évaluation des policies par le moteur¶
Les policies sont prises en compte lors de différents traitements par le moteur:
- Lors de la création de session, le moteur vérifie qu'il existe au moins
une policy qui autorise un accès (via une permission
access
,read
, ouwrite
). Un code d'erreur HTTP 403 est retourné si ce n'est pas le cas. - Lors du traitement d'une commande, le moteur vérifie que le sujet est en droit d'invoquer l'action demandée. Pour ce faire, le moteur effectue une recherche d'autorisation parmi toutes les policies applicables qui concernent l'action en question. L'action est autorisée si au moins une policy l'autorise et qu'aucune ne l'interdit.
-
Lors de la construction de l'arbre de sortie les policies sont également évaluées dans le but de déterminer les permissions (
read
etwrite
) et les actions autorisées. Ces informations apparaissent dans l'arbre de sortie via un élémentauthorizations
. La feuille de style qui met en forme l'écran peut donc s'appuyer sur cet élément pour afficher/masquer/griser les éléments de l'interface.En mode debug, des attributs préfixés par le namespace
ch.epilogic.ewt.debug
sont ajoutés (ils ne sont pas présents pour les autres modes de fonctionnement). Ces éléments donnent une indication sur la policy (et son niveau de priorité) qui a permis de déterminer le type d'autorisation, ce qui aide grandement au debuggage des policies.
Types de policies¶
Le modèle de policies AWS prévoit plusieurs types de policies https://docs.aws.amazon.com/fr_fr/IAM/latest/UserGuide/access_policies.html. Dans Ewt, on ne retient que les deux principaux types (du moins pour le moment):
- les policies de ressource : policy associée à une ressource et accordant une autorisation à un sujet (utilisateur, groupe ou rôle)
- les policies d'identité : policy associée à un utilisateur, un groupe d'utilisateurs ou un rôle et donnant l'accès à une ressource
Les policies d'identités sont à définir dans le sous-dossier policies
de
l'application.
Les policies de ressource peuvent être définies inline dans la descript
ou au niveau de fichiers XML placés dans le sous-dossier policies
de l'application. Ces derniers doivent avoir l'extension .policy
ou
.xml
(les autres types de fichiers sont ignorés, par contre
l'arborescence est parcourue récursivement, donc les fichiers présents
dans les sous-dossiers sont également traités).
Les policies inline et les policies définies au niveau des fichiers externes peuvent être référencées au niveau de la description.
Remarque sur le format¶
Dans AWS, les policies sont définies au format JSON. Dans Ewt les policies sont décrites au format XML car celui-ci autorise les retours ligne, ce qui le rend plus adapté à l'écriture de conditions sous la forme de scripts ou de requêtes SQL multilignes.
Resource policy¶
Une policy de ressource indique les droits rattachés à une ressource donnée. Les statements doivent donc décrire les autorisations et refus d'accès à cette ressource pour les différentes populations de sujets susceptibles d'utiliser l'application.
Les policies de resource sont vérifiées récursivement: si aucune policy de ressource n'est définie pour un champ, on s'appuie sur la policy définie pour son tuple parent, puis pour son groupe, puis son modèle.
Identity policy¶
Une policy d'identité décrit les droits que possède un utilisateur, un groupe d'utilisateur ou un rôle sur une ou plusieurs ressources.
Notons que l'implémentation des policies d'identité dans Ewt varie de celle
d'AWS. En particulier, chaque policy d'identité doit indiquer à quelle
catégorie de sujet elle s'applique. Cela se fait au moyen d'une entrée
appliesTo
dans la policy : on y décrit le/les users concernés, le/les
rôles concernés et/ou le/les groupes concernés.
Permissions¶
Les permissions gèrent l'accès aux différentes ressources de l'application (dossier, tuple, champ, etc.) ainsi que l'application elle-même. La version actuelle prévoit 3 types de permissions:
read
: Permet de lire le contenu d'un élément mais pas de le modifier.write
: Permet de lire et de modifier le contenu d'un élément.-
access
: Cette permission gère l'accès à l'application (et uniquement à l'application). Elle permet donc d'indiquer si un sujet est autorisé à utiliser l'application ou non. La requête sera rejetée avec un code HTTP 403 si cette permission ne peut pas être vérifiée. Notez que les permissionsread
etwrite
incluent implicitement la permissionaccess
. Cela signifie qu'il est possible de se passer de cette permission lorsque la policy accorde unallow
sur une permissionread
ouwrite
.À l'inverse, un refus de la permission
access
entraîne automatiquement un refus des permissionsread
etwrite
.
Permission access
La permission access
est incluse dans les permissions read
et
write
. Cela signifie qu'un sujet reçoit implicitement la permission
access
lorsqu'une policy accode un read
ou un write
. On est donc
en droit de se demander à quoi sert la permission access
.
Les premières versions du moteur Ewt n'intègraient pas la permission
access
. À la place, on se rabattait sur read
. Elle a été ajoutée afin
d'offrir un moyen de traiter différemment les comptes standards (les
comptes appartenant aux utilisateurs) et les comptes techniques (les
comptes utilisés par des services web). Ces derniers n'ont généralement
pas besoin d'accéder aux pages HTML de l'interface utilisateur.
L'utilisation de access
offre une granularité plus fine que read
car
elle permet d'accorder l'accès à l'application au compte technique (ce qui
l'autorise à invoquer un service par exemple) tout en garantissant que
le compte ne pourra pas accéder à l'interface utilisateur.
Actions¶
Les actions (open
, save
, close
, delete
, etc.) désignent les types
d'actions que le client peut envoyer au moteur via une commande. Il est
important de noter que les actions portent uniquement sur les groupes, les
dossiers ou sur l'application, alors que les permissions portent sur tous
les types d'objets (dossier, tuple, champ, etc.), ainsi que sur
l'application dans le cas de permission access
.
La version actuelle implémente les actions suivantes:
addTuple
(version 1.0)admin
(version 1.0)arrange
(version 1.0)close
(version 1.0)create
(version 1.0)clone
(version 1.0)delete
(version 1.0)delTuple
(version 1.0)dummy
(version 1.0)open
(version 1.0)reset
(version 1.0)save
(version 1.0)script
(version 1.0)setLocale
(version 1.0)setState
(version 1.0)setStyle
(version 1.0)setView
(version 1.0)
Le numéro de version indiqué est le numéro de la version du moteur de policies prenant en charge l'action donnée. Nous revenons plus bas sur le rôle du numéro de version des policies.
Les actions peuvent être inscrites avec une casse différente : celle-ci est ignorée lors du chargement de la policy.
Transitions¶
Les transitions sont des références à des transitions d'états définies
au niveau des modèles d'états (sous-dossier states
d'une
application).
Les règles transition
fonctionnent sur le même principe que les
règles action
.
Opérations¶
Les opérations représentent des ensembles de traitements propres à l'application. Il ne s'agit pas d'une notion prise en charge par Ewt, mais uniquement une facilité mise à disposition pour vérifier des droits sur la base d'un élément personnalisé.
Par exemple, une opération pourrait être "launchDatabaseClean". Le traitement sous-jacent de cette opération est propre à l'application et n'est pas une fonctionnalité d'Ewt. L'idée ici est de pouvoir demander à Ewt si une opération "launchDatabaseClean" a été considérée comme possible dans un contexte donné.
Infos de base¶
La policy est définie au moyen des éléments suivants:
-
attribut
name
: Nom de la policy formé de caractères alphanumériques et ne commençant pas par un chiffre. Ce nom sert à identifier la policy. Il peut être repris ensuite pour référencer la policy, par exemple au niveau de la descript. -
attribut
type
: Type de policy; peut contenir les valeursresource
ouidentity
-
attribut
priority
: Facultatif. Cet attribut permet de définir la priorité de la policy. Voir le chapitre Hiérarchie des policies et plus spécifiquement le point Hiérarchie par priorité pour une description plus détaillée. -
attribut
version
: Facultatif. Numéro de version selon lequel la policy doit être traitée. En pratique, le numéro de version sert à indiquer à Ewt sur quelle version du modèle de policy il doit s'appuyer. Il s'agit d'un garde-fou principalement destiné à l'interprétation de l'élément wildcard.Pour comprendre le rôle la version, prenons l'exemple suivant: on définit un statement qui est valable pour toutes les actions en notant
<action>*</action>
. Le périmètre des actions concernées peut varier au fil du temps, en particulier si une version future du moteur implémente une nouvelle action : dans ce cas, la nouvelle action sera de facto comprise dans le statement, ce qui peut représenter un risque selon la nature de cette nouvelle action.Pour éviter que l'expression wildcard n'englobe des fonctions non connues et non souhaitées, on indiquera au moyen de l'attribut
version
la version du moteur de traitement des policies à utiliser. Actuellement seule la version "1.0" est disponible, mais cela est susceptible d'évoluer à l'avenir.En l'absence de numéro de version, le moteur considère que la policy est compatible avec la dernière version en date du modèle. Le même résultat est également possible en spécifiant la valeur
latest
. -
attribut
disabled
: Facultatif. Cet attribut permet de désactiver une policy. Dans ce cas, la policy n'est pas chargée par le moteur.Cet attribut peut être pratique pendant développement pour désactiver provisoirement une policy.
-
élément
description
: Facultatif. Cet élément ne joue aucun rôle. Il permet de saisir une description de la policy, de son rôle, etc. -
élément
appliesTo
(uniquement requis pour les policies d'identité) : Filtre indiquant à quel genre de sujet la policy d'identité s'applique. Il permet de filtrer lesuser
,role
et/ougroup
auxquels la policy s'applique.L'élément sert essentiellement pour l'optimisation de traitement en interne au moteur. Lors de l'évaluation des policies, l'application ne vérifiera que les policies qui s'appliquent réellement à l'utilisateur connecté.
-
élément(s)
statement
: Règle de d'autorisation ou de refus (voir ci-dessous)
Les statements¶
Les statements sont des règles référencées par la policy. Ils constituent le coeur des policies.
Un statement n'est évalué que si le contexte déterminé par le sujet, la ressource et/ou les conditions est vérifié. En outre, certaines évaluations de policies s'effectuent dans le cadre d'un contrôle de permission et/ou d'action. Les éléments correspondants sont donc également pris en compte dans ce cas.
Les statements d'une policy sont généralement constitués de:
-
attribut
effect
: Cet élément peut prendre les valeursallow
oudeny
. Il s'agit de la décision retournée par le statement si ce dernier est applicable au contexte actuel (établi en fonction du contexte de dossier et du sujet connecté). -
attribut
level
: Facultatif. Cet attribut permet d'indiquer au moteur que le statement n'est à évaluer que pour un élément d'un niveau donné. Cela permet par exemple d'indiquer au moteur que le statement n'est à évaluer que pour un élément de niveau "tuple".L'attribut peut prendre les valeurs suivantes:
model
- Désigne le niveau "modèle".
document
(oudoc
)- Désigne le niveau "dossier", soit un modèle + un identifiant de dossier.
group
- Désigne le niveau "groupe", soit un modèle + un identifiant de dossier + un nom de groupe
column
- Désigne le niveau "colonne", soit un modèle + un identifiant de dossier + un nom de groupe + un nom de champ
- Ce niveau est particulier et n'existe pas dans les autres parties d'une application Ewt. De plus, il n'est utilisable que dans le cas de groupes multis. Comme son nom l'indique, il désigne une colonne de groupe. On peut l'associer à l'entête de colonne : il ne désigne pas des instances de champs, mais une colonne de la table.
tuple
- Désigne le niveau "tuple", soit un modèle + un identifiant de dossier + un nom de groupe + un identifiant de tuple
field
- Désigne le niveau "champ", c'est-à-dire un contexte complet
none
- Désigne un contexte vide
Voici un exemple de statement défini pour le niveau "tuple". Ici le but de ce statement est de désactiver l'action
delTuple
d'un dossier ayant un statut autre que "creation" et sur chaque ligne de commentaire dont l'utilisateur courant n'est pas l'auteur.1 2 3 4 5 6 7 8
<statement effect="deny" level="tuple"> <resource>ticket.commentaires</resource> <action>delTuple</action> <condition mode="state" reverse="true">creation</condition> <condition require="tupleId"><![CDATA[ return #idAuteur != $session.getPersistentObject("user-docId"); ]]></condition> </statement>
La condition de la ligne 4 filtre l'état du dossier et la condition de la ligne 6 vérifie que l'auteur du commentaire n'est pas l'utilisateur courant.
Ici le level "tuple" est nécessaire pour plusieurs raisons:
- L'action
delTuple
se rapporte exclusivement à un tuple - La condition de la ligne 6 fait référence à
#idAuteur
. Évaluée en-dehors du niveau "tuple", cette expression est soitnull
, soit un tableau de valeurs. En effet, si on se place au niveau "group", l'expression s'applique au niveau du groupe, et elle porte donc sur tous les tuples du groupe, raison pour laquelle elle contient un tableau de valeurs.
-
élément
subject
: Uniquement pour les policies de ressources.Cet élément permet de décrire les règles d'identification de sujets sur lesquels s'applique le statement. On définit la population au moyen de trois types d'éléments:
user
,role
et/ougroup
. Chaque élément peut figurer entre 0 et n fois. Il est possible de regrouper plusieurs valeurs d'un même type (par exemple plusieurs roles) en une seule en les séparant par une virgule (par exemple<role>EWT_1,EWT_2,EWT_3</role>
)Comme pour les actions décrites plus haut, il est possible d'ajouter un attribut
except
pour spécifier des exceptions.Si aucun sujet n'est indiqué, le statement est évalué pour tous les utilisateurs.
-
élément(s)
resource
: Uniquement pour les policies d'identité.Cet élément permet d'indiquer la ou les ressources pour lesquelles le statement s'applique. Les ressources sont à référencer à l'aide d'une expression de contexte.
Il est possible de référencer n'importe quelle ressource en indiquant une valeur wildcard
*
.Il est possible de spécifier une chaîne de caractères si on ne souhaite référencer qu'une seule valeur.
Attention, la valeur
"*"
n'est pas équivalente à la valeur""
.La valeur
"*"
désigne n'importe quel contexte non vide. Cela signifie qu'il faut qu'un dossier soit ouvert pour que le statement s'applique.La valeur vide (
<resource/>
) désigne aucun contexte. La valeur permet de représenter le cas où l'on est hors dossier. Ainsi, la référence<resource>,*</<resource>
permet d'englober à la fois le contexte "hors dossier" et le contexte "dossier ouvert", indépendamment de son modèle.Il est possible de ne pas spécifier de ressource au niveau d'un statement. Dans ce cas, le moteur n'effectue pas de contrôle de contexte. Cela signifie qu'il évalue le statement dans tous les cas, indépendamment du contexte actuel.
Gestion des exceptions
La question des exception au niveau des ressources est délicate et elle n'est pas recommandée car elle peut facilement amener à des situations difficiles à comprendre et à debugger.
Héritage
En premier lieu, il faut garder à l'esprit que les ressources héritent leurs autorisations de leurs parents. Par conséquent, si une exception est définie pour un niveau inférieur à une autre ressource du même statement, elle sera sans effet. Pour illustrer cela, prenons l'exemple suivant
1 2 3
<resource>ticket</resource> <resource except="true">ticket.base.notifications</resource> <resource except="true">ticket.commentaires.btn1</resource>
Ici la ressource
ticket
est à un niveau bien supérieur que les exceptions. Celles-ci n'appliqueront pas l'effet du statement, mais hériterons de l'effet du statement appliqué à la ressourceticket
. Au final, cela rend les exceptions sans effet.Comme indiqué plus haut, pour qu'une exception de ressource soit prise en compte, il faut qu'elle référence une autre ressource de même niveau. Par conséquent, les ressources devraient être déclarées ainsi pour que cela ait un sens:
1 2 3 4
<resource>ticket.base.*</resource> <resource except="true">ticket.base.notifications</resource> <resource>ticket.commentaires.*</resource> <resource except="true">ticket.commentaires.btn1</resource>
Cette notation est fastidieuse, c'est pourquoi dans une telle situation, il devient préférable de définir une policy supplémentaire qui vient imposer l'exception au moyen d'un niveau de priorité supérieur.
-
élément(s)
permission
: Cet élément permet de déclarer les permissions que l'on souhaite autoriser/refuser. Les permissions sontaccess
,read
ouwrite
. Pour spécifier plusieurs permissions, il est possible de répéter plusieurs fois l'élémentpermission
ou de noter les permissions via un seul élément en séparant les permissions par une virgule, par exempleread,write
. -
élément(s)
action
: Cet élément permet de déclarer les actions sur lesquelles porte le statement. Les actions possibles (open
,save
, etc.) sont données plus haut dans ce document. Les actions peuvent être notées via des élémentsaction
distincts, ou regroupés au sein d'une valeur séparée par des virgules.Il est possible de désigner "toutes les actions" au moyen de la valeur wildcard
*
. Vous pouvez également spécifier des exceptions à la liste d'actions. Pour cela, il suffit d'ajouter un attributexcept="true"
à l'élémentaction
(voir exemple plus bas). Veuillez toutefois lire plus haut l'importance de l'attributversion
lorsque vous définissez une règle portant sur toutes les actions.1 2 3 4 5 6
<statement effect="deny" version="1.0"> ... <action>*</action> <action except="true">open,close,arrange,save</action> ... </statement>
-
élément(s)
transition
: Cet élément permet de spécifier une ou plusieurs transitions à autoriser/refuser. Les transitions peuvent être notées via des élémentstransition
distincts, ou regroupés au sein d'une valeur séparée par des virgules. -
élément(s)
operation
: Cet élément permet de spécifier une ou plusieurs opérations à autoriser/refuser. Les opérations peuvent être notées via des élémentsoperation
distincts, ou regroupés au sein d'une valeur séparée par des virgules.Le terme opération ici ne désigne pas une fonctionnalité offerte par le moteur Ewt, mais un processus propre à l'application. On pourra par exemple se servir de cet élément pour déterminer s'il faut mettre à disposition ou non un bouton au niveau de l'interface utilisateur.
-
blocs d'éléments
facet
: Il est possible de regrouper des élémentsresource
,subject
,permission
,action
,transition
,operation
par blocs. Cette option remplit un rôle pratique : elle permet de regrouper des règles qui sont soumises à une même condition. Cela évite de créer plusieurs statements avec une même condition, ce qui présente un intérêt du point de vue syntaxique (cela évite les répétitions lorsqu'une condition est un script, voire un regroupement de conditions (voir élémentconditions
plus bas)), mais également une optimisation : cela évite au moteur de devoir évaluer plusieurs fois une même condition.Le moteur numérote les
facet
à partir de 1 selon l'ordre dans lequel ils sont définis. Les éléments définis directement dansstatement
sont quant à eux regroupés dans unfacet
portant le numéro 0. Ainsi, les lignes 2 et 3 de l'exemple ci-dessous constituent lefacet
#0 alors que les lignes 6 et 7 forment lefacet
#1.1 2 3 4 5 6 7 8 9
<statement effect="allow"> <resource>ticket</resource> <permission>read,write</permission> <facet> <resource>ticket.commentaires.btnActions</resource> <operation>edition</operation> </facet> </statement>
-
élément(s)
condition
: Cet élément contient une condition supplémentaire qui indique si le statement est applicable ou non. L'élément peut contenir un script, une requête SQL ou une liste d'états. Cette distinction peut être déclarée à l'aide de l'attributmode
. Le détail des différents modes est donné plus bas.La condition est censée générer une réponse booléenne (dans le cas du mode
state
, c'est la correspondance entre l'état actuel du dossier et l'état indiqué en condition qui génère la réponse booléenne). Lorsque la condition ne génère pas de réponse (en particulier pour les modesscript
etsql
) ou une réponsenull
, le moteur l'interprète comme unfalse
. Il est possible d'indiquer explicitement la valeur par défaut à appliquer dans ce cas avec l'attributdefault
.L'attribut
reverse
permet de faire fonctionner la condition en mode inversé. Ainsi, en mode inversé, le statement est appliqué lorsque la condition estfalse
. Ce mode est particulièrement pratique avec le modestate
lorsqu'un statement doit s'appliquer pour tous les états sauf ceux indiqués.Il est possible de spécifier plusieurs conditions pour un même statement. Veuillez lire plus haut la description de l'élément
conditions
(avec un "s" !) pour comprendre le comportement du moteur en présence de plusieurs conditions.- Mode
script
- En mode script, on s'attend à ce que la valeur fournie en retour
soit
true
oufalse
. La valeur de l'élémentcondition
est le script que le moteur devra évaluer. Notez qu'il est possible d'utiliser un élément CDATA pour faciliter la syntaxe. Cela évite de devoir échapper les caractères spéciaux du XML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<condition> <![CDATA[ if (#base.motifPrincipal) { switch (#base.motifPrincipal) { case "H-PP": case "H-IG": case "H-DP": return false; default: return true; } return true; ]]> </condition>
- Mode
sql
- Comme pour le mode
script
, on s'attend à ce que la valeur fournie en retour (1re colonne de la 1re ligne du resultset) soittrue
oufalse
. Les valeurs "true", "1" et "yes" sont interprétées commetrue
. - La condition en mode
sql
utilise la même notation que pour les options ou les valeurs par défaut de la descript : la requête doit être placée dans un élément<value>
et les éventuels paramètres dans des éléments<param>
. Lorsque ces derniers sont exprimés à l'aide d'une variable, ils doivent avoir un attributtype
, comme dans le cas de la descript. L'attribut est optionnel dans le cas d'expression sharp.1 2 3 4 5 6
<condition mode="sql" defaultValue="true"> <value>select MotifPrincipal not in ('H-PP','H-IG','H-DP') from ConsultationHOP where IdConsultation=?</value> <text:param>#idConsultation</text:param> </condition>
- Mode
state
- Une condition utilisant le mode
state
vérifie que le dossier courant est dans l'un des états déclarés dans la condition. - La valeur de l'élément
condition
peut être: -
- une chaîne de caractères : on indiquera le nom de l'état ou des
états qui remplissent la condition (utiliser la virgule comme
séparateur dans le cas où plusieurs états doivent être spécifiés)
<condition mode="state">monEtatA,monEtatB</condition>
- une chaîne de caractères : on indiquera le nom de l'état ou des
états qui remplissent la condition (utiliser la virgule comme
séparateur dans le cas où plusieurs états doivent être spécifiés)
-
- un ou plusieurs éléments
<state>
1 2 3 4
<condition mode="state"> <state>monEtatA</state> <state>monEtatB</state> </condition>
- un ou plusieurs éléments
-
- un élément ou plusieurs éléments
<states>
dont la valeur est une chaîne de caractères indiquant le nom d'un ou plusieurs états séparés par une virgule.
1 2 3
<condition mode="state"> <states>monEtatA,monEtatB</states> </condition>
- un élément ou plusieurs éléments
-
Il est possible de mixer entre les éléments
<state>
et<states>
.
Lorsque la condition fait référence à un ou plusieurs champs de dossier, il est nécessaire d'ajouter un attribut
require
à l'élémentcondition
pour indiquer au moteur que la condition ne peut s'exécuter que dans le contexte d'un dossier ouvert. L'attribut peut prendre les valeurs suivantes:docId
(oudocid
)- Cette valeur indique que la condition ne peut s'appliquer que dans le cas où le contexte de la ressource à évaluer possède un identifiant de dossier. Autrement dit, la condition n'est évaluable que dans le contexte d'un dossier ouvert.
tupleId
(outupleid
)- Cette valeur indique que la condition ne peut s'appliquer que dans le cas où le contexte de la ressource à évaluer possède un identifiant de tuple. Ce prérequis sert à cibler les tuples de groupes multi. Elle évincera par contre le groupe multi lui-même car celui-ci est une ressource dont le contexte s'exprime au moyen d'une expression sans identifiant de tuple.
Le fait de spécifier le pré-requis sert à ce que la condition soit évaluée dans le bon contexte. C'est également une manière pour le moteur d'optimiser le traitement des policies et d'éviter l'évaluation de statements non adaptés au contexte courant.
Il n'est pas nécessaire de spécifier l'attribut pour les conditions utilisant le mode
state
car le moteur sait déjà que dans ce cas la condition nécessite un dossier ouvert. L'attribut est donc ajouté automatiquement par le moteur. - Mode
-
élément
conditions
: L'élémentconditions
permet de regrouper plusieurs conditions ensemble et de spécifier un opérateur sur leur valeur de retour.Lorsqu'un statement possède plusieurs conditions, il est possible de définir plusieurs éléments
condition
les uns à la suite des autres. Dans ce cas, le moteur n'appliquera l'effet du statement que si toutes les conditions sont remplies. À l'inverse, le statement sera ignoré dès qu'une condition n'est pas remplie. On peut dire que dans ce cas, le moteur applique un opérateur logique "ET" (ouand
) entre les conditions.Il peut cependant arriver que l'on veuille appliquer un opérateur "OU" (ou
ou
) sur les conditions. Dans ce cas, il est nécessaire de définir un élémentconditions
et de lui ajouter un attributoperator="or"
. Dans ce cas l'effet associé au statement sera appliqué dès qu'une condition est remplis.L'élément
conditions
supporte donc deux types d'opérateurs:and
- Indique que toutes les conditions doivent être remplies pour que le statement s'applique. C'est le comportement par défaut.
or
- Indique que le statement s'applique dès qu'au moins une condition est vérifiée.
Voici un exemple de déclaration avec l'opérateur
or
. Dans cet exemple, on souhaite refuser l'écriture sur tous les champs du groupeticket.base
et bloquer l'actiondelete
lorsque le dossier n'est pas dans l'état "ticketCreation" ou que l'utilisateur courant n'est pas l'auteur du dossier.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<statement effect="deny"> <facet> <resource>ticket.base.*</resource> <permission>write</permission> </facet> <facet> <action>delete</action> </facet> <conditions operator="or"> <condition mode="state" reverse="true">ticketCreation</condition> <condition require="docId"><![CDATA[ return #idUtilisateur != $session.getPersistentObject("user-docId"); ]]></condition> </conditions> </statement>
Discussion de l'exemple ci-dessus
On notera au passage que le statement utilise deux "facets": l'un pour gérer les permissions et le second pour gérer l'action. Il ne serait pas correct de regrouper les deux facets en un seul car celles-ci ne s'appliquent pas dans le même contexte : la permission
write
porte ici sur des champs alors que l'actiondelete
, par nature, porte sur le dossier.
Policy pour accès à une application¶
Les servlets autorisent l'accès à une application lorsque la policy de base
autorise au moins une action à l'utilisateur. La policy de base est définie
dans la config via la propriété policies.policy
.
Exemple de policy de base:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Hiérarchie des policies¶
Le moteur traite les règles de policies de manière hiérarchique selon deux axes: la hiérarchie de structure et la hiérarchie par priorité.
Hiérarchie de structure¶
La hiérarchie de structure s'appuie sur la structure de la descript. On peut parler ici d'héritage. Dans Ewt, il existe deux formes d'héritage:
- l'héritage standard
- l'héritage ascendant des autorisations (
allow
)
Héritage standard¶
Une policy appliquée à un nœud donné, par exemple le nœud
<model>
, s'applique à toute la structure de ce nœud, donc à ses
groupes, ses tuples, ses champs.
Il est possible de définir d'autres policies dans les éléments de la sous-structure (groupes, tuples, champs) mais ces dernières ne peuvent pas contredire des règles définies plus haut. En particulier, elles ne peuvent autoriser des actions qui ont été refusées à un niveau supérieur.
En clair, si une policy impose un deny
sur le niveau model
, les
policies qui accordent un allow
sur les champs de ce même modèle seront
sans effet car bloqués par le deny
du niveau supérieur.
L'inverse est par contre possible : si une policy accorde un allow
sur le
niveau model
, il est bien entendu possible d'imposer un deny
sur un
champ. Le deny
prime sur le allow
dans l'héritage standard.
Héritage ascendant¶
L'héritage ascendant concerne uniquement les permissions avec un effet
allow
: si une policy accord un allow
sur un champ, alors ce allow
est également accordé à tous les éléments parents du champ, à condition
qu'aucune autre policy ne vienne à l'encontre de ce allow
.
Le mécanisme devient logique si on prend un exemple : une policy accord un
droit sur un champ. Pour que ce champ soit accessible, il faut bien entendu
que le tuple parent soit visible, de même que le groupe parent et le modèle
parent. Si le tuple, le groupe et le modèle n'ont pas de policy particulière
associée, alors ils reçoivent également le allow
pour permettre au champ
d'être accessible.
Hiérarchie par priorité¶
La hiérarchie par priorité offre une solution pour court-circuiter la limitation imposée par la hiérarchie de structure standard, à savoir le fait qu'un niveau inférieur ne peut pas accorder plus d'autorisation que ne le permet le niveau supérieur.
Prenons le cas suivant:
On souhaite définir une policy globale indiquant qu'un dossier
est en lecture seule lorsque son statut est "archivé". Pour cela, on définit
la policy de ressource au niveau de la descript. En imaginant que tous les
modèles possèdent un champ "statut", la policy pourrait être :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Cependant, on aimerait malgré tout autoriser un administrateur à intervenir
sur les champs d'un dossier archivé mais la hiérarchie de structure
l'interdit. Pour contourner cette limitation, il est possible d'utiliser la
notion de priorité. La priorité est représentée par une valeur numérique
rattachée à la policy via l'élément priority
.
Une policy peut accorder des droits plus étendus que son parent à la condition qu'elle ait une priorité supérieure ou égale à la policy qui a établi le deny sur une action donnée.
Évaluation des policies¶
https://docs.aws.amazon.com/fr_fr/IAM/latest/UserGuide/reference_policies_evaluation-logic.html
Exemple de policy d'identité¶
On souhaite donner accès à une catégorie d'utilisateurs pour qu'ils effectuent une tâche spécifique. Par exemple, on souhaite donner accès aux listes d'articles à des vendeurs pour qu'ils puissent saisir les articles qu'ils veulent mettre en vente. Ces vendeurs ne doivent pouvoir accéder qu'à leur liste d'article et à rien d'autre.
On définit alors une policy d'identité qui interdit l'accès à toute ressource qui n'est pas la liste d'articles du vendeur.
La policy suivante permet d'implémenter cela:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Remarque concernant les mises à jour de policy
Lors du développement, on peut être amené à modifier, voire ajouter ou
supprimer des policies. Il faut alors demander à l'application d'effectuer
un rechargement des policies pour que les modifications soient appliquées.
Ce rechargement peut être effectué au moyen de la commande reset
.
Cette action a pour effet de forcer un rechargement complet de l'application, de la config, de la descript, des policies, etc. Toutefois elle ne peut pas agir directement sur les objets chargés en mémoire, en particulier les dossiers ouverts. La nuance est peut-être difficile à percevoir. Pour mieux comprendre les choses, voyons comment Ewt organise les éléments.
L'application contient une table de policies. Lorsqu'une policy est appliqué à une ressource (un modèle, un tuple, un champ, etc.), cette dernière conserve en mémoire le nom de la policy en question. La policy en elle-même est décrite au niveau de la table de policies de l'application, mais le nom de la policy est rattaché à la ressource.
Lors d'un reset, la table des policies de l'application est rechargée, mais pas les références par nom qui sont enregistrées au niveau des ressources. Cela fait qu'après un reset, les ressources ont toujours les mêmes listes de noms de policies, dans le même ordre qu'avant le reset.
Par conséquent si le changement concerne purement la policy (ajout d'une action, modification de l'effet, modification des conditions, etc.), alors la nouvelle version de la policy sera bien prise en compte, car la ressource continuera de référencer la policy et celle-ci sera mise à jour.
Par contre si la modification consiste à ajouter une nouvelle policy à une ressource, ou à modifier l'ordre des policies au sein d'une ressource, alors la modification ne se remarquera pas immédiatement car la ressource conservera la liste de noms de policies qu'elle connaît, mais ignorera les nouvelles policies ou le nouvel ordre des policies. La modification ne s'appliquera qu'aux dossiers ouverts après le reset et pas à ceux qui étaient déjà ouverts avant le reset. Pour ces derniers, il faudra fermer puis rouvrir le dossier pour que la modification soit effective.
Contrôles¶
La mise en place de policies peut être rapidement complexe et peut présenter des pièges. En mode d'exécution "dev", le moteur effectue un certain nombre de contrôles sur les policies et signale les possibles erreurs sous la forme d'avertissement dans le log de l'application lorsqu'il charge celle-ci en mémoire (lors de l'initialisation de l'application et lors des "reset").
Voyons quelques problèmes courants que l'on peut rencontrer avec l'exemple ci-dessous:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Ce statement présente plusieurs défauts.
-
Niveaux de ressources
Le statement ci-dessus mélange des ressources de plusieurs niveaux, dont certains appartiennent aux autres. Ainsi, la référence de ressource
ticket
vient écraser toutes les autres références de ressources "fine grain". En effet, le fait d'associer la permissionread
et la resourceticket
indique au moteur que l'intégralité des éléments du contexteticket
est enread
. Les références aux autres ressources deviennent alors inutiles car ces dernières héritent naturellement les permissions de leur parent.La seule option pour éviter cela serait de séparer les règles en deux statements distincts, comme mentionné en introduction, mais présente le désavantage de dupliquer la condition sur les deux statements. Ce n'est pas idéal du point de vue syntaxique et cela oblige le moteur à évaluer deux fois une même condition.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<statement effect="allow"> <resource>ticket</resource> <action>arrange,close,save,script,setLocale,setStyle,setView</action> <action>addTuple,create,open</action> <condition mode="state">ticketCreation</condition> </statement> <statement effect="allow"> <resource>ticket.base</resource> <resource>ticket.commentaires.dateHeure</resource> <resource>ticket.commentaires.idAuteur</resource> <resource>ticket.commentaires.texte</resource> <permission>read</permission> <condition mode="state">ticketCreation</condition> </statement>
Pour éviter la répétition, on aura alors recours à des éléments
facet
, ce qui permet de regrouper tous les éléments dans le mêmestatement
et qui évite la répétition de la condition.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<statement effect="allow"> <facet> <resource>ticket</resource> <action>arrange,close,save,script,setLocale,setStyle,setView</action> <action>addTuple,create,open</action> </facet> <facet> <resource>ticket.base</resource> <resource>ticket.commentaires.dateHeure</resource> <resource>ticket.commentaires.idAuteur</resource> <resource>ticket.commentaires.texte</resource> <permission>read</permission> </facet> <condition mode="state">ticketCreation</condition> </statement>
-
Mélange d'actions ne portant pas sur le même niveau
L'exemple mélange des actions qui portent sur un niveau "document" (
create
,open
) et des actions qui concernent un niveau "tuple" (arrange
,addTuple
, etc.). En outre, il y associe des ressources qui référencent différents niveaux.Cela ne fait pas sens car une action
delete
ne concerne qu'un niveau modèle et non un tuple. Le moteur signalera une possible erreur en présence de statement présentant ces caractéristiques. -
Permissions et ressources
Le fait de mélanger une ressource
<resource>ticket</resource>
et une permission n'est généralement pas correcte ou pas souhaitée. Le moteur s'attend à ce que la ressource désigne un champ ou qu'elle soit notée avec un suffixe.*
. Dans notre cas, cela donnerait<resource>ticket.*</resource> <permission>read</permission>
Exemple¶
Ce chapitre présente un exemple d'implémentation de gestion de droits sur la base de policies. Pour cet exemple, nous nous appuyons sur une application très basique faisant intervenir 2 modèles:
- entreprise : contient les informations de base d'une entreprise
- personne : contient les informations de base d'une personne et une référence vers l'entreprise à laquelle la personne est rattachée
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
On prévoit 3 niveaux d'utilisateurs:
contact
: ce compte reçoit les rôlesEWT
etEWT-contact
responsable
: ce compte reçoit les rôlesEWT
etEWT-responsable
admin
: ce compte reçoit les rôlesEWT
etEWT-admin
L'idée est d'associer des contacts à des entreprises. Pour l'exercice, on prévoit les contraintes de sécurité suivantes:
-
Les contacts ont la possibilité de modifier les infos de leur compte personnel, à l'exception de la référence à l'entreprise et du champ "remarque". On souhaite que le champ remarque soit en lecture seule et que le champ "entreprise" ne soit pas visible de la personne.
-
Les responsables ont tous les droits sur la fiche d'entreprise à laquelle ils sont rattachés. Ils peuvent consulter les fiches des autres entreprises en lecture seule.
Ils ont également la possibilité de consulter les fiches de contact. La fiche personnelle est consultable en lecture et écriture. Les fiches des autres contacts sont accessibles en consultation uniquement, à l'exception toutefois de la référence d'entreprise et de la remarque, qui sont modifiables sous certaines conditions:
- La référence d'entreprise n'est modifiable que si elle est vide ou si elle correspond à l'entreprise à laquelle le responsable est lui-même rattaché.
- Le champ remarque n'est modifiable que dans le second cas de figure évoqué ci-dessus.
-
Les administrateurs ont les droits sur tous les dossiers et tous les champs.
Note
Pour des raisons de clarté, notre exemple considère une application sans gestion d'états. De ce fait, les policies présentées ci-après ne contiennent aucune règle concernant les transitions.
Mise en œuvre¶
Il est possible d'aborder l'exercice de différentes façons. Pour commencer, nous utilisons une gestion de droits uniquement basée sur des policies d'identité.
Dans un second temps, nous effectuerons une approche au moyen de policies basées sur les ressources.
Approche au moyen de policies basées sur les identités¶
Policy de base¶
Une policy de base main.policy
est pré-définie et donne accès à
l'application en lecture seule à tout utilisateur qui possède le rôle EWT
.
Les utilisateurs qui ne possèdent pas ce rôle recevront une erreur HTTP 403.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Administrateur¶
Le niveau administrateur est très simple à mettre en œuvre. La policy d'identité suivante donne accès à tout:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Contact¶
Pour rappel, les contacts ont la possibilité de modifier les infos de leur compte personnel, à l'exception de la référence à l'entreprise et du champ "remarque". On souhaite que le champ remarque soit en lecture seule et que le champ "entreprise" ne soit pas visible de la personne.
L'accès à la fiche personnelle se fait au moyen de la recherche. Une autorisation à évaluer le script de recherche est donc également nécessaire. La policy ci-dessous implémente ces différents aspects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
Responsable¶
Pour rappel, les responsables ont tous les droits sur la fiche d'entreprise à
laquelle ils sont rattachés. Ils peuvent consulter les fiches des autres
entreprises en lecture seule.
Les responsables ont également la possibilité de consulter les fiches de
contact, toutefois seules la référence d'entreprise et la remarque sont
modifiables sous certaines conditions:
- La référence d'entreprise n'est modifiable que si elle est vide ou si elle correspond à l'entreprise à laquelle le responsable est lui-même rattaché.
- Le champ remarque n'est modifiable que dans le second cas de figure évoqué ci-dessus.
Nous pouvons implémenter les droits du responsable sur sa fiche entreprise de deux manières:
- On peut définir un statement qui accorde les droits en lecture/écriture
sur tous les dossiers "entreprise", et définir un second statement qui bloque l'écriture lorsque l'idEntreprise courant ne correspond pas à celui de l'utilisateur.o - À l'inverse, on peut définir un statement qui autorise la lecture seule sur tous les dossiers "entreprise", et définir un second statement qui étend le droit à l'écriture lorsque l'idEntreprise correspond à celui de l'utilisateur.
Dans l'implémentation ci-dessous nous mettons en œuvre cette seconde option, pour deux raisons: d'une part cette manière de gérer les droits par ajout d'autorisation est plus propre (cela évite d'ajouter beaucoup de droits pour en retirer ensuite) et d'autre part cela permet de gérer également l'accès en lecture seule aux fiches de personnes via le même statement.
La policy d'identité pour les responsables peut être formulée ainsi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
|
Bilan¶
L'approche par policy basée sur les identités est fonctionnelle. Elle nécessite l'écriture de 8 statements.
On remarque toutefois qu'elle entraîne des répétitions au niveau des conditions des statements, en particulier au niveau de la policy "responsable".
Dans la pratique, on évitera la répétition de ces requêtes SQL. Pour ce faire, une solution serait d'utiliser un persistent object dans lequel on pourrait stocker l'identifiant de l'entreprise du responsable. Les objets persistents sont des objets stockés au niveau de la session. Ils sont donc disponibles en tout temps, tout au long de la session.
Une solution alternative est à l'étude dans Ewt (mais non implémentée actuellement). Il s'agirait de construire un rôle dérivé de type "owner" qui représente un propriétaire de ressource. La notion de rôle dérivé s'inspire de cerbos soient également repris dans Ewt, en particulier les rôles dérivés.
Approche au moyen de policies de ressource¶
Dans une approche basée sur des policies de ressource, il ne faut plus chercher à voir ce que peut faire un utilisateur, mais chercher à déterminer ce que les ressources autorisent. L'idée ici n'est plus d'attribuer des droits en fonction du type de sujet connecté, mais de décrire quels sujets ont le droit d'accéder aux ressources.
La première étape consiste donc à identifier les ressources. Dans notre exercice, nous avons:
- l'application
- le modèle "entreprise"
- le modèle "personne"
- le champ "personne.info.idEntreprise"
- le champ "personne.info.remarque"
Nous allons donc définir une policy pour chacune de ces ressources.
Application¶
La policy "main" permet de définir les droits sur l'application. Dans le cas de notre exercice, la policy doit a minima accorder un droit en lecture seule sur la page d'accueil.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
La policy ci-dessous doit être comprise ainsi: La policy main
accorde une
permission read et autorise les actions dummy, save et script aux
utilisateurs qui ont un rôle EWT. Elle accorde en outre toutes les
permissions et autorise toutes les actions au rôle EWT-admin.
Modèle "entreprise"¶
La fiche entreprise est accessible en lecture seule par les responsables. Elle est accessible en écriture par le responsable qui est rattaché à ladite fiche ainsi que par les administrateurs. On peut ignorer les administrateurs ici car les droits de ces derniers sont déjà entièrement gérés par la policy "main".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
Il reste à faire le lien entre le modèle "entreprise" et la policy "entreprise". Pour cela, il suffit d'ajouter une référence au niveau de la descript:
1 2 3 4 5 6 7 8 9 |
|
Une notation plus courte est également possible:
1 2 3 4 5 6 |
|
Modèle "personne"¶
Les règles définies pour cet exercice sont implémentables au moyen de trois policies : l'une pour le modèle, l'une pour le champ "idEntreprise" et la dernière pour le champ "remarque". La descript du modèle ressemble donc à ceci:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
La policy qui gère le modèle est la suivante:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
La policy qui gère les autorisations relatives au champ "idEntreprise" est:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
La policy qui gère les autorisations relatives au champ "remarque" est:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Bilan¶
L'approche par policy basée sur les ressources est également fonctionnelle et le résultat final est équivalent si l'on se base sur le fonctionnement de l'application. Elle fait intervenir 11 statements. C'est plus que pour l'approche utilisant des policies basées sur les identités, mais ce n'est pas forcément un signe de moins bonne performance : dans le cas des policies de ressources, le moteur n'est pas obligé d'évaluer toutes les policies. Il n'évalue que celles qui apportent une information utile. En effet, le moteur n'a pas besoin d'évaluer les policies référencées dans le modèle "personne" lorsqu'il traite un dossier du modèle "entreprise".
Des deux approches, il est difficile de dire laquelle est la plus simple et laquelle est la plus performante. Dans cet exemple nous avons confronté deux approches diamétralement opposées. Toutefois il est possible de mélanger les différents types de policies : certains aspects peuvent être traités au moyen de policies basées sur les identités alors que d'autres peuvent s'appuyer sur des policies de ressources.
Approche basée sur la hiérarchie d'accès¶
Dans les deux approches ci-dessus, nous n'avons pas tenu compte de la hiérarchie qui peut être établie entre les différents rôles. Une solution alternative pourrait être d'implémenter les policies sous forme de niveaux d'accès ou de niveaux de privilèges. Le rôle "contact" aurait un niveau de base, le rôle "responsable" un niveau intermédiaire et le rôle "admin" le niveau maximum.
On peut alors construire des policies pour chaque niveau de privilège de 0 à 9. Pour le niveau 6, cela pourrait ressembler à:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Il est possible de définir des policies équivalentes pour les rôles numérotés de 0 à 9. Ensuite il suffit de référencer les policies au niveau de la descript. Cela permet d'implémenter une gestion de droits basée sur les niveaux de privilèges.
Attention toutefois, la policy ci-dessus ne fait pas de distinction entre l'accès en lecture et l'accès en écriture. Il faudrait encore définie des policies spécifiques pour les différents types d'accès.