src/Controller/EntraController.php line 42

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Services\AuthService;
  4. use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
  5. use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
  6. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\RedirectResponse;
  9. use Symfony\Component\Routing\Annotation\Route;
  10. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  11. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  12. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  13. use Symfony\Component\Security\Http\Util\TargetPathTrait;
  14. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  15. use Symfony\Contracts\HttpClient\HttpClientInterface;
  16. use JMS\Serializer\SerializerInterface;
  17. use Psr\Log\LoggerInterface;
  18. use Lcobucci\JWT\Signer\Hmac\Sha256;
  19. use Lcobucci\JWT\Signer\Key\InMemory;
  20. use Symfony\Component\HttpFoundation\Response;
  21. use Lcobucci\JWT\Configuration;
  22. use Lcobucci\JWT\UnencryptedToken;
  23. use Symfony\Component\Uid\Uuid;
  24. class EntraController extends AbstractController
  25. {
  26.     use TargetPathTrait;
  27.     private $entra_url;
  28.     private $jwtConfig;
  29.     private $discoveryKeysUrl;
  30.     private $httpClient;
  31.     private $logger;
  32.     private $authService;
  33.     public function __construct(ParameterBagInterface $parameterBagLoggerInterface $loggerHttpClientInterface $httpClientAuthService $authService)
  34.     {
  35.         $this->entra_url $parameterBag->get('entra_parameters')['entra_url'];
  36.         $this->applicationObjectId $parameterBag->get('entra_parameters')['entra_object_id'];
  37.         $this->discoveryKeysUrl $this->entra_url '/discovery/keys';
  38.         $this->logger $logger;
  39.         $this->httpClient $httpClient;
  40.         $this->authService $authService;
  41.         $this->jwtConfig Configuration::forSymmetricSigner(
  42.             new \Lcobucci\JWT\Signer\Hmac\Sha256(),
  43.             InMemory::plainText('temporary-secret-key')
  44.         );
  45.     }
  46.     /**
  47.      * Start OAuth process with Entra Server
  48.      *
  49.      * @Route("/connect/entra", name="connect_entra_start")
  50.      */
  51.     public function connectAction(Request $requestClientRegistry $clientRegistrySessionInterface $session)
  52.     {
  53.         // Generate a unique ID for this login attempt
  54.         $authId Uuid::v4()->toRfc4122();
  55.         //Generate the code verifier
  56.         $codeVerifier bin2hex(random_bytes(64));
  57.         $codeChallenge strtr(rtrim(base64_encode(hash('sha256'$codeVerifiertrue)), '='), '+/''-_');
  58.         // Store the code verifier with the unique authId in session
  59.         $session->set('oauth2_code_verifier_' $authId$codeVerifier);
  60.         //store the target path with the unique authId in session
  61.         if ($request->get('retryRedirectUrl') == null) {
  62.             $targetPath $session->get('_security.main.target_path');
  63.             if ($targetPath != null) {
  64.                 $session->set('login_redirect_url_' $authId$targetPath);
  65.             }
  66.         } else {
  67.             $session->set('login_redirect_url_' $authId$request->get('retryRedirectUrl'));
  68.         }
  69.         return $clientRegistry
  70.             ->getClient('entra_id_external'// key used in config/packages/knpu_oauth2_client.yaml
  71.             ->redirect(["email""openid""profile""offline_access"], [
  72.                 'code_challenge' => $codeChallenge,
  73.                 'code_challenge_method' => 'S256',
  74.                 'state' => $authId// Pass the unique ID as the state parameter
  75.                 'route' => $request->headers->get('request_uri')
  76.             ]);
  77.     }
  78.     /**
  79.      * Callback after Entra connexion
  80.      *
  81.      * @Route("/connect/entra/check", name="connect_entra_check")
  82.      */
  83.     public function connectCheckAction(Request $requestClientRegistry $clientRegistry)
  84.     {
  85.         //blank because we are using a Symfony authenticator
  86.     }
  87.     /**
  88.      * @Route("/logout", name="app_logout")
  89.      */
  90.     public function logout(Request $requestSessionInterface $sessionTokenStorageInterface $tokenStorage): RedirectResponse
  91.     {
  92.         $session->invalidate();
  93.         $tokenStorage->setToken(null);
  94.         $azureLogoutUrl $this->entra_url '/oauth2/v2.0/logout?post_logout_redirect_uri=' urlencode($this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL));
  95.         return $this->redirect($azureLogoutUrl);
  96.         // Symfony gère automatiquement le processus de déconnexion
  97.         // Si vous avez besoin d'une logique supplémentaire, vous pouvez l'ajouter ici
  98.     }
  99.     /**
  100.      * @Route("/soft-logout", name="app_soft_logout")
  101.      */
  102.     public function softLogout(Request $requestSessionInterface $sessionTokenStorageInterface $tokenStorage): Response
  103.     {
  104.         $session->invalidate();
  105.         $tokenStorage->setToken(null);
  106.         return new Response('Logout successful'Response::HTTP_OK);
  107.     }
  108.     /**
  109.      * @Route("/slo", name="app_slo", methods={"GET"}) #TODO TEST
  110.      */
  111.     public function slo(Request $request): Response
  112.     {
  113.         $this->logger->info('Slo endpoint called');
  114.         $sid $request->get('sid');
  115.         $this->logger->info('sid: ' $sid);
  116.         $sessionExists $this->authService->getSessionBySid($sid);
  117.         if ($sessionExists) {
  118.             $this->container->get('security.token_storage')->setToken(null);
  119.             $request->getSession()->invalidate();
  120.             return new Response('Logout successful'Response::HTTP_OK);
  121.         }
  122.         return new Response('Invalid logout request'Response::HTTP_BAD_REQUEST);
  123.     }
  124. }