<?php
namespace App\Helper\Security;
use App\Helper\SuluHelper;
use App\Normalizer\Security\CustomerNormalizer;
use App\Security\Customer\Customer;
use Croisiland\CommonBundle\Provider\ErpUrlProvider;
use Croisiland\CommonBundle\Provider\SuluUrlProvider;
use Exception;
use Sulu\Component\DocumentManager\DocumentManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class SecurityHelper
{
private const string CUSTOMER_SESSION_TOKEN_KEY = 'customer_session_token';
protected HttpClientInterface $httpClient;
protected ParameterBagInterface $parameterBag;
protected RequestStack $requestStack;
protected DocumentManagerInterface $documentManager;
protected SuluHelper $suluHelper;
protected ErpUrlProvider $erpUrlProvider;
protected SuluUrlProvider $suluUrlProvider;
public function __construct(HttpClientInterface $httpClient,
ParameterBagInterface $parameterBag,
RequestStack $requestStack,
DocumentManagerInterface $documentManager,
SuluHelper $suluHelper,
ErpUrlProvider $erpUrlProvider,
SuluUrlProvider $suluUrlProvider)
{
$this->httpClient = $httpClient;
$this->parameterBag = $parameterBag;
$this->requestStack = $requestStack;
$this->documentManager = $documentManager;
$this->suluHelper = $suluHelper;
$this->erpUrlProvider = $erpUrlProvider;
$this->suluUrlProvider = $suluUrlProvider;
}
/**
* @param string $email
* @param string $password
* @param bool $rememberMe
* @return Customer
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function authenticateCustomer(string $email, string $password, bool $rememberMe = true): Customer
{
$response = $this->customerApiLoginFromCredentials($email, $password, $rememberMe);
return (new Customer())
->setEmail($email)
->setFirstName($response['first_name'])
->setLastName($response['last_name'])
->setToken($response['token']);
}
/**
* @return Customer|null
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function getLoggedCustomer(): ?Customer
{
$token = $this->requestStack->getCurrentRequest()->cookies->get(self::CUSTOMER_SESSION_TOKEN_KEY);
if (null === $token) {
$token = $this->requestStack->getSession()->get(self::CUSTOMER_SESSION_TOKEN_KEY);
}
if (null === $token) {
return null;
}
try {
$credentials = $this->customerApiLoginFromToken($token);
return (new Customer())
->setEmail($credentials['email'])
->setFirstName($credentials['first_name'])
->setLastName($credentials['last_name'])
->setToken($token);
}
catch (Exception $e) {
return null;
}
}
/**
* @param Response $response
* @param string $token
* @param bool $rememberMe
* @return void
*/
public function setCustomerToken(Response $response, string $token, bool $rememberMe = true): void
{
if ($rememberMe) {
$response->headers->setCookie(
Cookie::create(self::CUSTOMER_SESSION_TOKEN_KEY, $token, time() + 2592000)
);
}
else {
$this->requestStack->getSession()->set(self::CUSTOMER_SESSION_TOKEN_KEY, $token);
}
}
/**
* @param Response $response
* @return void
*/
public function removeCustomerToken(Response $response): void
{
$response->headers->setCookie(
Cookie::create(self::CUSTOMER_SESSION_TOKEN_KEY, '', time() - 1)
);
$this->requestStack->getSession()->remove(self::CUSTOMER_SESSION_TOKEN_KEY);
}
/**
* @param Customer $customer
* @return array<string>
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @throws Exception
*/
public function subscribe(Customer $customer): array
{
try {
$customerNormalizer = new CustomerNormalizer();
$url = $this->erpUrlProvider->generateUrl('subscription', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => array_merge($customerNormalizer->normalize($customer), [
'accountVerificationLink' => $this->suluUrlProvider->generateUrl('customer_waiting_subscription'),
])
]);
$content = $response->toArray(false);
}
catch (Exception|ExceptionInterface $e) {
throw new Exception("Impossible de procéder à l'inscription, veuillez réessayer plus tard");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return $content;
}
/**
* @param string $token
* @return array<string>
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @throws Exception
*/
public function getCustomerFromToken(string $token): array
{
try {
$url = $this->erpUrlProvider->generateUrl('get_customer_from_token', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => [
'token' => $token
]
]);
$content = $response->toArray(false);
}
catch (Exception $e) {
throw new Exception("Impossible de vérifier ce token");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return $content;
}
/**
* @param string $email
* @return array<string>
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function resetPasswordRequest(string $email): array
{
try {
$url = $this->erpUrlProvider->generateUrl('reset_password_request', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => [
'email' => $email,
'resetPasswordLink' => $this->suluUrlProvider->generateUrl('customer_reset_password'),
]
]);
$content = $response->toArray(false);
}
catch (Exception $e) {
throw new Exception("Une erreur s’est produite, veuillez réessayer ultérieurement.");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return $content;
}
/**
* @param string $token
* @return bool
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function checkResetPasswordToken(string $token): bool
{
try {
$url = $this->erpUrlProvider->generateUrl('check_reset_password_token', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => [
'token' => $token
]
]);
$content = $response->toArray(false);
}
catch (Exception $e) {
throw new Exception("Impossible de réinitialiser le mot de passe de ce compte");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return (bool)$content['checked'];
}
/**
* @param string $token
* @param string $password
* @return array<string>
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function updatePassword(string $token, string $password): array
{
try {
$url = $this->erpUrlProvider->generateUrl('update_password', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => [
'token' => $token,
'password' => $password
]
]);
$content = $response->toArray(false);
}
catch (Exception $e) {
throw new Exception("Impossible de modifier le mot de passe de ce compte");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return $content;
}
/**
* @param string $token
* @return array
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function accountVerification(string $token): array
{
try {
$url = $this->erpUrlProvider->generateUrl('account_verification', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => [
'token' => $token
]
]);
$content = $response->toArray(false);
}
catch (Exception $e) {
throw new Exception("Impossible vérifier votre compte, veuillez réessayer plus tard");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return $content;
}
/**
* @param string $email
* @return array
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function accountVerificationLinkRequest(string $email): array
{
try {
$url = $this->erpUrlProvider->generateUrl('account_verification_link_request', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => [
'email' => $email,
'accountVerificationLink' => $this->suluUrlProvider->generateUrl('customer_waiting_subscription'),
]
]);
$content = $response->toArray(false);
}
catch (Exception $e) {
throw new Exception("Impossible d'éffectuer votre demande, veuillez réessayer plus tard");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return $content;
}
/**
* @return string
*/
public function getIndexUrl(): string
{
return $this->erpUrlProvider->generateUrl('customer_portal_login', [
'redirectUrl' => urlencode($this->erpUrlProvider->generateUrl('customer_portal_home'))
]);
}
/**
* @param int $quoteId
* @return string
*/
public function getQuoteDetailsUrl(int $quoteId): string
{
return $this->erpUrlProvider->generateUrl('customer_portal_login', [
'redirectUrl' => urlencode($this->erpUrlProvider->generateUrl('customer_portal_commercial_proposal', ['quote' => $quoteId]))
]);
}
/**
* @return string
*/
public function getAccountVerificationUrl(): string
{
return $this->erpUrlProvider->generateUrl('account_verification', [], true);
}
/**
* @param string $email
* @param string $password
* @param bool $rememberMe
* @return string[]
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
private function customerApiLoginFromCredentials(string $email, string $password, bool $rememberMe = false): array
{
return $this->customerApiLogin([
'username' => $email,
'password' => $password,
'rememberMe' => $rememberMe,
]);
}
/**
* @param string $token
* @return string[]
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
private function customerApiLoginFromToken(string $token): array
{
return $this->customerApiLogin([
'authentication_token' => $token
]);
}
/**
* @param array<string> $body
* @return array<string>
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @throws Exception
*/
private function customerApiLogin(array $body): array
{
try {
$url = $this->erpUrlProvider->generateUrl('api_login', [], true);
$response = $this->httpClient->request('POST', $url, [
'body' => $body
]);
$content = $response->toArray(false);
}
catch (Exception $e) {
throw new Exception("Impossible de se connecter à votre compte client, veuillez réessayer plus tard.");
}
if (Response::HTTP_OK !== $response->getStatusCode())
{
throw new Exception($content['message']);
}
return $content;
}
}