Attention : vous consultez actuellement la documentation dédiée aux versions 1.x de Moodle. La documentation pour les versions 2.x de Moodle est consultable ici : Comment les permissions sont calculées ?, celle pour les versions 3.x de Moodle est consultable ici : Comment les permissions sont calculées ? et celle pour Moodle 4.x est consultable là : Comment les permissions sont calculées ?.

« Comment les permissions sont calculées ? » : différence entre les versions

De MoodleDocs
Aller à :navigation, rechercher
(Suite de la traduction)
mAucun résumé des modifications
 
(40 versions intermédiaires par 2 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
{{Rôles}}{{En cours de traduction}}
{{Rôles}}Une des questions posées très fréquemment est : ''Quelles permissions possède un utilisateur pour un contexte donné ?''
 
Une des questions posées très fréquemment est : ''Quelles permissions possède un utilisateur pour un contexte donné ?''


Cette page explique la fonction principale de Moodle utilisée pour répondre à cette question. Cette fonction est ''has_capability()''. Elle se trouve dans le fichier ''lib/accesslib.php''. Cette fonction implémente les règles pour calculer la "somme" des permissions de multiples rôles et dérogations. Pour un utilisateur donné, une capacité, et un contexte, la fonction renvoi ''true'' (vrai) si l'utilisateur est autorisé à effectuer l'action contrôlée par la capacité dans le contexte donné, et ''false'' (faux) sinon.   
Cette page explique la fonction principale de Moodle utilisée pour répondre à cette question. Cette fonction est ''has_capability()''. Elle se trouve dans le fichier ''lib/accesslib.php''. Cette fonction implémente les règles pour calculer la "somme" des permissions de multiples rôles et dérogations. Pour un utilisateur donné, une capacité, et un contexte, la fonction renvoi ''true'' (vrai) si l'utilisateur est autorisé à effectuer l'action contrôlée par la capacité dans le contexte donné, et ''false'' (faux) sinon.   
Ligne 7 : Ligne 5 :
Cette page est écrite autant pour les non programmeurs que pour les programmeurs. Elle décrit ''ce que'' la fonction fait, pas ''comment''. Le ''comment'' est compliqué, alors que le ''quoi'' est relativement simple !
Cette page est écrite autant pour les non programmeurs que pour les programmeurs. Elle décrit ''ce que'' la fonction fait, pas ''comment''. Le ''comment'' est compliqué, alors que le ''quoi'' est relativement simple !


Remarquez que la fonction ''n'essaie pas''  de répondre à la grande question posée dans la première phrase de cette page. Elle répond plutôt à la petite question "Un utilisateur peut-il faire ''CAP'' ici ?", où ''CAP'' est une capacité spécifique. Moodle ne calcule jamais la totalité des permissions d'un utilisateur. Une telle opération serait très coûteuse et et n'apporterait pas grand chose, puisque la plupart des permissions ne seraient jamais testées. Moodle calcule donc les permissions à la demande. Moodle ne place pas en cache les permissions calculées, mais les recalcule chaque fois qu'il est nécessaire de les tester. C'est la raison pour laquelle les attributions de rôles et les dérogations prennent effet immédiatement, et que ce n'était pas le cas dans Moodle 1.7.
Remarquez que la fonction ''n'essaie pas''  de répondre à la grande question posée dans la première phrase de cette page. Elle répond plutôt à la petite question ''Un utilisateur peut-il ici faire l'action correspondant à la capacité CAP ?'' Moodle ne calcule jamais la totalité des permissions d'un utilisateur. Une telle opération serait très coûteuse et n'apporterait pas grand chose, puisque la plupart des permissions ne seraient jamais testées. Moodle calcule donc les permissions à la demande. Moodle ne place pas en cache les permissions calculées, mais les recalcule chaque fois qu'il est nécessaire de les tester. C'est la raison pour laquelle les attributions de rôles et les dérogations prennent effet immédiatement (ce n'était pas le cas dans Moodle 1.7 et 1.8).


La fonction est appelée ainsi :
== Le calcul ==


    has_capability(CAPABILITY,CONTEXT,USER);
Lorsqu'un utilisateur tente d'effectuer une action contrôlée par une capacité, Moodle appelle la fonction has_capability pour voir si cette action doit être autorisée. La fonction est appelée ainsi :


Elle retourne un résultat vrai/faux :
    has_capability(CAP,CONTEXTE,UTILISATEUR);


* ''true'' signifie que l'utilisateur est autorisé à effectuer l'action
* CAP est la capacité qui contrôle l'action (par exemple ''mod/quiz:attempt'').
* ''false'' signifie que l'utilisateur n'est pas autorisé à effectuer l'action
* CONTEXTE est le contexte dans lequel la capacité est testée.
* UTILISATEUR est l'utilisateur qui tente d'effectuer l'action.


Le CONTEXT peut être le contexte Système ou tout autre contexte imbriqué de façon arbitraire dans le contexte Système. À l'interne, la fonction utilise une notation analogue à celle des chemins d'accès des fichiers Unix pour représenter les contextes (par exemple, /1/3/4/150). De tels détails ne sont pas nécessaires dans cette discussion.
La fonction retourne un résultat vrai/faux :


Supposons qu'un utilisateur soit sur le point de tenter un test (capacité ''mod/quiz:attempt'') dans le contexte d'un module imbriqué quatre niveaux au-dessous du contexte Système.
* ''true'' signifie que l'utilisateur est autorisé à effectuer l'action ;
* ''false'' signifie que l'utilisateur n'est pas autorisé à effectuer l'action.
 
=== Données utilisées par la fonction ===
 
Supposons que l'utilisateur UTILISATEUR soit sur le point de tenter un test (CAP = ''mod/quiz:attempt'') dans le contexte d'un module imbriqué quatre niveaux au-dessous du contexte Système.


       Système
       Système
Ligne 30 : Ligne 34 :
       Cours
       Cours
         |
         |
        Test  <--- l'utilisateur est ici
      Test  <--- l'utilisateur est ici
 
Le module Test fera appel à la fonction ''has_capability()'' pour déterminer s'il doit permettre à l'utilisateur d'effectuer cette action.
 
La fonction ''has_capability()'' considère les données de permissions suivantes :
 
* les ''[[Définir les rôles|définitions des rôles]]'' (situées dans le contexte Système),
* les ''[[Attribuer des rôles|attributions de rôles]]'' qui peuvent être effectuées dans n'importe lequel des cinq contextes concernés,
* les ''[[Définir des dérogations aux rôles|dérogations aux rôles]]'' ayant été définies dans n'importe lequel des contextes, sauf le contexte Système (il n'y a pas de dérogation de rôles possible dans le contexte Système). 
 
Il est à remarquer qu'il peut y avoir plusieurs rôles attribués et/ou plusieurs dérogations définies dans un même contexte. 
 
La permission pour l'utilisateur de tenter le test ou non dépend des données ci-dessus, ainsi que de l'emplacement de ces données dans la chaîne des contextes.
 
La fonction ''has_capability()'' considère tous les rôles et toutes les dérogations ayant un impact sur UTILISATEUR dans CONTEXTE, mais elle ignore toutes les capacités autres que CAP. Elle ignore notamment :
 
* les rôles qui ne sont pas attribués à l'utilisateur,
* les capacités autres que celles que nous testons et
* les permissions qui ne sont pas définies.
 
Cette simplification nous permet de voir chaque rôle ou chaque dérogation comme une ''simple permission'' ayant l'une des valeurs suivantes
 
    N - Non défini
    A - Autoriser
    P - Empêcher
    X - Interdire
 
Pour indiquer la permission associée à un rôle, nous utilisons la notation suivante : Si le rôle ''R1'' a la permission ''P'', nous écrivons ''R1(P)''.
 
=== Un exemple ===
 
Dans l'exemple de notre test, nous admettons que UTILISATEUR a quatre rôles : ''R1'', ''R2'', ''R3'' et ''R4'', et que chaque rôle a été attribué ou qu'une dérogation a été définie ainsi :
 
    0    Système        <---- Définition des permissions R1(A), R2(N), R3(N), R4(P)
            |                  Attribution du rôle R1
            |
    1    Catégorie A      <-------------- Définition des dérogations R1(N) et R4(N)
            |                         
            |                         
    2  Sous-catégorie B  <---- Attribution des rôles R2 et R3
            |
            |
    3      Cours          <-------------- Définition des dérogations R2(X) et R3(A)
            |
            |
    4      Test          <---- Attribution des rôles R4 et R1
 
Il est à remarquer que le rôle ''R1'' a été attribué dans deux contextes distincts. C'est une pratique inhabituelle, vraisemblablement une erreur, mais comme c'est autorisé dans Moodle, nous devons considérer cette possibilité qui pourrait survenir. En réalité, cet exemple a été construit afin d'explorer les cas limites de l'algorithme. Dans la pratique, le calcul des permissions est trivial et la fonction calcule le résultat que le bon sens et une simple analyse suggèrent (pour une discussion plus complète sur ce sujet, voir [[#Une remarque au sujet de l'algorithme|Une remarque au sujet de l'algorithme]] à la fin de cette page).
 
=== Représentation des données dans un tableau ===
 
Pour afficher de manière concise les données de permission, nous utilisons un tableau comprenant
* une colonne pour chaque attribution de rôle, triées par ordre croissant de profondeur de l'attribution. Les colonnes sont étiquetées avec les noms des rôles ;   
* une rangée pour chaque niveau de contexte, triées par ordre croissant de profondeur de l'imbrication. Les rangées sont étiquetées avec le niveau du contexte.
 
Dans l'exemple du test, ''R1'' est attribué dans le contexte Système. On le place donc dans la 1ère colonne. Les rôles ''R2'' et ''R3'' sont attribués dans le deuxième plus haut contexte. Ils sont donc placés dans les deux colonnes suivantes (leur ordre n'importe pas). Les rôles ''R4'' et ''R1'' sont attribués dans le contexte le plus bas. Nous les plaçons donc en dernier (ici encore, leur ordre n'importe pas). Voici donc notre tableau avec les colonnes et les rangées et leurs étiquettes :
 
        R1  R2  R3  R4  R1
      +------------------------
    0 |
    1 |
    2 |
    3 |
    4 |
 
Nous ajoutons des lignes verticales pour grouper les attributions de rôle effectuées dans le même contexte.
 
        R1  R2  R3  R4  R1
      +-----+---------+--------
    0 |    |        |
    1 |    |        |
    2 |    |        |
    3 |    |        |
    4 |    |        |
 
Nous pouvons maintenant incorporer au tableau les données de permission. Dans la première rangée, nous plaçons les permissions indiquées dans la définition des rôles.
 
        R1  R2  R3  R4  R1
      +-----+---------+--------
    0 |  A  | N    N  | P    A
    1 |    |        |
    2 |    |        |
    3 |    |        |
    4 |    |        |
 
Le reste des données provient des dérogations. Nous plaçons la valeur de chaque dérogation dans
* la colonne correspondant au rôle pour lequel la dérogation est effectuée ;
* la rangée correspondant au niveau dans lequel la dérogation est effectuée.
 
Commençons par ajouter l'une des dérogations :
 
        R1  R2  R3  R4  R1
      +-----+---------+--------
    0 |  A  | N    N  | P    A
    1 |    |        |
    2 |    |        |
    3 |    | X      |
    4 |    |        |
 
Le ''X'' représente la dérogation du rôle ''R2'' effectuée dans le contexte du cours. Ajoutons maintenant le reste des dérogations :
 
        R1  R2  R3  R4  R1
      +-----+---------+--------
    0 |  A  | N    N  | P    A
    1 |  N  |        | N    N
    2 |    |        |
    3 |    | X    A  |
    4 |    |        |
 
Le tableau est maintenant complet. Nous pouvons calculer la permission.
 
=== L'algorithme ===
 
L'algorithme parcourt le tableau de droite à gauche (en commençant par la colonne à l'extrême droite du tableau) et de bas en haut (ligne après ligne, en commençant par la ligne du bas). Les colonnes représentant des attributions de rôles effectuées dans le même contexte (i.e. celles qui ne sont pas séparées par une ligne verticale) sont traitées ensemble. L'algorithme se termine dès qu'une permission effective est obtenue.
 
Dans le tableau de notre exemple, nous considérons donc la suite de permissions ou groupe de permissions suivant :
 
    (N  N) -> (P  A) -> (X  A) -> (N  N) -> (N) -> (A)
 
Voici comment fonctionne l'algorithme :
 
#Si le tableau contient un ''X'', STOP. La permission calculée est ''X''.
#Commencer au bas de la dernière colonne.
#Si nous sommes en haut de la première colonne, STOP. La permission calculée est ''P''.
#Sinon, passer à la permission suivante ou au groupe de permissions suivant.
#Additionner les permissions du groupe en prenant les valeurs numériques suivantes : N = 0, A = +1, P = -1.
#*Si la somme est positive, la permission calculée est ''A'' ; STOP.
#*Si la somme est négative, la permission calculée est ''P'' ; STOP.
#*Si la somme est nulle, aller à l'étape 3.
 
L'algorithme se termine soit :
* quand un résultat déterminant est obtenu,
* quand la ligne du haut de la première colonne est atteinte sans obtenir de résultat déterminant.
 
=== Application de l'algorithme à notre exemple ===
 
Si nous appliquons l'algorithme avec les données de notre exemple, nous nous arrêtons tout de suite à l'étape 1 avec une permission calculée ''X''. Pour rendre l'exemple plus intéressant, remplaçons le ''X'' par un ''P' :


Le module test fera appel à la fonction ''has_capability'' pour voir s'il doit permettre à l'utilisateur d'effectuer cette action.
        R1  R2  R3  R4  R1
      +-----+---------+--------
    0 |  A  | A    P  | P    A
    1 |  N  |        | N    N
    2 |    |        |
    3 |    | P    A  |
    4 |    |        |


The function considers the following permissions data:
et effectuons maintenant les étapes de l'algorithme.


* ''Role definitions'' (these are in the System context)
* Il n'y a pas de ''X'' dans le tableau.
* ''Role assignments'' which have been made in any of the five contexts
* Commencer au bas de la dernière colonne.
* ''Role overrides'' which may occur in any of the contexts except System (there is no concept of override in System).
* Passer au groupe de permissions suivant.
* ''N'' + ''N'' = 0
* La somme est 0, passer au groupe de permissions suivant.
* ''P'' + ''A'' = 0.
* La somme est 0, passer au groupe de permissions suivant.
* ''P'' + ''A'' = 0.
* La somme est 0, passer au groupe de permissions suivant.
* ''A'' + ''P'' = 0.
* La somme est 0, passer au groupe de permissions suivant.
* ''N'' = 0.
* La somme est 0, passer au groupe de permissions suivant.
* ''A'' = +1.
* La somme est non-nulle, STOP. La permission calculée est ''A''.


Note that there may be multiple assignments and/or overrides in any single context.
La permission calculée est ''A'', la fonction retourne la valeur ''true'', permettant ainsi à UTILISATEUR d'effectuer l'action.


Whether or not the user can attempt the quiz is a function of the data, as well as the location of the data in the context chain.
Cependant, si la permission calculée avait été ''P'' ou ''X'', la fonction n'aurait pas retourné tout de suite ''false''. Elle testerait encore si UTILISATEUR a la capacité ''[[Capabilities/moodle/site:doanything|moodle/site:doanything]] = A'' (car cette permission a priorité sur toutes les autres). La fonction effectue ce contrôle en s'auto-appelant :


The function ignores any data that isn't used in the computation.  It ignores
        résultat final = has_capability(moodle/site:doanything, CONTEXTE, UTILISATEUR);


* roles that aren't assigned to the user
== Une remarque au sujet de l'algorithme ==
* capabilities other than one we're testing
* permissions that are Not set. 


After ignoring the above data, we are left with a very simple "data slice" consisting of just those permissions for the capability we're testing, in which all values are either Allow (A), Prevent (P), or Prohibit (X).  This data can be represented in a neat tabular form, resembling an addition problem. For our quiz example, suppose we have
Plus haut, nous avons dit que l'algorithme "calcule le résultat que le bon sens et une simple analyse suggèrent". Mais qu'est-ce que notre bon sens attend ? L'intuition nous dit que les permissions les plus proches de l'utilisateur ont plus de poids que les permissions plus éloignées. C'est la raison pour laquelle le tableau est construit de cette façon, et pourquoi l'algorithme parcourt le tableau dans cet ordre. La dernière colonne du tableau représente les attributions de rôle les plus proches de l'utilisateur. L'avant-dernière colonne représente les attributions de rôle un peu plus éloignées, etc. C'est pour cela que l'algorithme considère les colonnes de droite à gauche. Dans une même colonne, l'algorithme recherche en montant, afin de donner plus de poids aux dérogations les plus proches de l'utilisateur. Là encore, cela correspond à notre intuition sur les dérogations. S'il n'y a pas de dérogation dans une colonne (ou si les dérogations sont toutes sur Non défini), c'est la permission de la définition du rôle qui est utilisée.


    P  A  P
== Obtenir les résultats que vous attendez ==
          A
    P  A  X
    A    P
      P  A
    --------
      ?   


The top row represents the permissions in the role definitions, one permission from each role. In the example, you can see that the user is currently assigned three roles. The remaining rows represent the overrides.  In the example, you can see that the user has
Le calcul a plus de probabilité de calculer "le résultat que le bon sens et une simple analyse suggèrent" si vous conservez vos permissions aussi simples que possible. Pour cette raison, nous recommandons les règles suivantes lors de la définition des rôles et de la mise en place de dérogations. Si vous comprenez la description du calcul ci-dessus, vous comprendrez pourquoi ces règles font sens.


* one override in category A,
=== Lors de la définition des rôles ===
* three overrides in the category B
* two overrides the course
* two overrides in the quiz itself. 


When representing a complex example like this, it is convenient to line up the override permissions under the role that's being overridden, but it is not necessary to do so because we don't "add" permissions in columns the way we add numbers.
... utiliser ''Autoriser'' (A) pour les actions que vous voulez que le rôle puisse faire et utiliser ''Non défini'' (N) pour les actions dont vous ne vous préoccupez pas (qui devraient être une majorité).


We will "add" the permissions in some sense and write the result below the horizontal line.  The result, which we call the ''computed permission'', will be either ''A'', ''P'', or ''X''.  The function will return ''true'' or ''false'' based on the computed permission.
=== Lors de dérogations aux rôles ===


Before we start "adding," check the data to see if it contains a prohibit ''X'' anywhere. If it does, we're done.  The computed permission is ''X''.  For our example...
... laisser la permission de toutes les capacités sur ''Hériter'' (N), sauf celles, peu nombreuses, que vous voulez modifier. Pour celles-ci, utiliser ''Autoriser'' (A) pour les actions à autoriser, et ''Empêcher'' (P) pour celle que vous voulez empêcher.


    P  A  P
=== N'utilisez interdire que pour des rôles spéciaux ===
          A
    P  A  X
    A    P
      P  A
    --------
      X    <----- computed permission


La permission ''Interdire'' (X) n'existe que pour mettre en place le scénario suivant. Admettons que vous avez un étudiant malveillant qui poste incessamment des contenus inappropriés sur votre site Moodle. Vous devez pouvoir lui retirer sa capacité de contribuer aux discussions publiques jusqu'à ce qu'il promette de ne plus le faire, mais entre-temps, vous ne pouvez pas l'empêcher complètement de consulter les ressources, d'effectuer les tests, etc. parce qu'il doit continuer à étudier. C'est pourquoi vous devez avoir un moyen de bloquer son accès aux capacités comme ''mod/forum:post'' de sorte que le blocage ne puisse pas être court-circuité. Vous pouvez le faire en créant un nouveau rôle ''Étudiant malveillant'' qui définit cette capacité à ''Interdire'' (X). Si vous avez des problèmes avec un participant, vous lui attribuez temporairement ce rôle, soit dans le contexte du site, soit dans le contexte d'un cours.


If there is no ''X'', the addition algorithm must be used. Unlike normal addition, the addition algorithm
C'est en principe la seule raison d'utiliser la permission ''Interdire'' (X).


* starts on the bottom line and works its way up
== Un exemple pratique ==
* considers one whole line at a time (rather than working in columns)
* may stop with a result before reaching the top line.


Here is the algorithm:
Un utilisateur possède le rôle de ''Créateur de cours'', qui lui a été attribué dans la Sous-catégorie B. Il crée un cours (devenant ainsi ''Enseignant'' dans ce cours), puis crée une leçon dans ce cours. Il veut modifier la leçon (la modification des leçons est contrôlée par la capacité ''mod/lesson:edit''). Voici les données de permission :


#Start on the bottom line.
#If there is only one permission on the line, take its value as the computed permission and STOP
#If there are two more permissions on the line, add them using the following numerical equivalents: A = +1, P = -1
##If the sum is positive, the computed permission is ''A''. STOP 
##If the sum is negative, the computed permission is ''P''. STOP 
##If the sum is zero, the calculation is inconclusive.  If this this is already the top line, the computed permission is ''P''; STOP.  Otherwise, move to the line above and go to step 2.


Notice that the algorithm stops when either (1) a conclusive result is obtained, or (2) the top line is reached without obtaining a conclusive result.
    0    Système        <---- Définition des permissions : Utilisateur authentifié(N),
                                                            Créateur de cours(N), Enseignant(A)
            |                  Attribution du rôle Utilisateur authentifié
            |
    1    Catégorie A
            |                         
            |                         
    2 Sous-catégorie B  <---- Attribution du rôle Créateur de cours
            |
            |
    3      Cours          <---- Attribution du rôle Enseignant
            |
            |
    4      Leçon          <---- l'utilisateur essaie de modifier la leçon


Let's take our original example, replacing the ''X'' by ''P'' to make it more interesting:
Nous construisons le tableau et le remplissons avec les données de permission.


    P  A P
        U. auth.    Resp. Enseignant
          A
      +----------+--------+----------
     A P
     0 |    N    |  N    |    A  
     A     P
     1 |          |        |
       P  A
     2 |          |        |
     --------
    3 |          |       |     
      
     4 |          |       |


Now carry out the steps of the algorithm
Il n'y a pas de dérogation. Le tableau ne contient donc des données que dans la première rangée. L'algorithme calcule rapidement une permission ''A'' et la fonction retourne ''true''. L'utilisateur a l'autorisation de modifier la leçon !


* There are two permissions on line 5
Supposons maintenant qu'au niveau de la leçon, une dérogation ait été définie pour le rôle ''Enseignant'', dérogation dont la teneur est ''mod/lesson:edit = P''. Le tableau devient dans ce cas
* Since ''P + A = 0'', the result is inconclusive and we must look at line 4.
* There are two permissions on line 4.
* Since ''A + P = 0'', the result is inconclusive and we must look at line 3.
* There are three permissions on line 3.
* Since ''A + P + P = -1'' we have a conclusive result!  The computed permission is ''P''.  


    P  A P
        U. auth.    Resp. Enseignant
          A
      +----------+--------+----------
    P  A  P
    0 |    N    |  N    |    A
    A    P
    1 |          |        |
      P  A
    2 |          |        |
    --------
    3 |          |        |       
      P      <----- computed permission
    4 |          |        |    P               


If the computed permission had been ''A'', the function would have returned ''true'' without further ado, allowing the user to perform the action.
et il est clair que l'utilisateur n'a plus le droit de modifier la leçon.


However if the computed permission is ''P'' or ''X'', the function does not immediately return ''false''.  Rather, it tests if the user has ''moodle/site:doanything = Allow'' (since this permission trumps all others). The function does this by calling itself:
Mais supposons maintenant que l'administrateur ait décidé de définir au niveau de la sous-catégorie B une dérogation pour le rôle ''Créateur de cours'', dérogation dont la teneur est aussi ''mod/lesson:edit = P''. Nous avons le tableau suivant.


         final result = has_capability(moodle/site:doanything, CONTEXT, USER);
         U. auth.    Resp.  Enseignant
      +----------+--------+----------
    0 |    N    |  N    |    A
    1 |          |        |
    2 |          |  P    |
    3 |          |        |     
    4 |          |        |                     


À la surprise générale, on observe que l'utilisateur est encore autorisé à modifier la leçon ! Si vous avez compris le contenu de cette page, vous ne devriez pas être surpris, et vous devriez être capable d'expliquer pourquoi ce cas se produit.


==Voir aussi ==
== Voir aussi ==


*Discussions [http://moodle.org/mod/forum/discuss.php?d=90140 Logged in: what role am I?] et [http://moodle.org/mod/forum/discuss.php?d=66782 What happens if a user has multiple roles in a course?] dans les forums de Using Moodle (en anglais)
* Les discussions [http://moodle.org/mod/forum/discuss.php?d=90140 Logged in: what role am I?] et [http://moodle.org/mod/forum/discuss.php?d=66782 What happens if a user has multiple roles in a course?] dans les forums de Using Moodle (en anglais)
* Le script de debugage des droits sur les permissions [[:en:The rolesdebug.php roles debugging script|rolesdebug.php]] (en anglais)


[[Category:Rôles]]
[[Catégorie:Rôles]]


[[en:How permissions are calculated]]
[[en:How permissions are calculated]]

Dernière version du 9 novembre 2009 à 14:27

Une des questions posées très fréquemment est : Quelles permissions possède un utilisateur pour un contexte donné ?

Cette page explique la fonction principale de Moodle utilisée pour répondre à cette question. Cette fonction est has_capability(). Elle se trouve dans le fichier lib/accesslib.php. Cette fonction implémente les règles pour calculer la "somme" des permissions de multiples rôles et dérogations. Pour un utilisateur donné, une capacité, et un contexte, la fonction renvoi true (vrai) si l'utilisateur est autorisé à effectuer l'action contrôlée par la capacité dans le contexte donné, et false (faux) sinon.

Cette page est écrite autant pour les non programmeurs que pour les programmeurs. Elle décrit ce que la fonction fait, pas comment. Le comment est compliqué, alors que le quoi est relativement simple !

Remarquez que la fonction n'essaie pas de répondre à la grande question posée dans la première phrase de cette page. Elle répond plutôt à la petite question Un utilisateur peut-il ici faire l'action correspondant à la capacité CAP ? Moodle ne calcule jamais la totalité des permissions d'un utilisateur. Une telle opération serait très coûteuse et n'apporterait pas grand chose, puisque la plupart des permissions ne seraient jamais testées. Moodle calcule donc les permissions à la demande. Moodle ne place pas en cache les permissions calculées, mais les recalcule chaque fois qu'il est nécessaire de les tester. C'est la raison pour laquelle les attributions de rôles et les dérogations prennent effet immédiatement (ce n'était pas le cas dans Moodle 1.7 et 1.8).

Le calcul

Lorsqu'un utilisateur tente d'effectuer une action contrôlée par une capacité, Moodle appelle la fonction has_capability pour voir si cette action doit être autorisée. La fonction est appelée ainsi :

   has_capability(CAP,CONTEXTE,UTILISATEUR);
  • CAP est la capacité qui contrôle l'action (par exemple mod/quiz:attempt).
  • CONTEXTE est le contexte dans lequel la capacité est testée.
  • UTILISATEUR est l'utilisateur qui tente d'effectuer l'action.

La fonction retourne un résultat vrai/faux :

  • true signifie que l'utilisateur est autorisé à effectuer l'action ;
  • false signifie que l'utilisateur n'est pas autorisé à effectuer l'action.

Données utilisées par la fonction

Supposons que l'utilisateur UTILISATEUR soit sur le point de tenter un test (CAP = mod/quiz:attempt) dans le contexte d'un module imbriqué quatre niveaux au-dessous du contexte Système.

     Système
        |
    Catégorie A
        |					      
   Sous-catégorie B
        |
      Cours
        |
      Test  <--- l'utilisateur est ici

Le module Test fera appel à la fonction has_capability() pour déterminer s'il doit permettre à l'utilisateur d'effectuer cette action.

La fonction has_capability() considère les données de permissions suivantes :

  • les définitions des rôles (situées dans le contexte Système),
  • les attributions de rôles qui peuvent être effectuées dans n'importe lequel des cinq contextes concernés,
  • les dérogations aux rôles ayant été définies dans n'importe lequel des contextes, sauf le contexte Système (il n'y a pas de dérogation de rôles possible dans le contexte Système).

Il est à remarquer qu'il peut y avoir plusieurs rôles attribués et/ou plusieurs dérogations définies dans un même contexte.

La permission pour l'utilisateur de tenter le test ou non dépend des données ci-dessus, ainsi que de l'emplacement de ces données dans la chaîne des contextes.

La fonction has_capability() considère tous les rôles et toutes les dérogations ayant un impact sur UTILISATEUR dans CONTEXTE, mais elle ignore toutes les capacités autres que CAP. Elle ignore notamment :

  • les rôles qui ne sont pas attribués à l'utilisateur,
  • les capacités autres que celles que nous testons et
  • les permissions qui ne sont pas définies.

Cette simplification nous permet de voir chaque rôle ou chaque dérogation comme une simple permission ayant l'une des valeurs suivantes

   N - Non défini
   A - Autoriser
   P - Empêcher
   X - Interdire

Pour indiquer la permission associée à un rôle, nous utilisons la notation suivante : Si le rôle R1 a la permission P, nous écrivons R1(P).

Un exemple

Dans l'exemple de notre test, nous admettons que UTILISATEUR a quatre rôles : R1, R2, R3 et R4, et que chaque rôle a été attribué ou qu'une dérogation a été définie ainsi :

   0     Système         <---- Définition des permissions R1(A), R2(N), R3(N), R4(P)
            |                  Attribution du rôle R1
            |
   1    Catégorie A      <-------------- Définition des dérogations R1(N) et R4(N)
            |                          
            |                          
   2  Sous-catégorie B   <---- Attribution des rôles R2 et R3
            |
            |
   3      Cours          <-------------- Définition des dérogations R2(X) et R3(A)
            |
            |
   4      Test           <---- Attribution des rôles R4 et R1

Il est à remarquer que le rôle R1 a été attribué dans deux contextes distincts. C'est une pratique inhabituelle, vraisemblablement une erreur, mais comme c'est autorisé dans Moodle, nous devons considérer cette possibilité qui pourrait survenir. En réalité, cet exemple a été construit afin d'explorer les cas limites de l'algorithme. Dans la pratique, le calcul des permissions est trivial et la fonction calcule le résultat que le bon sens et une simple analyse suggèrent (pour une discussion plus complète sur ce sujet, voir Une remarque au sujet de l'algorithme à la fin de cette page).

Représentation des données dans un tableau

Pour afficher de manière concise les données de permission, nous utilisons un tableau comprenant

  • une colonne pour chaque attribution de rôle, triées par ordre croissant de profondeur de l'attribution. Les colonnes sont étiquetées avec les noms des rôles ;
  • une rangée pour chaque niveau de contexte, triées par ordre croissant de profondeur de l'imbrication. Les rangées sont étiquetées avec le niveau du contexte.

Dans l'exemple du test, R1 est attribué dans le contexte Système. On le place donc dans la 1ère colonne. Les rôles R2 et R3 sont attribués dans le deuxième plus haut contexte. Ils sont donc placés dans les deux colonnes suivantes (leur ordre n'importe pas). Les rôles R4 et R1 sont attribués dans le contexte le plus bas. Nous les plaçons donc en dernier (ici encore, leur ordre n'importe pas). Voici donc notre tableau avec les colonnes et les rangées et leurs étiquettes :

        R1   R2   R3   R4   R1
     +------------------------
   0 |
   1 |
   2 |
   3 |
   4 |

Nous ajoutons des lignes verticales pour grouper les attributions de rôle effectuées dans le même contexte.

        R1   R2   R3   R4   R1
     +-----+---------+--------
   0 |     |         |
   1 |     |         |
   2 |     |         |
   3 |     |         |
   4 |     |         |

Nous pouvons maintenant incorporer au tableau les données de permission. Dans la première rangée, nous plaçons les permissions indiquées dans la définition des rôles.

        R1   R2   R3   R4   R1
     +-----+---------+--------
   0 |  A  | N    N  | P    A
   1 |     |         |
   2 |     |         |
   3 |     |         |
   4 |     |         |

Le reste des données provient des dérogations. Nous plaçons la valeur de chaque dérogation dans

  • la colonne correspondant au rôle pour lequel la dérogation est effectuée ;
  • la rangée correspondant au niveau dans lequel la dérogation est effectuée.

Commençons par ajouter l'une des dérogations :

        R1   R2   R3   R4   R1
     +-----+---------+--------
   0 |  A  | N    N  | P    A
   1 |     |         |
   2 |     |         |
   3 |     | X       |
   4 |     |         |

Le X représente la dérogation du rôle R2 effectuée dans le contexte du cours. Ajoutons maintenant le reste des dérogations :

        R1   R2   R3   R4   R1
     +-----+---------+--------
   0 |  A  | N    N  | P    A
   1 |  N  |         | N    N
   2 |     |         |
   3 |     | X    A  |
   4 |     |         |

Le tableau est maintenant complet. Nous pouvons calculer la permission.

L'algorithme

L'algorithme parcourt le tableau de droite à gauche (en commençant par la colonne à l'extrême droite du tableau) et de bas en haut (ligne après ligne, en commençant par la ligne du bas). Les colonnes représentant des attributions de rôles effectuées dans le même contexte (i.e. celles qui ne sont pas séparées par une ligne verticale) sont traitées ensemble. L'algorithme se termine dès qu'une permission effective est obtenue.

Dans le tableau de notre exemple, nous considérons donc la suite de permissions ou groupe de permissions suivant :

   (N  N) -> (P  A) -> (X  A) -> (N  N) -> (N) -> (A)

Voici comment fonctionne l'algorithme :

  1. Si le tableau contient un X, STOP. La permission calculée est X.
  2. Commencer au bas de la dernière colonne.
  3. Si nous sommes en haut de la première colonne, STOP. La permission calculée est P.
  4. Sinon, passer à la permission suivante ou au groupe de permissions suivant.
  5. Additionner les permissions du groupe en prenant les valeurs numériques suivantes : N = 0, A = +1, P = -1.
    • Si la somme est positive, la permission calculée est A ; STOP.
    • Si la somme est négative, la permission calculée est P ; STOP.
    • Si la somme est nulle, aller à l'étape 3.

L'algorithme se termine soit :

  • quand un résultat déterminant est obtenu,
  • quand la ligne du haut de la première colonne est atteinte sans obtenir de résultat déterminant.

Application de l'algorithme à notre exemple

Si nous appliquons l'algorithme avec les données de notre exemple, nous nous arrêtons tout de suite à l'étape 1 avec une permission calculée X. Pour rendre l'exemple plus intéressant, remplaçons le X par un P' :

        R1   R2   R3   R4   R1
     +-----+---------+--------
   0 |  A  | A    P  | P    A
   1 |  N  |         | N    N
   2 |     |         |
   3 |     | P    A  |
   4 |     |         |

et effectuons maintenant les étapes de l'algorithme.

  • Il n'y a pas de X dans le tableau.
  • Commencer au bas de la dernière colonne.
  • Passer au groupe de permissions suivant.
  • N + N = 0
  • La somme est 0, passer au groupe de permissions suivant.
  • P + A = 0.
  • La somme est 0, passer au groupe de permissions suivant.
  • P + A = 0.
  • La somme est 0, passer au groupe de permissions suivant.
  • A + P = 0.
  • La somme est 0, passer au groupe de permissions suivant.
  • N = 0.
  • La somme est 0, passer au groupe de permissions suivant.
  • A = +1.
  • La somme est non-nulle, STOP. La permission calculée est A.

La permission calculée est A, la fonction retourne la valeur true, permettant ainsi à UTILISATEUR d'effectuer l'action.

Cependant, si la permission calculée avait été P ou X, la fonction n'aurait pas retourné tout de suite false. Elle testerait encore si UTILISATEUR a la capacité moodle/site:doanything = A (car cette permission a priorité sur toutes les autres). La fonction effectue ce contrôle en s'auto-appelant :

       résultat final = has_capability(moodle/site:doanything, CONTEXTE, UTILISATEUR);

Une remarque au sujet de l'algorithme

Plus haut, nous avons dit que l'algorithme "calcule le résultat que le bon sens et une simple analyse suggèrent". Mais qu'est-ce que notre bon sens attend ? L'intuition nous dit que les permissions les plus proches de l'utilisateur ont plus de poids que les permissions plus éloignées. C'est la raison pour laquelle le tableau est construit de cette façon, et pourquoi l'algorithme parcourt le tableau dans cet ordre. La dernière colonne du tableau représente les attributions de rôle les plus proches de l'utilisateur. L'avant-dernière colonne représente les attributions de rôle un peu plus éloignées, etc. C'est pour cela que l'algorithme considère les colonnes de droite à gauche. Dans une même colonne, l'algorithme recherche en montant, afin de donner plus de poids aux dérogations les plus proches de l'utilisateur. Là encore, cela correspond à notre intuition sur les dérogations. S'il n'y a pas de dérogation dans une colonne (ou si les dérogations sont toutes sur Non défini), c'est la permission de la définition du rôle qui est utilisée.

Obtenir les résultats que vous attendez

Le calcul a plus de probabilité de calculer "le résultat que le bon sens et une simple analyse suggèrent" si vous conservez vos permissions aussi simples que possible. Pour cette raison, nous recommandons les règles suivantes lors de la définition des rôles et de la mise en place de dérogations. Si vous comprenez la description du calcul ci-dessus, vous comprendrez pourquoi ces règles font sens.

Lors de la définition des rôles

... utiliser Autoriser (A) pour les actions que vous voulez que le rôle puisse faire et utiliser Non défini (N) pour les actions dont vous ne vous préoccupez pas (qui devraient être une majorité).

Lors de dérogations aux rôles

... laisser la permission de toutes les capacités sur Hériter (N), sauf celles, peu nombreuses, que vous voulez modifier. Pour celles-ci, utiliser Autoriser (A) pour les actions à autoriser, et Empêcher (P) pour celle que vous voulez empêcher.

N'utilisez interdire que pour des rôles spéciaux

La permission Interdire (X) n'existe que pour mettre en place le scénario suivant. Admettons que vous avez un étudiant malveillant qui poste incessamment des contenus inappropriés sur votre site Moodle. Vous devez pouvoir lui retirer sa capacité de contribuer aux discussions publiques jusqu'à ce qu'il promette de ne plus le faire, mais entre-temps, vous ne pouvez pas l'empêcher complètement de consulter les ressources, d'effectuer les tests, etc. parce qu'il doit continuer à étudier. C'est pourquoi vous devez avoir un moyen de bloquer son accès aux capacités comme mod/forum:post de sorte que le blocage ne puisse pas être court-circuité. Vous pouvez le faire en créant un nouveau rôle Étudiant malveillant qui définit cette capacité à Interdire (X). Si vous avez des problèmes avec un participant, vous lui attribuez temporairement ce rôle, soit dans le contexte du site, soit dans le contexte d'un cours.

C'est en principe la seule raison d'utiliser la permission Interdire (X).

Un exemple pratique

Un utilisateur possède le rôle de Créateur de cours, qui lui a été attribué dans la Sous-catégorie B. Il crée un cours (devenant ainsi Enseignant dans ce cours), puis crée une leçon dans ce cours. Il veut modifier la leçon (la modification des leçons est contrôlée par la capacité mod/lesson:edit). Voici les données de permission :


   0     Système         <---- Définition des permissions : Utilisateur authentifié(N),
                                                            Créateur de cours(N), Enseignant(A)
            |                  Attribution du rôle Utilisateur authentifié
            |
   1    Catégorie A
            |                          
            |                          
   2  Sous-catégorie B   <---- Attribution du rôle Créateur de cours
            |
            |
   3      Cours          <---- Attribution du rôle Enseignant
            |
            |
   4      Leçon          <---- l'utilisateur essaie de modifier la leçon

Nous construisons le tableau et le remplissons avec les données de permission.

       U. auth.    Resp.  Enseignant
     +----------+--------+----------
   0 |     N    |   N    |    A   
   1 |          |        | 
   2 |          |        |
   3 |          |        |       
   4 |          |        |

Il n'y a pas de dérogation. Le tableau ne contient donc des données que dans la première rangée. L'algorithme calcule rapidement une permission A et la fonction retourne true. L'utilisateur a l'autorisation de modifier la leçon !

Supposons maintenant qu'au niveau de la leçon, une dérogation ait été définie pour le rôle Enseignant, dérogation dont la teneur est mod/lesson:edit = P. Le tableau devient dans ce cas

       U. auth.    Resp.  Enseignant
     +----------+--------+----------
   0 |     N    |   N    |    A
   1 |          |        |
   2 |          |        | 
   3 |          |        |         
   4 |          |        |    P                

et il est clair que l'utilisateur n'a plus le droit de modifier la leçon.

Mais supposons maintenant que l'administrateur ait décidé de définir au niveau de la sous-catégorie B une dérogation pour le rôle Créateur de cours, dérogation dont la teneur est aussi mod/lesson:edit = P. Nous avons le tableau suivant.

       U. auth.    Resp.  Enseignant
     +----------+--------+----------
   0 |     N    |   N    |    A
   1 |          |        | 
   2 |          |   P    | 
   3 |          |        |      
   4 |          |        |                       

À la surprise générale, on observe que l'utilisateur est encore autorisé à modifier la leçon ! Si vous avez compris le contenu de cette page, vous ne devriez pas être surpris, et vous devriez être capable d'expliquer pourquoi ce cas se produit.

Voir aussi