✨ feat(LoginController): Ajoute l'authentification EsyWeb avec 2FA et avatar.
This commit is contained in:
158
src/Controller/Api/Private/EsyWeb/LoginController.php
Normal file
158
src/Controller/Api/Private/EsyWeb/LoginController.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Api\Private\EsyWeb;
|
||||
|
||||
use App\Entity\Account;
|
||||
use App\Entity\EsyWeb\WebsiteKey;
|
||||
use App\Repository\AccountRepository;
|
||||
use App\Repository\EsyWeb\WebsiteDnsRepository;
|
||||
use App\Repository\EsyWeb\WebsiteKeyRepository;
|
||||
use App\Service\Mailer\Mailer;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use LasseRafn\InitialAvatarGenerator\InitialAvatar;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
||||
|
||||
class LoginController extends AbstractController
|
||||
{
|
||||
|
||||
private const API_KEY_TYPE = 'api_key';
|
||||
|
||||
#[Route('/api/avatar', name: 'api_avatar', methods: ['GET'])]
|
||||
public function avatar(?Account $account)
|
||||
{
|
||||
$avatar = new InitialAvatar();
|
||||
|
||||
if(!$account instanceof Account) {
|
||||
$avatar->name("NC");
|
||||
} else {
|
||||
$avatar->name($account->getUserIdentifier());
|
||||
}
|
||||
|
||||
$image = $avatar->generateSvg();
|
||||
return new Response(
|
||||
$image->toXMLString(),
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'image/svg+xml']
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
#[Route('/api/private/esyweb/resend2fa', name: 'api_pivate_esyweb_resend2fa', methods: ['POST'])]
|
||||
public function resend2fa(Request $request,Mailer $mailer,AccountRepository $accountRepository): Response
|
||||
{
|
||||
$content = json_decode($request->getContent());
|
||||
$account = $content->account;
|
||||
$code = $content->faCode;
|
||||
|
||||
$account = $accountRepository->find($account);
|
||||
if(!$account instanceof Account) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
$mailer->send(
|
||||
$account->getEmail(),
|
||||
$account->getUsername(),
|
||||
'[Mainframe] - Double authentication',
|
||||
'mails/artemis/2fa.twig',
|
||||
['code' => $code, 'account' => $account]
|
||||
);
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
#[Route('/api/private/esyweb/login', name: 'api_private_esyweb_login', methods: ['POST'])]
|
||||
public function status(
|
||||
Request $request,
|
||||
WebsiteDnsRepository $websiteDnsRepository,
|
||||
WebsiteKeyRepository $websiteKeyRepository,
|
||||
AccountRepository $accountRepository,
|
||||
UserPasswordHasherInterface $passwordHasher,
|
||||
Security $security,
|
||||
Mailer $mailer,
|
||||
UploaderHelper $uploaderHelper,
|
||||
): JsonResponse {
|
||||
$errorResponse = function (): JsonResponse {
|
||||
return $this->json(['login' => false], Response::HTTP_UNAUTHORIZED);
|
||||
};
|
||||
$dns = $request->headers->get('EsyWebDns');
|
||||
$apiKey = $request->headers->get('EsyWebApiKey');
|
||||
|
||||
if (!$dns || !$apiKey) {
|
||||
// Note: The ApiSubscriber should ideally handle the *missing* headers.
|
||||
// This handles the case where the headers might be present but empty strings.
|
||||
return $errorResponse();
|
||||
}
|
||||
$websiteDns = $websiteDnsRepository->findOneBy(['dns' => $dns]);
|
||||
if (!$websiteDns) {
|
||||
return $errorResponse();
|
||||
}
|
||||
|
||||
// 3. Find WebsiteKey (checking against the constant for type)
|
||||
/** @var WebsiteKey|null $websiteApiKey */
|
||||
$websiteApiKey = $websiteKeyRepository->findOneBy([
|
||||
'apiKey' => $apiKey,
|
||||
'type' => self::API_KEY_TYPE
|
||||
]);
|
||||
|
||||
if (!$websiteApiKey) {
|
||||
return $errorResponse();
|
||||
}
|
||||
|
||||
// 4. Cross-reference the Website objects
|
||||
$websiteFromDns = $websiteDns->getWebsite();
|
||||
$websiteFromKey = $websiteApiKey->getWebsitre();
|
||||
|
||||
if (!$websiteFromDns || !$websiteFromKey || $websiteFromDns->getId() !== $websiteFromKey->getId()) {
|
||||
// This check ensures both the DNS and API Key belong to the same website
|
||||
return $errorResponse();
|
||||
}
|
||||
|
||||
$content = json_decode($request->getContent());
|
||||
if(!isset($content->username)) {
|
||||
return $errorResponse();
|
||||
}
|
||||
if(!isset($content->password)) {
|
||||
return $errorResponse();
|
||||
}
|
||||
$username = base64_decode($content->username);
|
||||
$password = base64_decode($content->password);
|
||||
|
||||
$account = $accountRepository->findOneBy(['username'=>$username]);
|
||||
if (!$account) {
|
||||
return $errorResponse();
|
||||
}
|
||||
$isPasswordValid = $passwordHasher->isPasswordValid(
|
||||
$account, // The UserInterface object
|
||||
$password // The plain-text password submitted by the user
|
||||
);
|
||||
if (!$isPasswordValid) {
|
||||
return $errorResponse();
|
||||
}
|
||||
|
||||
$security->login($account);
|
||||
|
||||
$code = random_int(1000, 9999);
|
||||
$mailer->send(
|
||||
$account->getEmail(),
|
||||
$account->getUsername(),
|
||||
'[Mainframe] - Double authentication',
|
||||
'mails/artemis/2fa.twig',
|
||||
['code' => $code, 'account' => $account]
|
||||
);
|
||||
if($_ENV['APP_ENV'] == "dev")
|
||||
$host = $_ENV['DEV_URL'];
|
||||
else
|
||||
$host = $request->getSchemeAndHttpHost();
|
||||
return $this->json(['login' => true,'2fa_required'=>true,'2faCode'=>$code,'user_data'=>[
|
||||
'username' => $account->getUsername(),
|
||||
'email' => $account->getEmail(),
|
||||
'role' => $account->getRoles()[0],
|
||||
'avatar' => $host. (($account->getAvatarOriginalName() != null)?$uploaderHelper->asset($account,'avatar'):$this->generateUrl('api_avatar',['id'=>$account->getId()]))
|
||||
]], Response::HTTP_OK);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user