src/Controller/Main/SecurityController.php line 156

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Main;
  3. use App\Entity\Main\User;
  4. use App\Events\Main\Registration\SecurityEvent;
  5. use App\EventSubscribers\Main\SecuritySubscriber;
  6. use App\Services\CartManager;
  7. use App\Form\Main\UserLoginType;
  8. use App\Services\ReferralProgramManager;
  9. use App\Services\Setup;
  10. use App\Twig\GoogleTagManagerExtension;
  11. use phpDocumentor\Reflection\Types\This;
  12. use Predis\Client;
  13. use Psr\Log\LoggerInterface;
  14. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  15. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  16. use Symfony\Component\HttpFoundation\RedirectResponse;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpFoundation\Response;
  19. use Symfony\Component\HttpFoundation\Session\Session;
  20. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  21. use Symfony\Component\Routing\Annotation\Route;
  22. use Symfony\Component\Routing\RouterInterface;
  23. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  24. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  25. use Symfony\Component\Security\Core\Security;
  26. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  27. /**
  28.  * @Route(
  29.  *     condition="not (context.getHost() matches '%coaching_domain.host.regexp%')"
  30.  * )
  31.  */
  32. class SecurityController extends AbstractController
  33. {
  34.     use BrulafineControllerTrait;
  35.     const
  36.         TEMPLATE_NAME_BASE 'templateBase',
  37.         TEMPLATE_NAME_CART 'templateCart',
  38.         ROUTE_OVER 'over',
  39.         ROUTE_FAILED_PAYMENT 'failed-payment',
  40.         ROUTE_OFFER_PREUPSELL CartManager::OFFER_PREUPSELL,
  41.         ROUTE_OFFER_UPSELL CartManager::OFFER_UPSELL
  42.     ;
  43.     const
  44.         AUTOLOGIN_DESTINATION_ROUTES = [
  45.             "home" => 'brulafine_home',
  46.             "pack" => 'brulafine_show_packs',
  47.             "packs" => 'brulafine_show_packs',
  48.             "account" => 'brulafine_user_compte',
  49.             "order" => 'brulafine_user_commandes',
  50.             "orders" => 'brulafine_user_commandes',
  51.             "password" => 'user_change_password',
  52.             "cyrielle" => 'brulafine_temoignage_interactive',
  53.             "testimonies" => 'brulafine_temoignages_no_page',
  54.             "testimony" => 'brulafine_temoignages_no_page',
  55.             "contact" => "brulafine_contact",
  56.             "ingredients" => "brulafine_ingredients",
  57.             "ingredient" => "brulafine_ingredients",
  58.             "cgv" => "brulafine_cgv",
  59.             "avis" => 'brulafine_avis_no_page',
  60.             "video" => 'brulafine_temoignage_videos',
  61.             "videos" => 'brulafine_temoignage_videos',
  62.             self::ROUTE_OVER => 'brulafine_over',
  63.             self::ROUTE_FAILED_PAYMENT => 'brulafine_payment',
  64.             self::ROUTE_OFFER_PREUPSELL => 'brulafine_offers',
  65.             self::ROUTE_OFFER_UPSELL => 'brulafine_offers',
  66.         ];
  67.     const
  68.         DESTINATION_ROUTES_USER_REQUIRED = [
  69.             "account" => 'brulafine_user_compte',
  70.             "order" => 'brulafine_user_commandes',
  71.             "orders" => 'brulafine_user_commandes',
  72.             "password" => 'user_change_password',
  73.             self::ROUTE_OVER => 'brulafine_over',
  74.             self::ROUTE_FAILED_PAYMENT => 'brulafine_payment',
  75.             self::ROUTE_OFFER_PREUPSELL => 'brulafine_offers',
  76.             self::ROUTE_OFFER_UPSELL => 'brulafine_offers',
  77.         ];
  78.     public function __construct(private AuthenticationUtils $authenticationUtils)
  79.     {
  80.     }
  81.     /**
  82.      * @param Request $request
  83.      *
  84.      * @param ReferralProgramManager $referralProgramManager
  85.      * @return Response
  86.      */
  87.     public function loginAction(Request $requestReferralProgramManager $referralProgramManagerAuthorizationCheckerInterface $authorizationCheckerAuthenticationUtils $authenticationUtils)
  88.     {
  89.         /** @var $session \Symfony\Component\HttpFoundation\Session\Session */
  90.         $session $request->getSession();
  91.         $setup $this->getSetup();
  92.         if ($authorizationChecker->isGranted('ROLE_USER')) {
  93.             if ($referralProgramManager->isReferralProgramEnabled($setup->getUser(), $setup->getSite())) {
  94.                 return $this->redirectToRoute('brulafine_user_referral_program');
  95.             }
  96.             return $this->redirectToRoute('brulafine_user_compte');
  97.         }
  98.         // last username entered by the user
  99.         $lastUsername $authenticationUtils->getLastUsername();
  100.         $authErrorKey Security::AUTHENTICATION_ERROR;
  101.         // get the error if any (works with forward and redirect -- see below)
  102.         if ($request->attributes->has($authErrorKey)) {
  103.             $error $request->attributes->get($authErrorKey);
  104.         } elseif (null !== $session && $session->has($authErrorKey)) {
  105.             $error $session->get($authErrorKey);
  106.             $session->remove($authErrorKey);
  107.             $session->set(GoogleTagManagerExtension::GTM_SESSION_LOGIN_EVENT_KEY$error->getMessage());
  108.         } else {
  109.             $error null;
  110.         }
  111.         $form $this->createForm(UserLoginType::class, [
  112.             '_username' => $lastUsername,
  113.         ]);
  114.         return $this->render(
  115.             $this->getTemplatesDir() . '/Security/views/Login/login.html.twig',
  116.             array(
  117.                 'error'         => $error,
  118.                 'form' => $form->createView(),
  119.                 'tracking' => $setup->getTracking(),
  120.                 'site' => $setup->getSite(),
  121.             )
  122.         );
  123.     }
  124.     /**
  125.      * @param Request $request
  126.      * @param $templateName
  127.      * @return Response
  128.      */
  129.     public function loginPartialAction(Request $request$templateName null)
  130.     {
  131.         /** @var $session \Symfony\Component\HttpFoundation\Session\Session */
  132.         $session $request->getSession();
  133.         $authErrorKey Security::AUTHENTICATION_ERROR;
  134.         // get the error if any (works with forward and redirect -- see below)
  135.         if ($request->attributes->has($authErrorKey)) {
  136.             $error $request->attributes->get($authErrorKey);
  137.         } elseif (null !== $session && $session->has($authErrorKey)) {
  138.             $error $session->get($authErrorKey);
  139.             $session->remove($authErrorKey);
  140.             $session->set(GoogleTagManagerExtension::GTM_SESSION_LOGIN_EVENT_KEY$error->getMessage());
  141.         } else {
  142.             $error null;
  143.         }
  144.         if (!$error instanceof AuthenticationException) {
  145.             $error null// The value does not come from the security component.
  146.         }
  147.         // last username entered by the user
  148.         $lastUsername $this->authenticationUtils->getLastUsername();
  149.         $form $this->createForm(UserLoginType::class, [
  150.             '_username' => $lastUsername,
  151.         ]);
  152.         $setup $this->getSetup();
  153.         return $this->renderLoginPartial([
  154.             'error' => $error,
  155.             'tracking' => $setup->getTracking(),
  156.             'site' => $setup->getSite(),
  157.             'form' => $form->createView(),
  158.             'templateName' => $templateName
  159.         ]);
  160.     }
  161.     /**
  162.      * Renders the login template with the given parameters. Overwrite this function in
  163.      * an extended controller to provide additional data for the login template.
  164.      *
  165.      * @param array $data
  166.      *
  167.      * @return Response
  168.      */
  169.     protected function renderLoginPartial(array $data)
  170.     {
  171.         return $this->render($this->getTemplatesDir() . '/Security/views/Login/login_partial.html.twig'$data);
  172.     }
  173.     /**
  174.      * Renders the login template with the given parameters. Overwrite this function in
  175.      * an extended controller to provide additional data for the login template.
  176.      *
  177.      * @param array $data
  178.      *
  179.      * @return Response
  180.      */
  181.     protected function renderLogin(array $data)
  182.     {
  183.         return $this->render($this->getTemplatesDir() . '/Security/views/Login/login.html.twig'$data);
  184.     }
  185.     /**
  186.      * @Route(
  187.      *     "/security/token/login/{loginId}/{loginToken}/{dest}",
  188.      *     name="brulafine_token_login",
  189.      *     defaults={"dest": "home", "data"= 0},
  190.      *     requirements={
  191.      *         "dest": "home|pack|packs|account|order|orders|password|cyrielle|testimonies|testimony|contact|ingredients|ingredient|cgv|over|failed-payment|offer-preupsell|offer-upsell|video|videos",
  192.      *         "loginId": "[0-9a-zA-Z]+",
  193.      *         "loginToken": "[0-9a-zA-Z]+"
  194.      *     }
  195.      * )
  196.      * @param Request $request
  197.      * @param $loginId
  198.      * @param $loginToken
  199.      * @param $dest
  200.      * @param RouterInterface $router
  201.      * @param LoggerInterface $logger
  202.      * @param Session $session
  203.      * @return Response
  204.      */
  205.     public function tokenLoginAction(Request $request$loginId$loginToken$destRouterInterface $routerLoggerInterface $loggerSession $session$redisClientEventDispatcherInterface $eventDispatcher)
  206.     {
  207.         //https://brulafine8up.dev.wcc-bg.com/security/token/login/2ba805dbd290855491f49edebfbb8d047f1bed37/9f3d4b64d188883156e08642d37d60caa71eb878e889d/failed-payment
  208.         // already logged in users can't access this place
  209.         if ($this->getUser() instanceof User) {
  210.             $routeToRedirect self::AUTOLOGIN_DESTINATION_ROUTES[$dest];
  211.             if (self::ROUTE_OVER === $dest && $request->query->get('data'null)) {
  212.                 return $this->redirectToRoute(self::AUTOLOGIN_DESTINATION_ROUTES[$dest], ['shortId' => $request->query->get('data')]);
  213.             }
  214.             if (self::ROUTE_FAILED_PAYMENT == $dest) {
  215.                 $request->getSession()->set(CartManager::CHECK_FAILED_PURCHASE_KEYtrue);
  216.             }
  217.             if (in_array($dest, [self::ROUTE_OFFER_PREUPSELLself::ROUTE_OFFER_UPSELL])) {
  218.                 $routeToRedirect $router->generate(self::AUTOLOGIN_DESTINATION_ROUTES[$dest], ['offer' => $dest]);
  219.                 return new RedirectResponse($routeToRedirect);
  220.             }
  221.             return $this->redirectToRoute($routeToRedirect);
  222.         }
  223.         $environment $this->getParameter("kernel.environment");
  224.         $redisKey ResettingController::AUTOLOGIN_ATTEMPTS_REDIS_KEY $request->getClientIp();
  225.         // prevent brut force attacks by limiting to 50 calls on this address by the same IP.
  226.         $redisClient->setex($redisKey3600, ((int) $redisClient->get($redisKey) + 1));
  227.         if ((int) $redisClient->get($redisKey) > 50 && 'test' != $environment) {
  228.             $logger->alert("Someone is trying to bruteforce the autologin url, IP {$request->getClientIp()}, number of tries so far : {$redisClient->get($redisKey)}");
  229.             $request->getSession()->set(GoogleTagManagerExtension::GTM_SESSION_LOGIN_EVENT_KEY"Too many autologin attempts");
  230.             throw new NotFoundHttpException();
  231.         }
  232.         $usersToLogin $this->getDoctrine()->getRepository(User::class)->getUserFromAutologinToken($loginToken);
  233.         if (!count($usersToLogin)) {
  234.             $request->getSession()->set(GoogleTagManagerExtension::GTM_SESSION_LOGIN_EVENT_KEY"autologin token invalid");
  235.             throw new NotFoundHttpException();
  236.         }
  237.         $userToLogin null;
  238.         foreach ($usersToLogin as $loopUser) {
  239.             if (!$loopUser instanceof User) {
  240.                 continue;
  241.             }
  242.             if ($loopUser->isValidAutoLoginToken($loginId$loginToken45)) {
  243.                 $userToLogin $loopUser;
  244.                 break;
  245.             }
  246.         }
  247.         if (!$userToLogin instanceof User) {
  248.             $request->getSession()->set(GoogleTagManagerExtension::GTM_SESSION_LOGIN_EVENT_KEY"autologin token invalid");
  249.             throw new NotFoundHttpException();
  250.         }
  251.         // check if the user is anonymized. If so he can't login.
  252.         if ($userToLogin->isAnonymized()) {
  253.             $userToLogin->eraseAutoLoginToken();
  254.             $this->getDoctrine()->flush();
  255.             throw new NotFoundHttpException();
  256.         }
  257.         // For Guest users we set the user to the session and don`t log them in.
  258.         if ($userToLogin->hasRole(User::ROLE_GUEST)) {
  259.             if (key_exists($destself::DESTINATION_ROUTES_USER_REQUIRED)) {
  260.                 $session->set(User::GUEST_USER_SESSION_KEY$userToLogin->getId());
  261.             }
  262.             if (self::ROUTE_OVER === $dest && $request->query->get('data'null)) {
  263.                 $routeToRedirect $router->generate(self::AUTOLOGIN_DESTINATION_ROUTES[$dest], ['shortId' => $request->query->get('data')]);
  264.             } else {
  265.                 $routeToRedirect $router->generate(self::AUTOLOGIN_DESTINATION_ROUTES[$dest]);
  266.             }
  267.             return new RedirectResponse($routeToRedirect);
  268.         }
  269.         $eventDispatcher->dispatch(
  270.             new SecurityEvent($userToLogin$request),
  271.             SecuritySubscriber::USER_LOGGED_IN
  272.         );
  273.         // 1. new special case, the route over requires the cart id.
  274.         // 2. new special case, we redirect to payment page users with failed purchases and allow them PayPal payment option with no limit.
  275.         if (self::ROUTE_OVER === $dest && $request->query->get('data'null)) {
  276.             $routeToRedirect $router->generate(self::AUTOLOGIN_DESTINATION_ROUTES[$dest], ['shortId' => $request->query->get('data')]);
  277.         } elseif (self::ROUTE_FAILED_PAYMENT === $dest) {
  278.             $request->getSession()->set(CartManager::CHECK_FAILED_PURCHASE_KEYtrue);
  279.             $routeToRedirect $router->generate(self::AUTOLOGIN_DESTINATION_ROUTES[$dest]);
  280.         } elseif (in_array($dest, [self::ROUTE_OFFER_PREUPSELLself::ROUTE_OFFER_UPSELL])) {
  281.             $routeToRedirect $router->generate(self::AUTOLOGIN_DESTINATION_ROUTES[$dest], ['offer' => $dest]);
  282.         } else {
  283.             $routeToRedirect $router->generate(self::AUTOLOGIN_DESTINATION_ROUTES[$dest]);
  284.         }
  285.         return new RedirectResponse($routeToRedirect);
  286.     }
  287. }