src/Controller/Main/SecurityController.php line 126

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Main;
  3. use App\Security\LoginFormAuthenticator;
  4. use App\Security\UserProvider;
  5. use App\Services\Admin\UserService;
  6. use App\Services\Main\SecurityService;
  7. use OneLogin\Saml2\Auth;
  8. use OneLogin\Saml2\Settings;
  9. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\RequestStack;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Routing\Annotation\Route;
  14. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  15. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  16. use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
  17. /**
  18.  * Class SecurityController.
  19.  */
  20. class SecurityController extends AbstractController
  21. {
  22.     private const ERROR_UNKNOW_TOKEN 'unknown_privateToken';
  23.     /**
  24.      * @var SecurityService
  25.      */
  26.     private SecurityService $securityService;
  27.     /**
  28.      * @var UserService
  29.      */
  30.     private UserService $userService;
  31.     /**
  32.      * @var LoginFormAuthenticator
  33.      */
  34.     private LoginFormAuthenticator $loginFormAuthenticator;
  35.     /**
  36.      * SecurityController constructor.
  37.      *
  38.      * @param SecurityService $securityService
  39.      * @param UserService $userService
  40.      * @param LoginFormAuthenticator $loginFormAuthenticator
  41.      */
  42.     public function __construct(
  43.         SecurityService $securityService,
  44.         UserService $userService,
  45.         LoginFormAuthenticator $loginFormAuthenticator
  46.     ) {
  47.         $this->securityService $securityService;
  48.         $this->userService $userService;
  49.         $this->loginFormAuthenticator $loginFormAuthenticator;
  50.     }
  51.     /**
  52.      * @Route("/", name="app.login")
  53.      *
  54.      * @param AuthenticationUtils $authenticationUtils
  55.      *
  56.      * @return Response
  57.      */
  58.     public function login(AuthenticationUtils $authenticationUtils): Response
  59.     {
  60.         if ($this->getUser()) {
  61.             return $this->redirectToRoute('dashboard.index');
  62.         }
  63.         // get the login error if there is one
  64.         $error $authenticationUtils->getLastAuthenticationError();
  65.         $options = [
  66.             'twoAuthRequired' => false,
  67.         ];
  68.         $messageData = [];
  69.         $errorMessage null;
  70.         if (null !== $error) {
  71.             $errorMessage $error->getMessage();
  72.             if (empty($errorMessage)) {
  73.                 $errorMessage $error->getMessageKey();
  74.             }
  75.             if (str_contains($errorMessage'security.twoAuth.required')) {
  76.                 $messageData $error->getMessageData();
  77.                 $options['twoAuthRequired'] = true;
  78.                 if (null !== $messageData['twoAuthToken']) {
  79.                     $this->addFlash(
  80.                         'danger',
  81.                         ('expiredToken' === $messageData['mailError'])
  82.                             ? 'security.twoAuth.expiredToken'
  83.                             'security.twoAuth.wrongToken'
  84.                     );
  85.                 }
  86.                 $this->addFlash('info'$errorMessage);
  87.             } else {
  88.                 $this->addFlash('danger'$errorMessage);
  89.             }
  90.         }
  91.         $loginForm $this->createForm('App\Form\Main\LoginType'null$options);
  92.         $lastUsername $authenticationUtils->getLastUsername();
  93.         if (!empty($lastUsername)) {
  94.             $loginForm->get('login')->setData($lastUsername);
  95.         }
  96.         return $this->render('security/login.html.twig', [
  97.             'loginForm' => $loginForm->createView(),
  98.             'last_username' => $lastUsername,
  99.             'last_password' => $messageData['password'] ?? null,
  100.             'isTwoAuthVerification' => $options['twoAuthRequired'],
  101.             'isTwoAuthMail' => ($options['twoAuthRequired'] && 'security.twoAuth.required.mail' === $errorMessage),
  102.         ]);
  103.     }
  104.     /**
  105.      * @Route("/login/forgot-password", name="app.forgot")
  106.      *
  107.      * @param Request $request
  108.      *
  109.      * @throws DecodingExceptionInterface
  110.      *
  111.      * @return Response
  112.      */
  113.     public function forgotPassword(Request $request): Response
  114.     {
  115.         if ($this->getUser()) {
  116.             return $this->redirectToRoute('dashboard.index');
  117.         }
  118.         $recoverPasswordForm $this->createForm('App\Form\Main\RecoverPasswordType');
  119.         $recoverPasswordForm->handleRequest($request);
  120.         if ($recoverPasswordForm->isSubmitted()) {
  121.             if ($recoverPasswordForm->isValid()) {
  122.                 $login $recoverPasswordForm->get('login')->getData();
  123.                 $responseArray $this->securityService->requestPasswordRecovery($login);
  124.                 if (!$responseArray['error']) {
  125.                     $this->addFlash('info''security.password.forgot.confirmation');
  126.                 } else {
  127.                     $this->addFlash('danger'$responseArray['message']);
  128.                 }
  129.             } else {
  130.                 $this->addFlash('danger''security.password.forgot.error.invalid');
  131.             }
  132.         }
  133.         return $this->render('security/forgotPassword.html.twig', [
  134.             'recoverPasswordForm' => $recoverPasswordForm->createView(),
  135.             'passwordRecovery' => $passwordRecovery ?? null,
  136.         ]);
  137.     }
  138.     /**
  139.      * @Route("/login/reset-password/{privateToken}", name="app.password.reset")
  140.      *
  141.      * @param $privateToken
  142.      * @param Request $request
  143.      *
  144.      * @throws DecodingExceptionInterface
  145.      *
  146.      * @return Response
  147.      */
  148.     public function resetPassword($privateTokenRequest $request): Response
  149.     {
  150.         if ($this->getUser()) {
  151.             return $this->redirectToRoute('dashboard.index');
  152.         }
  153.         $responseArray $this->securityService->getPasswordRecoveryByKey($privateToken);
  154.         if ($responseArray['error']) {
  155.             if (self::ERROR_UNKNOW_TOKEN === $responseArray['message']) {
  156.                 $this->addFlash('danger''security.password.reset.error.notfound');
  157.             } else {
  158.                 $this->addFlash('danger''global.errors.undefined');
  159.             }
  160.             return $this->redirectToRoute('root');
  161.         }
  162.         return $this->forward('App\Controller\Main\SecurityController::definePassword', [], $responseArray['content']);
  163.     }
  164.     /**
  165.      * @Route("/login/define-password", name="app.definePassword")
  166.      *
  167.      * @throws DecodingExceptionInterface
  168.      *
  169.      * @return Response
  170.      */
  171.     public function definePassword(Request $request): Response
  172.     {
  173.         if ($this->getUser()) {
  174.             $this->addFlash('danger''security.password.expired.label');
  175.             $this->logout();
  176.         }
  177.         $definePasswordForm $this->createForm('App\Form\Main\DefinePasswordType', [], [
  178.             'action' => $this->generateUrl('app.definePassword'),
  179.         ]);
  180.         $definePasswordForm->handleRequest($request);
  181.         if ($definePasswordForm->isSubmitted()) {
  182.             if ($definePasswordForm->isValid()) {
  183.                 $resetRequest $this->securityService->handleDefinePassword(
  184.                     $definePasswordForm->get('login')->getData(),
  185.                     $definePasswordForm->get('password')->getData()
  186.                 );
  187.                 $responseArray $resetRequest->getArrayResponse();
  188.                 if ($responseArray['error']) {
  189.                     $this->addFlash('danger''security.firstLogin.error');
  190.                 } else {
  191.                     return $this->redirectToRoute('app.login');
  192.                 }
  193.             } else {
  194.                 $this->addFlash('danger''security.firstLogin.error');
  195.             }
  196.         }
  197.         $rgpdOptions $request->query->get('rgpdOptions');
  198.         if (empty($rgpdOptions)) {
  199.             return $this->redirectToRoute('app.login');
  200.         }
  201.         return $this->render('security/definePassword.html.twig', [
  202.             'definePasswordForm' => $definePasswordForm->createView(),
  203.             'rgpdOptions' => $rgpdOptions,
  204.             'login' => $request->query->get('login'),
  205.         ]);
  206.     }
  207.     /**
  208.      * @Route("/login/first-login", name="app.firstLogin")
  209.      *
  210.      * @param Request $request
  211.      *
  212.      * @throws DecodingExceptionInterface
  213.      *
  214.      * @return Response
  215.      */
  216.     public function firstLogin(Request $request): Response
  217.     {
  218.         if ($this->getUser()) {
  219.             return $this->redirectToRoute('dashboard.index');
  220.         }
  221.         $firstLoginForm $this->createForm('App\Form\Main\FirstLoginType');
  222.         $firstLoginForm->handleRequest($request);
  223.         if ($firstLoginForm->isSubmitted()) {
  224.             if ($firstLoginForm->isValid()) {
  225.                 $resetRequest $this->securityService->handleFirstLogin(
  226.                     $firstLoginForm->get('email')->getData(),
  227.                     $firstLoginForm->get('login')->getData()
  228.                 );
  229.                 if (!$resetRequest->getArrayResponse()['error']) {
  230.                     return $this->forward(
  231.                         'App\Controller\Main\SecurityController::definePassword',
  232.                         [],
  233.                         $resetRequest->getContent()
  234.                     );
  235.                 }
  236.                 $this->addFlash('danger''security.firstLogin.error');
  237.             } else {
  238.                 $this->addFlash('danger''security.firstLogin.error');
  239.             }
  240.         }
  241.         return $this->render('security/firstLogin.html.twig', [
  242.             'firstLoginForm' => $firstLoginForm->createView(),
  243.         ]);
  244.     }
  245.     /**
  246.      * @Route("/logout", name="app.logout")
  247.      */
  248.     public function logout(): void
  249.     {
  250.     }
  251.     /**
  252.      * @Route("/classic-logout", name="app.logout.classic")
  253.      */
  254.     public function classicLogout()
  255.     {
  256.         //TODO: call API to delete refresh_token
  257.         $response $this->redirectToRoute('app.login');
  258.         $response->headers->clearCookie('PHPSESSID');
  259.         return $response;
  260.     }
  261.     /**
  262.      * @Route("/saml-login/{custId}", name="app.samlLogin", methods={"POST"})
  263.      * 
  264.      * @param string $custId
  265.      */
  266.     public function samlLogin(string $custIdRequest $request)
  267.     {
  268.         if ('' === $custId) {
  269.             return $this->redirectToRoute('root');
  270.         }
  271.         $settings $this->getParameter('hslavich_onelogin_saml');
  272.         $customerSettings $this->securityService->updateSSOParameters($settings$custId);
  273.         if (false !== $customerSettings) {
  274.             $auth = new Auth($customerSettings);
  275.             $auth->processResponse(null);
  276.             $errors $auth->getErrors();
  277.             if (!$auth->isAuthenticated()) {
  278.                 return $this->redirectToRoute('root');
  279.             }
  280.             $samlUserdata $auth->getAttributes();
  281.             $_SESSION['samlUserdata'] = $samlUserdata;
  282.             if (isset($samlUserdata['token'])) {
  283.                 $credential = [
  284.                     'ssoToken' => $samlUserdata['token'][0],
  285.                 ];
  286.                 $user $this->loginFormAuthenticator->getUser($credential, new UserProvider($this->securityService));
  287.                 $token = new UsernamePasswordToken($usernull'main'$user->getRoles());
  288.                 $this->get('security.token_storage')->setToken($token);
  289.                 $this->get('session')->set('_security_main'serialize($token));
  290.             }
  291.         }
  292.         return $this->redirectToRoute('root');
  293.     }
  294.     /**
  295.      * @Route("/get-metadata", name="app.getMetadata")
  296.      */
  297.     public function getMetadata()
  298.     {
  299.         $settings $this->getParameter('hslavich_onelogin_saml');
  300.         try {
  301.             $settings = new Settings($settingstrue);
  302.             $content $settings->getSPMetadata();
  303.             $errors $settings->validateMetadata($content);
  304.             if (empty($errors)) {
  305.                 $response = new Response($content);
  306.                 $response->headers->set('Content-Type''text/xml');
  307.                 return $response;
  308.             }
  309.             throw new OneLogin_Saml2_Error('Invalid SP metadata: '.implode(', '$errors), OneLogin_Saml2_Error::METADATA_SP_INVALID);
  310.         } catch (Exception $e) {
  311.             $content $e->getMessage();
  312.         }
  313.         return new Response(
  314.             $content
  315.         );
  316.     }
  317.     /**
  318.      * @Route("/login/define-two-auth", name="app.defineTwoAuth")
  319.      *
  320.      * @param RequestStack $requestStack
  321.      *
  322.      * @throws DecodingExceptionInterface
  323.      * 
  324.      * @return Response
  325.      */
  326.     public function defineTwoAuth(RequestStack $requestStack): Response
  327.     {
  328.         $session $requestStack->getSession();
  329.         $loginInformations $session->get('login-informations');
  330.         $qrCode $this->userService->getMyTotpQrCode();
  331.         $user $this->getUser();
  332.         //Logout user and clear this sentive information from session
  333.         $this->classicLogout();
  334.         return $this->render('security/defineTwoAuth.html.twig', [
  335.             'qrCode' => $qrCode,
  336.             'login' => $loginInformations['login'],
  337.             'password' => $loginInformations['password'],
  338.             'user' => $user,
  339.         ]);
  340.     }
  341.     /**
  342.      * @Route("/oauth/{customerId}/{authType}", name="oauth")
  343.      *
  344.      * @param RequestStack $requestStack
  345.      *
  346.      * @throws DecodingExceptionInterface
  347.      * 
  348.      * @return Response
  349.      */
  350.     public function oAuthResponse(Request $requeststring $customerIdstring $authType): Response
  351.     {
  352.         $parameters = [];
  353.         switch ($authType) {
  354.             case 'azure':
  355.                 $parameters = ['customerId' => $customerId'code' => $request->query->get('code')];
  356.                 break;
  357.             default:
  358.                 //TODO: add error message
  359.                 return $this->redirectToRoute('root');
  360.         }
  361.         $tokens $this->securityService->authWithOauth($authType$parameters);
  362.         if (empty($tokens['token']) || empty($tokens['refresh_token'])) {
  363.             return $this->redirectToRoute('app.login');
  364.         }
  365.         $user $this->loginFormAuthenticator->getUser([], new UserProvider($this->securityService), $tokens);
  366.         $token = new UsernamePasswordToken($usernull'main'$user->getRoles());
  367.         $this->get('security.token_storage')->setToken($token);
  368.         $this->get('session')->set('_security_main'serialize($token));
  369.         return $this->redirectToRoute('root');
  370.     }
  371. }