revision gestion cookie
This commit is contained in:
10
Caddyfile
10
Caddyfile
@@ -1,15 +1,11 @@
|
|||||||
:80 {
|
:80 {
|
||||||
# Force HTTP, désactive auto-HTTPS
|
# Force HTTP pour le développement
|
||||||
http://localhost {
|
http://localhost {
|
||||||
|
root * /app/public
|
||||||
php_server
|
php_server
|
||||||
route {
|
encode gzip
|
||||||
file_server
|
|
||||||
@php path *.php /index.php
|
|
||||||
php_fastcgi @php unix//run/php/php-fpm.sock
|
|
||||||
}
|
|
||||||
log {
|
log {
|
||||||
output stdout
|
output stdout
|
||||||
}
|
}
|
||||||
encode gzip
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,11 +4,14 @@ namespace App\Controller;
|
|||||||
|
|
||||||
use App\Form\CodeType;
|
use App\Form\CodeType;
|
||||||
use App\Hydra\Client;
|
use App\Hydra\Client;
|
||||||
|
use App\Hydra\HydraService;
|
||||||
use App\Service\CodeService;
|
use App\Service\CodeService;
|
||||||
use App\Service\CookieService;
|
use App\Service\CookieService;
|
||||||
use App\Service\DeviceService;
|
use App\Service\DeviceService;
|
||||||
use App\Service\MailerService;
|
use App\Service\MailerService;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpClient\Exception\ClientException;
|
||||||
use Symfony\Component\HttpFoundation\Cookie;
|
use Symfony\Component\HttpFoundation\Cookie;
|
||||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
@@ -17,6 +20,7 @@ use Symfony\Component\HttpFoundation\Response;
|
|||||||
use Symfony\Component\Mailer\MailerInterface;
|
use Symfony\Component\Mailer\MailerInterface;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
class MainController extends AbstractController
|
class MainController extends AbstractController
|
||||||
{
|
{
|
||||||
@@ -24,7 +28,9 @@ class MainController extends AbstractController
|
|||||||
private readonly CodeService $codeService,
|
private readonly CodeService $codeService,
|
||||||
private readonly Client $client,
|
private readonly Client $client,
|
||||||
private readonly CookieService $cookieService,
|
private readonly CookieService $cookieService,
|
||||||
private readonly MailerService $mailer
|
private readonly MailerService $mailer,
|
||||||
|
private readonly UrlGeneratorInterface $router,
|
||||||
|
private readonly HydraService $hydraService
|
||||||
|
|
||||||
){
|
){
|
||||||
|
|
||||||
@@ -34,13 +40,12 @@ class MainController extends AbstractController
|
|||||||
{
|
{
|
||||||
return new Response('<h1>Hello world</h1>');
|
return new Response('<h1>Hello world</h1>');
|
||||||
}
|
}
|
||||||
#[Route('/2fa', name: 'app_2fa')]
|
#[Route('/2fa', name: 'app_2fa', methods: ['GET', 'POST'])]
|
||||||
public function doubleFacteur(Request $request): Response
|
public function doubleFacteur(Request $request, LoggerInterface $logger): Response
|
||||||
{
|
{
|
||||||
$loginChallenge = $request->query->get('loginchallenge');
|
$loginChallenge = $request->query->get('loginchallenge');
|
||||||
$identifier = $request->query->get('identifier');
|
$identifier = $request->query->get('identifier');
|
||||||
$res = $this->client->fetchLoginRequestInfo($loginChallenge);
|
$res = $this->client->fetchLoginRequestInfo($loginChallenge);
|
||||||
$loginRequestInfo = $res->toArray();
|
|
||||||
if (200 !== $res->getStatusCode()) {
|
if (200 !== $res->getStatusCode()) {
|
||||||
throw new BadRequestException();
|
throw new BadRequestException();
|
||||||
}
|
}
|
||||||
@@ -50,7 +55,8 @@ class MainController extends AbstractController
|
|||||||
'subject' => $identifier,
|
'subject' => $identifier,
|
||||||
'remember' => true,
|
'remember' => true,
|
||||||
])->toArray();
|
])->toArray();
|
||||||
|
// dd($loginAcceptRes);
|
||||||
|
|
||||||
return new RedirectResponse($loginAcceptRes['redirect_to']);
|
return new RedirectResponse($loginAcceptRes['redirect_to']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,22 +68,28 @@ class MainController extends AbstractController
|
|||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()){
|
if ($form->isSubmitted() && $form->isValid()){
|
||||||
$cookie = null;
|
$cookie = null;
|
||||||
if($form->get('remember_device')){
|
if($form->get('remember_device')->getData()){
|
||||||
$cookie = $this->cookieService->createCookie($identifier);
|
$cookie = $this->cookieService->createCookie($identifier);
|
||||||
}
|
}
|
||||||
|
try{
|
||||||
|
|
||||||
$loginAcceptRes = $this->client->acceptLoginRequest($loginChallenge, [
|
$loginAcceptRes = $this->client->acceptLoginRequest($loginChallenge, [
|
||||||
'subject' => $identifier,
|
'subject' => $identifier,
|
||||||
'remember' => true,
|
'remember' => true,
|
||||||
])->toArray();
|
])->toArray();
|
||||||
|
}catch(ClientException $e){
|
||||||
|
dump($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dump($loginAcceptRes);
|
|
||||||
$response = new RedirectResponse($loginAcceptRes['redirect_to']);
|
$response = new RedirectResponse($loginAcceptRes['redirect_to']);
|
||||||
|
if ($cookie !== null) {
|
||||||
null !== $cookie ?: $response->headers->setCookie($cookie);
|
$response->headers->setCookie($cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
dump('here');
|
||||||
return $this->render('base.html.twig', [
|
return $this->render('base.html.twig', [
|
||||||
'form'=>$form
|
'form'=>$form
|
||||||
]);
|
]);
|
||||||
|
@@ -26,7 +26,7 @@ class CodeType extends AbstractType
|
|||||||
],
|
],
|
||||||
])
|
])
|
||||||
->add('remember_device', CheckboxType::class, [
|
->add('remember_device', CheckboxType::class, [
|
||||||
'label'=>('Se souvenir de cet ordinateur'),
|
'label'=>'Se souvenir de cet ordinateur',
|
||||||
'required'=> false,
|
'required'=> false,
|
||||||
'mapped'=>false,
|
'mapped'=>false,
|
||||||
])
|
])
|
||||||
|
@@ -63,6 +63,7 @@ class HydraService extends AbstractController
|
|||||||
],
|
],
|
||||||
])->toArray();
|
])->toArray();
|
||||||
|
|
||||||
|
dd(vars: $consentAcceptResponse);
|
||||||
return new RedirectResponse($consentAcceptResponse['redirect_to']);
|
return new RedirectResponse($consentAcceptResponse['redirect_to']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,30 +11,33 @@ class CookieService
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly ParameterBagInterface $params
|
private readonly ParameterBagInterface $params
|
||||||
){}
|
){}
|
||||||
private const COOKIE_2FA = 'user_info-2fa';
|
private const COOKIE_2FA = 'remember_2fa';
|
||||||
public function isValid(Request $request, string $login): bool
|
public function isValid(Request $request, string $login): bool
|
||||||
{
|
{
|
||||||
$cookieValue = $request->cookies->get(self::COOKIE_2FA);
|
$cookieValue = $request->cookies->get(self::COOKIE_2FA);
|
||||||
if(!$cookieValue){
|
if(!$cookieValue){
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[$encodedData, $signature] = explode('.', $cookieValue);
|
[$encodedData, $signature] = explode('.', $cookieValue);
|
||||||
$dataJson = base64_decode($encodedData);
|
$dataJson = base64_decode($encodedData);
|
||||||
$secret = $this->params->get('kernel.secret');
|
$secret = $this->params->get('kernel.secret');
|
||||||
if (hash_hmac('sha256', $dataJson, $secret) !== $signature) {
|
if (hash_hmac('sha256', $dataJson, $secret) !== $signature) {
|
||||||
return false; // Signature invalide
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = json_decode($dataJson, true);
|
$data = json_decode($dataJson, true);
|
||||||
if (!$data || $data['login'] !== $login) {
|
if (!$data || $data['login'] !== $login) {
|
||||||
return false; // Login non correspondant
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculer la validité avec la durée paramétrable actuelle
|
$duration = new \DateInterval($this->params->get('app.2fa_remember_duration'));
|
||||||
$duration = new \DateInterval($this->params->get('app.2fa_remember_duration')); // ex. P30D
|
$createdAt = (new \DateTimeImmutable())->setTimestamp($data['created_at']);
|
||||||
$expirationTime = $data['created_at'] + $duration->format('%s'); // Convertir en secondes
|
$expirationTime = $createdAt->add($duration)->getTimestamp();
|
||||||
|
|
||||||
if (time() > $expirationTime) {
|
if (time() > $expirationTime) {
|
||||||
return false; // Expiré selon la durée actuelle
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -63,7 +66,7 @@ class CookieService
|
|||||||
->withSecure($this->params->get('kernel.environment') === 'prod')
|
->withSecure($this->params->get('kernel.environment') === 'prod')
|
||||||
->withHttpOnly(true)
|
->withHttpOnly(true)
|
||||||
->withSameSite('Lax')
|
->withSameSite('Lax')
|
||||||
->withPath('/hydra-otp')
|
->withPath('/')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,9 +7,6 @@
|
|||||||
{% block stylesheets %}
|
{% block stylesheets %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block javascripts %}
|
|
||||||
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
|
||||||
{% endblock %}
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -30,8 +27,8 @@
|
|||||||
|
|
||||||
<div syle="">
|
<div syle="">
|
||||||
{{ form_start(form) }}
|
{{ form_start(form) }}
|
||||||
{{ form_errors(form.code) }}
|
|
||||||
{{ form_row(form.code) }}
|
{{ form_row(form.code) }}
|
||||||
|
{{ form_row(form.remember_device) }}
|
||||||
{{form_end(form)}}
|
{{form_end(form)}}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Reference in New Issue
Block a user