vendor/sentry/sentry-symfony/src/EventListener/LoginListener.php line 48

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\RequestEvent;
  8. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  9. use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
  10. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  11. use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
  12. use Symfony\Component\Security\Core\User\UserInterface;
  13. use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
  14. final class LoginListener
  15. {
  16.     use KernelEventForwardCompatibilityTrait;
  17.     /**
  18.      * @var HubInterface The current hub
  19.      */
  20.     private $hub;
  21.     /**
  22.      * @var TokenStorageInterface|null The token storage
  23.      */
  24.     private $tokenStorage;
  25.     /**
  26.      * Constructor.
  27.      *
  28.      * @param HubInterface               $hub          The current hub
  29.      * @param TokenStorageInterface|null $tokenStorage The token storage
  30.      */
  31.     public function __construct(HubInterface $hub, ?TokenStorageInterface $tokenStorage)
  32.     {
  33.         $this->hub $hub;
  34.         $this->tokenStorage $tokenStorage;
  35.     }
  36.     /**
  37.      * This method is called for each request handled by the framework and
  38.      * fills the Sentry scope with information about the current user.
  39.      */
  40.     public function handleKernelRequestEvent(RequestEvent $event): void
  41.     {
  42.         if (null === $this->tokenStorage || !$this->isMainRequest($event)) {
  43.             return;
  44.         }
  45.         $token $this->tokenStorage->getToken();
  46.         if (null !== $token) {
  47.             $this->updateUserContext($token);
  48.         }
  49.     }
  50.     /**
  51.      * This method is called after authentication was fully successful. It allows
  52.      * to set information like the username of the currently authenticated user
  53.      * and of the impersonator, if any, on the Sentry's context.
  54.      */
  55.     public function handleLoginSuccessEvent(LoginSuccessEvent $event): void
  56.     {
  57.         $this->updateUserContext($event->getAuthenticatedToken());
  58.     }
  59.     /**
  60.      * This method is called when an authentication provider authenticates the
  61.      * user. It is the event closest to {@see LoginSuccessEvent} in versions of
  62.      * the framework where it doesn't exist.
  63.      */
  64.     public function handleAuthenticationSuccessEvent(AuthenticationSuccessEvent $event): void
  65.     {
  66.         $this->updateUserContext($event->getAuthenticationToken());
  67.     }
  68.     private function updateUserContext(TokenInterface $token): void
  69.     {
  70.         if (!$this->isTokenAuthenticated($token)) {
  71.             return;
  72.         }
  73.         $client $this->hub->getClient();
  74.         if (null === $client || !$client->getOptions()->shouldSendDefaultPii()) {
  75.             return;
  76.         }
  77.         $this->hub->configureScope(function (Scope $scope) use ($token): void {
  78.             $user $scope->getUser() ?? new UserDataBag();
  79.             if (null === $user->getId()) {
  80.                 $user->setId($this->getUserIdentifier($token->getUser()));
  81.             }
  82.             $impersonatorUser $this->getImpersonatorUser($token);
  83.             if (null !== $impersonatorUser) {
  84.                 $user->setMetadata('impersonator_username'$impersonatorUser);
  85.             }
  86.             $scope->setUser($user);
  87.         });
  88.     }
  89.     private function isTokenAuthenticated(TokenInterface $token): bool
  90.     {
  91.         if (method_exists($token'isAuthenticated') && !$token->isAuthenticated(false)) {
  92.             return false;
  93.         }
  94.         return null !== $token->getUser();
  95.     }
  96.     /**
  97.      * @param UserInterface|\Stringable|string|null $user
  98.      */
  99.     private function getUserIdentifier($user): ?string
  100.     {
  101.         if ($user instanceof UserInterface) {
  102.             if (method_exists($user'getUserIdentifier')) {
  103.                 return $user->getUserIdentifier();
  104.             }
  105.             if (method_exists($user'getUsername')) {
  106.                 return $user->getUsername();
  107.             }
  108.         }
  109.         if (\is_string($user)) {
  110.             return $user;
  111.         }
  112.         if (\is_object($user) && method_exists($user'__toString')) {
  113.             return (string) $user;
  114.         }
  115.         return null;
  116.     }
  117.     private function getImpersonatorUser(TokenInterface $token): ?string
  118.     {
  119.         if ($token instanceof SwitchUserToken) {
  120.             return $this->getUserIdentifier($token->getOriginalToken()->getUser());
  121.         }
  122.         return null;
  123.     }
  124. }