Paillasse/docs/adr/0010-lti-moodle-comme-sixieme-facon-de-rejoindre.md
Adam Belkacemi 91d7cde4c1 ajoute Moodle LTI 1.3 (V2), une 6e façon de rejoindre une classe
LTI authentifie l'élève et le fait rejoindre sa classe (même code que
le code/QR existant), pas lancer un lab précis - relecture du
CLAUDE.md qui liste LTI avec les autres façons d'ajouter des élèves.
packbackbooks/lti-1p3-tool (Apache-2.0, recommandé par le CLAUDE.md),
trois ponts vers Redis/cookies/MariaDB, élève retrouvé par identité
Moodle stable pour ne jamais créer de doublon. Enregistrement d'une
plateforme/d'un déploiement par commande Artisan (opération rare,
faite à la main par Adam), jamais une page d'administration.

Corrige au passage un vrai bug préexistant trouvé en vérifiant en réel
sur le serveur : withoutMiddleware(ValidateCsrfToken::class) sur une
route ne retire jamais le vrai middleware CSRF (ValidateCsrfToken est
un alias déprécié de PreventRequestForgery, pas la classe réellement
enregistrée) - /csp-rapport avait le même défaut depuis l'étape 14,
invisible faute de surveillance. Corrigé pour les deux par la bonne
méthode (validateCsrfTokens except, dans bootstrap/app.php).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-14 13:51:47 +02:00

4 KiB

ADR 0010 — LTI 1.3 Moodle : une 6ᵉ façon de rejoindre une classe, pas un lancement de lab

  • Date : 2026-10-14
  • Statut : accepté

Contexte

CLAUDE.md, section 6 : « Moodle LTI 1.3 (V2) » est listé avec les autres façons d'ajouter des élèves (code/QR, import CSV, saisie rapide, invitation e-mail) — pas dans la description de l'espace de lab. Avancé à la demande explicite d'Adam (bloc C terminé, V2 lancée par anticipation).

Décisions

LTI sert à rejoindre une classe, pas à lancer un lab précis. Un lancement Moodle authentifie l'élève (OIDC + jeton signé) et le fait atterrir sur son tableau de bord habituel (eleve.show) — depuis là, il choisit un lab ou un devoir normalement, par le portail. Construire un lien direct vers un lab précis aurait demandé de router l'admission dans une séance (SeanceController::admettre), bien plus complexe, pour un besoin que le CLAUDE.md ne demande pas.

L'URL de lancement réutilise code_classe existant (/lti/lancement/{code_classe}), pas un nouveau jeton ou une nouvelle table de liaison. Exactement la même donnée que celle déjà affichée pour « Faire rejoindre tes élèves » (code/QR) — LTI est juste une 6ᵉ porte vers la même classe, pas un concept à part.

packbackbooks/lti-1p3-tool (Apache-2.0), recommandé par le CLAUDE.md. Bibliothèque bas niveau (pas de dépendance à un framework) : il faut lui fournir trois implémentations (ICache, ICookie, IDatabase, dans App\Services\Lti\) qui s'appuient sur Redis, les cookies et les tables lti_plateformes/lti_deploiements déjà en place.

Élève provisionné automatiquement au premier lancement, retrouvé par (classe_id, lti_emetteur, lti_sub) ensuite — jamais de doublon de compte à chaque connexion. Prénom/nom lus depuis les claims standards (given_name/family_name, puis name, jamais inventés : « Élève » / « Moodle » si Moodle n'envoie rien). Code secret généré au hasard, haché, jamais affiché : cet élève se connecte toujours via Moodle, jamais par identifiant/code comme les autres.

Cookie SameSite=None; Secure pour le jeton d'état OIDC. Sans ça, le cookie ne survit jamais au POST final que Moodle envoie depuis son propre domaine — chaque lancement échouerait silencieusement (« Please make sure you have cookies… », message déjà prévu par la bibliothèque pour ce cas précis, qui n'arrive qu'avec un réglage de cookie insuffisant).

Sécurité x-pack… non, pas de rapport ici — mais même logique que pour Elasticsearch/Ceph : une seule clé RSA par plateforme Moodle enregistrée (générée par le portail lui-même à l'enregistrement, phpseclib4\Crypt\RSA, jamais collée par Adam), exposée en public via /lti/cles.json — c'est le fonctionnement normal du protocole (Moodle doit pouvoir vérifier les jetons que nous lui envoyons, si jamais le portail appelle un service LTI plus tard), pas une fuite.

Enregistrement manuel, par commande Artisan, jamais une page d'administration. Une plateforme Moodle se configure une fois par établissement, par Adam, avec des informations lues dans l'administration Moodle — une page web pour ça serait une fonctionnalité sans usage réel (CLAUDE.md, section 8). lti:enregistrer-plateforme et lti:enregistrer-deploiement, voir docs/runbooks/lti-moodle.md.

Conséquences

  • Testé avec un jeton LTI réellement signé (RS256, paire de clés générée dans le test), jeu de clés de « Moodle » simulé : lancement validé de bout en bout, élève créé avec le bon prénom/nom, deuxième lancement du même élève ne crée pas de deuxième compte. Pas de vrai Moodle disponible pour vérifier en conditions réelles — à refaire dès qu'Adam a un Moodle de test.
  • En dette : pas de web service LTI (AGS pour les notes, NRPS pour la liste des inscrits, Deep Linking) — seul le lancement de ressource est géré, comme décidé ci-dessus. Les classes de la bibliothèque pour ces services existent déjà (LtiAssignmentsGradesService etc.) si le besoin devient réel.