- <?php
- declare(strict_types=1);
- /**
-  * @author Maciej Kaczmarek <maciej.kaczmarek@autentika.pl>
-  */
- namespace Hitso\Bundle\CommonBundle\EventListener;
- use Anyx\LoginGateBundle\Service\BruteForceChecker;
- use Doctrine\ORM\EntityManagerInterface;
- use FOS\UserBundle\Event\UserEvent;
- use FOS\UserBundle\FOSUserEvents;
- use Hitso\Bundle\CommonBundle\Entity\Log\Security;
- use Hitso\Bundle\CommonBundle\Entity\User;
- use Hitso\Bundle\CommonBundle\Entity\UserConnection;
- use Hitso\Bundle\CommonBundle\Entity\UserLogEntry;
- use Hitso\Bundle\CommonBundle\Security\Event\OAuthEvent;
- use Hitso\Bundle\MultiSiteBundle\MultiSite\SiteContext;
- use Hitso\Bundle\MultiSiteBundle\Router\MultiSiteRouter;
- use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken;
- use Symfony\Component\EventDispatcher\EventSubscriberInterface;
- use Symfony\Component\HttpFoundation\RedirectResponse;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\HttpFoundation\Session\Session;
- use Symfony\Component\HttpFoundation\Session\SessionInterface;
- use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
- use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
- use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
- use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
- use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
- use Symfony\Component\Security\Http\ParameterBagUtils;
- use Symfony\Component\Security\Http\SecurityEvents;
- /**
-  * Class SecurityListener
-  *
-  * @codeCoverageIgnore
-  */
- class SecurityListener implements EventSubscriberInterface, LogoutHandlerInterface, AuthenticationSuccessHandlerInterface
- {
-     /**
-      * @var EntityManagerInterface
-      */
-     private $manager;
-     /**
-      * @var $router MultiSiteRouter
-      */
-     protected $router;
-     /**
-      * @var $session Session
-      */
-     protected $session;
-     /**
-      * @var UserConnection
-      */
-     private $connection;
-     /**
-      * @var SiteContext
-      */
-     private $context;
-     /**
-      * @var BruteForceChecker
-      */
-     private $bruteForceChecker;
-     /**
-      * SecurityListener constructor.
-      *
-      * @param EntityManagerInterface $manager
-      * @param MultiSiteRouter        $router
-      * @param SessionInterface       $session
-      * @param SiteContext            $context
-      */
-     public function __construct(
-         EntityManagerInterface $manager,
-         MultiSiteRouter $router,
-         SessionInterface $session,
-         SiteContext $context,
-         BruteForceChecker $bruteForceChecker
-     ) {
-         $this->manager           = $manager;
-         $this->router            = $router;
-         $this->session           = $session;
-         $this->context           = $context;
-         $this->bruteForceChecker = $bruteForceChecker;
-     }
-     /**
-      * @inheritdoc
-      */
-     public static function getSubscribedEvents()
-     {
-         return [
-             SecurityEvents::INTERACTIVE_LOGIN        => 'onInteractiveLogin',
-             FOSUserEvents::SECURITY_IMPLICIT_LOGIN   => 'onImplicitLogin',
-             FOSUserEvents::REGISTRATION_COMPLETED    => 'onRegisterComplete',
-             FOSUserEvents::REGISTRATION_CONFIRMED    => 'onRegisterConfirmed',
-             FOSUserEvents::RESETTING_RESET_COMPLETED => 'onResetComplete',
-             OAuthEvent::EVENT_NAME                   => 'onOAuthEvent',
-         ];
-     }
-     /**
-      * Listens to interactive login event fired by Symfony Security component and logs:
-      *   - OAuth login
-      *   - interactive login
-      *
-      * @param InteractiveLoginEvent $e
-      *
-      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
-      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
-      */
-     public function onInteractiveLogin(InteractiveLoginEvent $e)
-     {
-         $token = $e->getAuthenticationToken();
-         $this->setDefaultLocale($token);
-         if ($token instanceof OAuthToken) {
-             $this->log(
-                 new Security(
-                     Security::ACTION_LOGIN,
-                     Security::METHOD_OAUTH,
-                     $token->getResourceOwnerName(),
-                     $this->connection ? $this->connection->getIdentifier() : null
-                 ),
-                 $token
-             );
-         } elseif ($token instanceof RememberMeToken) {
-             $this->log(new Security(Security::ACTION_LOGIN, Security::METHOD_REMEMBER_ME), $token);
-         } else {
-             $this->log(new Security(Security::ACTION_LOGIN, Security::METHOD_INTERACTIVE), $token);
-         }
-     }
-     /**
-      * Save a log entry to the database.
-      *
-      * @param UserLogEntry $entry
-      * @param null         $tokenOrUser
-      */
-     private function log(UserLogEntry $entry, $tokenOrUser = null)
-     {
-         $user = $this->getUserFromToken($tokenOrUser);
-         if ($user instanceof User) {
-             $entry->setUser($user);
-             $entry->setExtraData([
-                 'device' => $user->getLastLoginDevice(),
-             ]);
-         }
-         if (null !== $entry->getUser()) {
-             $this->manager->persist($entry);
-             $this->manager->flush();
-         }
-     }
-     /**
-      * @param null $tokenOrUser
-      *
-      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
-      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
-      */
-     private function setDefaultLocale($tokenOrUser = null)
-     {
-         $user  = $this->getUserFromToken($tokenOrUser);
-         $sites = $this->context->getSites();
-         if ($sites->has($user->getDefaultLocale())) {
-             $site = $sites->get($user->getDefaultLocale());
-             if (isset($user, $site)) {
-                 $this->context->setContentSite($site);
-             }
-         }
-     }
-     /**
-      * @param null $tokenOrUser
-      *
-      * @return mixed|null
-      */
-     private function getUserFromToken($tokenOrUser = null)
-     {
-         if ($tokenOrUser instanceof TokenInterface) {
-             return $tokenOrUser->getUser();
-         } elseif ($tokenOrUser instanceof User) {
-             return $tokenOrUser;
-         }
-         return null;
-     }
-     /**
-      * Listens to implicit login event fired by FOSUserBundle.
-      *
-      * @param UserEvent $e
-      *
-      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
-      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
-      */
-     public function onImplicitLogin(UserEvent $e)
-     {
-         $this->setDefaultLocale($e->getUser());
-         $this->log(new Security(Security::ACTION_LOGIN, Security::METHOD_IMPLICIT), $e->getUser());
-     }
-     /**
-      * Listens to register complete event fired by FOSUserBundle.
-      *
-      * @param UserEvent $e
-      */
-     public function onRegisterComplete(UserEvent $e)
-     {
-         $this->log(new Security(Security::ACTION_REGISTER, Security::METHOD_INTERACTIVE), $e->getUser());
-     }
-     /**
-      * Listens to register confirmed event fired by FOSUserBundle.
-      *
-      * @param UserEvent $e
-      */
-     public function onRegisterConfirmed(UserEvent $e)
-     {
-         $this->log(new Security(Security::ACTION_REGISTER_CONFIRMED, Security::METHOD_INTERACTIVE), $e->getUser());
-     }
-     /**
-      * Listens to reset complete event fired by FOSUserBundle.
-      *
-      * @param UserEvent $e
-      */
-     public function onResetComplete(UserEvent $e)
-     {
-         $this->log(new Security(Security::ACTION_RESET_PASSWORD, Security::METHOD_INTERACTIVE), $e->getUser());
-     }
-     /**
-      * Listens to OAuth event fired by Hitso's OAuth user provider.
-      *
-      * @param OAuthEvent $e
-      *
-      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
-      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
-      */
-     public function onOAuthEvent(OAuthEvent $e)
-     {
-         $this->connection = $connection = $e->getConnection();
-         $this->setDefaultLocale($e->getUser());
-         if ($e->isNewUser()) {
-             $this->log(
-                 new Security(
-                     Security::ACTION_REGISTER,
-                     Security::METHOD_OAUTH,
-                     $connection->getProvider(),
-                     $connection->getIdentifier()
-                 ),
-                 $e->getUser()
-             );
-             if ($e->getUser()->isEnabled()) {
-                 $this->log(
-                     new Security(
-                         Security::ACTION_REGISTER_CONFIRMED, Security::METHOD_IMPLICIT
-                     ),
-                     $e->getUser()
-                 );
-             }
-         }
-         if ($e->isNewConnection()) {
-             $this->log(
-                 new Security(
-                     Security::ACTION_CONNECT,
-                     Security::METHOD_OAUTH,
-                     $connection->getProvider(),
-                     $connection->getIdentifier()
-                 ),
-                 $e->getUser()
-             );
-         }
-     }
-     /**
-      * This method is called by the LogoutListener when a user has requested
-      * to be logged out. Usually, you would unset session variables, or remove
-      * cookies, etc.
-      *
-      * @param Request        $request
-      * @param Response       $response
-      * @param TokenInterface $token
-      */
-     public function logout(Request $request, Response $response, TokenInterface $token)
-     {
-         $securityLog = new Security(Security::ACTION_LOGOUT);
-         $this->log($securityLog, $token);
-     }
-     /**
-      * @param InteractiveLoginEvent $event
-      *
-      * @throws \Hitso\Bundle\CommonBundle\Exception\InvalidArgumentException
-      * @throws \Hitso\Bundle\MultiSiteBundle\Exception\InvalidArgumentException
-      */
-     public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
-     {
-         $token   = $event->getAuthenticationToken();
-         $request = $event->getRequest();
-         $this->setDefaultLocale($token);
-         $this->onAuthenticationSuccess($request, $token);
-     }
-     /**
-      * @param Request        $request
-      * @param TokenInterface $token
-      *
-      * @return RedirectResponse|Response
-      */
-     public function onAuthenticationSuccess(Request $request, TokenInterface $token)
-     {
-         $targetUrl = urldecode(ParameterBagUtils::getRequestParameterValue($request, '_target_path'));
-         if ($targetUrl === '') {
-             $targetUrl = $this->router->getRouteCollection()->get('homepage') ? $this->router->generate('homepage') : '/';
-         }
-         $this->bruteForceChecker->getStorage()->clearCountAttempts($request);
-         return new RedirectResponse($targetUrl);
-     }
- }
-