<?php
//----------------------------------------------------------------------
// src/Controller/Security/SecurityController.php
//----------------------------------------------------------------------
namespace App\Controller\Security;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Contracts\Translation\TranslatorInterface;
use App\Entity\Access;
use App\Entity\AccessClient\AccessClient;
use App\Entity\TOS\TermCond;
use App\Entity\TOS\TermCondAccept;
use App\Services\AccessTools;
use App\Services\Communication\Email\AccessEmails;
use App\Services\Communication\Email\AccessClientEmails;
use App\Services\Dashboard\LoginTools as DashboardLoginTools;
use App\Services\Security\IpTools;
use App\Services\Security\PasswordTools;
use App\Services\SocietyGroupGenerator;
use App\Entity\Config\Config;
use App\Services\AccessClient\AccessClientTools;
use App\Services\LogTools;
use App\Services\Security\SecurityTools;
use App\Validator\ActivationCode;
use App\Validator\LostPwd;
use App\Validator\LostPwdCode;
use App\Validator\Password;
class SecurityController extends AbstractController
{
public function __construct(
ManagerRegistry $doctrine, LogTools $logTools, Security $security, TranslatorInterface $translator, AccessTools $accessTools,
PasswordTools $passwordTools, AccessEmails $accessEmails, AccessClientEmails $accessClientEmails, SocietyGroupGenerator $societyGroupGenerator,
DashboardLoginTools $dashboardLoginTools, IpTools $ipTools, SecurityTools $securityTools, AccessClientTools $accessClientTools
)
{
$this->em = $doctrine->getManager();
$this->logTools = $logTools;
$this->security = $security;
$this->translator = $translator;
$this->accessTools = $accessTools;
$this->passwordTools = $passwordTools;
$this->accessEmails = $accessEmails;
$this->accessClientEmails = $accessClientEmails;
$this->societyGroupGenerator = $societyGroupGenerator;
$this->dashboardLoginTools = $dashboardLoginTools;
$this->ipTools = $ipTools;
$this->securityTools = $securityTools;
$this->accessClientTools = $accessClientTools;
}
public function kickOut(Request $request)
{
$this->securityTools->logout($request->getSession());
return $this->redirectToRoute('login');
}
public function loginRedirect(Request $request, AccessTools $accessTools): Response
{
if ($this->security->isGranted('IS_AUTHENTICATED_FULLY'))
{
// $this->logTools->plooplog("[SecurityController][loginRedirect] ".$this->getUser()->displayForLog());
// Language
if ($this->getUser() !== null && $this->getUser()->getLanguage() !== null)
{
$request->getSession()->set('_locale', $this->getUser()->getLanguage());
}
if ($this->isGranted('ROLE_USER'))
{
// Plan.io Task #3710 : Check that the user who passed the firewall has a SocietyGroup
$societyGroup = $this->getUser()->getSocietyGroup();
if ($societyGroup === null)
{
// This should not happen
$this->logTools->errorlog("societyGroup is null in loginRedirect in SecurityController");
$this->securityTools->logout($request->getSession());
return $this->redirectToRoute('login');
}
// Check that the society group is active
if ($societyGroup->isInactive())
{
$this->logTools->errorlog("societyGroup is inactive in loginRedirect in SecurityController");
$this->securityTools->logout($request->getSession());
return $this->redirectToRoute('authentication_error');
}
// Check if the Terms and Conditions have been accepted
// Get latest terms and conditions chart
// Plan.io Task #4327 : Get that of Rekapp Accesses, not AccessClients
$term = $this->em->getRepository(TermCond::class)->findOneBy(array(
'clientPlatform' => 0,
), array(
'creationDate' => 'DESC',
));
if ($term !== null)
{
$acceptation = $this->em->getRepository(TermCondAccept::class)
->findOneBy(array(
'access' => $this->getUser(),
'termCond' => $term,
));
if ($acceptation === null)
{
// Not yet accepted => Redirect to acceptation page
return $this->redirectToRoute('icod_terms_and_conditions', array(
'id' => $term->getId(),
));
}
}
// Plan.io Task #3275
// Log successfull login
$this->dashboardLoginTools->logSuccessfulLogin($this->getUser());
// Plan.io Task #4453 #TODO one day (or not)
// If we want to call it on user login this is the place [Update Permission Cache]
// Redirect
if ($this->getUser() !== null)
{
if (!empty($this->getUser()->getReferer()))
{
// Get the redirect data stored into the access
$referer = json_decode($this->getUser()->getReferer(), true);
$url = $referer['url'];
$redirect = !$referer['dont_redirect'];
// Erase data in all cases, since a redirect will happen anyhow
$this->getUser()->setReferer(null);
try
{
$this->em->flush();
}
catch (\Exception $e)
{
$this->logTools->errorlog($e->getMessage());
}
// Redirect or not :)
if (!empty($url))
{
if ($redirect)
{
return new RedirectResponse($referer['url']);
}
}
}
}
// If we are here it means that nothing else was found
// Just go the usual way
return $this->redirectToRoute('icod_platform_menu');
}
else
{
if ($this->isGranted('ROLE_ADMIN'))
{
// Plan.io Task #4001
// Each user should go to its own happy place
// if ($this->isGranted('open_sesame'))
// {
// return $this->redirectToRoute('icod_admin_dashboard_open_sesame');
// }
if ($this->security->isGranted('is_admin'))
{
return $this->redirectToRoute('icod_admin_dashboard');
}
}
}
return $this->redirectToRoute('test');
}
return $this->redirectToRoute('login');
}
public function handleRedirectUrl(Request $request): JsonResponse
{
if (!$request->isXmlHttpRequest())
{
return new JsonResponse(array('status' => 'Error'),400);
}
if (!isset($request->request))
{
return new JsonResponse(array('status' => 'Error'),400);
}
// Get data
$id = intval($request->request->get('id'));
$route = strip_tags($request->request->get('route'));
$dontRedirect = intval($request->request->get('dont_redirect'));
$username = strip_tags($request->request->get('username'));
$access = $this->em->getRepository(Access::class)
->findOneByUsername($username);
if ($access === null)
{
return new JsonResponse(array('status' => 'Error'),200);
}
$url = null;
if ($id == 0)
{
try
{
$url = $this->generateUrl($route);
}
catch (\Exception $e)
{
return new JsonResponse(array('status' => 'Error'),200);
}
}
else
{
try
{
$url = $this->generateUrl($route, array('id' => $id));
}
catch (\Exception $e)
{
return new JsonResponse(array('status' => 'Error'),200);
}
}
$config = $this->em->getRepository(Config::class)
->findOneByName(Config::URL);
if ($config === null)
{
return new JsonResponse(array('status' => 'Error'),200);
}
$url = $config->getValue() . $url;
$access->setReferer(json_encode(array(
'route' => $route,
'id' => $id,
'url' => $url,
'dont_redirect' => $dontRedirect,
)));
try
{
$this->em->flush();
}
catch (\Exception $e)
{
$this->logTools->errorlog($e->getMessage());
$this->logTools->errorlog_db($e);
return new JsonResponse(array('status' => 'Error'),200);
}
return new JsonResponse(array('status' => 'Done'),200);
}
public function termsAndConditions(Request $request, TermCond $terms): Response
{
if ($this->security->isGranted('IS_AUTHENTICATED_FULLY'))
{
$form = $this->createFormBuilder([])->getForm();
if ($request->isMethod('POST'))
{
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$acceptation = new TermCondAccept();
$acceptation->setAccess($this->getUser());
$acceptation->setTermCond($terms);
$this->em->persist($acceptation);
try
{
$this->em->flush();
}
catch (\Exception $e)
{
$this->logTools->errorlog($e->getMessage());
$this->logTools->errorlog_db($e);
}
// After that form is submited, redirect to route : login_redirect
return $this->redirectToRoute('login_redirect');
}
}
else
{
// Kick the user out
$this->redirect($this->generateUrl('logout'));
}
return $this->render('security/terms_and_conditions.html.twig', array(
'form' => $form->createView(),
'terms' => $terms,
));
}
return $this->redirectToRoute('login');
}
public function maintenance(Request $request): Response
{
return $this->render('security/maintenance.html.twig');
}
// This is called when a new access follows the activation link sent in an email
// Since we identify the user using a unique activation code,
// we can decide whether to activate an Access or an AccessClient using only the code.
// Thus, we can use the same method, validator, etc ...
public function activation(Request $request, UserPasswordHasherInterface $hasher, $code): Response
{
// IpBan ?
$ip = $request->getClientIp();
if ($this->ipTools->isBanned($ip))
{
throw new AccessDeniedException('');
}
// Before anything else : Check that the code exists
$accessRepository = $this->em->getRepository(Access::class);
$accessForCode = $accessRepository->findOneBy(array(
'activationCode' => $code,
));
if ($accessForCode === null)
{
// Plan.io Task #4327
// If not an Access, maybe an AccessClient ?
$accessClientRepository = $this->em->getRepository(AccessClient::class);
$accessForCode = $accessClientRepository->findOneBy(array(
'activationCode' => $code,
));
}
if ($accessForCode === null)
{
// Nope, inform user
$flashBag = $this->translator->trans('invalid_credentials', array(), 'validators');
$this->addFlash('error', $flashBag);
// Fail2Ban, just in case
$this->ipTools->fail2ban(array(
'error' => "invalid_code : ".$code,
));
// Redirect to activation error page
return $this->redirectToRoute('activation_error');
}
// Plan.io Task #4327
$loginRoute = "login";
$isAccessClient = false;
if ($accessForCode instanceof AccessClient)
{
$loginRoute = "access_client_login";
$isAccessClient = true;
}
if ($accessForCode->getActivationDate() !== null)
{
// User already activated, redirect to login, with message
$msg = $this->translator->trans('access_already_activated');
return $this->redirectToRoute($loginRoute, array(
'username' => $accessForCode->getUsername(),
'activation_message' => $msg,
));
}
// If we are here it means we have an active activation code
// Plan.io Task #3389, modified by Plan.io Task #4327
if ($accessForCode instanceof Access)
{
if ($accessForCode->getSocietyGroupRequest() !== null)
{
// This is an account creation for an external user
// So no need to test for society group
}
else
{
// However, if the society group of the access is inactive, do not go any further
if ($accessForCode->getSocietyGroup() !== null && $accessForCode->getSocietyGroup()->isInactive())
{
return $this->redirectToRoute('authentication_error');
}
}
}
// Ask the user for password
$form = $this->createFormBuilder()
->add('password', PasswordType::class, array(
'label' => false,
'required' => true,
'constraints' => array(
new Password(),
new NotBlank(),
new NotNull(),
)
))
->add('passwordRepeat', PasswordType::class, array(
'label' => false,
'required' => true,
'constraints' => array(
new NotBlank(),
new NotNull(),
)
))
->add('code', HiddenType::class, array(
'label' => false,
'required' => false,
'data' => $code,
'error_bubbling' => true,
'constraints' => array(
new ActivationCode()
)
));
$form = $form->getForm();
if ($request->isMethod('POST'))
{
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// Step ONE : Check that the code exists and has an access
// Done by ActivationCode Validator
// Step TWO : Check that the access has not already been activated
// Done by ActivationCode Validator
// Step THREE : Check if the access has email address (this should always be true)
// Done by ActivationCode Validator
// Step FOUR : Check if the passwords match and none is null
// Checked by Password Validator
// If we are here it means we have a valid code and two matching passwords
// Get the password
$form_pwd = $form['password']->getData();
// Encode the password
$encoded_password = $hasher->hashPassword($accessForCode, $form_pwd);
// Update access
$accessForCode->setPassword($encoded_password);
$accessForCode->setActivationDate(new \DateTime());
// Activate access
$accessForCode->activate();
// Persist
$this->em->persist($accessForCode);
// Plan.io Task #3389, modified by Plan.io Task #4327
if ($accessForCode instanceof Access)
{
if ($accessForCode->getSocietyGroupRequest() !== null)
{
// Create SocietyGroup
$societyGroupRequest = $accessForCode->getSocietyGroupRequest();
$societyGroup = $this->societyGroupGenerator->createSocietyGroupForRequest($societyGroupRequest, $accessForCode);
if ($societyGroup === null)
{
$this->logTools->errorLog("SocietyGroup could not be created for SocietyGroupRequest ".$societyGroupRequest->displayForLog());
$flashBag = $this->translator->trans('error_try_again_later');
$this->addFlash('error', $flashBag);
return $this->render('security/access_activation/activation.html.twig', array(
'form' => $form->createView(),
'email' => $accessForCode->getEmail(),
'today' => new \DateTime(),
));
}
}
}
// Plan.io Task #4408
if ($accessForCode instanceof AccessClient)
{
$this->accessClientTools->activateCommercialConsentForAccessClient($accessForCode);
}
// Logging
$sourceInfo = $this->translator->trans('activation_source');
// TODO #4327 : Add Logging for AccessClient also
if ($accessForCode instanceof Access)
{
// Plan.io Task #3922
$accessForCode->setLoggingData([
"info" => $sourceInfo,
]);
}
try
{
$this->em->flush();
}
catch (\Exception $e)
{
$this->logTools->errorLog($e->getMessage());
$this->logTools->errorlog_db($e);
$flashBag = $this->translator->trans('error_try_again_later');
$this->addFlash('error', $flashBag);
return $this->render('security/access_activation/activation.html.twig', array(
'form' => $form->createView(),
'email' => $accessForCode->getEmail(),
'today' => new \DateTime(),
));
}
$flashBag = $this->translator->trans('activation_success');
$this->addFlash('activation_message', $flashBag);
return $this->redirectToRoute($loginRoute, array(
'username' => $accessForCode->getUsername(),
));
}
else
{
// The form is invalid
// Fail2Ban, just in case
$this->ipTools->fail2ban(array(
'form_errors' => $form->getErrors(true, true),
'username' => $accessForCode->getUsername(),
));
}
}
return $this->render('security/access_activation/activation.html.twig', array(
'form' => $form->createView(),
'email' => $accessForCode->getEmail(),
'today' => new \DateTime(),
'isAccessClient' => $isAccessClient,
));
}
/**
* Plan.io Task #4327
* Contrary to account activation, things are trickier for the recovery of lost passwords.
* Since we only have an email address to work with,
* we have no way of knowing if we are looking for an Access, or an AccessClient.
* Two solutions
* 1. Duplicate the code and have two routes and two controllers
* 2. Handle the case where the same email address is used
* by both an Access and an AccessClient (which will represent a small minority, ...)
* Go with solution number two ;)
* If the email is associated with both an Access and an AccessClient
* the method will generate two reset codes and send two emails ;)
*/
public function lostPassword(Request $request, $userEmail = null): Response
{
// // IpBan ?
$ip = $request->getClientIp();
if ($this->ipTools->isBanned($ip))
{
throw new AccessDeniedException('');
}
$form = $this->createFormBuilder()
->add('email', EmailType::class, array(
'required' => true,
'label' => false,
'data' => $userEmail,
'constraints' => array(
new NotBlank(),
new NotNull(),
new LostPwd(),
),
'attr' => array(
'class' => 'login-form',
)
))
->getForm();
if ($request->isMethod('POST'))
{
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// #2641 If Casto -> do not do lost password process
if (strpos($form->getData()['email'], '@castorama.fr') !== false)
return $this->redirectToRoute('activation_error');
// Get the access
// We know that it exists and it is active thanks to the validator - Not any more :)
// edit @ 21/12/2020 : If we receive a lost password request for an inactive user
// we send an activation email instead of a lost password email
// and inform the user
// edit @ 09/03/2021 : If we receive a lost password request for an inactive user
// AND the user has never been activated before,
// we send an activation email instead of a lost password email
// and inform the user
// This ensures that users who have been manually deactivated
// cannot reclaim their accounts
// See below @ if ($form->isValid()) else {...}
$access = $this->em->getRepository(Access::class)
->findOneByEmail($form->getData()['email']);
// Plan.io Task #4327
$accessClient = $this->em->getRepository(AccessClient::class)
->findOneByEmail($form->getData()['email']);
if ($access !== null)
{
// If the society group of the access is inactive, do not go any further
if ($access->getSocietyGroup() !== null && $access->getSocietyGroup()->isInactive())
{
return $this->redirectToRoute('authentication_error');
}
// If we are here it means the access is not null and active
// Generate code
$code = $this->passwordTools->generateUniqueActivationCode();
$access->setLostPwdCode($code);
}
// Since both Access and AccessClient could be not null, handle both
if ($accessClient !== null)
{
// Generate code
// Yes, another one :)
// Even if both are not null, I want different codes
$code = $this->passwordTools->generateUniqueActivationCode();
$accessClient->setLostPwdCode($code);
}
$allGood = true;
try
{
$this->em->flush();
}
catch (\Exception $e)
{
$allGood = false;
$this->logTools->errorLog($e->getMessage());
$this->logTools->errorlog_db($e);
}
if ($allGood)
{
if ($access !== null)
{
// Send mail
$this->accessEmails->sendResetPwdEmail($access);
}
if ($accessClient !== null)
{
// Logging
// TODO #4327 : Add Logging for AccessClient also
// Send mail
$this->accessClientEmails->sendResetPwdEmail($accessClient);
}
// Inform user
$flashBag = $this->translator->trans('reset_link_sent_success');
$this->addFlash('activation_message', $flashBag);
return $this->redirectToRoute('login', array(
'username' => $userEmail,
));
}
else
{
// Something went wrong, Inform user
$flashBag = $this->translator->trans('unknown_error');
$this->addFlash('error', $flashBag);
return $this->redirectToRoute('activation_error');
}
}
else
{
// The form is invalid
// Fail2Ban, just in case
$this->ipTools->fail2ban(array(
'form_errors' => $form->getErrors(true, true),
'username' => $form->getData()['email'],
));
// We only need to know if the Violation is inactive_access
foreach ($form->getErrors(true, true) as $key => $error)
{
if ($error->getCause() !== null)
{
if ($error->getCause()->getMessageTemplate())
{
if ($error->getCause()->getMessageTemplate() == 'inactive_access')
{
// If we are here it means the access is inactive
// #2641 If Casto -> do not do lost password process
if (strpos($form->getData()['email'], '@castorama.fr') !== false)
return $this->redirectToRoute('activation_error');
$access = $this->em->getRepository(Access::class)
->findOneByEmail($form->getData()['email']);
$accessClient = $this->em->getRepository(AccessClient::class)
->findOneByEmail($form->getData()['email']);
if ($access !== null)
{
// If the society group of the access is inactive, do not go any further
if ($access->getSocietyGroup() !== null && $access->getSocietyGroup()->isInactive())
{
return $this->redirectToRoute('authentication_error');
}
}
$flush = false;
// Only sending activation link if all below conditions are true :
// - the access is inactive
// - the society group of the access is active (checked above)
// - the access has never been activated before
if ($access !== null && $access->isInactive() && $access->getActivationDate() === null)
{
// Activation code for access
$code = $this->passwordTools->generateUniqueActivationCode();
$access->setActivationCode($code);
$access->setActivationDate(null);
$flush = true;
}
if ($accessClient !== null && $accessClient->isInactive() && $accessClient->getActivationDate() === null)
{
// Activation code for access
$code = $this->passwordTools->generateUniqueActivationCode();
$accessClient->setActivationCode($code);
$accessClient->setActivationDate(null);
$flush = true;
}
if ($flush)
{
$allGood = true;
try
{
$this->em->flush();
}
catch (\Exception $e)
{
$allGood = false;
$this->logTools->errorLog($e->getMessage());
$this->logTools->errorlog_db($e);
}
if ($allGood)
{
// Send mail
if ($access !== null)
{
$this->accessEmails->sendActivationRequiredEmail($access, true);
}
if ($accessClient !== null)
{
$this->accessClientEmails->sendActivationRequiredEmail($accessClient, null, true);
}
return $this->render('security/access_lost_pwd/lost.html.twig', array(
'form' => $form->createView(),
));
}
else
{
// Something went wrong, Inform user
$flashBag = $this->translator->trans('unknown_error');
$this->addFlash('error', $flashBag);
return $this->redirectToRoute('activation_error');
}
}
else
{
return $this->redirectToRoute('authentication_error');
}
}
}
}
}
}
}
return $this->render('security/access_lost_pwd/lost.html.twig', array(
'form' => $form->createView(),
));
}
// This is called when a new access follows the reset link sent in an email
// Since we identify the user using a unique reset code,
// we can decide whether to activate an Access or an AccessClient using only the code.
// Thus, we can use the same method, validator, etc ...
public function resetPassword(Request $request, UserPasswordHasherInterface $hasher, $code): Response
{
// IpBan ?
$ip = $request->getClientIp();
if ($this->ipTools->isBanned($ip))
{
throw new AccessDeniedException('');
}
// Before anything else : Check that the code exists
$accessRepository = $this->em->getRepository(Access::class);
$accessForCode = $accessRepository->findOneBy(array(
'lostPwdCode' => $code,
));
if ($accessForCode === null)
{
// Plan.io Task #4327
// If not an Access, maybe an AccessClient ?
$accessClientRepository = $this->em->getRepository(AccessClient::class);
$accessForCode = $accessClientRepository->findOneBy(array(
'lostPwdCode' => $code,
));
}
if ($accessForCode === null)
{
// Nope, inform user
$flashBag = $this->translator->trans('invalid_credentials', array(), 'validators');
$this->addFlash('error', $flashBag);
// Fail2Ban, just in case
$this->ipTools->fail2ban(array(
'error' => "invalid_code : ".$code,
));
// Redirect to activation error page
return $this->redirectToRoute('activation_error');
}
// Plan.io Task #4327
$loginRoute = "login";
if ($accessForCode instanceof AccessClient)
{
$loginRoute = "access_client_login";
}
// If we are here it means we have an active code for a forgotten password
// Ask the user for password
$form = $this->createFormBuilder()
->add('password', PasswordType::class, array(
'label' => false,
'required' => true,
'constraints' => array(
new Password(),
new NotBlank(),
new NotNull(),
)
))
->add('passwordRepeat', PasswordType::class, array(
'label' => false,
'required' => true,
'constraints' => array(
new NotBlank(),
new NotNull(),
)
))
->add('code', HiddenType::class, array(
'label' => false,
'required' => false,
'data' => $code,
'error_bubbling' => true,
'constraints' => array(
new LostPwdCode()
)
));
$form = $form->getForm();
if ($request->isMethod('POST'))
{
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// Step ONE : Check that the code exists and has an access
// Done by LostPwdCode Validator
// Step TWO : Check if the access has email address (this should always be true)
// Done by LostPwdCode Validator
// Step THREE : Check if the passwords match and none is null
// Checked by Password Validator
// If we are here it means we have a valid code and two matching passwords
// Get the password
$form_pwd = $form['password']->getData();
// Encode the password
$encoded_password = $hasher->hashPassword($accessForCode, $form_pwd);
// Update access
$accessForCode->setPassword($encoded_password);
$accessForCode->setActivationDate(new \DateTime());
// Remove code
$accessForCode->setLostPwdCode(null);
// Persist
$this->em->persist($accessForCode);
// Logging
$sourceInfo = $this->translator->trans('lost_pwd_source');
// Plan.io Task #3922
$accessForCode->setLoggingData([
"info" => $sourceInfo,
]);
// TODO #4327 : Add Logging for AccessClient also
try
{
$this->em->flush();
}
catch (\Exception $e)
{
$this->logTools->errorLog($e->getMessage());
$this->logTools->errorlog_db($e);
$flashBag = $this->translator->trans('unknown_error');
$this->addFlash('error', $flashBag);
return $this->render('security/access_lost_pwd/reset.html.twig', array(
'form' => $form->createView(),
'email' => $accessForCode->getEmail(),
'today' => new \DateTime(),
));
}
$flashBag = $this->translator->trans('password_changed_success');
$this->addFlash('activation_message', $flashBag);
return $this->redirectToRoute($loginRoute, array(
'username' => $accessForCode->getUsername(),
));
}
else
{
// The form is invalid
// Fail2Ban, just in case
$this->ipTools->fail2ban(array(
'form_errors' => $form->getErrors(true, true),
'username' => $accessForCode->getUsername(),
));
}
}
return $this->render('security/access_lost_pwd/reset.html.twig', array(
'form' => $form->createView(),
'email' => $accessForCode->getEmail(),
'today' => new \DateTime(),
));
}
public function authenticationError(Request $request): Response
{
// If the user is already logged in, redirect
if ($this->isGranted('IS_AUTHENTICATED_FULLY'))
{
return $this->redirectToRoute('login_redirect');
}
$today = new \DateTime();
$flashBag = $this->translator->trans("invalid_credentials", array(), "validators");
$this->addFlash('login_error', $flashBag);
return $this->render('security/login.html.twig', array(
'last_username' => null,
'username' => null,
'error' => null,
'today' => $today,
));
}
public function activationError(Request $request): Response
{
return $this->render('security/access_activation/activation_error.html.twig', array(
));
}
}