Étape 5 sur 5 · environ 30 min

Vérifiez le chemin complet d’une note protégée

Cette dernière étape vous fait observer des preuves concrètes dans trois interfaces et l’API. Elle permet de distinguer l’identité, les autorisations, le filtrage des enregistrements, le stockage et la simple présentation.

1. Attribuez une responsabilité à chaque couche

Gardez ce tableau sous les yeux pendant les tests. Une couche peut collaborer avec la suivante, mais elle ne remplace pas son rôle.

CoucheResponsabilité dans ce parcoursCe qu’elle ne doit pas faire
Session Odoo ou clé d’API BearerÉtablir l’identité. La session identifie le compte connecté ; la clé Bearer identifie le compte Odoo qui la possède. Odoo place ensuite cet utilisateur dans env.user ou request.env.user.Recevoir un user_id choisi par le navigateur ou accorder un droit supplémentaire.
Modèle training.noteLorsque les clients du parcours n’envoient pas user_id, remplir ce champ avec l’utilisateur courant grâce à sa valeur par défaut.Considérer cette valeur par défaut comme une validation d’un user_id envoyé par un formulaire, Owl ou l’API.
ACLAutoriser ou refuser une opération sur le modèle : lire, créer, modifier ou supprimer training.note pour le groupe Training Notes User.Choisir quelles lignes précises l’utilisateur peut atteindre.
Règle sur les enregistrements (record rule dans Odoo)Limiter les enregistrements accessibles par son domaine [('user_id', '=', user.id)]. Elle répond à la question « quelles notes ? ».Accorder une opération que l’ACL n’autorise pas.
ORMExécuter la recherche ou l’écriture dans l’environnement authentifié et appliquer le modèle, l’ACL et la règle sur les enregistrements avant l’accès SQL.Contourner les contrôles avec sudo().
PostgreSQLStocker les lignes de la table training_note, notamment l’identifiant entier de la relation user_id.Déduire l’identité depuis une saisie du navigateur ou remplacer les contrôles de l’ORM.
InterfacePrésenter et saisir les données : vue standard, page QWeb ou action cliente Owl.Devenir une frontière de sécurité grâce à un champ masqué, un bouton absent ou un filtre JavaScript.

2. Exécutez la matrice à deux utilisateurs

Utilisez les notes nommées dans la section 3. Dans chaque session, consignez seulement le résultat observé : la liste de la personne connectée contient-elle sa note et exclut-elle celle de l’autre ?

ParcoursTest avec AlexTest avec SamPreuve à observer
Vue standardCréation de Alex · vue standard acceptée ; Sam · vue standard est absente.Création de Sam · vue standard acceptée ; Alex · vue standard est absente.Le champ Propriétaire affiche le bon compte, mais la vue n’a pas choisi l’identité.
Page QWeb /training/notesLe POST crée Alex · page QWeb, puis la redirection 303 affiche cette note seulement.Le POST crée Sam · page QWeb, puis la page n’affiche pas la note d’Alex.La même URL et le même gabarit reçoivent des enregistrements différents après le filtrage de l’ORM.
Action cliente OwlAlex · Owl est créé et relu ; aucune note de Sam n’apparaît.Sam · Owl est créé et relu ; aucune note d’Alex n’apparaît.searchRead et this.orm.create utilisent la session Odoo, sans propriétaire fourni.
API Bearer /training/api/notesAvec la clé d’Alex, le GET répond 200 avec ses notes et n’inclut pas celles de Sam.Avec la clé de Sam, le GET répond 200 avec ses notes et n’inclut pas celles d’Alex.La clé établit l’identité ; le contrôleur et l’ORM appliquent ensuite la même règle de propriétaire.
Lecture de la matrice

Les créations acceptées reçoivent automatiquement le propriétaire de la session. Les lectures croisées restent absentes ou refusées dans les trois interfaces et l’API. Les différences de HTML, d’action JavaScript ou de JSON sont des différences de présentation et de transport, pas de politique.

3. Vérifiez aussi un accès direct et les appels API refusés

  1. Dans la session de Sam, ouvrez la fiche Sam · vue standard et copiez son URL. Connectez-vous comme Alex et ouvrez cette URL : Odoo doit refuser l’accès ou signaler que l’enregistrement est indisponible, sans révéler son titre ni son contenu.
  2. Dans la liste standard d’Alex, recherchez exactement Sam · vue standard : aucun résultat ne doit apparaître. Ce résultat vient de la règle sur les enregistrements, pas d’un filtre ajouté à la vue.
  3. Appelez /training/api/notes sans en-tête Authorization, comme au Jour 4 : Odoo répond 401. Une clé valide est nécessaire pour établir l’identité.
  4. Rejouez ensuite le GET avec les clés d’Alex et de Sam, à l’étape précédente. Les deux requêtes visent la même URL, mais chacune reçoit seulement les notes de son propriétaire.
L’interface ne protège jamais à elle seule

Un champ en lecture seule ou masqué, un bouton supprimé et un filtre côté client améliorent l’expérience, mais ne sont pas des frontières de sécurité. Aucun navigateur ni client ne fournit un user_id digne de confiance. Dans ce parcours, les clients ne l’envoient pas et le défaut utilise env.user. Un module qui accepterait ce champ devrait le vérifier côté serveur. Aucune route ne doit utiliser sudo() pour faire disparaître un refus.

4. Diagnostiquez dans cet ordre

Si une observation ne correspond pas à la matrice, contrôlez uniquement les éléments déjà démontrés dans le parcours :

  1. Modèle : dans custom_addons/training_hello/models/training_note.py, vérifiez le champ user_id, son défaut fondé sur self.env.user et l’absence de create() ou write() ajoutés pour cet exercice. Redémarrez Odoo après une correction Python.
  2. ACL : dans custom_addons/training_hello/security/ir.model.access.csv, vérifiez la ligne de training.note : group_training_note_user et les quatre permissions CRUD valent 1. Une modification demande une mise à niveau de Hello Odoo.
  3. Règle : dans custom_addons/training_hello/security/training_note_security.xml, contrôlez domain_force et le domaine exact [('user_id', '=', user.id)]. Mettez le module à niveau pour recharger le XML.
  4. Chargement : dans custom_addons/training_hello/__manifest__.py, vérifiez que la liste data contient l’ACL puis le XML de sécurité, avant les vues et les gabarits. Mettez le module à niveau après cette correction.
  5. Page QWeb : dans custom_addons/training_hello/controllers/training_notes.py, vérifiez auth="user", request.env["training.note"] et les routes /training/notes. Le contrôleur ne doit ni recevoir user_id ni appeler sudo().
  6. Owl : dans custom_addons/training_hello/static/src/training_notes/training_notes.js, vérifiez searchRead, this.orm.create("training.note", ...) et l’absence de propriétaire dans les valeurs envoyées. Mettez le module à niveau, puis rechargez les assets du navigateur.
  7. API : dans custom_addons/training_hello/controllers/notes_api.py, vérifiez auth="bearer", request.env.user et le domaine du propriétaire. Le contrôleur ne doit ni recevoir user_id ni appeler sudo().

Après chaque correction, rejouez la ligne concernée de la matrice avec Alex et Sam. Ne contournez pas un refus en ajoutant sudo() ou un identifiant envoyé par le client : vous masqueriez précisément le défaut à diagnostiquer.

Ce que vous devez retenir

La session ou la clé Bearer établit l’identité. L’ACL autorise des opérations sur le modèle training.note. La règle sur les enregistrements limite les lignes à leur propriétaire. Dans les créations du parcours, l’absence de user_id laisse le défaut du modèle utiliser cette identité, puis l’ORM fait respecter les droits avant que PostgreSQL ne stocke la ligne. Les vues standard, QWeb, Owl et l’API sont quatre chemins vers la même donnée protégée.

Fin du Jour 5

Vous avez vérifié la même politique avec Alex et Sam dans trois interfaces et l’API. Chaque note appartient au compte authentifié, les notes de l’autre compte restent inaccessibles et aucun client ne choisit l’identité de confiance.

Nettoyez les secrets avant d’archiver votre copie

Dans Odoo, révoquez les deux clés temporaires du Jour 5, celle d’Alex et celle de Sam. Effacez TRAINING_API_KEY_ALEX, TRAINING_API_KEY_SAM et TRAINING_DATABASE du terminal. Ne placez jamais ces secrets dans les sources, les captures ou les archives.