<?php
namespace App\Controller;
use App\Entity\User;
use App\Event\UserForgotPasswordEvent;
use App\Event\UserResetPasswordEvent;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="login", methods={"GET", "POST"})
* @param AuthenticationUtils $authenticationUtils
* @param AuthorizationCheckerInterface $authorizationChecker
* @return RedirectResponse|Response
*/
public function login(AuthenticationUtils $authenticationUtils, AuthorizationCheckerInterface $authorizationChecker)
{
if ($authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute("index");
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
$view = $this->renderView('administration/security/login.html.twig', [
'last_username' => $lastUsername,
'error' => $error,
]);
return new Response($view, Response::HTTP_OK, ['X-login-page' => '1']);
}
/**
* @Route("/recovery", name="recovery", methods={"GET", "POST"})
* @return RedirectResponse|Response
*/
public function recovery()
{
$view = $this->renderView('administration/security/recovery.html.twig');
return new Response($view);
}
/**
* @Route("/password_recovery",
* condition="request.isXmlHttpRequest()",
* name="password_recovery",
* methods={"POST"},
* options = { "expose" = true }
* )
*
* @param Request $request
* @param EntityManagerInterface $dm
* @param EventDispatcherInterface $eventDispatcher
* @return JsonResponse
* @throws \Exception
*/
public function passwordRecovery(Request $request, EntityManagerInterface $dm, EventDispatcherInterface $eventDispatcher)
{
$email = $request->get('_username', false);
if (false === $email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
return new JsonResponse ([
'status' => 'error',
'messages' => 'INVALID_MAIL_ERROR'
]);
}
if (!$user = $dm->getRepository(User::class)->findOneBy(['email' => $email])) {
return new JsonResponse ([
'status' => 'error',
'messages' => 'MAIL_NOT_FOUND_ERROR'
]);
}
$token = rtrim(chunk_split(strtolower(md5(uniqid(random_bytes(32), true))), 8, '-'), '-');
$user->setRegeneratePasswordToken($token);
$dm->persist($user);
$dm->flush();
$eventDispatcher->dispatch(new UserForgotPasswordEvent($user), UserForgotPasswordEvent::NAME);
return new JsonResponse([
'status' => 'ok'
]
);
}
/**
* @Route("/password_reset/{token}",
* name="reset_user_password_with_token",
* methods={"GET"},
* options = { "expose" = true }
* )
*
* @param Request $request
* @param EntityManagerInterface $dm
* @return Response
* @throws \Exception
*/
public function passwordReset(Request $request, EntityManagerInterface $dm, $token)
{
$tokenExists = true;
if (!$user = $dm->getRepository(User::class)->findOneBy(['regeneratePasswordToken' => $token])) {
$tokenExists = false;
}
$view = $this->renderView('administration/security/reset.html.twig', ['token'=> $token, 'tokenExists' => $tokenExists]);
return new Response($view);
}
/**
* @Route("/password_reset_action/{token}",
* condition="request.isXmlHttpRequest()",
* name="password_reset_action",
* methods={"POST"},
* options = { "expose" = true }
* )
*
* @param Request $request
* @param EntityManagerInterface $dm
* @param EventDispatcherInterface $eventDispatcher
* @return JsonResponse
* @throws \Exception
*/
public function passwordResetAction(Request $request, EntityManagerInterface $dm, EventDispatcherInterface $eventDispatcher, UserPasswordEncoderInterface $passwordEncoder, $token)
{
$passwordOne = $request->get('_password_1', false);
$passwordTwo = $request->get('_password_2', false);
if ($passwordOne !== $passwordTwo){
return new JsonResponse ([
'status' => 'error',
'messages' => 'PASSWORD_MISMATCH'
]);
}
if (!$user = $dm->getRepository(User::class)->findOneBy(['regeneratePasswordToken' => $token])) {
return new JsonResponse ([
'status' => 'error',
'messages' => 'USER_NOT_FOUND_ERROR'
]);
}
$user->setRegeneratePasswordToken('');
$user->setPassword($passwordEncoder->encodePassword($user, $passwordOne));
$dm->persist($user);
$dm->flush();
$eventDispatcher->dispatch(new UserResetPasswordEvent($user), UserResetPasswordEvent::NAME);
return new JsonResponse([
'status' => 'ok'
]
);
}
/**
* @Route("/admin/change_password",
* condition="request.isXmlHttpRequest()",
* name="password_change_action",
* methods={"POST"},
* options = { "expose" = true }
* )
*
* @param Request $request
* @param EntityManagerInterface $dm
* @param EventDispatcherInterface $eventDispatcher
* @param UserPasswordEncoderInterface $passwordEncoder
* @param Security $security
* @return JsonResponse
*/
public function passwordChangeAction(Request $request, EntityManagerInterface $dm, EventDispatcherInterface $eventDispatcher, UserPasswordEncoderInterface $passwordEncoder, Security $security)
{
$oldPassword = $request->get('_oldPassword', false);
$passwordOne = $request->get('_password_1', false);
$passwordTwo = $request->get('_password_2', false);
$user = $security->getToken()->getUser();
if (!$passwordEncoder->isPasswordValid($user, $oldPassword)){
return new JsonResponse ([
'status' => 'error',
'messages' => 'CURRENT_PASSWORD_INVALID'
]);
}
if ($passwordOne !== $passwordTwo){
return new JsonResponse ([
'status' => 'error',
'messages' => 'PASSWORD_MISMATCH'
]);
}
$user->setPassword($passwordEncoder->encodePassword($user, $passwordOne));
$dm->persist($user);
$dm->flush();
$eventDispatcher->dispatch(new UserResetPasswordEvent($user), UserResetPasswordEvent::NAME);
return new JsonResponse([
'status' => 'ok'
]
);
}
}