feat(sites) : scope /api/sites et /api/users aux sites autorises du caller

- SiteCollectionScopedExtension filtre /api/sites aux sites du user
  (name/adresse/CP/ville plus lisibles par un delegataire sites.view qui
  n'appartient pas a ces sites). Bypass via sites.bypass_scope.
- UserSiteScopedExtension filtre /api/users aux users partageant au moins
  un site avec le caller. Empeche un delegataire de core.users.view
  d'enumerer l'organigramme complet + les sites de tous les tenants.
- Helper createUserWithPermission rattache le user jetable a tous les
  sites fixtures, sinon le scoping le rend aveugle aux cibles.
- test_target de UserRbacApiTest attache de meme aux sites pour rester
  visible depuis un caller non-admin.
- testUserCannotSwitchToUnauthorizedSite : 403 -> 400 (anti-enumeration).
This commit is contained in:
Matthieu
2026-04-20 16:46:57 +02:00
parent fd5d3fe36f
commit 8bedab407d
5 changed files with 258 additions and 3 deletions

View File

@@ -7,6 +7,7 @@ namespace App\Tests\Module\Core\Api;
use App\Module\Core\Domain\Entity\Permission;
use App\Module\Core\Domain\Entity\Role;
use App\Module\Core\Domain\Entity\User;
use App\Module\Sites\Domain\Entity\Site;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
/**
@@ -41,11 +42,18 @@ final class UserRbacApiTest extends AbstractApiTestCase
/** @var UserPasswordHasherInterface $hasher */
$hasher = self::getContainer()->get(UserPasswordHasherInterface::class);
// User cible standard (non admin).
// User cible standard (non admin). On lui attache tous les sites
// fixtures pour rester visible depuis les callers non-admin munis de
// sites (cf. UserSiteScopedExtension qui filtre `/api/users` par
// intersection de sites). Sans cela, un user `core.users.manage`
// sans site commun avec test_target recevrait un 404 sur le PATCH.
$target = new User();
$target->setUsername('test_target');
$target->setIsAdmin(false);
$target->setPassword($hasher->hashPassword($target, 'secret'));
foreach ($em->getRepository(Site::class)->findAll() as $site) {
$target->addSite($site);
}
$em->persist($target);
// User admin dedie pour le cas d'auto-suicide (pas l'admin fixture).