vendor/pimcore/portal-engine/src/Controller/AuthController.php line 97

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under following license:
  6.  * - Pimcore Commercial License (PCL)
  7.  *
  8.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  9.  *  @license    http://www.pimcore.org/license     PCL
  10.  */
  11. namespace Pimcore\Bundle\PortalEngineBundle\Controller;
  12. use GuzzleHttp\ClientInterface;
  13. use Pimcore\Bundle\OpenIdConnectBundle\Client\Provider\OpenIdConnectProvider;
  14. use Pimcore\Bundle\OpenIdConnectBundle\Session\Configurator;
  15. use Pimcore\Bundle\PortalEngineBundle\Exception\OutputErrorException;
  16. use Pimcore\Bundle\PortalEngineBundle\Form\LoginForm;
  17. use Pimcore\Bundle\PortalEngineBundle\Form\RecoverPasswordForm;
  18. use Pimcore\Bundle\PortalEngineBundle\Model\View\Notification;
  19. use Pimcore\Bundle\PortalEngineBundle\Service\Content\HeadTitleService;
  20. use Pimcore\Bundle\PortalEngineBundle\Service\Frontend\FrontendNotificationService;
  21. use Pimcore\Bundle\PortalEngineBundle\Service\PortalConfig\PortalConfigService;
  22. use Pimcore\Bundle\PortalEngineBundle\Service\Security\Authentication\OpenIdConnectAuthenticator;
  23. use Pimcore\Bundle\PortalEngineBundle\Service\Security\Authentication\User\PasswordChangeableService;
  24. use Pimcore\Bundle\PortalEngineBundle\Service\Security\Authentication\User\RecoverPasswordService;
  25. use Pimcore\Tool;
  26. use Symfony\Component\Form\FormFactoryInterface;
  27. use Symfony\Component\Form\FormInterface;
  28. use Symfony\Component\HttpFoundation\Request;
  29. use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag;
  30. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  31. use Symfony\Component\Routing\Annotation\Route;
  32. use Symfony\Contracts\Translation\LocaleAwareInterface;
  33. use Symfony\Contracts\Translation\TranslatorInterface;
  34. /**
  35.  * @Route("/auth", condition="request.attributes.get('isPortalEngineSite')")
  36.  */
  37. class AuthController extends AbstractSiteController
  38. {
  39.     protected ClientInterface $httpClient;
  40.     /**
  41.      * @param ClientInterface $httpClient
  42.      */
  43.     public function __construct(ClientInterface $httpClient)
  44.     {
  45.         $this->httpClient $httpClient;
  46.     }
  47.     /**
  48.      * @Route("/login",
  49.      *     name="pimcore_portalengine_auth_login"
  50.      * )
  51.      */
  52.     public function loginAction(Request $requestFormFactoryInterface $formFactoryHeadTitleService $headTitleServiceTranslatorInterface $translatorPortalConfigService $portalConfigServicePasswordChangeableService $passwordChangeableService)
  53.     {
  54.         /** @var string $locale */
  55.         $locale $request->getPreferredLanguage(Tool::getValidLanguages());
  56.         if ($translator instanceof LocaleAwareInterface) {
  57.             $translator->setLocale($locale);
  58.         }
  59.         $request->setLocale($locale);
  60.         $portalName $portalConfigService->getPortalName();
  61.         $oidcProviders $portalConfigService->getCurrentPortalConfig()->getOidcConfigs();
  62.         $headTitleService->setTitle($translator->trans('portal-engine.content.title.auth-login', ['%name%' => $portalName]));
  63.         $loginForm $formFactory->create(LoginForm::class);
  64.         return $this->renderTemplate('@PimcorePortalEngine/auth/login.html.twig', [
  65.             'form' => $loginForm->createView(),
  66.             'loginFailed' => (bool)$request->query->get('loginFailed'),
  67.             'portalName' => $portalName,
  68.             'oidcProviderNames' => array_keys($oidcProviders),
  69.             'showRecoverPassword' => $passwordChangeableService->isPasswordChangeable()
  70.         ]);
  71.     }
  72.     /**
  73.      * @Route("/logout",
  74.      *     name="pimcore_portalengine_auth_logout"
  75.      * )
  76.      */
  77.     public function logoutAction(Request $request)
  78.     {
  79.         return $this->redirectToRoute('pimcore_portalengine_auth_login');
  80.     }
  81.     /**
  82.      * @Route("/recover-password",
  83.      *     name="pimcore_portalengine_auth_recover_password"
  84.      * )
  85.      */
  86.     public function recoverPasswordAction(Request $requestTranslatorInterface $translatorFormFactoryInterface $formFactoryFrontendNotificationService $frontendNotificationServiceRecoverPasswordService $recoverPasswordServicePasswordChangeableService $passwordChangeableServiceHeadTitleService $headTitleService)
  87.     {
  88.         if (!$passwordChangeableService->isPasswordChangeable()) {
  89.             throw new NotFoundHttpException('password not changeable');
  90.         }
  91.         /** @var string $locale */
  92.         $locale $request->getPreferredLanguage(Tool::getValidLanguages());
  93.         if ($translator instanceof LocaleAwareInterface) {
  94.             $translator->setLocale($locale);
  95.         }
  96.         $request->setLocale($locale);
  97.         $headTitleService->setTitle($translator->trans('portal-engine.content.title.auth-recover-password'));
  98.         /** @var FormInterface $recoverPasswordForm */
  99.         $recoverPasswordForm $formFactory
  100.             ->create(RecoverPasswordForm::class)
  101.             ->handleRequest($request);
  102.         if ($request->isMethod(Request::METHOD_POST) && $recoverPasswordForm->isSubmitted() && $recoverPasswordForm->isValid()) {
  103.             try {
  104.                 /** @var string $userIdentifier */
  105.                 $userIdentifier = (string)$recoverPasswordForm->get('userIdentifier')->getData();
  106.                 if (empty($userIdentifier)) {
  107.                     throw new OutputErrorException($translator->trans('portal-engine.auth.user-not-found'));
  108.                 }
  109.                 $recoverPasswordService->recoverPassword($userIdentifier);
  110.                 $frontendNotificationService
  111.                     ->addNotification($translator->trans('portal-engine.auth.password-recover-email'), Notification::HTML_CLASS_SUCCESS);
  112.             } catch (\Exception $e) {
  113.                 if ($e instanceof OutputErrorException) {
  114.                     $frontendNotificationService->addNotification($e->getMessage(), Notification::HTML_CLASS_DANGER);
  115.                 }
  116.             }
  117.         }
  118.         return $this->renderTemplate('@PimcorePortalEngine/auth/recover_password.html.twig', [
  119.             'recoverPasswordForm' => $recoverPasswordForm->createView(),
  120.             'notification' => $frontendNotificationService->getNotification()
  121.         ]);
  122.     }
  123.     /**
  124.      * @Route("/oidc/endpoint",
  125.      *     name="pimcore_portalengine_auth_oidc"
  126.      * )
  127.      */
  128.     public function oidcAction(Request $requestPortalConfigService $portalConfigService)
  129.     {
  130.         if (!class_exists('Pimcore\\Bundle\\OpenIdConnectBundle\\PimcoreOpenIdConnectBundle')) {
  131.             throw new \Exception('OpenID Connect Bundle not available');
  132.         }
  133.         if ($request->get('error')) {
  134.             throw new \Exception(strip_tags($request->get('error')) . ': ' strip_tags($request->get('error_description')));
  135.         }
  136.         $portalConfig $portalConfigService->getCurrentPortalConfig();
  137.         $session $request->getSession();
  138.         /** @var NamespacedAttributeBag $sessionBag */
  139.         $sessionBag $session->getBag(Configurator::SESSION_BAG_NAME); // @phpstan-ignore-line
  140.         // if coming back from provider, use provider from session
  141.         if ($request->get('code')) {
  142.             $providerName $sessionBag->get(OpenIdConnectAuthenticator::SESSION_KEY_PROVIDER);
  143.         } else {
  144.             $providerName $request->get('provider');
  145.             $sessionBag->set(OpenIdConnectAuthenticator::SESSION_KEY_PROVIDER$providerName);
  146.         }
  147.         $oidcConfig $portalConfig->getOidcConfig($providerName);
  148.         if (empty($oidcConfig)) {
  149.             throw new \InvalidArgumentException(sprintf('Provider `%s` unknown.'strip_tags($request->get('provider'))));
  150.         }
  151.         $provider = new OpenIdConnectProvider([   // @phpstan-ignore-line
  152.             'clientId' => $oidcConfig->getClientId(),
  153.             'clientSecret' => $oidcConfig->getClientSecret(),
  154.             'urlDiscovery' => $oidcConfig->getDiscoveryUrl(),
  155.             'redirectUri' => $request->getSchemeAndHttpHost() . $request->getPathInfo(),
  156.             'scopes' => $oidcConfig->getScopes()
  157.         ]);
  158.         $provider->setHttpClient($this->httpClient); // @phpstan-ignore-line
  159.         if (!$request->get('code')) {
  160.             // If we don't have an authorization code then get one
  161.             $authUrl $provider->getAuthorizationUrl(); // @phpstan-ignore-line
  162.             $sessionBag->set(OpenIdConnectAuthenticator::SESSION_KEY_STATE$provider->getState()); // @phpstan-ignore-line
  163.             return $this->redirect($authUrl);
  164.         } elseif (!$request->get('state') || ($request->get('state') !== $sessionBag->get('oauth2state'))) {
  165.             // Check given state against previously stored one to mitigate CSRF attack
  166.             $sessionBag->remove(OpenIdConnectAuthenticator::SESSION_KEY_STATE);
  167.             throw new \Exception('Invalid state');
  168.         }
  169.         return $this->redirectToRoute('pimcore_portalengine_auth_login');
  170.     }
  171. }