<?php
/*
* Unauthorized copying of this file, via any medium is strictly prohibited
* Proprietary and confidential.
*
* @author Bilel AZRI <azri.bilel@gmail.com>
* @author Assma BEN SASSI <bensassiasma.bws@gmail.com>
*
* Bicking man (c) 2019-present.
*/
declare(strict_types=1);
namespace App\Security;
use App\Entity\User\Admin;
use App\Entity\User\Organizer;
use App\Entity\User\User;
use App\Repository\User\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
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\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class FrontAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'front.security.app_login';
/**
* The Entity manager used to retrieve users.
*
* @var EntityManagerInterface
*/
private $entityManager;
/**
* The Url generator used to generate urls.
*
* @var UrlGeneratorInterface
*/
private $urlGenerator;
/**
* The Csrf token manager used to validate the csrf token.
*
* @var CsrfTokenManagerInterface
*/
private $csrfTokenManager;
/**
* The Password Encoder used to validate the password.
*
* @var UserPasswordEncoderInterface
*/
private $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request): bool
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
/**
* @return array{username: string, password: string, csrf_token: string}
*/
public function getCredentials(Request $request): array
{
/**
* @var string
*/
$username = $request->request->get('username');
/**
* @var string
*/
$password = $request->request->get('password');
/**
* @var string
*/
$csrf = $request->request->get('_csrf_token');
$credentials = ['username' => $username, 'password' => $password, 'csrf_token' => $csrf];
/** @var Session $session */
$session = $request->getSession();
$session->set(Security::LAST_USERNAME, $credentials['username']);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider): User
{
/** @var array{username: string, password: string, csrf_token: string} $credentials */
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException('Invalid Csrf Token.');
}
/** @var UserRepository $repo */
$repo = $this->entityManager->getRepository(User::class);
$user = $repo->findOneByUsername($credentials['username']);
if (null === $user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('User could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user): bool
{
/** @var array{username: string, password: string, csrf_token: string} $credentials */
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
/**
* @param string $providerKey
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): Response
{
if (null !== $headerAccept = $request->headers->get('accept')) {
if (false !== strpos($headerAccept, 'json')) {
return new JsonResponse(['status' => 'failed', 'message' => 'You entered in secure area without login!'], Response::HTTP_UNAUTHORIZED);
}
}
/** @var SessionInterface $session */
$session = $request->getSession();
$targetPath = $this->getTargetPath($session, $providerKey);
if (null !== $targetPath) {
return new RedirectResponse($targetPath);
}
$user = $token->getUser();
if ($user instanceof Admin || $user instanceof Organizer) {
return new RedirectResponse($this->urlGenerator->generate('back.dashboard.index'));
}
return new RedirectResponse($this->urlGenerator->generate('front.course.index'));
}
protected function getLoginUrl(): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}