Vérification challenge dans la session #31 #32

Merged
mlamalle merged 3 commits from issue-31 into develop 2024-04-25 11:27:01 +02:00
3 changed files with 37 additions and 30 deletions
Showing only changes of commit bcc91a17b4 - Show all commits

View File

@ -6,11 +6,12 @@ use App\Entity\User;
use App\Hydra\Client; use App\Hydra\Client;
use App\Hydra\HydraService; use App\Hydra\HydraService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class MainController extends AbstractController class MainController extends AbstractController
{ {
@ -26,7 +27,7 @@ class MainController extends AbstractController
} }
#[Route('/', name: 'app_home')] #[Route('/', name: 'app_home')]
public function home(Request $request) public function home(Request $request): RedirectResponse
{ {
return $this->hydra->handleLoginRequest($request); return $this->hydra->handleLoginRequest($request);
} }
@ -34,26 +35,33 @@ class MainController extends AbstractController
* Route de Healthcheck (notament pour kubernetes) * Route de Healthcheck (notament pour kubernetes)
*/ */
#[Route('/health', name: 'health')] #[Route('/health', name: 'health')]
public function health(Request $request) public function health(Request $request): Response
{ {
return new Response('healthy', 200); return new Response('healthy', 200);
} }
#[Route('/connect/login-accept', name: 'app_login_accept')] #[Route('/connect/login-accept', name: 'app_login_accept', methods: ['GET'])]
public function loginAccept(Request $request) public function loginAccept(Request $request): RedirectResponse
{ {
/** @var User */
$user = $this->getUser(); $user = $this->getUser();
$loginAcceptRes = $this->client->acceptLoginRequest($this->session->get('challenge'), [
'subject' => $user->getLogin(), if (!$user instanceof User) {
'remember' => true, throw new AccessDeniedException();
])->toArray(); }
$challenge = $this->session->get('challenge');
if (!$challenge) {
return new RedirectResponse($this->getParameter('issuer_url'));
}
$loginAcceptRes = $this->client->acceptLoginRequest($challenge, [
'subject' => $user->getLogin(),
'remember' => true,
])->toArray();
return new RedirectResponse($loginAcceptRes['redirect_to']); return new RedirectResponse($loginAcceptRes['redirect_to']);
} }
#[Route('/connect/consent', name: 'app_consent')] #[Route('/connect/consent', name: 'app_consent')]
public function consent(Request $request) public function consent(Request $request): RedirectResponse
{ {
return $this->hydra->handleConsentRequest($request); return $this->hydra->handleConsentRequest($request);
} }

View File

@ -2,6 +2,7 @@
namespace App\Hydra; namespace App\Hydra;
use App\Entity\User;
use App\Hydra\Exception\InvalidChallengeException; use App\Hydra\Exception\InvalidChallengeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Exception\BadRequestException;
@ -9,13 +10,14 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class HydraService extends AbstractController class HydraService extends AbstractController
{ {
public SessionInterface $session; private SessionInterface $session;
public Client $client; private Client $client;
public TokenStorageInterface $tokenStorage; private TokenStorageInterface $tokenStorage;
public string $baseUrl; private string $baseUrl;
public function __construct(Client $client, SessionInterface $session, TokenStorageInterface $tokenStorage, string $baseUrl) public function __construct(Client $client, SessionInterface $session, TokenStorageInterface $tokenStorage, string $baseUrl)
{ {
@ -25,7 +27,7 @@ class HydraService extends AbstractController
$this->baseUrl = $baseUrl; $this->baseUrl = $baseUrl;
} }
public function handleLoginRequest(Request $request) public function handleLoginRequest(Request $request): RedirectResponse
{ {
$challenge = $request->query->get('login_challenge'); $challenge = $request->query->get('login_challenge');
// S'il n'y a pas de challenge, on déclenche une bad request // S'il n'y a pas de challenge, on déclenche une bad request
@ -37,15 +39,15 @@ class HydraService extends AbstractController
$loginRequestInfo = $res->toArray(); $loginRequestInfo = $res->toArray();
if (200 !== $res->getStatusCode()) { if (200 !== $res->getStatusCode()) {
$this->session->clear(); $this->session->clear();
throw new BadRequestException('pas de code 200'); throw new BadRequestException();
} }
// si le challenge est validé par hydra, on le stocke en session pour l'utiliser par la suite et on redirige vers une route interne protégée qui va déclencher l'identification FranceConnect // si le challenge est validé par hydra, on le stocke en session pour l'utiliser par la suite et on redirige vers une route interne protégée qui va déclencher l'identification FranceConnect
$this->session->set('challenge', $loginRequestInfo['challenge']); $this->session->set('challenge', $loginRequestInfo['challenge']);
return new RedirectResponse($this->baseUrl.'/connect/login-accept'); return new RedirectResponse($this->baseUrl . '/connect/login-accept');
} }
public function handleConsentRequest(Request $request) public function handleConsentRequest(Request $request): RedirectResponse
{ {
$challenge = $request->query->get('consent_challenge'); $challenge = $request->query->get('consent_challenge');
if (!$challenge) { if (!$challenge) {
@ -53,8 +55,10 @@ class HydraService extends AbstractController
} }
$consentRequestInfo = $this->client->fetchConsentRequestInfo($challenge)->toArray(); $consentRequestInfo = $this->client->fetchConsentRequestInfo($challenge)->toArray();
/** @var User */
$user = $this->getUser(); $user = $this->getUser();
if (!$user instanceof User) {
throw new AccessDeniedException('Utilisateur non autorisé.');
}
$consentAcceptResponse = $this->client->acceptConsentRequest($consentRequestInfo['challenge'], [ $consentAcceptResponse = $this->client->acceptConsentRequest($consentRequestInfo['challenge'], [
'grant_scope' => $consentRequestInfo['requested_scope'], 'grant_scope' => $consentRequestInfo['requested_scope'],
'session' => [ 'session' => [
@ -65,7 +69,7 @@ class HydraService extends AbstractController
return new RedirectResponse($consentAcceptResponse['redirect_to']); return new RedirectResponse($consentAcceptResponse['redirect_to']);
} }
public function handleLogoutRequest(Request $request) public function handleLogoutRequest(Request $request): RedirectResponse
{ {
$logoutChallenge = $request->get('logout_challenge'); $logoutChallenge = $request->get('logout_challenge');
if (empty($logoutChallenge)) { if (empty($logoutChallenge)) {

View File

@ -17,7 +17,7 @@ class SQLLoginService extends AbstractController
$this->sqlLoginRequest = $sqlLoginRequest; $this->sqlLoginRequest = $sqlLoginRequest;
} }
public function fetchDatas($login) public function fetchDatas(string $login)
{ {
try { try {
$dbh = $this->getConnection(); $dbh = $this->getConnection();
@ -36,12 +36,7 @@ class SQLLoginService extends AbstractController
return $datas; return $datas;
} }
/** public function fetchPassword(string $login)
* @param mixed $login
*
* @return bool
*/
public function fetchPassword($login)
{ {
try { try {
$dbh = $this->getConnection(); $dbh = $this->getConnection();
@ -57,7 +52,7 @@ class SQLLoginService extends AbstractController
return [ return [
$password[$this->sqlLoginRequest->getPasswordColumnName()], $password[$this->sqlLoginRequest->getPasswordColumnName()],
isset($password[$this->sqlLoginRequest->getSaltColumnName()]) ? $password[$this->sqlLoginRequest->getSaltColumnName()] : null, isset($password[$this->sqlLoginRequest->getSaltColumnName()]) ? $password[$this->sqlLoginRequest->getSaltColumnName()] : null,
]; ];
} }
return false; return false;