Skip to Content
MoodlePartie 2 — Administration, rôles et permissionsContextes, rôles et capabilities : le modèle de permissions de Moodle

Chapitre 1 — Contextes, rôles et capabilities : le modèle de permissions de Moodle

⏱️ TL;DR

  • Toute action dans Moodle se résout par une seule question : « cet utilisateur a-t-il cette capability dans ce contexte ? ».
  • Les contextes forment un arbre (Système, Utilisateur, Catégorie, Cours, Module, Bloc), matérialisé en base par mdl_context et son champ path ; l’héritage est strictement descendant.
  • Un rôle est un paquet de permissions sur des capabilities : défini globalement une seule fois, assigné localement (utilisateur + rôle + contexte, table mdl_role_assignments).
  • Une capability est une action atomique namespacée (mod/quiz:attempt), déclarée par le cœur ou un plugin, avec un niveau de contexte minimal et des indicateurs de risque (XSS, dataloss…).
  • Quatre permissions : Not set (abstention/héritage), Allow, Prevent (refus négociable), Prohibit (veto absolu, non surchargeable). Refus par défaut en l’absence de tout Allow.
  • Algorithme en 4 étapes : chaîne de contextes → rôles de l’utilisateur sur la chaîne → valeur la plus spécifique par rôle → agrégation entre rôles (un Prohibit → non ; sinon un Allow → oui ; sinon non).
  • Verticalement, la spécificité tranche ; horizontalement, Allow bat Prevent — mais rien ne bat Prohibit.
  • Les overrides surchargent un rôle dans un contexte : c’est la réponse aux besoins locaux ; ils ciblent des rôles, jamais des individus.
  • L’administrateur n’est pas un rôle : c’est un statut hors modèle qui court-circuite les vérifications — ne testez jamais des permissions en tant qu’admin.
  • Outil de diagnostic n°1 : l’écran « Vérifier les permissions », disponible dans chaque contexte.

🎯 Objectifs

À la fin de ce chapitre, vous saurez :

  • expliquer et articuler les quatre briques du modèle : contexte, rôle, capability, permission ;
  • dérouler l’algorithme de résolution de permissions sur n’importe quel cas concret (rôles multiples, overrides, Prohibit) ;
  • assigner un rôle et poser un override au bon niveau de l’arbre via l’interface d’administration, en appliquant le principe du moindre privilège ;
  • diagnostiquer un problème de permissions avec « Vérifier les permissions » et les tables sous-jacentes ;
  • transposer tout le modèle dans votre vocabulaire de développeur web (RBAC, claims, cascade CSS, React Context).

Introduction : pourquoi ce chapitre est LE chapitre fondamental

Si vous ne deviez retenir qu’un seul chapitre de toute cette documentation avant de toucher à quoi que ce soit dans Moodle, ce serait celui-ci. Le modèle de permissions de Moodle — le triptyque contexte / rôle / capability — irrigue absolument tout le reste de la plateforme : chaque page affichée, chaque bouton visible ou masqué, chaque appel de web service, chaque plugin que vous développerez plus tard passe, à un moment ou à un autre, par une question unique : « cet utilisateur a-t-il cette capability dans ce contexte ? ».

Venant du monde Next.js/React, vous avez probablement déjà implémenté de l’authentification (NextAuth, Clerk, Auth0…) et de l’autorisation (un middleware qui vérifie un rôle dans un JWT, un composant <RequireRole role="admin">, une table permissions maison). Moodle a résolu ce problème il y a vingt ans, à une échelle et avec une granularité qui dépassent largement ce qu’on trouve dans la plupart des applications web : des centaines de capabilities (capacités), des rôles entièrement redéfinissables, et surtout une hiérarchie de contextes dans laquelle les permissions se propagent et se surchargent, un peu comme la cascade CSS ou le Context API de React.

Ce chapitre est fonctionnel : nous allons tout faire et tout comprendre via l’interface d’administration web. Aucune ligne de PHP ici — le code viendra dans les parties développeur. En revanche, nous nous autoriserons quelques apartés sur le modèle de données sous-jacent (les tables mdl_context, mdl_role, mdl_role_assignments, mdl_role_capabilities…), car pour un développeur, voir les tables aide énormément à démystifier la magie.

À la fin de ce chapitre, vous saurez :

  • expliquer ce qu’est un contexte, un rôle, une capability et une permission, et comment ils s’articulent ;
  • dérouler mentalement l’algorithme de résolution de permissions de Moodle sur n’importe quel cas, y compris les conflits entre rôles multiples ;
  • utiliser l’interface d’administration pour définir des rôles, les assigner dans un contexte, et surcharger (override) des permissions localement ;
  • transposer tout ce modèle dans votre vocabulaire de développeur web (RBAC, claims, cascade CSS, React Context).

💡 Pour un dev React : gardez cette image en tête pendant tout le chapitre. Le modèle de permissions de Moodle, c’est comme si vous combiniez RBAC (des rôles qui regroupent des permissions), React Context (des valeurs héritées de l’arbre des composants, surchargeables par un Provider local) et la cascade CSS (des règles qui se combinent selon la spécificité, avec un !important absolu appelé Prohibit). Chaque section de ce chapitre viendra enrichir cette analogie.


1. Pourquoi un modèle de permissions aussi riche ?

1.1 Le problème à résoudre : le multi-tenant pédagogique

Une plateforme Moodle typique n’est pas « une application avec des admins et des utilisateurs ». C’est un empilement d’organisations imbriquées :

  • Une université héberge des facultés (catégories de cours), qui contiennent des départements (sous-catégories), qui contiennent des cours, qui contiennent des activités (quiz, forums, devoirs…) et des blocs.
  • Une même personne physique peut être enseignante dans un cours, étudiante dans un autre (formation continue), responsable de toute une catégorie, et simple utilisatrice authentifiée partout ailleurs.
  • Un parent doit pouvoir consulter les notes de son enfant — et uniquement de son enfant — sans rien voir d’autre.
  • Un tuteur externe doit pouvoir corriger les devoirs d’un seul groupe, dans une seule activité, pendant un seul semestre.

Un système binaire « admin / user », ou même un RBAC plat à cinq rôles globaux, explose immédiatement face à ces besoins. Il faut :

  1. De la granularité fonctionnelle : ne pas dire « ce rôle peut gérer les cours », mais « ce rôle peut démarrer une discussion de forum, tenter un quiz, voir les notes cachées, supprimer une activité »… Moodle expose ainsi plusieurs centaines de capabilities distinctes (environ 700 dans une installation standard, davantage avec des plugins).
  2. De la granularité spatiale : le même rôle « Enseignant » ne doit s’appliquer qu’à l’endroit où la personne enseigne. D’où la notion de contexte : un rôle est défini une fois globalement, mais assigné localement, dans un nœud précis de l’arbre du site.
  3. De la surcharge locale : dans ce forum précis, les étudiants ne doivent pas pouvoir répondre (forum d’annonces) ; dans ce cours précis, cet étudiant-là doit exceptionnellement pouvoir noter ses pairs. D’où les overrides (dérogations/surcharges) de permissions par contexte.

1.2 Les trois briques et leur articulation

Le modèle tient en une phrase que vous devriez apprendre par cœur :

Un rôle est un ensemble de permissions sur des capabilities ; il est défini globalement mais assigné à un utilisateur dans un contexte ; les permissions héritent le long de l’arbre des contextes et peuvent être surchargées localement.

Décomposons le vocabulaire, que nous approfondirons section par section :

TermeDéfinition courteAnalogie dev web
Context (contexte)Un « lieu » de la plateforme : le site, une catégorie, un cours, une activité, un bloc, un utilisateur. Les contextes forment un arbre.Un nœud de l’arbre React ; un scope.
Capability (capacité)Une action atomique nommée, ex. mod/quiz:attempt (« tenter un quiz »).Une permission fine dans une ACL ; un claim ; un scope OAuth.
PermissionLa valeur qu’un rôle donne à une capability : Not set, Allow, Prevent ou Prohibit.La valeur d’une règle CSS : héritée, définie, annulée, ou !important.
Role (rôle)Un paquet nommé de couples capability → permission (ex. « Enseignant », « Étudiant »).Un rôle RBAC ; un preset de claims.
Role assignment (attribution de rôle)Le fait de donner un rôle à un utilisateur dans un contexte précis.<PermissionsProvider role="teacher"> posé à un endroit précis de l’arbre.
Override (dérogation)La surcharge locale, dans un contexte, de la permission d’une capability pour un rôle.Une règle CSS plus spécifique ; un Provider React qui redéfinit une valeur héritée.

⚠️ Piège : en français, l’interface Moodle et la documentation utilisent parfois « permission » de façon ambiguë, tantôt pour désigner la valeur (Allow/Prevent…), tantôt pour l’ensemble du système (« les permissions du cours »). Dans ce chapitre, permission = la valeur parmi Not set / Allow / Prevent / Prohibit, et rien d’autre. La « chose » sur laquelle porte la permission est toujours une capability.

📚 Aller plus loin : la page de référence côté développeur est « Roles and permissions » sur moodledev.io (https://moodledev.io/docs/apis/subsystems/roles ), et côté administrateur les pages « Rôles et permissions » sur docs.moodle.org/fr. Elles reprennent exactement les concepts de ce chapitre, en anglais et avec le détail des API.


2. Les contextes : la géographie de Moodle

2.1 Définition

Un context (contexte) est un espace de la plateforme dans lequel des rôles peuvent être assignés et des permissions évaluées. Chaque « objet conteneur » de Moodle possède exactement un contexte : le site en a un, chaque catégorie de cours en a un, chaque cours, chaque activité, chaque bloc, et — c’est plus surprenant — chaque utilisateur.

Les contextes forment un arbre dont la racine est le contexte Système. Toute vérification de permission se fait dans un contexte donné, et la réponse dépend des rôles de l’utilisateur dans ce contexte et dans tous ses ancêtres.

2.2 Les six types de contextes

Moodle définit six niveaux de contexte (le « context level »), du plus englobant au plus fin :

NiveauNomCe qu’il représenteExemples de rôles typiquement assignés là
SystemSystèmeLe site entier, racine de l’arbre.Administrateur (cas spécial, voir plus bas), Manager (gestionnaire) global, Créateur de cours global.
UserUtilisateurLe profil d’un utilisateur donné.Parent/Mentor, tuteur individuel.
Course categoryCatégorie de coursUne catégorie (et, par héritage, tout ce qu’elle contient : sous-catégories et cours).Manager de catégorie, Créateur de cours de catégorie.
CourseCoursUn cours précis. C’est le contexte le plus utilisé au quotidien.Enseignant, Enseignant non éditeur, Étudiant.
ModuleModule d’activitéUne activité ou ressource précise dans un cours (un quiz, un forum, un devoir…).Rarement des assignations directes ; surtout des overrides. Parfois un « correcteur » sur un seul devoir.
BlockBlocUne instance de bloc précise (bloc HTML, bloc calendrier…).Quasiment jamais d’assignation ; le contexte existe surtout pour la cohérence du modèle.

Deux précisions importantes :

  • La page d’accueil du site (« Front page ») est techniquement un cours spécial (le cours d’identifiant 1 en base) ; elle possède donc un contexte de niveau Course directement sous le contexte Système, avec son propre rôle par défaut (« Utilisateur authentifié sur la page d’accueil »).
  • Les sous-catégories ont chacune leur propre contexte de niveau Course category, enfant du contexte de leur catégorie parente : l’arbre des catégories se reflète tel quel dans l’arbre des contextes.

💡 Pour un dev React : pensez à l’arbre des contextes comme à l’arbre des composants React de votre application. Le contexte Système, c’est votre <App> ou votre layout.tsx racine ; une catégorie, c’est un layout de segment ; un cours, c’est une page ; une activité, c’est un composant enfant. Et comme avec le Context API, une valeur fournie en haut de l’arbre est visible partout en dessous, sauf si un Provider plus proche la redéfinit. C’est exactement le mécanisme d’héritage des permissions que nous allons détailler.

2.3 L’arbre des contextes : schéma avec exemple concret

Prenons un site universitaire avec une catégorie « Sciences », un cours « Physique 101 » contenant un quiz et un bloc. Voici l’arbre des contextes correspondant :

Système (racine — tout le site) ├── Utilisateur : Alice ← contexte User (un par utilisateur) ├── Utilisateur : Bob ← contexte User │ └── (blocs du tableau de bord de Bob…) ├── Cours : Page d'accueil du site ← cours spécial id=1 │ └── Bloc : « Annonces du site » └── Catégorie : Sciences ├── Catégorie : Physique ← sous-catégorie │ │ │ └── Cours : Physique 101 │ │ │ ├── Activité : Quiz « Examen blanc n°1 » │ ├── Activité : Forum « Questions/Réponses » │ └── Bloc : « Derniers badges » └── Catégorie : Chimie └── Cours : Chimie organique └── …

Lisez cet arbre comme une carte : quand Moodle se demande si Bob peut « tenter » le quiz « Examen blanc n°1 », il regarde les rôles de Bob dans le contexte du quiz, puis dans celui du cours Physique 101, puis de la catégorie Physique, puis de la catégorie Sciences, puis du Système — et il combine le tout selon des règles précises (section 6).

2.4 Le « context path » et l’héritage descendant

Chaque contexte connaît son chemin complet depuis la racine : c’est le context path (chemin de contexte). C’est lui qui rend l’héritage efficace : pour trouver tous les ancêtres d’un contexte, il suffit de lire son chemin ; pour trouver tous ses descendants, il suffit de chercher les chemins qui commencent par le sien.

L’héritage est strictement descendant :

  • Un rôle assigné dans la catégorie « Sciences » vaut dans « Sciences », dans « Physique », dans « Physique 101 », dans le quiz, dans le bloc… bref, dans tout le sous-arbre.
  • Un rôle assigné dans « Physique 101 » ne « remonte » jamais : il ne donne aucun droit dans la catégorie, ni dans les autres cours.
  • De même, un override posé dans un contexte ne s’applique qu’à ce contexte et à ses descendants.

⚠️ Piège : l’héritage descendant est puissant mais dangereux. Assigner le rôle « Manager » à quelqu’un dans le contexte Système, « juste pour dépanner », revient à lui donner des droits étendus sur tous les cours du site, présents et futurs. Règle d’or : assignez toujours un rôle dans le contexte le plus bas (le plus spécifique) qui suffit au besoin. C’est le principe du moindre privilège, version Moodle.

Aparté modèle de données : la table mdl_context

Chaque contexte est une ligne de la table mdl_context, avec notamment :

ChampRôle
idIdentifiant du contexte (celui qu’on retrouve partout, y compris dans les URL des pages de permissions : contextid=…).
contextlevelLe type de contexte, codé numériquement : 10 = Système, 30 = Utilisateur, 40 = Catégorie, 50 = Cours, 70 = Module, 80 = Bloc.
instanceidL’identifiant de l’objet représenté : id du cours dans mdl_course, id de la catégorie dans mdl_course_categories, etc. (0 pour le Système).
pathLe chemin complet sous forme /1/27/153/489 — la liste des id de contextes depuis la racine (le Système a presque toujours l’id 1).
depthLa profondeur dans l’arbre (1 pour le Système, 2 pour une catégorie racine, etc.), redondante avec path mais bien pratique pour trier « du plus général au plus spécifique ».

Une requête illustrative pour retrouver tous les ancêtres du contexte 489 :

SELECT * FROM mdl_context WHERE id IN (1, 27, 153, 489) -- ids extraits de path = '/1/27/153/489' ORDER BY depth;

Et tous ses descendants :

SELECT * FROM mdl_context WHERE path LIKE '/1/27/153/489/%';

C’est ce champ path — un classique du stockage d’arbres en SQL (« materialized path », chemin matérialisé) — qui permet à Moodle de résoudre les permissions sans requêtes récursives.

💡 Pour un dev React : path et depth, c’est l’équivalent des segments d’URL dans Next.js App Router. /1/27/153/489, lisez-le comme /app/sciences/physique/physique-101/quiz/page.tsx : chaque segment hérite des layouts (et ici des permissions) de ses parents, et la profondeur détermine l’ordre d’application. Les overrides, on va le voir, jouent le rôle des layouts imbriqués qui redéfinissent localement ce que le parent fournissait.

2.5 Le contexte User : un cas à part

Le contexte Utilisateur surprend toujours les débutants : à quoi sert un contexte attaché à… une personne ?

Il ne s’agit pas des droits de cet utilisateur, mais des droits sur cet utilisateur. Le contexte User de Bob est le « territoire » constitué du profil de Bob, de ses données personnelles, de ses notes agrégées, de son tableau de bord. Assigner un rôle à Alice dans le contexte User de Bob signifie : « Alice a ces droits à propos de Bob ».

Le cas d’école est le rôle Parent (ou Mentor), qui n’existe pas en standard mais que tout administrateur finit par créer (nous y reviendrons au chapitre 2) : on crée un rôle contenant des capabilities comme « voir le profil » et « voir le rapport de notes de l’utilisateur », on le rend assignable au niveau User, puis on assigne ce rôle au parent dans le contexte User de l’enfant. Le parent voit alors les notes de son enfant, et uniquement les siennes.

Notez la position du contexte User dans l’arbre : il est enfant direct du Système, pas d’un cours ni d’une catégorie. Les rôles assignés dans un contexte User ne donnent donc aucun droit dans les cours de l’utilisateur — seulement sur les pages « personnelles » (profil, rapports individuels).

⚠️ Piège : ne confondez pas « assigner un rôle à Bob dans un contexte » (Bob reçoit des droits) et « assigner un rôle à Alice dans le contexte User de Bob » (Alice reçoit des droits sur Bob). L’interface est similaire, la sémantique est opposée. Le chemin UI pour la seconde opération passe par le profil de Bob : Profil de l’utilisateur > Préférences > Rôles > Attribuer des rôles relatifs à cet utilisateur.

📚 Aller plus loin : la recette complète du rôle Parent est documentée sur docs.moodle.org (cherchez « Parent role » ; la page existe aussi en français : « Rôle Parent »). Elle constitue un excellent exercice de synthèse de ce chapitre et du suivant.


3. Les rôles : des paquets de permissions, définis globalement, assignés localement

3.1 Ce qu’est un rôle (et ce qu’il n’est pas)

Un role (rôle) est un objet nommé — « Enseignant », « Étudiant », « Manager »… — qui associe à chaque capability du système une permission (Not set, Allow, Prevent ou Prohibit). C’est tout. Un rôle :

  • n’est pas un utilisateur ni un groupe d’utilisateurs : c’est un gabarit de droits, qui existe même si personne ne le porte ;
  • n’est pas lié à un endroit : sa définition est unique et globale pour tout le site ;
  • ne fait rien tout seul : il ne produit d’effet que lorsqu’il est assigné à un utilisateur dans un contexte.

Cette séparation définition/assignation est le cœur du modèle :

DÉFINITION (globale, une seule fois) ASSIGNATION (locale, autant que nécessaire) ┌────────────────────────────────────┐ ┌──────────────────────────────────────────┐ │ Rôle « Enseignant » │ │ Alice est Enseignant dans Physique101│ │ mod/quiz:attempt → Allow │ ───▶ │ Alice est Étudiant dans Anglais B2 │ │ moodle/course:update → Allow │ │ Carol est Enseignant dans Chimie Org.│ │ mod/forum:deleteanypost → Allow │ │ David est Manager dans cat. Scienc│ │ … (700+ capabilities) │ └──────────────────────────────────────────┘ └────────────────────────────────────┘ (table mdl_role_assignments : (tables mdl_role + userid + roleid + contextid) mdl_role_capabilities)

Alice peut donc être Enseignante ici et Étudiante là : le rôle est une relation triangulaire utilisateur–rôle–contexte, jamais une étiquette globale collée sur l’utilisateur.

💡 Pour un dev React : si vous avez déjà mis un champ role: "admin" | "user" dans votre table users ou dans un JWT, vous voyez la différence : Moodle ne stocke jamais le rôle « sur » l’utilisateur. L’équivalent JS serait une table de jointure (userId, roleId, scopeId) — c’est très exactement mdl_role_assignments (userid, roleid, contextid). Quand on vous demandera « quel est le rôle de cet utilisateur ? » sur un site Moodle, la seule réponse correcte est : « dans quel contexte ? ».

3.2 Où l’on définit les rôles dans l’interface

Le tableau de bord des rôles se trouve dans :

Administration du site > Utilisateurs > Permissions > Définition des rôles

Cet écran liste tous les rôles du site (les rôles standards : Manager, Créateur de cours, Enseignant, Enseignant non éditeur, Étudiant, Invité, Utilisateur authentifié, Utilisateur authentifié sur la page d’accueil — détaillés au chapitre 2), avec pour chacun sa description et le nombre d’utilisateurs qui le portent. En cliquant sur un rôle, on accède à sa fiche ; le bouton Modifier ouvre le formulaire de définition, qui contient :

  • le nom et le nom abrégé (shortname, identifiant technique, ex. editingteacher) ;
  • l’archetype (archétype) : le rôle standard dont ce rôle « s’inspire », utilisé pour les remises à zéro et pour que les plugins fraîchement installés sachent quelles permissions par défaut donner — nous détaillerons cette notion au chapitre 2 ;
  • les niveaux de contexte où ce rôle peut être attribué (cases à cocher : Système, Utilisateur, Catégorie, Cours, Activité, Bloc) — c’est un garde-fou d’interface : un rôle « Étudiant » n’a aucun sens au niveau Système, donc la case n’est pas cochée et l’interface ne le proposera jamais là ;
  • les rôles que ce rôle peut lui-même attribuer / retirer / surcharger (c’est ainsi qu’un Enseignant peut inscrire des Étudiants mais pas nommer d’autres Enseignants, selon la configuration) ;
  • et enfin l’immense liste des capabilities, groupées par composant, avec pour chacune quatre boutons radio : Not set, Allow, Prevent, Prohibit, plus les pictogrammes de risque (section 4.3).

L’écran de définition offre une barre de filtre (très utile : tapez quiz pour ne voir que les capabilities des quiz) et, en haut, un mode « avancé » qui révèle les colonnes Prevent/Prohibit — par défaut, seuls Not set et Allow sont visibles pour éviter les accidents.

⚠️ Piège : modifier la définition d’un rôle standard a un effet global et immédiat sur tout le site. Décocher mod/forum:replypost dans le rôle Étudiant empêche tous les étudiants de répondre dans tous les forums de tous les cours. Si votre besoin est local (« dans ce cours », « dans ce forum »), la bonne réponse n’est jamais de modifier le rôle global, mais de poser un override dans le contexte visé (section 7). Modifiez la définition globale uniquement pour des politiques d’établissement.

À noter également, sur le même écran « Définition des rôles », deux onglets voisins :

  • Autoriser les attributions de rôles / Autoriser les dérogations de rôles / Autoriser les changements de rôle : des matrices rôle × rôle qui définissent qui a le droit de donner quoi à qui ;
  • la possibilité de dupliquer un rôle existant (bouton dans la liste) — la méthode recommandée pour créer un rôle personnalisé : dupliquez « Enseignant », renommez, ajustez.

3.3 Le cas particulier de l’administrateur

Le compte administrateur principal et les membres de la liste Administration du site > Utilisateurs > Permissions > Administrateurs du site ne passent pas par le système de rôles : Moodle leur répond « oui » à presque toutes les vérifications de capability, sans consulter les assignations (seules quelques capabilities marquées comme jamais accordées aux admins font exception, ainsi que les fonctions volontairement bloquées comme la connexion sous un autre nom vers un autre admin). L’administrateur n’est donc pas un rôle : c’est un statut hors modèle. Conséquence pratique : tester des permissions en étant connecté comme admin ne prouve rien — utilisez la fonction « Se connecter sous le nom… » ou un compte de test.

💡 Pour un dev React : l’admin Moodle, c’est le bypass que vous avez peut-être déjà codé : if (user.isSuperAdmin) return true; tout en haut de votre middleware d’autorisation, avant même de lire les rôles. Pratique, mais ça signifie aussi que votre environnement de test doit inclure des comptes non-admin, exactement comme vous testez vos routes protégées avec un utilisateur lambda et pas seulement avec votre compte de dev.


4. Les capabilities : l’atome du système

4.1 Définition et nomenclature

Une capability (capacité) est la description d’une action atomique et contrôlable, identifiée par un nom de la forme :

composant/nom_de_la_capacité

Exemples représentatifs :

CapabilitySignificationComposant
moodle/course:updateModifier les réglages d’un coursCœur de Moodle (moodle)
moodle/course:manageactivitiesAjouter/modifier/supprimer des activitésCœur
moodle/site:configConfigurer le site (la capability la plus puissante)Cœur
moodle/grade:viewallVoir les notes de tous les utilisateursCœur (carnet de notes)
moodle/user:viewdetailsVoir le profil détaillé d’un utilisateurCœur
mod/quiz:attemptTenter (passer) un quizModule d’activité Quiz
mod/quiz:gradeNoter manuellement un quizModule Quiz
mod/forum:startdiscussionDémarrer une discussion dans un forumModule Forum
mod/forum:replypostRépondre à un message de forumModule Forum
mod/assign:gradeÉvaluer un devoirModule Devoir (assign)
block/html:addinstanceAjouter une instance du bloc HTMLBloc HTML
enrol/manual:enrolInscrire manuellement des utilisateursPlugin d’inscription manuelle

La partie gauche (moodle, mod/quiz, block/html, enrol/manual…) identifie le composant qui déclare la capability : le cœur ou un plugin. Chaque plugin apporte ses propres capabilities à l’installation — c’est ainsi que le système reste extensible : quand vous développerez votre premier plugin, vous déclarerez vos propres capabilities et elles apparaîtront automatiquement dans tous les écrans de définition de rôles.

La partie droite suit une convention verbe/objet lisible : view, update, delete, manage, attempt, grade

💡 Pour un dev React : une capability, c’est un claim au sens JWT/OAuth : une chaîne namespacée qui décrit un droit fin (mod/quiz:attempt ressemble furieusement à un scope OAuth quiz:attempt). La grande différence : dans un JWT, les claims sont figés à l’émission du token et valent partout ; dans Moodle, la « valeur » d’une capability est recalculée à chaque vérification, en fonction du contexte. C’est un système de claims dynamiques et positionnels.

4.2 Le « context level » minimal d’une capability

Chaque capability déclare le niveau de contexte le plus profond où elle a du sens, son context level. Par exemple :

  • mod/quiz:attempt est déclarée au niveau Module : elle peut être surchargée quiz par quiz ;
  • moodle/course:update est déclarée au niveau Cours : la surcharger dans un quiz n’aurait aucun sens (on ne modifie pas « un cours » depuis un quiz) ;
  • moodle/site:config est déclarée au niveau Système : elle ne peut être accordée que par un rôle évalué au niveau site.

Concrètement, ce niveau détermine dans quels écrans d’override la capability apparaît : l’écran « Permissions » d’un forum ne liste que les capabilities pertinentes au niveau Module (celles du forum, des blocs qu’il pourrait contenir, etc.), pas moodle/site:config. Cela ne limite pas où l’on peut donner la capability — un rôle assigné au niveau catégorie peut parfaitement accorder mod/quiz:attempt, qui s’appliquera par héritage à tous les quiz de la catégorie — mais jusqu’où l’on peut la raffiner.

4.3 Les niveaux de risque

Dans tous les écrans de définition de rôles et d’overrides, certaines capabilities portent des pictogrammes d’avertissement. Ce sont les risk flags (indicateurs de risque), déclarés par le développeur de la capability :

RisqueSignificationExemple de capability concernée
XSSL’utilisateur peut soumettre du contenu HTML/JS non filtré → risque d’injection de script (Cross-Site Scripting).moodle/course:update (description de cours en HTML brut selon réglages), capabilities d’édition « trusted text ».
ConfigL’utilisateur peut modifier la configuration du site.moodle/site:config
SpamL’utilisateur peut envoyer des messages à d’autres ou publier du contenu visible → risque de spam.moodle/site:sendmessage, capabilities de forum.
DatalossL’utilisateur peut détruire massivement des données.moodle/course:delete, moodle/course:manageactivities (suppression d’activités).
PersonalL’utilisateur peut accéder à des données personnelles d’autrui.moodle/user:viewhiddendetails, moodle/grade:viewall

(Il existe aussi un risque plus rare, Managetrust, lié à la gestion des marques de confiance sur les contenus.)

Ces indicateurs sont purement informatifs : rien n’empêche techniquement d’accorder une capability risquée à un rôle. Ils servent de signal à l’administrateur : « réfléchis à deux fois avant de donner ça à un rôle porté par des non-permanents ». Le réglage Administration du site > Utilisateurs > Permissions > Politiques utilisateur permet en complément de définir des garde-fous globaux (rôle par défaut des utilisateurs, rôle des visiteurs anonymes, etc.).

⚠️ Piège : le risque XSS est le plus sournois. Accorder à un rôle « étudiant amélioré » une capability marquée XSS (souvent pour débloquer une fonctionnalité d’édition) revient potentiellement à autoriser tous ses porteurs à injecter du JavaScript dans des pages vues par d’autres — y compris par des enseignants et des admins, dont la session peut alors être détournée. En cas de doute, cherchez la capability sur docs.moodle.org avant de l’accorder : chaque capability y a sa page dédiée expliquant le risque.

📚 Aller plus loin : docs.moodle.org maintient une page par capability (cherchez par exemple « Capabilities/mod/quiz:attempt »), avec sa signification, ses risques et les rôles qui l’ont par défaut. Côté développeur, la déclaration des risques est documentée dans « Roles and permissions » sur moodledev.io.

Aparté modèle de données : mdl_role et mdl_role_capabilities

La définition des rôles tient dans deux tables :

  • mdl_role : une ligne par rôle (id, name, shortname, archetype, sortorder).
  • mdl_role_capabilities : une ligne par triplet (rôle, capability, contexte) avec la permission en valeur numérique. Pour la définition globale d’un rôle, contextid pointe vers le contexte Système ; pour un override, il pointe vers le contexte surchargé. Définition et override vivent donc dans la même table — un override n’est rien d’autre qu’une ligne de mdl_role_capabilities posée plus bas dans l’arbre.

Les permissions y sont codées : 1 = Allow, -1 = Prevent, -1000 = Prohibit ; Not set = absence de ligne (ou 0). La valeur extrême -1000 de Prohibit n’est pas anodine : elle garantit qu’aucune somme de +1 ne pourra jamais la compenser — nous y reviendrons.

-- « Que donne le rôle Étudiant sur les forums, globalement ? » SELECT rc.capability, rc.permission FROM mdl_role_capabilities rc JOIN mdl_role r ON r.id = rc.roleid WHERE r.shortname = 'student' AND rc.capability LIKE 'mod/forum:%' AND rc.contextid = 1; -- contexte Système = définition globale

5. Les quatre permissions : Not set, Allow, Prevent, Prohibit

Pour chaque couple (rôle, capability), la permission prend l’une de quatre valeurs. Leur compréhension fine est indispensable, car toute la subtilité du modèle est là.

5.1 Tableau comparatif

PermissionLibellé FR de l’interfaceEffet dans ce rôlePeut être surchargée plus bas dans l’arbre ?Peut être compensée par un autre rôle ?Analogie CSS
Not set (Inherit)Non défini / HériterLe rôle ne dit rien : on hérite de ce qui a été décidé dans les contextes parents ; si personne ne dit rien nulle part, la réponse par défaut est non.OuiOui (un autre rôle peut dire Allow)Propriété non déclarée : la valeur héritée s’applique.
AllowAutoriserLe rôle accorde la capability dans le contexte d’assignation et tous ses descendants.Oui (un override Prevent plus bas peut l’annuler)Règle normale qui définit une valeur.
PreventEmpêcherLe rôle retire la capability — mais « poliment » : un Allow plus spécifique (override plus bas) ou un Allow venant d’un autre rôle du même utilisateur peut la rétablir.OuiOuiRègle qui remet la valeur à none, mais surchargeable par un sélecteur plus spécifique.
ProhibitInterdireVeto absolu. Dès qu’un des rôles de l’utilisateur porte Prohibit sur la capability dans le contexte ou un ancêtre, la réponse est non, définitivement : aucun Allow, d’aucun rôle, à aucun niveau plus bas, ne peut le contrer.Non (dans le sous-arbre)Non!important posé sur l’ancêtre — rien de plus spécifique ne gagne.

5.2 Comprendre chaque valeur

Not set / Inherit est la valeur par défaut de la quasi-totalité des capabilities dans la quasi-totalité des rôles. Elle signifie « ce rôle n’a pas d’opinion ». Le mot important est inherit : si le rôle Étudiant dit « Not set » sur mod/quiz:attempt au niveau d’un quiz particulier (via un override), alors la décision prise plus haut (la définition globale du rôle, qui dit Allow) continue de s’appliquer. Not set n’est pas un refus : c’est une abstention.

Allow est la seule valeur positive. Notez bien la valeur par défaut du système : en l’absence de tout Allow, la réponse est non. Moodle est « deny by default » (refus par défaut) : une capability qu’aucun rôle n’accorde nulle part est refusée.

Prevent est un refus local et négociable. Ses deux points faibles (qui sont aussi sa souplesse) :

  1. Il peut être annulé plus bas dans l’arbre par un override Allow plus spécifique.
  2. Il peut être annulé au même niveau par un autre rôle de l’utilisateur qui dit Allow (voir l’algorithme, section 6).

Prohibit est l’arme nucléaire. Il a été conçu pour des cas comme : « cet utilisateur a spammé les forums ; je veux être certain qu’il ne pourra plus poster nulle part, quels que soient les rôles qu’un enseignant pourrait lui donner dans son cours ». On crée alors (par exemple) un rôle « Interdit de forum » qui met mod/forum:replypost et consorts à Prohibit, on l’assigne au niveau Système, et plus aucune combinaison de rôles ou d’overrides en aval ne pourra rendre la parole à cet utilisateur. Une seule chose annule un Prohibit : le retirer (ou retirer l’assignation du rôle qui le porte), à l’endroit exact où il a été posé.

⚠️ Piège : Prevent ≠ Prohibit, et confondre les deux est l’erreur n°1 des administrateurs débutants. Si vous mettez Prevent sur mod/forum:replypost dans le rôle Étudiant au niveau d’un cours, mais que certains étudiants ont aussi un second rôle (tuteur, par exemple) qui dit Allow, ils pourront toujours poster. Prevent perd contre Allow entre rôles. Si vous voulez un blocage inconditionnel : Prohibit. Réciproquement, n’utilisez jamais Prohibit pour un besoin ordinaire : posé trop haut, il est extrêmement difficile à diagnostiquer (« pourquoi ce prof ne peut-il pas faire X alors que son rôle le permet ?! ») car rien, plus bas, ne semble l’expliquer.

💡 Pour un dev React : la meilleure analogie de Prohibit est le !important posé dans un style parent… mais en plus radical, car en CSS un autre !important plus spécifique peut encore gagner, alors que dans Moodle rien ne bat un Prohibit hérité. Autre analogie parlante : dans un middleware Next.js, c’est le return new Response(null, { status: 403 }) placé tout en haut de la chaîne — les handlers suivants ne sont même plus consultés. Prevent, lui, ressemble davantage à un defaultDeny local que n’importe quel handler suivant peut encore renverser.

5.3 Deux axes de combinaison

Retenez qu’il y a deux dimensions dans lesquelles les permissions se combinent, et qu’elles n’obéissent pas aux mêmes règles :

  1. L’axe vertical (hiérarchie des contextes), pour un même rôle : la valeur la plus spécifique (posée dans le contexte le plus profond) gagne. Un override Allow dans le quiz bat un Prevent défini au niveau du cours, qui bat lui-même la définition globale du rôle. Exception : Prohibit, qui une fois posé verrouille tout son sous-arbre.
  2. L’axe horizontal (rôles multiples), à spécificité égale : les valeurs des différents rôles de l’utilisateur s’agrègent ; Allow gagne contre Prevent (il suffit qu’un rôle autorise), mais Prohibit gagne contre tout.

L’algorithme complet, maintenant.


6. L’algorithme de résolution, pas à pas

6.1 La question posée

Toute vérification a la forme : « l’utilisateur U a-t-il la capability C dans le contexte X ? » (c’est la fonction interne has_capability, que vous manipulerez côté développeur ; ici nous la déroulons à la main).

6.2 Les étapes

Voici l’algorithme, tel qu’on peut le simuler de tête :

Étape 0 — Court-circuits. Si U est administrateur du site : oui (sauf rares exceptions). Si le compte de U est suspendu ou si la capability n’existe pas : non.

Étape 1 — Construire la chaîne de contextes. À partir du path du contexte X, lister X et tous ses ancêtres jusqu’au Système. Exemple pour le quiz de tout à l’heure : [Quiz, Cours Physique 101, Cat. Physique, Cat. Sciences, Système].

Étape 2 — Collecter les rôles de U. Rassembler toutes les assignations de rôle de U dont le contexte est X ou l’un de ses ancêtres. (Un rôle assigné dans un contexte frère ou descendant est ignoré.) S’y ajoutent les rôles automatiques : « Utilisateur authentifié » (assigné implicitement à tout utilisateur connecté au niveau Système) et, le cas échéant, le rôle par défaut de la page d’accueil ou le rôle Invité.

Étape 3 — Pour chaque rôle, calculer SA réponse. Pour un rôle R donné, on cherche ce que R dit de C au niveau le plus spécifique : on parcourt la chaîne de contextes du plus profond (X) vers la racine, et on s’arrête à la première valeur non-« Not set » trouvée pour (R, C) — que ce soit un override ou, au sommet, la définition globale du rôle. Cette valeur (Allow, Prevent ou Prohibit) est la réponse de R. Si on ne trouve rien : R s’abstient (équivalent Not set).

Étape 4 — Agréger entre les rôles. On combine les réponses de tous les rôles :

  1. Si au moins un rôle répond Prohibit (à n’importe quel niveau de la chaîne, même non « le plus spécifique » — un Prohibit rencontré n’importe où dans la chaîne du rôle l’emporte dans ce rôle) → NON, définitif.
  2. Sinon, si au moins un rôle répond AllowOUI.
  3. Sinon (que des Prevent et des abstentions, ou rien du tout) → NON.

Une nuance à bien saisir à l’étape 3 : pour Allow et Prevent, c’est la spécificité qui tranche à l’intérieur d’un rôle (le plus proche de X gagne) ; pour Prohibit, la spécificité ne joue pas — un Prohibit posé n’importe où sur la chaîne contamine tout ce qui est en dessous et ne peut pas être « re-surchargé » plus bas.

6.3 Schéma du pipeline de décision

« U a-t-il C dans X ? » ┌──────────────────────────────┐ │ 0. U est admin du site ? │──oui──▶ ✅ OUI (bypass) └──────────────┬───────────────┘ │ non ┌──────────────────────────────┐ │ 1. Chaîne de contextes │ │ X → parent → … → Système │ (lecture du champ path) └──────────────┬───────────────┘ ┌──────────────────────────────┐ │ 2. Rôles de U assignés dans │ (mdl_role_assignments │ X ou un ancêtre │ + rôles implicites) └──────────────┬───────────────┘ ┌──────────────────────────────┐ │ 3. Pour chaque rôle : │ (mdl_role_capabilities : │ valeur la plus SPÉCIFIQUE │ overrides du + profond │ de C sur la chaîne │ au + général, puis │ (Prohibit = partout) │ définition globale) └──────────────┬───────────────┘ ┌──────────────────────────────┐ │ 4. Agrégation entre rôles : │ │ un Prohibit ? ──▶ ❌ NON │ (veto absolu) │ sinon un Allow ? ─▶ ✅ OUI │ │ sinon ──▶ ❌ NON │ (refus par défaut) └──────────────────────────────┘

6.4 Exemple déroulé n°1 — Étudiant avec un override au niveau du cours

Situation. Bob est Étudiant dans « Physique 101 ». Le rôle Étudiant accorde globalement mod/forum:startdiscussion (Allow). L’enseignante a posé, au niveau du cours, un override mettant mod/forum:startdiscussion à Prevent pour le rôle Étudiant (elle veut garder la main sur la création de discussions). Question : Bob peut-il démarrer une discussion dans le forum « Questions/Réponses » ?

Déroulé.

  1. Chaîne de contextes : [Forum Q/R, Cours Physique 101, Cat. Physique, Cat. Sciences, Système].
  2. Rôles de Bob sur la chaîne : Étudiant (assigné dans le cours) + Utilisateur authentifié (Système).
  3. Réponse de chaque rôle :
    • Étudiant : on part du forum et on remonte. Au niveau Forum : rien. Au niveau Cours : override Prevent → on s’arrête : la réponse du rôle Étudiant est Prevent. (La définition globale Allow, plus haut, n’est même pas consultée : moins spécifique.)
    • Utilisateur authentifié : ne dit rien sur cette capability → abstention.
  4. Agrégation : pas de Prohibit ; pas d’Allow ; il reste un Prevent et une abstention → NON.

Variante. L’enseignante veut ré-autoriser la création de discussions dans un seul forum (le forum « Entraide libre »). Elle pose dans ce forum un override mod/forum:startdiscussion = Allow pour Étudiant. Nouveau déroulé pour ce forum : au niveau Forum, le rôle Étudiant trouve Allow (plus spécifique que le Prevent du cours) → réponse du rôle : Allow → agrégation : OUI. La spécificité a renversé le Prevent — exactement comme un sélecteur CSS plus spécifique.

6.5 Exemple déroulé n°2 — Enseignant frappé d’un Prohibit au niveau catégorie

Situation. Carol est Enseignante dans « Chimie organique ». Suite à un incident, l’administrateur a créé un rôle « Sanction – édition gelée » qui met moodle/course:update à Prohibit, et l’a assigné à Carol dans la catégorie « Sciences ». Le rôle Enseignant, lui, accorde moodle/course:update (Allow) globalement. Carol peut-elle modifier les réglages de son cours ?

Déroulé.

  1. Chaîne : [Cours Chimie organique, Cat. Chimie, Cat. Sciences, Système].
  2. Rôles de Carol sur la chaîne : Enseignant (dans le cours), « Sanction » (dans la cat. Sciences), Utilisateur authentifié (Système).
  3. Réponse de chaque rôle :
    • Enseignant : définition globale → Allow.
    • Sanction : Prohibit sur la chaîne (posé dans sa définition, le rôle étant assigné à la catégorie Sciences qui est un ancêtre) → Prohibit.
    • Utilisateur authentifié : abstention.
  4. Agrégation : un Prohibit est présent → NON, définitif.

Point crucial : même si un collègue bien intentionné pose un override Allow sur moodle/course:update au niveau du cours pour le rôle « Sanction », ça ne change rien : Prohibit n’est pas surchargeable dans son sous-arbre. Et même si Carol reçoit un troisième rôle Manager avec Allow : toujours non. Le seul remède est de retirer l’assignation du rôle Sanction (ou son Prohibit) là où il a été posé. C’est toute la valeur — et tout le danger — de Prohibit.

6.6 Exemple déroulé n°3 — Deux rôles contradictoires dans le même contexte

Situation. David est à la fois Étudiant et Enseignant non éditeur (non-editing teacher) dans « Physique 101 » (cas réel : un doctorant qui suit le cours et encadre les TD). La capability moodle/grade:viewall (voir les notes de tout le monde) vaut, par définition globale : Prevent chez Étudiant, Allow chez Enseignant non éditeur. David voit-il les notes de tous ?

Déroulé.

  1. Chaîne : [Cours Physique 101, Cat. Physique, Cat. Sciences, Système].
  2. Rôles : Étudiant (cours), Enseignant non éditeur (cours), Utilisateur authentifié (Système).
  3. Réponses : Étudiant → Prevent (définition globale) ; Enseignant non éditeur → Allow (définition globale) ; Utilisateur authentifié → abstention.
  4. Agrégation : pas de Prohibit ; au moins un Allow → OUI.

Moralité : entre rôles, Allow bat Prevent. Le cumul de rôles est « optimiste » : on additionne les droits. C’est voulu — un second rôle est censé ajouter des responsabilités, pas en retirer. Si l’établissement voulait vraiment que les étudiants-encadrants ne voient pas les notes, il faudrait soit un Prohibit (brutal), soit ne pas cumuler les rôles et créer un rôle sur mesure (propre).

Variante avec override. L’enseignante du cours ne veut pas que David voie les notes. Elle pose au niveau du cours un override moodle/grade:viewall = Prevent pour le rôle Enseignant non éditeur. Nouveau calcul : Étudiant → Prevent ; Enseignant non éditeur → Prevent (l’override du cours, plus spécifique, remplace l’Allow global) ; → plus aucun Allow → NON. Notez que l’override frappe le rôle dans le contexte, donc tous les enseignants non éditeurs de ce cours, pas seulement David — pour cibler une seule personne, il aurait fallu un rôle dédié. Gardez ce point en tête : les overrides ciblent des rôles, jamais des individus.

⚠️ Piège : « l’addition » des rôles surprend souvent en sens inverse : donner à quelqu’un un rôle très restrictif n’enlève rien à ses autres rôles (sauf Prohibit). Créer un rôle « Lecture seule » plein de Prevent et l’ajouter à un Enseignant ne le mettra pas en lecture seule : ses Allow d’Enseignant gagneront. Pour restreindre, il faut soit retirer le rôle permissif, soit surcharger le rôle permissif là où c’est nécessaire, soit — en dernier recours — utiliser Prohibit.

💡 Pour un dev React : l’agrégation entre rôles ressemble à un Array.some() : roles.some(r => r.says(cap) === ALLOW) … précédé d’un roles.some(r => r.says(cap) === PROHIBIT) → false. Tandis que la résolution à l’intérieur d’un rôle ressemble à la remontée de prototypes ou à useContext : on prend le Provider le plus proche. Deux algorithmes différents sur deux axes différents — c’est LA subtilité à mémoriser.

6.7 L’outil de diagnostic : « Vérifier les permissions »

Bonne nouvelle : vous n’avez pas à dérouler cet algorithme de tête en production. Chaque contexte offre un écran « Vérifier les permissions » (Check permissions) :

  • au niveau système : Administration du site > Utilisateurs > Permissions > Vérifier les permissions du système ;
  • dans un cours : page Participants, menu déroulant en haut à gauche > Vérifier les permissions ;
  • dans une activité : menu de l’activité (onglet Plus ou roue dentée selon le thème) > Permissions, puis lien/onglet Vérifier les permissions.

On y choisit un utilisateur, et Moodle affiche la liste complète des capabilities avec, pour chacune, Oui/Non — le résultat final de l’algorithme, tel qu’il serait calculé pour cet utilisateur dans ce contexte. C’est l’outil n°1 de débogage de permissions ; prenez le réflexe de l’utiliser avant toute modification.

📚 Aller plus loin : cherchez « Vérifier les permissions » (Check permissions) sur docs.moodle.org/fr. En complément, l’écran « Permissions » de chaque contexte (section suivante) montre qui a chaque capability via quels rôles — la vue inverse, par capability plutôt que par utilisateur.


7. Les overrides : surcharger les permissions dans un contexte

7.1 Principe

Un override (dérogation de permission) consiste à dire : « dans ce contexte (et son sous-arbre), pour ce rôle, la capability C vaut désormais V » — où V est Allow, Prevent, Prohibit… ou Not set (retour à l’héritage, ce qui revient à supprimer l’override).

Relisez la phrase : un override modifie le comportement d’un rôle dans un lieu. Il ne touche ni la définition globale du rôle (les autres cours ne voient rien), ni un utilisateur en particulier (tous les porteurs du rôle dans ce sous-arbre sont concernés).

7.2 Chemins d’interface

Dans un cours : page du cours > onglet Participants > menu déroulant (en haut de la page, celui qui affiche « Utilisateurs inscrits » par défaut) > Permissions. L’écran liste toutes les capabilities pertinentes au niveau cours, avec pour chacune les rôles qui l’ont (colonne « Rôles avec permission ») et ceux qui en sont exclus (« Interdit »). Les icônes + et en face de chaque capability permettent d’ajouter/retirer un rôle : c’est la façon rapide de poser un override Allow ou Prevent. Pour un contrôle complet (dont Prohibit), passez par le menu déroulant > Autres utilisateurs / ou directement l’écran « Dérogations » selon la version du thème : le formulaire d’override complet s’obtient en choisissant le rôle à surcharger, ce qui ouvre la grande liste de capabilities avec les quatre boutons radio.

Dans une activité (module) : ouvrez l’activité (le quiz, le forum…) > menu de l’activité (barre d’onglets sous le titre : Plus > Permissions, ou roue dentée > Permissions selon le thème Boost/vos réglages). Même écran que pour le cours, mais restreint aux capabilities qui ont du sens au niveau Module — c’est le « context level » de la section 4.2 à l’œuvre.

Dans une catégorie : page de la catégorie > roue dentée / menu Plus > Permissions (ou via Administration du site > Cours > Gestion des cours et catégories, puis le menu contextuel de la catégorie).

Au niveau du site : Administration du site > Utilisateurs > Permissions > Définition des rôles reste le lieu de la définition globale ; il n’y a pas d’« override système » à proprement parler puisque la définition globale est la valeur au niveau Système.

Sur tous ces écrans, un override actif est signalé (valeur en gras/mention « dérogation ») pour le distinguer de la valeur héritée.

7.3 Cas d’usage classiques

BesoinOverride à poserContexte
Forum « Annonces » où seuls les enseignants publientmod/forum:replypost et mod/forum:startdiscussionPrevent pour ÉtudiantLe forum (niveau Module). (Les forums de type « Annonces » le font déjà nativement — bon exemple à disséquer !)
Autoriser les étudiants à évaluer les travaux de leurs pairs dans UN devoirmod/assign:gradeAllow pour ÉtudiantLe devoir (Module)
Quiz d’entraînement dont les tentatives sont ouvertes même aux visiteurs invitésmod/quiz:attemptAllow pour InvitéLe quiz (Module)
Cacher le carnet de notes aux étudiants d’un seul coursmoodle/grade:viewPrevent pour ÉtudiantLe cours
Verrouiller toute discussion dans les forums d’une catégorie entièremod/forum:replypostPrevent (ou Prohibit si des rôles multiples circulent) pour ÉtudiantLa catégorie
Permettre aux enseignants non éditeurs de gérer les groupes dans un coursmoodle/course:managegroupsAllow pour Enseignant non éditeurLe cours

7.4 Override vs modification du rôle global : l’arbre de décision

Le besoin concerne-t-il TOUT le site ? │ │ oui non │ │ ▼ ▼ Modifier la DÉFINITION Le besoin concerne-t-il un LIEU du rôle (cours, activité, catégorie) ? (Déf. des rôles) │ │ oui non : il concerne │ UNE PERSONNE ▼ │ Poser un OVERRIDE ▼ dans ce contexte Assigner/retirer un rôle à cette personne dans le bon contexte (voire créer un rôle sur mesure)

⚠️ Piège : les overrides sont invisibles depuis l’écran global « Définition des rôles » — ils ne vivent que dans leur contexte. Un site qui accumule des overrides posés au fil des ans par des dizaines d’enseignants devient très difficile à auditer (« pourquoi ce forum se comporte-t-il différemment ?! »). Deux réflexes : documenter les overrides posés (le champ description du cours, un wiki d’admin), et privilégier les solutions natives quand elles existent (le type de forum « Annonces » plutôt qu’un override, les restrictions d’accès plutôt qu’un bricolage de permissions).

⚠️ Piège : qui peut poser des overrides ? Par défaut, les Enseignants peuvent surcharger certains rôles (Étudiant, Invité…) dans leur cours — c’est contrôlé par la capability moodle/role:override et par la matrice « Autoriser les dérogations de rôles » (Administration du site > Utilisateurs > Permissions > Définition des rôles > onglet correspondant). Si un enseignant ne voit pas l’écran Permissions, vérifiez ces deux endroits — pas seulement le premier.

💡 Pour un dev React : un override, c’est littéralement un <Context.Provider value={...}> posé plus bas dans l’arbre : tout le sous-arbre voit la nouvelle valeur, le reste de l’application ne voit rien, et retirer le Provider (= remettre « Not set ») restaure la valeur héritée. Poussons l’analogie : modifier la définition globale du rôle = changer le defaultValue de createContext ; poser un override = ajouter un Provider local ; Prohibit = une valeur gelée par Object.freeze que plus aucun Provider enfant ne peut masquer (là, l’analogie React atteint ses limites — React n’a pas d’équivalent, c’est une spécificité Moodle).


8. L’assignation de rôles dans un contexte

8.1 Principe et chemins d’interface

L’assignment (attribution de rôle) est l’acte qui donne vie au modèle : tel utilisateur porte tel rôle dans tel contexte. Chaque niveau de contexte a son point d’entrée UI :

ContexteChemin d’interfaceExemple d’usage
SystèmeAdministration du site > Utilisateurs > Permissions > Attribution des rôles systèmeNommer un Manager global, un Créateur de cours global. On n’y propose que les rôles autorisés au niveau Système — jamais Étudiant ni Enseignant.
CatégoriePage de la catégorie > roue dentée / menu Plus > Attribution des rôles (ou via Gestion des cours et catégories)Un « Manager de la catégorie Sciences » qui peut créer, trier, sauvegarder tous les cours de la catégorie — sans être admin du site.
CoursCours > Participants. L’inscription (« Inscrire des utilisateurs ») attribue le rôle en même temps qu’elle inscrit ; le menu déroulant > Autres utilisateurs permet d’attribuer un rôle sans inscription (accès au cours sans figurer comme participant).Inscrire des Étudiants, nommer un Enseignant ; donner un accès d’inspection à un conseiller pédagogique via « Autres utilisateurs ».
Activité (module)Activité > Plus > Permissions, puis l’onglet/le lien Rôles attribués localement (Locally assigned roles)Nommer un étudiant « modérateur » d’un seul forum (rôle Enseignant non éditeur assigné dans le contexte du forum : il modère ce forum et rien d’autre).
BlocBloc en mode édition > menu du bloc > Permissions / Attribution des rôles dans le blocRarissime ; existe pour la complétude (ex. déléguer la gestion d’un bloc HTML précis).
UtilisateurProfil de l’utilisateur cible > Préférences > Rôles > Attribuer des rôles relatifs à cet utilisateurLe rôle Parent : assigné au parent dans le contexte User de l’enfant (section 2.5).

Deux remarques structurantes :

  • Inscription ≠ assignation. Être inscrit (enrolled) dans un cours et avoir un rôle dans le contexte du cours sont deux mécanismes distincts, presque toujours couplés (les méthodes d’inscription attribuent un rôle par défaut, réglé dans chaque méthode : Administration du cours > Utilisateurs > Méthodes d’inscription) mais découplables : « Autres utilisateurs » donne un rôle sans inscription ; et une inscription suspendue conserve l’assignation. L’inscription gouverne l’appartenance (apparaître dans Participants, recevoir les notifications, avoir un carnet de notes) ; le rôle gouverne les droits. Nous y reviendrons dans le chapitre consacré aux inscriptions.
  • La liste des rôles proposés dépend du contexte (les cases « niveaux de contexte où ce rôle peut être attribué » de la définition du rôle) et de qui vous êtes (matrice « Autoriser les attributions de rôles » : un Enseignant peut typiquement attribuer Étudiant et Enseignant non éditeur, pas Manager).

⚠️ Piège : assigner le rôle Étudiant au niveau d’une catégorie est une fausse bonne idée fréquente (« comme ça ils sont inscrits à tous les cours de la catégorie ! »). D’abord, ce n’est pas une inscription : les cours ne les compteront pas comme participants, le carnet de notes et les rapports se comporteront bizarrement. Ensuite, l’héritage donnera des droits d’étudiant sur des cours où ils n’ont rien à faire. Pour de l’inscription en masse, utilisez les mécanismes d’inscription (cohortes, sync, CSV) — pas les rôles de catégorie. Les rôles de catégorie sont pour l’encadrement (Manager, Créateur de cours), pas pour les apprenants.

8.2 Aparté modèle de données : mdl_role_assignments

Chaque assignation est une ligne :

-- « Qui est quoi dans le contexte 489 (notre cours Physique 101) ? » SELECT u.username, r.shortname AS role FROM mdl_role_assignments ra JOIN mdl_user u ON u.id = ra.userid JOIN mdl_role r ON r.id = ra.roleid WHERE ra.contextid = 489;

Les colonnes clés : userid, roleid, contextid, plus component/itemid quand l’assignation est gérée automatiquement par un plugin (une méthode d’inscription, par exemple) — dans ce cas l’interface l’affiche comme non modifiable manuellement.

💡 Pour un dev React : le trio mdl_role_assignments / mdl_role_capabilities / mdl_context, c’est un design pattern que vous pouvez réutiliser tel quel dans une app Next.js multi-tenant : une table d’arbre à chemin matérialisé (vos organisations/espaces), une table de définitions de rôles, une table de jointure (user, role, node). Beaucoup de SaaS B2B (Notion, Google Drive, GitHub avec ses organisations/teams/repos) implémentent des variantes de ce schéma. Moodle est une excellente étude de cas d’un tel système poussé à maturité.

📚 Aller plus loin : « Attribution des rôles » (Assign roles) sur docs.moodle.org/fr décrit chaque écran capture par capture ; la page « Category enrolments » explique pourquoi l’inscription par rôle de catégorie est déconseillée et quelles alternatives utiliser.


9. L’analogie complète pour développeur web : RBAC, claims, CSS, React Context

Cette section rassemble et systématise les analogies semées dans le chapitre. Elle vous servira de « dictionnaire bilingue » Moodle ↔ dev web.

9.1 Par rapport au RBAC classique

Le RBAC (Role-Based Access Control, contrôle d’accès à base de rôles) de manuel, c’est : users ⟶ roles ⟶ permissions, à plat. Moodle est un RBAC contextuel/hiérarchique :

RBAC classiqueMoodle
Un utilisateur a des rôles (globaux).Un utilisateur a des rôles par contexte (relation ternaire).
Un rôle est un ensemble de permissions booléennes.Un rôle donne à chaque capability une valeur à 4 états (dont deux négatifs de force différente).
La vérification est user.roles.flatMap(r => r.perms).includes(p).La vérification remonte un arbre, applique la spécificité par rôle, puis agrège entre rôles avec veto.
Pas de négation (on ne « retire » pas via un rôle).Prevent et Prohibit permettent des rôles restrictifs et des vetos.
Pas de surcharge locale.Overrides par contexte.

Si vous connaissez les modèles plus avancés — ABAC (Attribute-Based), ReBAC (Relationship-Based, façon Google Zanzibar / SpiceDB / OpenFGA) — Moodle est plus proche d’un ReBAC arborescent : la question « U peut-il C sur X ? » se résout en suivant des relations (assignations) le long d’un graphe (l’arbre des contextes), exactement comme un check Zanzibar suit des tuples object#relation@user avec héritage.

9.2 Par rapport à un système de claims (JWT)

  • Une capability ≈ un claim/scope (mod/quiz:attemptquiz:attempt).
  • Un rôle ≈ un preset de claims (comme les « roles » qu’Auth0 ou Keycloak compilent en scopes).
  • Différences majeures : les « claims » Moodle sont résolus dynamiquement à chaque requête (pas figés dans un token — pas de problème d’invalidation/expiration : retirer un rôle est effectif immédiatement) et paramétrés par le contexte (le même « token » répondrait différemment selon la page). Si vous deviez encoder les permissions Moodle dans un JWT, il faudrait un claim par capability par contexte — des dizaines de milliers d’entrées : c’est pour cela que Moodle calcule à la volée (avec des caches agressifs, que vous découvrirez côté développeur).

9.3 Par rapport à la cascade CSS

L’analogie la plus fidèle pour la résolution verticale :

CSSMoodle
Propriété héritée du parent (color).Permission héritée du contexte parent.
Sélecteur plus spécifique qui gagne.Override dans un contexte plus profond qui gagne.
Valeur inherit / propriété non déclarée.Not set.
Déclaration normale.Allow / Prevent (valeurs opposées de même force).
!important posé chez un ancêtre, qu’aucune règle descendante ne peut battre.Prohibit (en plus fort : même un autre « !important » ne le bat pas).
Plusieurs feuilles de style qui se combinent.Plusieurs rôles qui s’agrègent — mais attention, la règle d’agrégation Moodle (Allow gagne, sauf Prohibit) n’a pas d’équivalent CSS : c’est l’endroit où l’analogie casse.

9.4 Par rapport à React Context / Next.js

  • Arbre des contextes ≈ arbre des composants / des layouts. Le Système est le root layout ; chaque catégorie/cours/activité est un segment imbriqué.
  • Définition globale d’un rôle ≈ createContext(defaultValue).
  • Override ≈ <Provider value> local : visible par tout le sous-arbre, invisible ailleurs.
  • has_capabilityuseContext + logique d’agrégation : le composant consommateur lit la valeur résolue à sa position dans l’arbre.
  • Assignation de rôle ≈ monter un <RoleProvider role="teacher"> autour d’un segment précis pour un utilisateur donné.
  • L’écran « Vérifier les permissions » ≈ React DevTools, onglet Components : inspecter, à un nœud donné, la valeur effective de chaque contexte et d’où elle vient.

💡 Pour un dev React : une transposition possible du pipeline complet en pseudo-TypeScript (pour l’intuition uniquement — le vrai code viendra plus tard) :

function hasCapability(user: User, cap: string, ctx: Ctx): boolean \{ if (user.isSiteAdmin) return true; // bypass const chain = ctx.pathToRoot(); // [ctx, ..., system] const roles = user.assignmentsIn(chain); // rôles hérités const verdicts = roles.map(r => r.mostSpecificValue(cap, chain)); if (verdicts.includes(PROHIBIT)) return false; // veto return verdicts.includes(ALLOW); // deny by default \}

Si vous savez relire cette fonction dans un mois, vous avez acquis l’essentiel du chapitre.


10. Récapitulatif visuel : le pipeline « has_capability »

Un dernier schéma, tout-en-un, qui superpose les données (à gauche) et l’algorithme (à droite) :

DONNÉES (tables) ALGORITHME (à chaque vérification) ┌───────────────────────┐ │ mdl_context │ « Bob a-t-il mod/quiz:attempt │ id, level, path, │ dans le Quiz (ctx 612) ? » │ depth, instanceid │ │ └──────────┬────────────┘ ▼ │ path du ctx 612 : (1) chaîne = /1/27/153/489/612 │ /1/27/153/489/612 Système→Sciences→Physique │ →Physique101→Quiz ┌──────────┴────────────┐ │ │ mdl_role_assignments │ ▼ │ userid,roleid,ctxid │──────────▶ (2) rôles de Bob sur la chaîne : └───────────────────────┘ • Étudiant @ ctx 489 (cours) • Auth. user @ ctx 1 (système) ┌───────────────────────┐ │ │ mdl_role │ ▼ │ id, shortname, │ (3) valeur par rôle, du + spécifique │ archetype │ au + général : └───────────────────────┘ • Étudiant : ctx612? — ctx489? — … ┌───────────────────────┐ ctx1(déf. globale) → ALLOW │ mdl_role_capabilities │──────────▶ • Auth.user : (rien) → not set │ roleid, capability, │ │ │ permission, ctxid │ ▼ │ (1/-1/-1000) │ (4) agrégation : └───────────────────────┘ prohibit ? non allow ? OUI ──▶ ✅ Bob peut tenter le quiz

Prenez l’habitude, face à tout problème de permission, de dérouler ces quatre étapes dans l’ordre : chaîne → rôles → valeur par rôle → agrégation. Neuf mystères sur dix se dissipent à l’étape 2 (un rôle assigné plus haut qu’on ne le croyait) ou 3 (un override oublié).

📚 Aller plus loin : côté développeur, moodledev.io documente has_capability() et la « Access API » (https://moodledev.io/docs/apis/subsystems/access ) — vous y retrouverez mot pour mot les étapes ci-dessus, plus les mécanismes de cache. Lecture recommandée après la partie développeur de ce cours, pour ne pas brûler les étapes.


11. Boîte à outils : chemins d’administration et glossaire

11.1 Les chemins UI à mettre en favoris

TâcheChemin
Voir / modifier / créer des rôlesAdministration du site > Utilisateurs > Permissions > Définition des rôles
Contrôler qui peut attribuer / surcharger / prendre quels rôlesDéfinition des rôles > onglets Autoriser les attributions / dérogations / changements de rôle
Assigner des rôles au niveau du siteAdministration du site > Utilisateurs > Permissions > Attribution des rôles système
Gérer la liste des administrateursAdministration du site > Utilisateurs > Permissions > Administrateurs du site
Politiques globales (rôle des visiteurs, des invités, rôle par défaut)Administration du site > Utilisateurs > Permissions > Politiques utilisateur
Tester les permissions d’un utilisateur au niveau siteAdministration du site > Utilisateurs > Permissions > Vérifier les permissions du système
Inscrire des utilisateurs / attribuer des rôles dans un coursCours > Participants > Inscrire des utilisateurs / menu déroulant
Donner un rôle dans un cours sans inscrireCours > Participants > menu déroulant > Autres utilisateurs
Overrides au niveau d’un coursCours > Participants > menu déroulant > Permissions
Overrides / rôles locaux dans une activitéActivité > Plus > Permissions (+ Rôles attribués localement)
Rôles / permissions d’une catégoriePage de la catégorie > menu (roue dentée / Plus) > Attribution des rôles / Permissions
Rôles « relatifs à un utilisateur » (Parent…)Profil de l’utilisateur > Préférences > Rôles > Attribuer des rôles relatifs à cet utilisateur
Vérifier les permissions dans un contexte quelconqueÉcran Permissions du contexte > Vérifier les permissions
Se mettre à la place d’un utilisateurProfil de l’utilisateur > Se connecter sous ce nom (ou, dans un cours, « Prendre le rôle… » pour une simulation approximative — attention, la prise de rôle ne simule que le rôle, pas les assignations réelles de la personne)

(Les libellés exacts peuvent varier légèrement d’un thème ou d’une version mineure à l’autre ; la structure Administration du site > Utilisateurs > Permissions, elle, est stable depuis de nombreuses versions, et l’organisation par onglets des cours — Participants, Plus… — est celle du thème Boost depuis Moodle 4.x.)

11.2 Glossaire du chapitre

Terme (EN)Terme (FR)Définition
ContextContexteNœud de l’arbre des « lieux » de Moodle (Système, Utilisateur, Catégorie, Cours, Module, Bloc) dans lequel rôles et permissions s’appliquent. Table mdl_context, champs path/depth.
Context levelNiveau de contexteLe type d’un contexte (System=10 … Block=80) ; aussi, pour une capability, le niveau le plus profond où elle peut être surchargée.
Context pathChemin de contexteLa liste des ancêtres d’un contexte, matérialisée en base (/1/27/153/489) ; support de l’héritage descendant.
CapabilityCapacitéAction atomique contrôlable, nommée composant/nom (ex. mod/quiz:attempt), portant des indicateurs de risque (XSS, config, spam, dataloss, personal).
PermissionPermissionValeur donnée par un rôle à une capability : Not set (héritage), Allow (autoriser), Prevent (empêcher, négociable), Prohibit (interdire, veto absolu).
RoleRôleEnsemble nommé de couples capability→permission ; défini une fois globalement, produit ses effets via des assignations en contexte. Tables mdl_role, mdl_role_capabilities.
Role assignmentAttribution de rôleLe triplet utilisateur–rôle–contexte qui active un rôle pour quelqu’un quelque part. Table mdl_role_assignments.
OverrideDérogation / surchargeRedéfinition locale, dans un contexte, de la permission d’une capability pour un rôle ; s’applique au sous-arbre. Stockée dans mdl_role_capabilities avec le contextid du contexte surchargé.
ArchetypeArchétypeRôle standard de référence dont s’inspire un rôle personnalisé (valeurs par défaut, remise à zéro, permissions par défaut des nouveaux plugins). Simplement introduit ici : détaillé au chapitre 2.
has_capabilityLe nom (côté code) de la vérification « U a-t-il C dans X ? » ; l’algorithme en 4 étapes de la section 6.

Résumé

Les points à retenir absolument :

  • Tout est contexte. Moodle organise le site en un arbre de contextes — Système, Utilisateurs, Catégories, Cours, Modules, Blocs — matérialisé en base par mdl_context et son champ path. Toute permission s’évalue dans un contexte et hérite de ses ancêtres, jamais l’inverse.
  • Le contexte User est le « territoire » d’une personne : y assigner un rôle à quelqu’un d’autre (Parent, Mentor) donne des droits sur cette personne, pas des droits à cette personne.
  • Un rôle = un paquet de permissions sur des capabilities. Il est défini globalement (Administration du site > Utilisateurs > Permissions > Définition des rôles) mais assigné localement (utilisateur + rôle + contexte, table mdl_role_assignments). La question « quel est le rôle de X ? » n’a de sens que suivie de « …dans quel contexte ? ».
  • Une capability est une action atomique namespacée (mod/quiz:attempt, moodle/course:update), déclarée par le cœur ou par un plugin, avec un niveau de contexte minimal et des indicateurs de risque (XSS, config, spam, dataloss, personal) à prendre au sérieux.
  • Quatre permissions : Not set (abstention/héritage), Allow, Prevent (refus négociable), Prohibit (veto absolu, non surchargeable, non compensable). Refus par défaut en l’absence de tout Allow.
  • L’algorithme en 4 étapes : (1) chaîne de contextes via path ; (2) collecte des rôles de l’utilisateur sur la chaîne ; (3) pour chaque rôle, la valeur la plus spécifique gagne (sauf Prohibit, qui gagne partout) ; (4) agrégation entre rôles : un Prohibit → non ; sinon un Allow → oui ; sinon non. Verticalement, la spécificité tranche ; horizontalement, Allow bat Prevent.
  • Les overrides surchargent un rôle dans un contexte (écran « Permissions » du cours/de l’activité) : c’est la réponse aux besoins locaux — ne modifiez la définition globale d’un rôle que pour des politiques valables sur tout le site. Les overrides ciblent des rôles, jamais des individus.
  • Principe du moindre privilège : toujours assigner au contexte le plus bas suffisant ; se méfier des rôles au niveau Système et Catégorie ; ne jamais utiliser Prohibit pour un besoin ordinaire ; ne jamais « inscrire » via un rôle de catégorie.
  • Outils de diagnostic : « Vérifier les permissions » dans chaque contexte, « Se connecter sous le nom… », et — en dernier recours — les tables mdl_context, mdl_role, mdl_role_assignments, mdl_role_capabilities.
  • Pour votre culture de dev web : c’est un RBAC hiérarchique/contextuel, cousin des systèmes ReBAC (Zanzibar), qui combine l’héritage descendant de React Context, la spécificité de la cascade CSS, et un !important absolu nommé Prohibit.

Dans le prochain chapitre

Maintenant que vous maîtrisez la mécanique — contextes, rôles, capabilities, permissions, résolution —, il est temps de rencontrer les acteurs : le chapitre 2 passe en revue les rôles standards de Moodle (Manager, Créateur de cours, Enseignant, Enseignant non éditeur, Étudiant, Invité, Utilisateur authentifié…) : ce que chacun peut faire par défaut, la notion d’archetype que nous n’avons fait qu’effleurer ici, les réglages de rôles par défaut du site, et les recettes éprouvées de rôles personnalisés — dont le fameux rôle Parent que ce chapitre vous a déjà fait entrevoir. Vous verrez qu’avec le modèle en tête, chaque rôle standard se lit comme une simple liste de choix éditoriaux — et que les modifier sans se brûler devient un geste raisonné plutôt qu’un pari.