src/EventSubscriber/AclAccessSubscriber.php line 92

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use App\Constants\ACL;
  4. use App\Entity\User;
  5. use App\Services\Common\AclServiceV2;
  6. use JsonException;
  7. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8. use Symfony\Component\HttpKernel\Event\RequestEvent;
  9. use Symfony\Component\HttpKernel\KernelEvents;
  10. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  11. use Symfony\Component\Security\Core\Security;
  12. /**
  13. * Classe AclAccessSubscriber
  14. *
  15. * Cette classe est un abonné aux événements qui gère les droits d'accès aux différentes parties de l'application.
  16. * Elle écoute les requêtes entrantes et applique les règles d'accès définies.
  17. *
  18. * Méthodes :
  19. * - __construct: Constructeur de la classe, initialise les dépendances nécessaires pour la gestion des accès.
  20. * - onKernelRequest: Méthode appelée lors de l'événement de requête du noyau. Utilisée pour vérifier les droits
  21. * d'accès de l'utilisateur courant pour la requête en cours.
  22. * - isUriPublic: (Méthode privée) Détermine si l'URI courante est accessible publiquement sans restrictions
  23. * d'accès.
  24. *
  25. * @package App\EventSubscriber
  26. */
  27. class AclAccessSubscriber implements EventSubscriberInterface
  28. {
  29. private AclServiceV2 $aclService;
  30. private Security $security;
  31. /**
  32. * @param AclServiceV2 $aclService
  33. * @param Security $security
  34. */
  35. public function __construct( AclServiceV2 $aclService, Security $security )
  36. {
  37. $this->aclService = $aclService;
  38. $this->security = $security;
  39. }
  40. /**
  41. * Méthode appelée lors de l'événement de requête du noyau. Utilisée pour vérifier les droits d'accès de
  42. * l'utilisateur courant pour la requête en cours.
  43. *
  44. * @return string[]
  45. */
  46. public static function getSubscribedEvents(): array
  47. {
  48. return [
  49. KernelEvents::REQUEST => 'onKernelRequest',
  50. ];
  51. }
  52. /**
  53. * Listener sur la possibilité d'accéder ou non à la route de la request
  54. *
  55. * Vérifie si la route est "publique"
  56. * Vérifie si le currentUser a le droit d'accéder à la route → 403 si userIsGranted retourne FALSE
  57. * Si la route concerne le back et que le currentUser est un ROLE_USER retourne une 403
  58. *
  59. * @param RequestEvent $event
  60. *
  61. * @return void
  62. *
  63. * @throws JsonException
  64. */
  65. public function onKernelRequest( RequestEvent $event ): void
  66. {
  67. $request = $event->getRequest();
  68. /** @var User $currentUser */
  69. $currentUser = $this->security->getUser();
  70. $env = $request->get( '_env' ) ?? ACL::FRONT_ENV;
  71. $route = $request->get( '_route' );
  72. $params = json_encode( $request->get( '_route_params' ), JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE );
  73. if (
  74. $route === NULL || // pas de route
  75. $this->isUriPublic( $request->getRequestUri() )
  76. ) {
  77. return;
  78. }
  79. $isGranted = $this->aclService->userIsGranted(
  80. $currentUser,
  81. [
  82. 'route' => $route,
  83. 'params' => $params,
  84. 'component' => ACL::ACL_NO_COMPONENT,
  85. 'slug' => ACL::ACL_NO_SLUG,
  86. 'action' => ACL::READ,
  87. 'env' => $env,
  88. ]
  89. );
  90. // on bloque en plus l'accès back pour les user, en cas de soucis sur le security.yaml
  91. if ( !$isGranted || ( $env === ACL::BACK_ENV && $currentUser->isUser() ) ) {
  92. throw new AccessDeniedException( 'Vous ne disposez pas des droits suffisants pour cette page' );
  93. }
  94. }
  95. /**
  96. * Vérifie que l'url ne fait pas partie de la liste des urls accessibles par tout le monde
  97. *
  98. * @param string $uriRequested
  99. *
  100. * @return bool
  101. */
  102. private function isUriPublic( string $uriRequested ): bool
  103. {
  104. $uriPublic = [
  105. '/build/',
  106. '/js/',
  107. '/_wdt/',
  108. '/_profiler/',
  109. // uri venant de security.yaml access_control
  110. '/static-file',
  111. '/static-project-file',
  112. '/cron',
  113. '/cache-clear',
  114. '/closed-platform',
  115. '/wm-api/login',
  116. '/wm-api/doc',
  117. '/white-mark',
  118. '/api',
  119. '/portal',
  120. '/monetico',
  121. '/stripe',
  122. '/dtv/api',
  123. '/ems-api',
  124. '/charitips/webhook/donation-success',
  125. '/saml/login',
  126. '/saml/metadata',
  127. '/saml/acs',
  128. '/saml/logout',
  129. '/login',
  130. '/register',
  131. '/membership/register',
  132. '/reset-password',
  133. '/profil/accept-cgu-first',
  134. '/profil/welcome-register',
  135. '/bo-parameters',
  136. '/document',
  137. '/front-css-custom.css',
  138. '/dev',
  139. '/version',
  140. '/bdd-up',
  141. '/upgrade',
  142. '/catalogue/search.json',
  143. '/create-developer',
  144. ];
  145. $selected = array_filter( $uriPublic, static function ( $el ) use ( $uriRequested ) {
  146. return strpos( $uriRequested, $el ) === 0;
  147. } );
  148. return $selected !== [];
  149. }
  150. }