Invalid state parameter passed in callback URL. Avec le bundle Oauth2
Bonjour,
J'ai un soucis avec Oauth2. Il me retourne comme erreur "Invalid state parameter passed in callback URL."
Je suis sur symfony 6
J'ignore d'où ça peut provenir, en localhost tout fonctionne mais en production j'ai cette erreur. Lorsque j'ajoute use_state: true en paramètre une autre erreur m'est retourné: "Authentication failed! Did you authorize our app?"
J'ai cherché partout une solution sans rien trouver.
knpu_oauth2_client.yaml
Code:
1 2 3 4 5 6 7 8 9 10 11 12
| ```lang-yaml
knpu_oauth2_client:
clients:
azure:
type: azure
client_id: '%env(OAUTH_AZURE_CLIENT_ID)%'
client_secret: '%env(OAUTH_AZURE_CLIENT_SECRET)%'
redirect_route: connect_azure_check
redirect_params: {}
# scope: {}
tenant: '%env(AZURE_TENANT_ID)%'
``` |
security.yaml
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| ```lang-yaml
security:
enable_authenticator_manager: true
# <a href="https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords" target="_blank">https://symfony.com/doc/current/secu...hing-passwords</a>
# <a href="https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider" target="_blank">https://symfony.com/doc/current/secu...-user-provider</a>
providers:
# used to reload user from session & other features (e.g. switch_user)
users_in_memory: { memory: null }
my_provider:
entity: {class: App\Entity\User, property: uuid}
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: my_provider
custom_authenticators:
- App\Security\AzureAuthenticator
logout: true
# activate different ways to authenticate
# <a href="https://symfony.com/doc/current/security.html#firewalls-authentication" target="_blank">https://symfony.com/doc/current/secu...authentication</a>
# <a href="https://symfony.com/doc/current/security/impersonating_user.html" target="_blank">https://symfony.com/doc/current/secu...ting_user.html</a>
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/connect/azure, role: PUBLIC_ACCESS }
- { path: ^/, roles: ROLE_USER}
``` |
AzureController.php
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| ```lang-php
<?php
namespace App\Controller;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class AzureController extends AbstractController
{
/**
* Cette fonction effectue la connexion avec Azure
* Ex: Si vous allez sur cette route, un formulaire microsoft vous demandera de vous connecter
*/
#[Route('/connect/azure', name: 'connect_azure', )]
public function connectAction(ClientRegistry $clientRegistry)
{
return $clientRegistry
->getClient('azure')
->redirect([
'openid', 'profile', 'email'
], []);
}
/**
* Cette fonction permet de savoir si l'authentification à réussi
* Ex: Après vous être connecté ci-dessus, vous serez rediriger sur cette route qui vous redirigera à son tour vers la route home
*/
#[Route('/connect/azure/check', name: 'connect_azure_check', schemes:['http'])]
public function connectCheckAction(Request $request, ClientRegistry $clientRegistry)
{
try {
return $this->redirectToRoute('home');
} catch (IdentityProviderException $e) {
return new JsonResponse(array('status' => false, 'message' => "User not found!", 'error' => $e->getMessage()));
}
}
}
``` |
AzureAuthenticator.php
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| ```lang-php
<?php
namespace App\Security;
use App\Entity\User;
use League\OAuth2\Client\Provider\azureUser;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
class AzureAuthenticator extends OAuth2Authenticator implements AuthenticationEntryPointInterface
{
private ClientRegistry $clientRegistry;
private EntityManagerInterface $entityManager;
private RouterInterface $router;
public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router)
{
$this->clientRegistry = $clientRegistry;
$this->entityManager = $entityManager;
$this->router = $router;
}
/**
* Cette fonction renvoie true alors la fonction authenticate sera appelée
* @param Request $request
* @return bool|null
*/
public function supports(Request $request): ?bool
{
return $request->attributes->get('_route') === 'connect_azure_check';
}
/**
* Cette fonction permet de traiter les données et de les utiliser. Elle vérifie également si l'utilisateur est déjà existant en base de donnée, si se n'est pas le cas elle l'ajoute.
* @param Request $request
* @return Passport
*/
public function authenticate(Request $request): Passport
{
$client = $this->clientRegistry->getClient('azure');
$accessToken = $this->fetchAccessToken($client);
return new SelfValidatingPassport(
new UserBadge($accessToken->getToken(), function() use ($accessToken, $client) {
/** @var AzureUser $AzureUser */
$AzureUser = $client->fetchUserFromToken($accessToken);
// 1) have they logged in with Azure before? Easy!
$existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['uuid' => $AzureUser->getId()]);
if ($existingUser) {
return $existingUser;
}
$user = new User();
$user->setUuid($AzureUser->getId());
$user->setNom($AzureUser->claim('family_name'));
$user->setPrenom($AzureUser->claim('given_name'));
$user->setEmail($AzureUser->claim('upn'));
$this->entityManager->persist($user);
$this->entityManager->flush();
return $user;
})
);
}
/**
* Si l'authentification réussi, l'utilisateur sera renvoyé sur la route home
* @param Request $request
* @param TokenInterface $token
* @param string $firewallName
* @return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
$targetUrl = $this->router->generate('home');
return new RedirectResponse($targetUrl);
}
/**
* Si l'authentification échoue, l'utilisateur sera informé avec un message d'erreur
* @param Request $request
* @param AuthenticationException $exception
* @return Response|null
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$message = strtr($exception->getMessageKey(), $exception->getMessageData());
return new Response($message, Response::HTTP_FORBIDDEN);
}
/**
* Cette fonction permet de rediriger l'utilisateur sur la route de connexion
* Dès que l'utilisateur sera sur une route qu'il n'a pas le droit d'avoir accès il sera rediriger à cet endroit (Dans le cas de notre application toutes les routes sont par défaut interdite)
* @param Request $request
* @param AuthenticationException|null $authException
* @return Response
*/
public function start(Request $request, AuthenticationException $authException = null): Response
{
return new RedirectResponse(
'/connect/azure',
Response::HTTP_TEMPORARY_REDIRECT
);
}
}
``` |