Aller au contenu principal

SEC-P0-001A — Autorisation de création Publication par Acteur

Statut : rapport d’implémentation
Date : 2026-08-06
Périmètre traité : POST /api/v1/publications uniquement

Vulnérabilité initiale

L’audit SEC-P0-001 a confirmé un IDOR sur POST /api/v1/publications.

Avant correction, la route était protégée par :

  • identify.app
  • auth:sanctum
  • throttle:publication-write
  • validation exists:acteurs,id sur acteur_id
  • validation de scope applicatif dans PublicationWriteService

La création ne vérifiait pas que l’utilisateur authentifié avait un droit réel sur l’acteur ciblé par acteur_id.

Scénario d’exploitation

Un utilisateur authentifié rattaché à l’acteur A pouvait envoyer :

{
"titre": "Publication IDOR",
"contenu": "Tentative avec acteur_id falsifié.",
"scope": "public",
"type_id": "...",
"acteur_id": "acteur-B"
}

Si acteur-B existait et que le scope était compatible avec X-App-Source, le service pouvait créer la publication pour l’acteur B.

Règle cible

Pour créer une publication avec un acteur_id, l’utilisateur doit être autorisé sur cet acteur via le RBAC Acteur canonique.

Règle appliquée :

  • admin global : autorisé par ActorAccessService;
  • owner : autorisé car le rôle possède manage_publications;
  • collaborateur actif : autorisé uniquement si son rôle possède manage_publications;
  • collaborateur sans permission : refusé;
  • collaborateur inactif : refusé;
  • projection legacy user_acteurs seule : refusée.

Aucun nouveau rôle et aucune nouvelle permission n’ont été créés.

Mécanisme d’autorisation utilisé

Le correctif réutilise ActorAccessService::hasPermission($profile, $acteurId, 'manage_publications').

Ce mécanisme s’appuie sur :

  • acteur_collaborateurs;
  • acteur_roles;
  • acteur_permissions;
  • statut collaborateur active;
  • rôle admin global via Profile::isAdmin().

user_acteurs n’est pas utilisé comme source d’autorisation.

Code modifié

  • api/app/Modules/Publication/Controllers/PublicationWriteController.php
    • injection de ActorAccessService;
    • ajout du contrôle avant tout appel à PublicationWriteService::createPublication();
    • refus HTTP 403 générique si l’utilisateur n’a pas manage_publications sur l’acteur ciblé.

Le contrôle est placé dans le contrôleur de la route générique POST /api/v1/publications, conformément au périmètre SEC-P0-001A. Les autres consommateurs existants de PublicationWriteService, notamment AssoSuite et Mairie, conservent leurs mécanismes d’autorisation propres et restent hors périmètre de cette mission.

Tests ajoutés

Fichier modifié :

  • api/tests/Feature/Publication/PublicationWriteTest.php

Scénarios ajoutés :

  • collaborateur actif avec manage_publications peut créer une publication;
  • collaborateur sans manage_publications est refusé;
  • collaborateur inactif est refusé;
  • owner de l’acteur A ne peut pas publier pour l’acteur B;
  • utilisateur authentifié sans acteur est refusé;
  • projection legacy user_acteurs seule est refusée;
  • admin global conserve le comportement historique.

Le test create_publication_regression_idor_acteur_id_tiers_est_refuse_et_ne_cree_rien caractérise le scénario IDOR initial : il aurait créé une publication avant correction, et prouve désormais le refus.

Comportement refusé

Après correction, les requêtes suivantes retournent 403 et ne créent aucune ligne dans publications :

  • utilisateur sans droit sur l’acteur ciblé;
  • utilisateur owner d’un autre acteur;
  • collaborateur actif sans permission;
  • collaborateur inactif;
  • utilisateur présent seulement dans user_acteurs.

Compatibilité préservée

Les cas légitimes restent compatibles :

  • owner existant;
  • collaborateur actif doté de manage_publications;
  • admin global;
  • validation de scope existante;
  • règles de modération initiale existantes;
  • structure de réponse 201 existante.

Dette restante

Cette mission ne traite volontairement pas les autres sous-chantiers SEC-P0-001 :

  • routes IA avec actor_id;
  • abonnements et boosts;
  • Analytics;
  • services mairie avec {acteurId} et {communeId};
  • pivots commune_ids;
  • guard Acteur central;
  • Workspace;
  • dmv_public.

Ces sujets restent à traiter dans les PR suivantes de SEC-P0-001.