src/Hitso/Bundle/CommonBundle/EventListener/SecurityListener.php line 217

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4.  * @author Maciej Kaczmarek <maciej.kaczmarek@autentika.pl>
  5.  */
  6. namespace Hitso\Bundle\CommonBundle\EventListener;
  7. use Anyx\LoginGateBundle\Service\BruteForceChecker;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use FOS\UserBundle\Event\UserEvent;
  10. use FOS\UserBundle\FOSUserEvents;
  11. use Hitso\Bundle\CommonBundle\Entity\Log\Security;
  12. use Hitso\Bundle\CommonBundle\Entity\User;
  13. use Hitso\Bundle\CommonBundle\Entity\UserConnection;
  14. use Hitso\Bundle\CommonBundle\Entity\UserLogEntry;
  15. use Hitso\Bundle\CommonBundle\Security\Event\OAuthEvent;
  16. use Hitso\Bundle\MultiSiteBundle\MultiSite\SiteContext;
  17. use Hitso\Bundle\MultiSiteBundle\Router\MultiSiteRouter;
  18. use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use Symfony\Component\HttpFoundation\RedirectResponse;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\HttpFoundation\Session\Session;
  24. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  25. use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
  26. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  27. use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
  28. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  29. use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
  30. use Symfony\Component\Security\Http\ParameterBagUtils;
  31. use Symfony\Component\Security\Http\SecurityEvents;
  32. /**
  33.  * Class SecurityListener
  34.  *
  35.  * @codeCoverageIgnore
  36.  */
  37. class SecurityListener implements EventSubscriberInterfaceLogoutHandlerInterfaceAuthenticationSuccessHandlerInterface
  38. {
  39.     /**
  40.      * @var EntityManagerInterface
  41.      */
  42.     private $manager;
  43.     /**
  44.      * @var $router MultiSiteRouter
  45.      */
  46.     protected $router;
  47.     /**
  48.      * @var $session Session
  49.      */
  50.     protected $session;
  51.     /**
  52.      * @var UserConnection
  53.      */
  54.     private $connection;
  55.     /**
  56.      * @var SiteContext
  57.      */
  58.     private $context;
  59.     /**
  60.      * @var BruteForceChecker
  61.      */
  62.     private $bruteForceChecker;
  63.     /**
  64.      * SecurityListener constructor.
  65.      *
  66.      * @param EntityManagerInterface $manager
  67.      * @param MultiSiteRouter        $router
  68.      * @param SessionInterface       $session
  69.      * @param SiteContext            $context
  70.      */
  71.     public function __construct(
  72.         EntityManagerInterface $manager,
  73.         MultiSiteRouter $router,
  74.         SessionInterface $session,
  75.         SiteContext $context,
  76.         BruteForceChecker $bruteForceChecker
  77.     ) {
  78.         $this->manager           $manager;
  79.         $this->router            $router;
  80.         $this->session           $session;
  81.         $this->context           $context;
  82.         $this->bruteForceChecker $bruteForceChecker;
  83.     }
  84.     /**
  85.      * @inheritdoc
  86.      */
  87.     public static function getSubscribedEvents()
  88.     {
  89.         return [
  90.             SecurityEvents::INTERACTIVE_LOGIN        => 'onInteractiveLogin',
  91.             FOSUserEvents::SECURITY_IMPLICIT_LOGIN   => 'onImplicitLogin',
  92.             FOSUserEvents::REGISTRATION_COMPLETED    => 'onRegisterComplete',
  93.             FOSUserEvents::REGISTRATION_CONFIRMED    => 'onRegisterConfirmed',
  94.             FOSUserEvents::RESETTING_RESET_COMPLETED => 'onResetComplete',
  95.             OAuthEvent::EVENT_NAME                   => 'onOAuthEvent',
  96.         ];
  97.     }
  98.     /**
  99.      * Listens to interactive login event fired by Symfony Security component and logs:
  100.      *   - OAuth login
  101.      *   - interactive login
  102.      *
  103.      * @param InteractiveLoginEvent $e
  104.      *
  105.      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
  106.      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
  107.      */
  108.     public function onInteractiveLogin(InteractiveLoginEvent $e)
  109.     {
  110.         $token $e->getAuthenticationToken();
  111.         $this->setDefaultLocale($token);
  112.         if ($token instanceof OAuthToken) {
  113.             $this->log(
  114.                 new Security(
  115.                     Security::ACTION_LOGIN,
  116.                     Security::METHOD_OAUTH,
  117.                     $token->getResourceOwnerName(),
  118.                     $this->connection $this->connection->getIdentifier() : null
  119.                 ),
  120.                 $token
  121.             );
  122.         } elseif ($token instanceof RememberMeToken) {
  123.             $this->log(new Security(Security::ACTION_LOGINSecurity::METHOD_REMEMBER_ME), $token);
  124.         } else {
  125.             $this->log(new Security(Security::ACTION_LOGINSecurity::METHOD_INTERACTIVE), $token);
  126.         }
  127.     }
  128.     /**
  129.      * Save a log entry to the database.
  130.      *
  131.      * @param UserLogEntry $entry
  132.      * @param null         $tokenOrUser
  133.      */
  134.     private function log(UserLogEntry $entry$tokenOrUser null)
  135.     {
  136.         $user $this->getUserFromToken($tokenOrUser);
  137.         if ($user instanceof User) {
  138.             $entry->setUser($user);
  139.             $entry->setExtraData([
  140.                 'device' => $user->getLastLoginDevice(),
  141.             ]);
  142.         }
  143.         if (null !== $entry->getUser()) {
  144.             $this->manager->persist($entry);
  145.             $this->manager->flush();
  146.         }
  147.     }
  148.     /**
  149.      * @param null $tokenOrUser
  150.      *
  151.      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
  152.      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
  153.      */
  154.     private function setDefaultLocale($tokenOrUser null)
  155.     {
  156.         $user  $this->getUserFromToken($tokenOrUser);
  157.         $sites $this->context->getSites();
  158.         if ($sites->has($user->getDefaultLocale())) {
  159.             $site $sites->get($user->getDefaultLocale());
  160.             if (isset($user$site)) {
  161.                 $this->context->setContentSite($site);
  162.             }
  163.         }
  164.     }
  165.     /**
  166.      * @param null $tokenOrUser
  167.      *
  168.      * @return mixed|null
  169.      */
  170.     private function getUserFromToken($tokenOrUser null)
  171.     {
  172.         if ($tokenOrUser instanceof TokenInterface) {
  173.             return $tokenOrUser->getUser();
  174.         } elseif ($tokenOrUser instanceof User) {
  175.             return $tokenOrUser;
  176.         }
  177.         return null;
  178.     }
  179.     /**
  180.      * Listens to implicit login event fired by FOSUserBundle.
  181.      *
  182.      * @param UserEvent $e
  183.      *
  184.      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
  185.      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
  186.      */
  187.     public function onImplicitLogin(UserEvent $e)
  188.     {
  189.         $this->setDefaultLocale($e->getUser());
  190.         $this->log(new Security(Security::ACTION_LOGINSecurity::METHOD_IMPLICIT), $e->getUser());
  191.     }
  192.     /**
  193.      * Listens to register complete event fired by FOSUserBundle.
  194.      *
  195.      * @param UserEvent $e
  196.      */
  197.     public function onRegisterComplete(UserEvent $e)
  198.     {
  199.         $this->log(new Security(Security::ACTION_REGISTERSecurity::METHOD_INTERACTIVE), $e->getUser());
  200.     }
  201.     /**
  202.      * Listens to register confirmed event fired by FOSUserBundle.
  203.      *
  204.      * @param UserEvent $e
  205.      */
  206.     public function onRegisterConfirmed(UserEvent $e)
  207.     {
  208.         $this->log(new Security(Security::ACTION_REGISTER_CONFIRMEDSecurity::METHOD_INTERACTIVE), $e->getUser());
  209.     }
  210.     /**
  211.      * Listens to reset complete event fired by FOSUserBundle.
  212.      *
  213.      * @param UserEvent $e
  214.      */
  215.     public function onResetComplete(UserEvent $e)
  216.     {
  217.         $this->log(new Security(Security::ACTION_RESET_PASSWORDSecurity::METHOD_INTERACTIVE), $e->getUser());
  218.     }
  219.     /**
  220.      * Listens to OAuth event fired by Hitso's OAuth user provider.
  221.      *
  222.      * @param OAuthEvent $e
  223.      *
  224.      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
  225.      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
  226.      */
  227.     public function onOAuthEvent(OAuthEvent $e)
  228.     {
  229.         $this->connection $connection $e->getConnection();
  230.         $this->setDefaultLocale($e->getUser());
  231.         if ($e->isNewUser()) {
  232.             $this->log(
  233.                 new Security(
  234.                     Security::ACTION_REGISTER,
  235.                     Security::METHOD_OAUTH,
  236.                     $connection->getProvider(),
  237.                     $connection->getIdentifier()
  238.                 ),
  239.                 $e->getUser()
  240.             );
  241.             if ($e->getUser()->isEnabled()) {
  242.                 $this->log(
  243.                     new Security(
  244.                         Security::ACTION_REGISTER_CONFIRMEDSecurity::METHOD_IMPLICIT
  245.                     ),
  246.                     $e->getUser()
  247.                 );
  248.             }
  249.         }
  250.         if ($e->isNewConnection()) {
  251.             $this->log(
  252.                 new Security(
  253.                     Security::ACTION_CONNECT,
  254.                     Security::METHOD_OAUTH,
  255.                     $connection->getProvider(),
  256.                     $connection->getIdentifier()
  257.                 ),
  258.                 $e->getUser()
  259.             );
  260.         }
  261.     }
  262.     /**
  263.      * This method is called by the LogoutListener when a user has requested
  264.      * to be logged out. Usually, you would unset session variables, or remove
  265.      * cookies, etc.
  266.      *
  267.      * @param Request        $request
  268.      * @param Response       $response
  269.      * @param TokenInterface $token
  270.      */
  271.     public function logout(Request $requestResponse $responseTokenInterface $token)
  272.     {
  273.         $securityLog = new Security(Security::ACTION_LOGOUT);
  274.         $this->log($securityLog$token);
  275.     }
  276.     /**
  277.      * @param InteractiveLoginEvent $event
  278.      *
  279.      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
  280.      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
  281.      */
  282.     public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
  283.     {
  284.         $token   $event->getAuthenticationToken();
  285.         $request $event->getRequest();
  286.         $this->setDefaultLocale($token);
  287.         $this->onAuthenticationSuccess($request$token);
  288.     }
  289.     /**
  290.      * @param Request        $request
  291.      * @param TokenInterface $token
  292.      *
  293.      * @return RedirectResponse|Response
  294.      */
  295.     public function onAuthenticationSuccess(Request $requestTokenInterface $token)
  296.     {
  297.         $targetUrl urldecode(ParameterBagUtils::getRequestParameterValue($request'_target_path'));
  298.         if ($targetUrl === '') {
  299.             $targetUrl $this->router->getRouteCollection()->get('homepage') ? $this->router->generate('homepage') : '/';
  300.         }
  301.         $this->bruteForceChecker->getStorage()->clearCountAttempts($request);
  302.         return new RedirectResponse($targetUrl);
  303.     }
  304. }