src/Controller/SecurityController.php line 86

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\CustomerDetail;
  4. use App\Entity\DeviceKey;
  5. use App\Entity\PageDesign;
  6. use App\Entity\Plan;
  7. use App\Entity\ResetPassword;
  8. use App\Entity\User;
  9. use App\Entity\Workspace;
  10. use App\Form\RegisterUserType;
  11. use App\Repository\PageDesignRepository;
  12. use App\Repository\ResetPasswordRepository;
  13. use App\Repository\UserRepository;
  14. use App\Security\LoginFormAuthenticator;
  15. use App\Service\MailService;
  16. use App\Service\UserService;
  17. use App\Utils\CommonFunctions;
  18. use App\Utils\Commons;
  19. use App\Utils\UserValidator;
  20. use DateTime;
  21. use DateTimeZone;
  22. use Doctrine\ORM\NonUniqueResultException;
  23. use Doctrine\ORM\NoResultException;
  24. use Exception;
  25. use ReCaptcha\ReCaptcha;
  26. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  27. use Symfony\Component\Form\Extension\Core\Type\EmailType;
  28. use Symfony\Component\Form\Extension\Core\Type\PasswordType;
  29. use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
  30. use Symfony\Component\HttpFoundation\JsonResponse;
  31. use Symfony\Component\HttpFoundation\RedirectResponse;
  32. use Symfony\Component\HttpFoundation\Request;
  33. use Symfony\Component\HttpFoundation\Response;
  34. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  35. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  36. use Symfony\Component\Routing\Annotation\Route;
  37. use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
  38. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  39. use Symfony\Component\Form\FormError;
  40. use Symfony\Contracts\Translation\TranslatorInterface;
  41. use Twig\Error\LoaderError;
  42. use Twig\Error\RuntimeError;
  43. use Twig\Error\SyntaxError;
  44. class SecurityController extends AbstractController
  45. {
  46.     /**
  47.      * Frontend Login Page
  48.      * Accepts symfony's built-in guard authentication provider to authenticate user
  49.      * which is configured in security.yaml under firewall.
  50.      * Throws authenticationUtils error if user does not exists.
  51.      * Check LoginFormAuthenticator to see user token based authentication.
  52.      *
  53.      * @Route("/", name="app_login")
  54.      * @param Request $request
  55.      * @param AuthenticationUtils $authenticationUtils
  56.      * @param PageDesignRepository $pageDesignRepository
  57.      * @param CommonFunctions $commonFunctions
  58.      * @return Response
  59.      */
  60.     public function login(Request $requestAuthenticationUtils $authenticationUtilsPageDesignRepository $pageDesignRepositoryCommonFunctions $commonFunctions): Response
  61.     {
  62.         // Redirect if user already authenticated
  63.         if ($this->isGranted('ROLE_ADMIN') || $this->isGranted('ROLE_USER')) {
  64.             return $this->redirectToRoute('dashboard_index');
  65.         } else if ($this->isGranted('ROLE_BACKEND_USER')) {
  66.             return $this->redirectToRoute('admin_dashboard_index');
  67.         }
  68.         // get the login error if there is one
  69.         $error $authenticationUtils->getLastAuthenticationError();
  70.         // last username entered by the user
  71.         $lastUsername $authenticationUtils->getLastUsername();
  72. //        dump($commons::$localeList);
  73. //        die;
  74.         return $this->render('security/login.html.twig',
  75.             [
  76.                 'last_username' => $lastUsername,
  77.                 'error' => $error,
  78.                 'page_design' => $commonFunctions->findFirstByPageDesignType($pageDesignRepositoryPageDesign::LOGIN_TYPE$request->getLocale())
  79.             ]
  80.         );
  81.     }
  82.     /**
  83.      * Reset Password Page
  84.      * Send password reset mail to registered users.
  85.      *
  86.      * @Route("/verify/password/send/mail", name="app_password_send_mail" )
  87.      * @param Request $request
  88.      * @param UserRepository $userRepository
  89.      * @param UserService $userService
  90.      * @param MailService $mailService
  91.      * @param TranslatorInterface $translator
  92.      * @param null $user
  93.      * @return Response
  94.      */
  95.     public function sendEmailPasswordLink(Request $requestUserRepository $userRepositoryUserService $userServiceMailService $mailServiceTranslatorInterface $translator$user null): Response
  96.     {
  97.         $form $this->createFormBuilder()->add('email'EmailType::class)->getForm();
  98.         $form->handleRequest($request);
  99.         $sent false;
  100.         if ($form->isSubmitted() && $form->isValid()) {
  101.             $sent true;
  102.             $user $userRepository->findOneBy(['email' => $form->get('email')->getData()]);
  103.             if (is_object($user)) {
  104.                 $resetPassword $userService->checkAndCreatePasswordResets($user);
  105.                 try {
  106.                     $mailService->sendPasswordResetEmail($user$resetPassword);
  107.                 } catch (LoaderError RuntimeError SyntaxError $e) {
  108.                     $this->addFlash("success"$translator->trans("email.sending_error"));
  109.                 }
  110.             }
  111.             //no validation anymore!
  112.             //else {
  113.               //  $form->get('email')->addError(new FormError($translator->trans('msg.email_not_found')));
  114.            // }
  115.         }
  116.         return $this->render('security/verify.password.mail.html.twig', [
  117.             'resetPassword' => $form->createView(),
  118.             'sent' => $sent
  119.         ]);
  120.     }
  121.     /**
  122.      * Confirm Password entry page.
  123.      * Accepts unique identifier and registered email.
  124.      * User redirected to this url only after email is triggered to their respective inbox.
  125.      *
  126.      * @Route("/reset/password", name="app_reset_password", methods={"GET","POST"})
  127.      * @param Request $request
  128.      * @param LoginFormAuthenticator $loginFormAuthenticator
  129.      * @param GuardAuthenticatorHandler $guardHandler
  130.      * @param UserValidator $userValidator
  131.      * @param TranslatorInterface $translator
  132.      * @param ResetPasswordRepository $resetPasswordRepository
  133.      * @param UserRepository $userRepository
  134.      * @param UserPasswordHasherInterface $userPasswordHasher
  135.      * @param int $flag
  136.      * @return Response
  137.      * @throws NonUniqueResultException
  138.      */
  139.     public function recoverPassword(Request $requestLoginFormAuthenticator $loginFormAuthenticatorGuardAuthenticatorHandler $guardHandlerUserValidator $userValidatorTranslatorInterface $translatorResetPasswordRepository $resetPasswordRepositoryUserRepository $userRepositoryUserPasswordHasherInterface $userPasswordHasher$flag 0): Response
  140.     {
  141.         if ($this->getUser() !== null) {
  142.             throw new NotFoundHttpException("You are logged in!");
  143.         }
  144.         $resetPassword $resetPasswordRepository->findByIdentifier($request->query->get('email'), $request->query->get('identifier'));
  145.         if (!$resetPassword) {
  146.             throw new NotFoundHttpException($translator->trans('msg.email_not_found'));
  147.         }
  148.         $user $userRepository->find($resetPassword->getUser());
  149.         if (!is_object($user)) {
  150.             throw new NotFoundHttpException($translator->trans('msg.email_not_found'));
  151.         }
  152.         // create password reset form
  153.         $form $this->createFormBuilder($user)->add('password'RepeatedType::class, [
  154.             'type' => PasswordType::class,
  155.             'invalid_message' => 'Password must match.',
  156.             'first_options' => ['label' => $translator->trans('user.form.password')],
  157.             'second_options' => ['label' => $translator->trans('confirm_password.confirm')],
  158.         ])
  159.             ->setAction($this->generateUrl('app_reset_password', ['email' => $request->query->get('email'), 'identifier' => $request->query->get('identifier')]))
  160.             ->setMethod('POST')
  161.             ->getForm();
  162.         $form->handleRequest($request);
  163.         if ($form->isSubmitted() && $form->isValid()) {
  164.             $password $userValidator->validatePassword($form->get('password')->getData());
  165.             if ($password == null) {
  166.                 $form->get('password')->get('first')->addError(new FormError($translator->trans('msg.password_validator_error')));
  167.                 $html $this->renderView('user/recover.password.html.twig', [
  168.                     'form' => $form->createView(),
  169.                     'flag' => $flag,
  170.                 ]);
  171.                 return new Response($html400);
  172.             }
  173.             $em $this->getDoctrine()->getManager();
  174.             // encode password with PasswordEncoder service
  175.             $user->setPassword($userPasswordHasher->hashPassword($user$password));
  176.             $em->persist($user);
  177.             // successfully reset password flag to display message
  178.             $role $user->getRoles();
  179.             $user->setResetPassword(null);
  180.             $em->persist($user);
  181.             $em->flush();
  182.             $em->remove($resetPassword);
  183.             $em->flush();
  184.             if ($role[0] == 'ROLE_BACKEND_USER') {
  185.                 return $this->redirectToRoute('backend_login');
  186.             } else {
  187.                 //login with the user
  188.                 return $guardHandler->authenticateUserAndHandleSuccess(
  189.                     $user,
  190.                     $request,
  191.                     $loginFormAuthenticator,
  192.                     'main'
  193.                 );
  194.             }
  195.         }
  196.         return $this->render('user/recover.password.html.twig', [
  197.             'form' => $form->createView(),
  198.             'user' => $user
  199.         ]);
  200.     }
  201.     /**
  202.      * Symfony's default logout path
  203.      * @Route("/logout", name="app_logout")
  204.      * @throws Exception
  205.      */
  206.     public function logout()
  207.     {
  208.         throw new Exception('This method can be blank - it will be intercepted by the logout key on your firewall');
  209.     }
  210.     /**
  211.      * @Route("/backend/logout", name="app_backend_logout")
  212.      * @throws Exception
  213.      */
  214.     public function backendLogout()
  215.     {
  216.         throw new Exception('This method can be blank - it will be intercepted by the logout key on your firewall');
  217.     }
  218.     /**
  219.      * Redirect based on user role after logout
  220.      *
  221.      * @Route("/logout/redirect", name="redirect_after_logout")
  222.      * @return RedirectResponse
  223.      */
  224.     public function redirectAfterLogout(): RedirectResponse
  225.     {
  226.         $roles $this->getUser()->getRoles();
  227.         $userRole $roles[0];
  228.         $role "USER";
  229.         if ($userRole == 'ROLE_SUPER_ADMIN' or $userRole == 'ROLE_BACKEND_USER') {
  230.             $role "ADMIN";
  231.         }
  232. //        $this->redirectToRoute('app_logout');
  233.         if ($role == 'ADMIN') {
  234.             return $this->redirectToRoute('backend_login');
  235.         } else {
  236.             return $this->redirectToRoute('app_login');
  237.         }
  238.     }
  239.     /**
  240.      * Register Page
  241.      * Register user as customer.
  242.      *
  243.      * @Route("/register", name="app_register")
  244.      * @param Request $request
  245.      * @param PageDesignRepository $pageDesignRepository
  246.      * @param CommonFunctions $commonFunctions
  247.      * @param MailService $mailService
  248.      * @param TranslatorInterface $translator
  249.      * @param UserPasswordHasherInterface $userPasswordHasher
  250.      * @return Response
  251.      * @throws NoResultException
  252.      * @throws NonUniqueResultException
  253.      */
  254.     public function register(Request $requestPageDesignRepository $pageDesignRepositoryUserPasswordHasherInterface $userPasswordHasherMailService $mailServiceTranslatorInterface $translatorCommonFunctions $commonFunctions): Response
  255.     {
  256.         $user = new User();
  257.         $form $this->createForm(RegisterUserType::class, $user, ['is_user_registration' => true]);
  258.         $form->handleRequest($request);
  259.         $em $this->getDoctrine()->getManager();
  260.         if ($form->isSubmitted()) {
  261.             if ($form->isValid()) {
  262.                 $emailNotUsedInOldEmailField true;
  263.                 $oldEmailRecordsCount intval($em->getRepository(User::class)->checkEmailInOldEmailsUsed($user));
  264.                 if ($oldEmailRecordsCount 0) {
  265.                     $emailNotUsedInOldEmailField false;
  266.                 }
  267.                 if ($emailNotUsedInOldEmailField === true) {
  268.                     $user->setPassword($userPasswordHasher->hashPassword($user$user->generateRandomPassword()));
  269.                     $user->setUsername($user->getEmail());
  270.                     $user->setRoles([Commons::ROLE_ADMIN]); // set User role as customer
  271.                     // create new workspace for customer and credit the user.
  272.                     $workspace = new Workspace();
  273.                     $workspace->setOwner($user);
  274.                     $key md5(uniqid(rand(), true));
  275.                     $workspace->setCustomerKey($key);
  276.                     $defaultPlan $em->getRepository(Plan::class)->findOneBy(['defaultPlan' => true]);
  277.                     if (is_object($defaultPlan)) {
  278.                         $workspace->setPlan($defaultPlan);
  279.                     }
  280.                     // create new customer detail
  281.                     $customerDetail = new CustomerDetail();
  282.                     $customerDetail->setCustomer($user);
  283.                     $customerDetail->setCentralEmailAddress($user->getEmail());
  284.                     $em->persist($workspace);
  285.                     $hash hash('sha256'uniqid(rand(), true));
  286.                     $deviceKey = new DeviceKey();
  287.                     $deviceKey->setDeviceKey($hash);
  288.                     $deviceKey->setKeyType("sha_256");
  289.                     $deviceKey->setWorkspace($workspace);
  290.                     $em->persist($deviceKey);
  291.                     $user->setWorkspace($workspace);
  292.                     $em->persist($user);
  293.                     $em->persist($workspace);
  294.                     $em->persist($customerDetail);
  295.                     $em->flush();
  296.                     $numLength strlen((string)$customerDetail->getId()) + 5;
  297.                     $customerId str_pad($customerDetail->getId(), $numLength'0'STR_PAD_LEFT);
  298.                     $customerDetail->setCustomerNumber($customerId);
  299.                     $em->persist($customerDetail);
  300.                     $em->flush();
  301.                     $resetPassword = new ResetPassword();
  302.                     $resetPassword->setUser($user);
  303.                     $resetPassword->setLinkExpireDateTime(new DateTime());
  304.                     $em->persist($resetPassword);
  305.                     $em->flush();
  306.                     try {
  307.                         $mailService->sendRegistrationEmail($user$resetPassword);
  308.                     } catch (LoaderError RuntimeError SyntaxError $e) {
  309.                         $this->addFlash("success"$translator->trans("email.sending_error"));
  310.                     }
  311.                     try {
  312.                         $mailService->sendRegistrationAdminEmail($user);
  313.                     } catch (LoaderError RuntimeError SyntaxError $e) {
  314.                         $this->addFlash("success"$translator->trans("email.sending_error"));
  315.                     }
  316.                     return $this->redirectToRoute('app_register_success');
  317.                 }
  318.                 $form->get("email")->addError(new FormError($translator->trans("entity.msg.email_exists")));
  319.             }
  320.         }
  321.         return $this->render('security/register.html.twig', [
  322.             'registrationForm' => $form->createView(),
  323.             'user' => $user,
  324.             'page_design' => $commonFunctions->findFirstByPageDesignType($pageDesignRepositoryPageDesign::REGISTER_TYPE$request->getLocale())
  325.         ]);
  326.     }
  327.     /**
  328.      * Register Success Page
  329.      *
  330.      * @Route("/register/success", name="app_register_success")
  331.      * @return Response
  332.      */
  333.     public function registerSuccess(): Response
  334.     {
  335.         return $this->render('security/register_success.html.twig');
  336.     }
  337.     /**
  338.      * Backend Login Page
  339.      * Accepts symfony's built-in guard authentication provider to authenticate user
  340.      * which is configured in security.yaml under firewall.
  341.      * Throws authenticationUtils error if user does not exists.
  342.      * Check LoginFormAuthenticator to see user token based authentication.
  343.      *
  344.      * @Route("/backend", name="backend_login")
  345.      * @param AuthenticationUtils $authenticationUtils
  346.      * @return Response
  347.      */
  348.     public function backendLogin(AuthenticationUtils $authenticationUtils): Response
  349.     {
  350.         // Redirect if user already authenticated
  351.         if ($this->isGranted('ROLE_ADMIN') || $this->isGranted('ROLE_USER')) {
  352.             return $this->redirectToRoute('dashboard_index');
  353.         } else if ($this->isGranted('ROLE_BACKEND_USER')) {
  354.             return $this->redirectToRoute('admin_dashboard_index');
  355.         }
  356.         // get the login error if there is one
  357.         $error $authenticationUtils->getLastAuthenticationError();
  358.         // last username entered by the user
  359.         $lastUsername $authenticationUtils->getLastUsername();
  360.         return $this->render('security/admin-login.html.twig', ['last_username' => $lastUsername'error' => $error]);
  361.     }
  362.     /**
  363.      * @Route("/recaptcha", name="verify_recaptcha")
  364.      * @param Request $request
  365.      * @return JsonResponse
  366.      */
  367.     public function verifyRecaptcha(Request $request): JsonResponse
  368.     {
  369.         $errors = array();
  370.         $success false;
  371.         if ($request->get('token')) {
  372.             $token $request->get('token');
  373.             $recaptcha = new ReCaptcha($_ENV['GOOGLE_RECAPTCHA_SECRET']);
  374.             $resp $recaptcha
  375.                 ->setScoreThreshold(0.8)
  376.                 ->verify($token);
  377.             if ($resp->isSuccess()) {
  378.                 // Verified!
  379.                 $success true;
  380.             } else {
  381.                 $errors $resp->getErrorCodes();
  382.             }
  383.         }
  384.         return new JsonResponse(["success" => $success"errors" => $errors]);
  385.     }
  386.     /**
  387.      * @Route("/imprint", name="imprint")
  388.      * @return Response
  389.      */
  390.     public function imprint(): Response
  391.     {
  392.         return $this->render('security/imprint.html.twig');
  393.     }
  394.     /**
  395.      * @Route("/privacy", name="privacy")
  396.      * @return Response
  397.      */
  398.     public function privacyPolicy(): Response
  399.     {
  400.         return $this->render('security/privacy.html.twig');
  401.     }
  402.     /**
  403.      * @Route("/gtc", name="gtc")
  404.      * @return Response
  405.      */
  406.     public function gtc(): Response
  407.     {
  408.         return $this->render('security/gtc.html.twig');
  409.     }
  410.     /**
  411.      * @Route("/refresh", name="app_refresh")
  412.      * @return JsonResponse
  413.      */
  414.     public function refresh(): JsonResponse
  415.     {
  416.         return new JsonResponse(['success' => 1], 200, [], false);
  417.     }
  418.     /**
  419.      * @Route("/cookie/plan/{id}", name="plan_cookie")
  420.      * @param Plan|null $plan
  421.      * @return RedirectResponse
  422.      */
  423.     public function planCookie(Plan $plan null): RedirectResponse
  424.     {
  425.         if (!is_null($plan)) {
  426.             setcookie('plan_register'$plan->getId(), 0'/');
  427.         }
  428.         return $this->redirectToRoute('app_register');
  429.     }
  430.     /**
  431.      *
  432.      * @Route("/recover/email", name="app_recover_email", methods={"GET"})
  433.      * @param Request $request
  434.      * @param TranslatorInterface $translator
  435.      * @param UserRepository $userRepository
  436.      * @return Response
  437.      * @throws Exception
  438.      */
  439.     public function recoverEmail(Request $requestTranslatorInterface $translatorUserRepository $userRepository): Response
  440.     {
  441.         if ($this->getUser() !== null) {
  442.             $this->addFlash("success"$translator->trans('email_restore.error_logged_in'));
  443.             return $this->redirectToRoute('app_login');
  444.         }
  445.         if (!$request->query->has("email") || !$request->query->has("identifier")) {
  446.             $this->addFlash("success"$translator->trans('email_restore.not_found'));
  447.             return $this->redirectToRoute('app_login');
  448.         }
  449.         $user $userRepository->findOneBy([
  450.                 'oldEmail' => $request->query->get('email'),
  451.                 'emailRecoveryCode' => $request->query->get('identifier')
  452.             ]
  453.         );
  454.         if (!is_object($user)) {
  455.             $this->addFlash("success"$translator->trans('email_restore.not_found'));
  456.             return $this->redirectToRoute('app_login');
  457.         }
  458.         if ($user->getEmailRecoveryCodeExpireDateTime() < new DateTime('now', new DateTimeZone("UTC"))) {
  459.             $this->addFlash("success"$translator->trans('email_restore.key_expired'));
  460.             return $this->redirectToRoute('app_login');
  461.         }
  462.         $em $this->getDoctrine()->getManager();
  463.         $user->setEmail($user->getOldEmail());
  464.         $user->setEmailRecoveryCodeExpireDateTime(null);
  465.         $user->setEmailRecoveryCode(null);
  466.         $user->setOldEmail(null);
  467.         $em->persist($user);
  468.         $em->flush();
  469.         $role $user->getRoles();
  470.         if ($role[0] == 'ROLE_BACKEND_USER') {
  471.             return $this->redirectToRoute('backend_login');
  472.         } else {
  473.             $this->addFlash("success"$translator->trans('email_restore.success'));
  474.             return $this->redirectToRoute('app_login');
  475.         }
  476.     }
  477. }