src/Platform/SecurityBundle/Service/Authenticator/LoginFormAuthenticator.php line 95

Open in your IDE?
  1. <?php
  2. namespace Platform\SecurityBundle\Service\Authenticator;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Platform\SecurityBundle\Controller\LoginController;
  5. use Platform\SecurityBundle\Doctrine\Identity\AccountRepository;
  6. use Platform\SecurityBundle\Entity\Identity\Account;
  7. use Platform\SecurityBundle\Entity\Login\Attempt;
  8. use Symfony\Component\HttpFoundation\RedirectResponse;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpFoundation\Response;
  11. use Symfony\Component\Routing\RouterInterface;
  12. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  13. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  14. use Symfony\Component\Security\Core\Exception\UserNotFoundException;
  15. use Symfony\Component\Security\Core\Security;
  16. use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
  17. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
  18. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  19. use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
  20. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  21. use Symfony\Component\Security\Http\HttpUtils;
  22. use Symfony\Component\Security\Http\Util\TargetPathTrait;
  23. use Exception;
  24. class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
  25. {
  26.     use TargetPathTrait;
  27.     /**
  28.      * @var EntityManagerInterface
  29.      */
  30.     protected EntityManagerInterface $em;
  31.     /**
  32.      * @var RouterInterface
  33.      */
  34.     protected RouterInterface $router;
  35.     /**
  36.      * @var AccountRepository
  37.      */
  38.     protected AccountRepository $accountRepository;
  39.     /**
  40.      * @var HttpUtils
  41.      */
  42.     protected HttpUtils $httpUtils;
  43.     /**
  44.      * @param EntityManagerInterface $em
  45.      * @param RouterInterface $router
  46.      * @param HttpUtils $httpUtils
  47.      */
  48.     public function __construct(
  49.         EntityManagerInterface $em,
  50.         RouterInterface $router,
  51.         HttpUtils $httpUtils
  52.     )
  53.     {
  54.         $this->em $em;
  55.         $this->router $router;
  56.         $this->httpUtils $httpUtils;
  57.         /** @var AccountRepository $accountRepository */
  58.         $accountRepository $this->em->getRepository(Account::class);
  59.         $this->accountRepository $accountRepository;
  60.     }
  61.     /**
  62.      * @param Request $request
  63.      * @return string
  64.      */
  65.     protected function getLoginUrl(Request $request): string
  66.     {
  67.         return $this->router->generate(LoginController::ROUTES__SELECT);
  68.     }
  69.     /**
  70.      * @param Request $request
  71.      * @return Passport
  72.      */
  73.     public function authenticate(Request $request): Passport
  74.     {
  75.         $email trim($request->request->get('login')['username']);
  76.         $password trim($request->request->get('login')['password']);
  77.         $csrfToken trim($request->request->get('login')['_token']);
  78.         if (empty($email) || empty($password) || empty($csrfToken)) {
  79.             throw new AuthenticationException('Improper login.');
  80.         }
  81.         return new Passport(
  82.             new UserBadge($email, function (string $userIdentifier) {
  83.                 $account $this->accountRepository->findOneBy(['email' => $userIdentifier]);
  84.                 if ( ! $account instanceof Account) {
  85.                     throw new UserNotFoundException();
  86.                 }
  87.                 return $account;
  88.             }),
  89.             new PasswordCredentials($password),
  90.             [
  91.                 new CsrfTokenBadge('login'$csrfToken),
  92.             ]
  93.         );
  94.     }
  95.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  96.     {
  97.         /** @var Account $account */
  98.         $account = ($token->getUser() instanceof Account) ? $token->getUser() : null;
  99.         $this->logSuccessfulAttempt($account$request->getClientIp());
  100.         return null;
  101.     }
  102.     /**
  103.      * @param Request $request
  104.      * @param AuthenticationException $exception
  105.      * @return Response
  106.      * @throws Exception
  107.      */
  108.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): Response
  109.     {
  110.         $message = ( ! empty($exception->getMessage())) ? trim(substr($exception->getMessage(), 0250)) : null;
  111.         $this->logFailedAttempt($request->getClientIp(), $message);
  112.         $request->getSession()->set(Security::AUTHENTICATION_ERROR$exception);
  113.         return new RedirectResponse(
  114.             $this->router->generate(LoginController::ROUTES__SELECT)
  115.         );
  116.     }
  117.     /**
  118.      * @param Account $account
  119.      * @param string|null $ip
  120.      * @return void
  121.      * @throws Exception
  122.      */
  123.     private function logSuccessfulAttempt(Account $account, ?string $ip): void
  124.     {
  125.         $attempt = (new Attempt())
  126.             ->setAccount($account)
  127.             ->setRedirect(null)
  128.             ->setIp($ip)
  129.             ->setStatus(true)
  130.             ->setAuthType(Attempt::AUTH_TYPE__WEB)
  131.         ;
  132.         $this->em->persist($attempt);
  133.         $this->em->flush();
  134.     }
  135.     /**
  136.      * @param string|null $ip
  137.      * @param string|null $message
  138.      * @return void
  139.      * @throws Exception
  140.      */
  141.     private function logFailedAttempt(?string $ip, ?string $message): void
  142.     {
  143.         $attempt = (new Attempt())
  144.             ->setRedirect(null)
  145.             ->setIp($ip)
  146.             ->setStatus(false)
  147.             ->setAuthType(Attempt::AUTH_TYPE__WEB)
  148.         ;
  149.         if ( ! empty($message)) {
  150.             $attempt->setMessage($message);
  151.         }
  152.         $this->em->persist($attempt);
  153.         $this->em->flush();
  154.     }
  155. }