src/Controller/SecurityController.php line 87

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by PhpStorm.
  4.  * User: uwethiess
  5.  * Date: 07.10.16
  6.  * Time: 12:36
  7.  */
  8. namespace App\Controller;
  9. use App\Api\ProthelisApi;
  10. use App\Entity\User;
  11. use App\Form\LoginForm;
  12. use App\Form\PasswordRequestForm;
  13. use App\Form\PasswordResetForm;
  14. use App\Security\LoginFormAuthenticator;
  15. use App\Service\DBLogService;
  16. use Symfony\Component\Mailer\MailerInterface;
  17. use Symfony\Component\Mime\Address;
  18. use Symfony\Component\Mime\Email;
  19. use Symfony\Component\Routing\Annotation\Route;
  20. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
  23. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  24. use Symfony\Contracts\Translation\TranslatorInterface;
  25. class SecurityController extends AbstractController
  26. {
  27.     /**
  28.      * @var TranslatorInterface
  29.      */
  30.     private $translator;
  31.     private MailerInterface $mailer;
  32.     private DBLogService $DBLog;
  33.     private GuardAuthenticatorHandler $authenticatorHandler;
  34.     private LoginFormAuthenticator $authenticator;
  35.     /**
  36.      * SecurityController constructor.
  37.      */
  38.     public function __construct(TranslatorInterface $translatorMailerInterface $mailerDBLogService $DBLogGuardAuthenticatorHandler $authenticatorHandlerLoginFormAuthenticator $authenticator) {
  39.         $this->translator $translator;
  40.         $this->mailer $mailer;
  41.         $this->DBLog $DBLog;
  42.         $this->authenticatorHandler $authenticatorHandler;
  43.         $this->authenticator $authenticator;
  44.     }
  45.     /**
  46.      * @Route("/login", name="security_login")
  47.      */
  48.     public function loginAction(AuthenticationUtils $authenticationUtils)
  49.     {
  50.         // get the login error if there is one
  51.         $error $authenticationUtils->getLastAuthenticationError();
  52.         // last username entered by the user
  53.         $lastUsername $authenticationUtils->getLastUsername();
  54.         $form $this->createForm(
  55.             LoginForm::class,
  56.             [
  57.                 '_username' => $lastUsername,
  58.             ]
  59.         );
  60.         
  61.         return $this->render(
  62.             'security/login.html.twig',
  63.             array(
  64.                 'form'  => $form->createView(),
  65.                 'error' => $error,
  66.                 'login' => true
  67.             )
  68.         );
  69.     }
  70.     /**
  71.      * @Route("/logout", name="security_logout")
  72.      */
  73.     public function logoutAction()
  74.     {
  75.         throw new \Exception('this should not be reached.');
  76.     }
  77.     
  78.     /**
  79.      * @Route("/resetpassword", name="reset_password")
  80.      */
  81.     public function resetPassword(Request $request)
  82.     {
  83.         $form $this->createForm(PasswordRequestForm::class);
  84.         $form->handleRequest($request);
  85.         if ($form->isSubmitted() && $form->isValid()) {
  86.             $formData $form->getData();
  87.             $em $this->getDoctrine()
  88.                 ->getManager();
  89.             $user $em->getRepository(User::class)
  90.                 ->findByEmail($formData['_email']);
  91.             if (empty($user)) {
  92.                 $this->DBLog->debug('api''set password', [
  93.                     'email' => $formData['_email'],
  94.                     'response' => 'email not found',
  95.                 ]);
  96.                 $this->addFlash('error''User not found');
  97.             } else {
  98.                 $this->DBLog->debug('api''set password requested', [
  99.                     'email' => $formData['_email']
  100.                 ]);
  101. //                $this->addFlash('success', 'User found');
  102.                 $this->sendPasswordResetMail($user);
  103.                 
  104.                 return $this->render(
  105.                     'account/resetpassword.html.twig',
  106.                     [
  107.                         'step'      => 1,
  108.                         'formData'  => $formData,
  109.                         'resetForm' => $form->createView(),
  110.                     ]
  111.                 );
  112.             }
  113.         }
  114.         
  115.         return $this->render(
  116.             'account/resetpassword.html.twig',
  117.             [
  118.                 'step'      => 0,
  119.                 'resetForm' => $form->createView(),
  120.             ]
  121.         );
  122. //        return $this->redirectToRoute('user_account');
  123.     }
  124.     
  125.     /**
  126.      * @Route("/resettoken/{token}", name="reset_password_token")
  127.      */
  128.     public function resetPasswordToken($tokenRequest $request)
  129.     {
  130.         $max_time_sec 60 60 24;
  131.         $error false;
  132.         $userpassword null;
  133.         $token urldecode($token);
  134.         $token base64_decode($token);
  135.         $token $this->decryptData($token);
  136.         $token json_decode($token);
  137.         $time_passed strtotime('now') - strtotime($token->ts);
  138.         if ($time_passed $max_time_sec) {
  139.             $error 'expired';
  140.         }
  141.         $em $this->getDoctrine()
  142.             ->getManager();
  143.         /**
  144.          * Distinguish where the user requested the password reset.
  145.          * For account page, check user against
  146.          */
  147.         switch ($token->source) {
  148.             case 'api':
  149.                 $userdata ProthelisApi::getUserByEmail($token->email);
  150.                 if (!empty($userdata)) {
  151.                     $userpassword $userdata->password;
  152.                     /**
  153.                      * Check if API user already exists in local db
  154.                      */
  155.                     $user $em->getRepository(User::class)
  156.                         ->findbyUsername($userdata->username);
  157.                     if (!empty($user)) {
  158.                         /*
  159.                          * user exists
  160.                          */
  161.                     } else {
  162.                         // create empty user for form
  163.                         $user = new User();
  164.                         $user->setUsername($userdata->username);
  165.                     }
  166.                 }
  167.                 break;
  168.             case 'account':
  169.             default:
  170.                 /** @var User $user */
  171.                 $user $em->getRepository(User::class)
  172.                     ->findByEmail($token->email);
  173.                 if (!empty($user)) {
  174.                     $userpassword $user->getPassword();
  175.                 }
  176.                 break;
  177.         }
  178.         if (!$error && $userpassword !== $token->oldpw) {
  179.             $error 'already_used';
  180.         }
  181.         //display form
  182.         $form $this->createForm(PasswordResetForm::class, $user);
  183.         $form->handleRequest($request);
  184.         if ($error === false) {
  185.             if ($form->isSubmitted() && $form->isValid()) {
  186.                 $formData $form->getData();
  187.                 // send new password to api
  188.                 $response ProthelisApi::setUserParam($user->getUsername(), 'password'$user->getPlainPassword());
  189.                 // todo: check for negative response
  190.                 $this->DBLog->debug('api''set password', [
  191.                     'username' => $user->getUsername(),
  192.                     'response' => $response,
  193.                     ]);
  194.                 $this->addFlash(
  195.                     'success',
  196.                     $this->translator
  197.                         ->trans('account.resetpw.success.msgshort')
  198.                 );
  199.                 if ($user->getId() !== null) {
  200.                     // user has local account, auto login
  201.                     $em->flush();
  202.                     
  203.                     return $this->authenticatorHandler
  204.                         ->authenticateUserAndHandleSuccess(
  205.                             $user,
  206.                             $request,
  207.                             $this->authenticator,
  208.                             'main'
  209.                         );
  210.                 } else {
  211.                     // user has no local account, don't log in
  212.                     return $this->redirectToRoute('security_login');
  213.                     return $this->render(
  214.                         'account/error_message.html.twig',
  215.                         [
  216.                             'message' => [
  217.                                 'title' => $this->translator
  218.                                     ->trans('account.resetpw.success.title'),
  219.                                 'body'  => $this->translator
  220.                                     ->trans('account.resetpw.success.msgshort') . ' ' $this->translator
  221.                                     ->trans('account.resetpw.success.msgwebapp'),
  222.                                 'link'  => [
  223.                                     'href'  => 'https://my-prothelis.de',
  224.                                     'title' => 'Prothelis Web App',
  225.                                 ],
  226.                             ],
  227.                         ]
  228.                     );
  229.                 }
  230.             }
  231.         } else {
  232.             $this->DBLog->debug('api''set password', [
  233.                 'username' => $user $user->getUsername() : null,
  234.                 'response' => ['status' => 'error''token' => $token'msg' => $error],
  235.             ]);
  236.             return $this->redirectToRoute('security_login');
  237.             return $this->render(
  238.                 'account/error_message.html.twig',
  239.                 [
  240.                     'message' => [
  241.                         'title' => $this->translator
  242.                             ->trans('account.error.oopsie'),
  243.                         'body'  => $this->translator
  244.                             ->trans('account.resetpw.error.' $error),
  245.                         'link'  => [
  246.                             'href'  => $this->get('router')
  247.                                 ->generate('reset_password'),
  248.                             'title' => $this->translator
  249.                                 ->trans('account.resetpw.title'),
  250.                         ],
  251.                     ],
  252.                 ]
  253.             );
  254.         }
  255.         
  256.         return $this->render(
  257.             'account/passwordform.html.twig',
  258.             [
  259.                 'passwordForm' => $form->createView(),
  260.             ]
  261.         );
  262.     }
  263.     
  264.     private function sendPasswordResetMail(User $user)
  265.     {
  266.         $locale $user->getLocale();
  267.         if (!$locale) {
  268.             $locale 'en';
  269.         }
  270.         $this->translator->setLocale($locale);
  271.         /** @var Email $message */
  272.         $message = (new Email())
  273.             ->subject($this->translator->trans('email.reset_password.subject'))
  274.             ->from(new Address('support@prothelis.de''Prothelis Support'))
  275.             ->to($user->getEmailAddress())
  276.             ->html(
  277.                 $this->renderView(
  278.                     'email/reset_password.html.twig',
  279.                     ['resetLink' => $this->getResetLink($user)]
  280.                 )
  281.             );
  282.         $this->mailer->send($message);
  283.     }
  284.     
  285.     private function getResetLink(User $user)
  286.     {
  287.         $locale $user->getLocale() ?: 'de';
  288.         $url 'https://my-prothelis.de/account/'.$locale.'/resettoken/';
  289.         $token = [
  290.             'email'  => $user->getEmailAddress(),
  291.             'oldpw'  => $user->getPassword(),
  292.             'ts'     => date('Y-m-d H:i:s'),
  293.             'source' => 'account',
  294.         ];
  295.         $token json_encode($token);
  296.         $token_enc $this->encryptData($token);
  297.         $token_b64 base64_encode($token_enc);
  298.         $token_url urlencode(urlencode($token_b64));
  299.         
  300.         return $url $token_url;
  301.     }
  302.     
  303.     function encryptData($plaintext)
  304.     {
  305.         $key $_ENV['APP_SECRET'];
  306.         $iv 'c4HQEm7dK6Niuq[H';
  307.         $ciphertext openssl_encrypt($plaintext'AES-128-CBC'$keyOPENSSL_RAW_DATA$iv);
  308.         
  309.         return $ciphertext;
  310.     }
  311.     
  312.     function decryptData($ciphertext)
  313.     {
  314.         $key $_ENV['APP_SECRET'];
  315.         $iv 'c4HQEm7dK6Niuq[H';
  316.         $plaintext openssl_decrypt($ciphertext'AES-128-CBC'$keyOPENSSL_RAW_DATA$iv);
  317.         
  318.         return $plaintext;
  319.     }
  320. }
  321. ?>