src/Listener/Security/LockoutPolicyListener.php line 46

Open in your IDE?
  1. <?php
  2. namespace App\Listener\Security;
  3. use App\Entity\Notification;
  4. use App\Entity\Notification\StaffNotification;
  5. use App\Entity\User;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8. use Symfony\Component\HttpFoundation\RequestStack;
  9. use Symfony\Component\Security\Core\AuthenticationEvents;
  10. use Symfony\Component\Security\Core\Event\AuthenticationEvent;
  11. use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
  12. use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
  13. class LockoutPolicyListener implements EventSubscriberInterface
  14. {
  15.     /**
  16.      * @var EntityManagerInterface
  17.      */
  18.     private $em;
  19.     /**
  20.      * @var int
  21.      */
  22.     private $lockoutPolicy;
  23.     /**
  24.      * @var RequestStack
  25.      */
  26.     private $requestStack;
  27.     public static function getSubscribedEvents()
  28.     {
  29.         return [
  30.             AuthenticationEvents::AUTHENTICATION_FAILURE => 'onFailure',
  31.             AuthenticationEvents::AUTHENTICATION_SUCCESS => 'onSuccess',
  32.         ];
  33.     }
  34.     public function __construct(EntityManagerInterface $emRequestStack $requestStackint $lockoutPolicy)
  35.     {
  36.         $this->em $em;
  37.         $this->lockoutPolicy $lockoutPolicy;
  38.         $this->requestStack $requestStack;
  39.     }
  40.     public function onFailure(AuthenticationFailureEvent $event)
  41.     {
  42.         $email $event->getAuthenticationToken()->getCredentials()['_username'];
  43.         $user $this->em->getRepository(User::class)->findUser($email);
  44.         if (!$user instanceof User) {
  45.             return;
  46.         }
  47.         if ($user->getGroups()->isEmpty()) {
  48.             return;
  49.         }
  50.         if ($user->isRemoved()) {
  51.             return;
  52.         }
  53.         if ($user->getFailures() >= $this->lockoutPolicy) {
  54.             throw new CustomUserMessageAuthenticationException('account.locked');
  55.         }
  56.         $user->incrementFailures();
  57.         if ($user->getFailures() >= $this->lockoutPolicy) {
  58.             // Create staff notification
  59.             $notification = (new StaffNotification())->setup(
  60.                 $user,
  61.                 sprintf('User %s has been blocked due to too many consecutive authentication failures.'$user->getEmail()),
  62.                 sprintf('user.lockout.%d'$user->getId()),
  63.                 'staff.users.index',
  64.                 false
  65.             );
  66.             $this->em->getRepository(Notification::class)->notifyStaff($notificationfalse);
  67.         }
  68.         $this->em->flush();
  69.     }
  70.     public function onSuccess(AuthenticationEvent $event)
  71.     {
  72.         $user $event->getAuthenticationToken()->getUser();
  73.         if (!$user instanceof User) {
  74.             return;
  75.         }
  76.         $user->resetFailures();
  77.         $this->em->flush();
  78.     }
  79. }