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

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.     // TODO: redirecting still not works
  27.     use TargetPathTrait;
  28.     /**
  29.      * @var EntityManagerInterface
  30.      */
  31.     protected EntityManagerInterface $em;
  32.     /**
  33.      * @var RouterInterface
  34.      */
  35.     protected RouterInterface $router;
  36.     /**
  37.      * @var AccountRepository
  38.      */
  39.     protected AccountRepository $accountRepository;
  40.     /**
  41.      * @var HttpUtils
  42.      */
  43.     protected HttpUtils $httpUtils;
  44.     /**
  45.      * @param EntityManagerInterface $em
  46.      * @param RouterInterface $router
  47.      * @param HttpUtils $httpUtils
  48.      */
  49.     public function __construct(
  50.         EntityManagerInterface $em,
  51.         RouterInterface $router,
  52.         HttpUtils $httpUtils
  53.     )
  54.     {
  55.         $this->em $em;
  56.         $this->router $router;
  57.         $this->httpUtils $httpUtils;
  58.         /** @var AccountRepository $accountRepository */
  59.         $accountRepository $this->em->getRepository(Account::class);
  60.         $this->accountRepository $accountRepository;
  61.     }
  62.     /**
  63.      * @param Request $request
  64.      * @return string
  65.      */
  66.     protected function getLoginUrl(Request $request): string
  67.     {
  68.         return $this->router->generate(LoginController::ROUTES__SELECT);
  69.     }
  70.     /**
  71.      * @param Request $request
  72.      * @return Passport
  73.      */
  74.     public function authenticate(Request $request): Passport
  75.     {
  76.         $email trim($request->request->get('login')['username']);
  77.         $password trim($request->request->get('login')['password']);
  78.         $csrfToken trim($request->request->get('login')['_token']);
  79.         if (empty($email) || empty($password) || empty($csrfToken)) {
  80.             throw new AuthenticationException('Improper login.');
  81.         }
  82.         return new Passport(
  83.             new UserBadge($email, function (string $userIdentifier) {
  84.                 $account $this->accountRepository->findOneBy(['email' => $userIdentifier]);
  85.                 if ( ! $account instanceof Account) {
  86.                     throw new UserNotFoundException();
  87.                 }
  88.                 return $account;
  89.             }),
  90.             new PasswordCredentials($password),
  91.             [
  92.                 new CsrfTokenBadge('login'$csrfToken),
  93.             ]
  94.         );
  95.     }
  96.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  97.     {
  98.         /** @var Account $account */
  99.         $account = ($token->getUser() instanceof Account) ? $token->getUser() : null;
  100.         $this->logSuccessfulAttempt($account$request->getClientIp());
  101.         // TODO: redirecting still not works
  102.         /*
  103.         if ($target = $this->getTargetPath($request->getSession(), $firewallName)) {
  104.             return new RedirectResponse($target);
  105.         }
  106.         */
  107.         return null;
  108.     }
  109.     /**
  110.      * @param Request $request
  111.      * @param AuthenticationException $exception
  112.      * @return Response
  113.      * @throws Exception
  114.      */
  115.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): Response
  116.     {
  117.         $message = ( ! empty($exception->getMessage())) ? trim(substr($exception->getMessage(), 0250)) : null;
  118.         $this->logFailedAttempt($request->getClientIp(), $message);
  119.         $request->getSession()->set(Security::AUTHENTICATION_ERROR$exception);
  120.         return new RedirectResponse(
  121.             $this->router->generate(LoginController::ROUTES__SELECT)
  122.         );
  123.     }
  124.     /**
  125.      * @param Account $account
  126.      * @param string|null $ip
  127.      * @return void
  128.      * @throws Exception
  129.      */
  130.     private function logSuccessfulAttempt(Account $account, ?string $ip): void
  131.     {
  132.         $attempt = (new Attempt())
  133.             ->setAccount($account)
  134.             ->setRedirect(null)
  135.             ->setIp($ip)
  136.             ->setStatus(true)
  137.             ->setAuthType(Attempt::AUTH_TYPE__WEB)
  138.         ;
  139.         $this->em->persist($attempt);
  140.         $this->em->flush();
  141.     }
  142.     /**
  143.      * @param string|null $ip
  144.      * @param string|null $message
  145.      * @return void
  146.      * @throws Exception
  147.      */
  148.     private function logFailedAttempt(?string $ip, ?string $message): void
  149.     {
  150.         $attempt = (new Attempt())
  151.             ->setRedirect(null)
  152.             ->setIp($ip)
  153.             ->setStatus(false)
  154.             ->setAuthType(Attempt::AUTH_TYPE__WEB)
  155.         ;
  156.         if ( ! empty($message)) {
  157.             $attempt->setMessage($message);
  158.         }
  159.         $this->em->persist($attempt);
  160.         $this->em->flush();
  161.     }
  162. }