<?php
namespace App\Security;
use App\Entity\SonataUserUser;
use App\Repository\SonataUserUserRepository;
use App\Services\ApiConsumer;
use App\Utils\EAS256CBC;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Exception\ManagerException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class UserAuthenticator extends AbstractAuthenticator
{
protected HttpClientInterface $httpClient;
protected ApiConsumer $apiConsumer;
protected EAS256CBC $EAS256CBC;
protected EntityManagerInterface $entityManager;
protected SonataUserUserRepository $userRepository;
public function __construct(HttpClientInterface $httpClient, ApiConsumer $apiConsumer, EAS256CBC $EAS256CBC, EntityManagerInterface $entityManager, SonataUserUserRepository $userRepository)
{
$this->httpClient = $httpClient;
$this->apiConsumer = $apiConsumer;
$this->EAS256CBC = $EAS256CBC;
$this->entityManager = $entityManager;
$this->userRepository = $userRepository;
}
/**
* Called on every request to decide if this authenticator should be
* used for the request. Returning `false` will cause this authenticator
* to be skipped.
*/
public function supports(Request $request): ?bool
{
if ($request->request->get('_username')) {
return true;
} else {
return false;
}
}
public function authenticate(Request $request): SelfValidatingPassport
{
$session = $request->getSession();
$password = $request->request->get('_password') ?? NULL;
$username = $request->request->get('_username') ?? NULL;
if (!$username || !$password) {
throw new AuthenticationException('Usuario y contraseña son requeridos.');
}
try {
$userPasswordHash = $this->EAS256CBC->encrypt($username . '#' . $password, $this->apiConsumer::$key);
$user_data = $this->apiConsumer->getClienteValidar($userPasswordHash);
if ($user_data instanceof Response) {
throw new AuthenticationException('No se pudo validar el usuario en este momento. Intente nuevamente más tarde.');
}
$isEmptyPayload =
$user_data === null ||
$user_data === '[]' ||
$user_data === '' ||
(is_array($user_data) && count($user_data) === 0) ||
(is_object($user_data) && count((array)$user_data) === 0);
if ($isEmptyPayload) {
throw new AuthenticationException('Usuario o contraseña son incorrectos.');
}
$user = $this->userRepository->findOneBy(['username' => $username]);
if (!$user) {
$user = new SonataUserUser();
$user->setUsername($username);
$user->setUsernameCanonical($username);
$user->setEmail($username);
$user->setEmailCanonical($username);
$user->setEnabled(true);
$user->setRoles(['ROLE_USER']);
$user->setPassword($userPasswordHash);
$user->setUserPassHash($userPasswordHash);
}else{
$user->setUserPassHash($userPasswordHash);
}
$this->entityManager->persist($user);
$this->entityManager->flush();
$session->set('user_password_hash', $userPasswordHash);
$session->set('user_module_name', $user_data);
return new SelfValidatingPassport(
new UserBadge($username, function () use ($user) {
return $user;
})
);
} catch (\Exception|ManagerException $e) {
throw new AuthenticationException($e->getMessage());
}
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
$data = [
[
"result" => "success",
"token" => $token->getUsername(),
"user" => [
"id" => $token->getUser()->getId(),
],
"errors" => [
"issues" => ""
]
]
];
return new JsonResponse($data, 200, ['json_encode_options' => JSON_UNESCAPED_SLASHES]);
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$data = [
[
"result" => "error",
"token" => '',
"user" => [
"id" => '',
],
"errors" => [
"issues" => $exception->getMessage()
]
]
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED, ['json_encode_options' => JSON_UNESCAPED_SLASHES]);
}
}