vendor/sentry/sentry-symfony/src/EventListener/RequestListener.php line 84

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Sentry\SentryBundle\EventListener;
  4. use Sentry\State\HubInterface;
  5. use Sentry\State\Scope;
  6. use Sentry\UserDataBag;
  7. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  8. use Symfony\Component\HttpKernel\Event\RequestEvent;
  9. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  10. use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
  11. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  12. use Symfony\Component\Security\Core\User\UserInterface;
  13. /**
  14.  * This listener ensures that a new {@see \Sentry\State\Scope} is created for
  15.  * each request and that it is filled with useful information, e.g. the IP
  16.  * address of the client.
  17.  */
  18. final class RequestListener
  19. {
  20.     use KernelEventForwardCompatibilityTrait;
  21.     /**
  22.      * @var HubInterface The current hub
  23.      */
  24.     private $hub;
  25.     /**
  26.      * @var TokenStorageInterface|null The token storage
  27.      */
  28.     private $tokenStorage;
  29.     /**
  30.      * Constructor.
  31.      *
  32.      * @param HubInterface               $hub          The current hub
  33.      * @param TokenStorageInterface|null $tokenStorage The token storage
  34.      */
  35.     public function __construct(HubInterface $hub, ?TokenStorageInterface $tokenStorage)
  36.     {
  37.         $this->hub $hub;
  38.         $this->tokenStorage $tokenStorage;
  39.     }
  40.     /**
  41.      * This method is called for each request handled by the framework and
  42.      * fills the Sentry scope with information about the current user.
  43.      *
  44.      * @param RequestEvent $event The event
  45.      */
  46.     public function handleKernelRequestEvent(RequestEvent $event): void
  47.     {
  48.         if (!$this->isMainRequest($event)) {
  49.             return;
  50.         }
  51.         $client $this->hub->getClient();
  52.         if (null === $client || !$client->getOptions()->shouldSendDefaultPii()) {
  53.             return;
  54.         }
  55.         $userData = new UserDataBag();
  56.         $userData->setIpAddress($event->getRequest()->getClientIp());
  57.         if (null !== $this->tokenStorage) {
  58.             $this->setUserData($userData$this->tokenStorage->getToken());
  59.         }
  60.         $this->hub->configureScope(static function (Scope $scope) use ($userData): void {
  61.             $scope->setUser($userData);
  62.         });
  63.     }
  64.     /**
  65.      * This method is called for each request handled by the framework and
  66.      * sets the route on the current Sentry scope.
  67.      *
  68.      * @param ControllerEvent $event The event
  69.      */
  70.     public function handleKernelControllerEvent(ControllerEvent $event): void
  71.     {
  72.         if (!$this->isMainRequest($event)) {
  73.             return;
  74.         }
  75.         $route $event->getRequest()->attributes->get('_route');
  76.         if (!\is_string($route)) {
  77.             return;
  78.         }
  79.         $this->hub->configureScope(static function (Scope $scope) use ($route): void {
  80.             $scope->setTag('route'$route);
  81.         });
  82.     }
  83.     /**
  84.      * @param UserInterface|object|string|null $user
  85.      */
  86.     private function getUsername($user): ?string
  87.     {
  88.         if ($user instanceof UserInterface) {
  89.             if (method_exists($user'getUserIdentifier')) {
  90.                 return $user->getUserIdentifier();
  91.             }
  92.             if (method_exists($user'getUsername')) {
  93.                 return $user->getUsername();
  94.             }
  95.         }
  96.         if (\is_string($user)) {
  97.             return $user;
  98.         }
  99.         if (\is_object($user) && method_exists($user'__toString')) {
  100.             return (string) $user;
  101.         }
  102.         return null;
  103.     }
  104.     private function getImpersonatorUser(TokenInterface $token): ?string
  105.     {
  106.         if (!$token instanceof SwitchUserToken) {
  107.             return null;
  108.         }
  109.         return $this->getUsername($token->getOriginalToken()->getUser());
  110.     }
  111.     private function setUserData(UserDataBag $userData, ?TokenInterface $token): void
  112.     {
  113.         if (null === $token || !$this->isTokenAuthenticated($token)) {
  114.             return;
  115.         }
  116.         $userData->setUsername($this->getUsername($token->getUser()));
  117.         $impersonatorUser $this->getImpersonatorUser($token);
  118.         if (null !== $impersonatorUser) {
  119.             $userData->setMetadata('impersonator_username'$impersonatorUser);
  120.         }
  121.     }
  122.     private function isTokenAuthenticated(TokenInterface $token): bool
  123.     {
  124.         if (method_exists($token'isAuthenticated') && !$token->isAuthenticated(false)) {
  125.             return false;
  126.         }
  127.         return null !== $token->getUser();
  128.     }
  129. }