src/Platform/SecurityBundle/Controller/LoginController.php line 53

Open in your IDE?
  1. <?php
  2. namespace Platform\SecurityBundle\Controller;
  3. use Cms\BulletinBundle\Model\Bulletins\PasswordResetFinBulletin;
  4. use Cms\BulletinBundle\Service\BulletinService;
  5. use Cms\CoreBundle\Model\Scenes\DashboardScenes\DocumentScene;
  6. use Cms\CoreBundle\Util\Controller;
  7. use Platform\SecurityBundle\Entity\Identity\Account;
  8. use Platform\SecurityBundle\Entity\Login\ResetToken;
  9. use Platform\SecurityBundle\Form\Type\LoginType;
  10. use Platform\SecurityBundle\Form\Type\ResetPasswordRequestType;
  11. use Platform\SecurityBundle\Form\Type\ResetPasswordType;
  12. use Platform\SecurityBundle\Model\OAuth\AuthenticationTypesBitwise;
  13. use Platform\SecurityBundle\Service\Login\LoginSystem;
  14. use Platform\SecurityBundle\Service\OAuth\OAuthProviderService;
  15. use Platform\SecurityBundle\Service\PasswordService;
  16. use Symfony\Component\Routing\Annotation\Route;
  17. use Symfony\Component\Form\FormError;
  18. use Symfony\Component\HttpFoundation\RedirectResponse;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  21. use Symfony\Component\Security\Core\Exception\BadCredentialsException;
  22. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  23. /**
  24.  * Class LoginController
  25.  * @package Platform\SecurityBundle\Controller
  26.  */
  27. final class LoginController extends Controller
  28. {
  29.     public const ROUTES__SELECT 'platform.security.login.default.select';
  30.     public const ROUTES__RESET_PASSWORD 'platform.security.login.standard.reset.password';
  31.     public const ROUTES__CHANGE_PASSWORD 'platform.security.login.standard.change.password';
  32.     /**
  33.      * Handles reset password requests
  34.      *
  35.      * @param Request $request
  36.      * @return DocumentScene|RedirectResponse
  37.      *
  38.      * @Route(
  39.      *  "/reset-password",
  40.      *  name = LoginController::ROUTES__RESET_PASSWORD
  41.      * )
  42.      */
  43.     public function resetPasswordAction(
  44.         PasswordService $passwordService,
  45.         Request $request
  46.     )
  47.     {
  48.         // make sure passwords are supported
  49.         if ( ! $this->getGlobalContext()->getTenant()->getAuthenticationTypes()->hasFlag(AuthenticationTypesBitwise::INTERNAL__PASSWORD)) {
  50.             throw new \Exception();
  51.         }
  52.         $form $this->createForm(ResetPasswordRequestType::class, [], []);
  53.         if ($this->handleForm($form)) {
  54.             $account $this->getEntityManager()->getRepository(Account::class)->findOneByEmail($form->get('email')->getData());
  55.             if ( ! empty($account) &&  ! empty($account->getPassword())) {
  56.                 $passwordService->sendResetPasswordInitEmail(
  57.                     $request,
  58.                     $account
  59.                 );
  60.             }
  61.             return $this->view(
  62.                 '@PlatformSecurity/Login/message.html.twig',
  63.                 array(
  64.                     'message' => sprintf(
  65.                         'A reset confirmation will be sent shortly if the email address<br /><br /><strong>%s</strong><br /><br />is linked to a valid account.',
  66.                         $form->get('email')->getData()
  67.                     ),
  68.                     'routes' => array(
  69.                         'login' => LoginController::ROUTES__SELECT,
  70.                     ),
  71.                 )
  72.             );
  73.         }
  74.         return $this->view(array(
  75.             'form' => $form->createView(),
  76.             'routes' => array(
  77.                 'login' => LoginController::ROUTES__SELECT,
  78.             )
  79.         ));
  80.     }
  81.     /**
  82.      * Handles change password requests
  83.      *
  84.      * @param Request $request
  85.      * @param string $token
  86.      * @return DocumentScene|RedirectResponse
  87.      * @throws \Exception
  88.      *
  89.      * @Route(
  90.      *  "/change-password/{token}",
  91.      *  name = LoginController::ROUTES__CHANGE_PASSWORD,
  92.      *  requirements = {
  93.      *      "token" = "[0-9a-f]+"
  94.      *  }
  95.      * )
  96.      */
  97.     public function changePasswordAction(
  98.         BulletinService $bulletinService,
  99.         Request $request,
  100.         string $token
  101.     )
  102.     {
  103.         // make sure passwords are supported
  104.         if ( ! $this->getGlobalContext()->getTenant()->getAuthenticationTypes()->hasFlag(AuthenticationTypesBitwise::INTERNAL__PASSWORD)) {
  105.             throw new \Exception();
  106.         }
  107.         // find the reset request
  108.         /** @var array|ResetToken[] $resets */
  109.         $resets $this->getEntityManager()->getRepository(ResetToken::class)->findBy(array(
  110.             'token' => $token,
  111.         ));
  112.         // should only be one
  113.         if (count($resets) > 1) {
  114.             throw new \Exception();
  115.         } else if (count($resets) < 1) {
  116.             throw new \Exception();
  117.         }
  118.         $reset $resets[0];
  119.         // make sure it has not been used
  120.         if ($reset->getState() !== ResetToken::STATES__UNUSED) {
  121.             throw new NotFoundHttpException();
  122.         }
  123.         // make sure it is not expired
  124.         if ($reset->isExpired()) {
  125.             throw new NotFoundHttpException();
  126.         }
  127.         // get the account tied to this
  128.         $account $reset->getAccount();
  129.         // form stuff
  130.         $form $this->createForm(ResetPasswordType::class);
  131.         // try to handle form submission
  132.         if ($this->handleForm($form$request)) {
  133.             // get the input password
  134.             $password $form->getData()['password'];
  135.             // update with the new password
  136.             $this->getEntityManager()->save($account->setPasswordRaw($password));
  137.             // also flag the reset token as being used
  138.             $reset->setState(ResetToken::STATES__USED);
  139.             $this->getEntityManager()->save($reset);
  140.             // send out confirmation email
  141.             $bulletinService->send((new PasswordResetFinBulletin())
  142.                 ->setTo($account->getEmail())
  143.                 ->setAccount($account)
  144.                 ->setDashboard($this->getGlobalContext()->getDashboardUrl()));
  145.             // record log
  146.             $this->getActivityLogger()->createLog($account$account->getId());
  147.             // back to the login screen
  148.             return $this->redirectToRoute(
  149.                 LoginController::ROUTES__SELECT
  150.             );
  151.         }
  152.         return $this->view(array(
  153.             'email' => $account->getEmail(),
  154.             'form' => $form->createView(),
  155.             'routes' => array('login' => LoginController::ROUTES__SELECT)
  156.         ));
  157.     }
  158.     /**
  159.      * Shows the visitor which login types are supported.
  160.      * If only one type is supported, the visitor is instead automatically redirected to the page for that type.
  161.      *
  162.      * @param Request $request
  163.      * @return DocumentScene|RedirectResponse
  164.      *
  165.      * @Route(
  166.      *     "",
  167.      *     name = LoginController::ROUTES__SELECT
  168.      * )
  169.      */
  170.     public function selectAction(
  171.         LoginSystem $loginSystem,
  172.         OAuthProviderService $oAuthProviderService,
  173.         Request $request
  174.     )
  175.     {
  176.         // determine if we should allow logins
  177.         // need a way for csadmin to bypass
  178.         // TODO: do we need to move this over into the new login logic?
  179.         $allow $this->getGlobalContext()->getTenant()->getAuthenticationTypes()->hasFlag(AuthenticationTypesBitwise::INTERNAL__PASSWORD);
  180.         if ( ! $allow) {
  181.             $allow $request->query->getBoolean('csadmin'false);
  182.         }
  183.         // create form for standard login
  184.         $autofill $request->query->get('autofill'null);
  185.         try {
  186.             $autofill openssl_decrypt(
  187.                 $autofill,
  188.                 'aes128',
  189.                 $this->getParameter('kernel.secret')
  190.             );
  191.         } catch (\Exception $e) {
  192.             $autofill null;
  193.         }
  194.         $form $this->createForm(
  195.             LoginType::class,
  196.             [
  197.                 'username' => $autofill,
  198.             ],
  199.         );
  200.         // pass through login errors
  201.         if ($error $this->getAuthenticationUtils()->getLastAuthenticationError()) {
  202.             $form->addError(new FormError(
  203.                 ($error instanceof BadCredentialsException)
  204.                     ? 'Bad login credentials.'
  205.                     $error->getMessage(),
  206.             ));
  207.         }
  208.         return $this->view(
  209.             [
  210.                 'form' => ($allow) ? $form->createView() : null,
  211.                 'redirect' => $request->query->get('redirect'),
  212.                 'providers' => $oAuthProviderService->getProviders($this->getGlobalContext()->getTenant()),
  213.                 'errors' => $this->getSession()->getFlashBag()->get(SingleSignOnController::ROUTES__FINISH.'__errors'),
  214.                 'routes' => array(
  215.                     'oauth__start' => SingleSignOnController::ROUTES__START,
  216.                     'reset_password' => LoginController::ROUTES__RESET_PASSWORD
  217.                 ),
  218.                 'tenant' => $this->getGlobalContext()->getTenant(),
  219.             ]
  220.         );
  221.     }
  222.     /**
  223.      * @return AuthenticationUtils
  224.      */
  225.     private function getAuthenticationUtils(): AuthenticationUtils
  226.     {
  227.         return $this->get(__METHOD__);
  228.     }
  229. }