<?php
namespace App\Controller;
use App\Entity\User;
use App\Events\Events;
use App\Form\PwdType;
use App\Form\ResetPwdType;
use App\Service\email\EmailHandlerMailgun;
use App\Service\JwtHandler;
use Doctrine\Persistence\ManagerRegistry;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Client\Provider\KeycloakClient;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Validator\Constraints\IsTrue;
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils, ClientRegistry $clientRegistry): Response
{
// Si le visiteur est déjà identifié, on le redirige
if ($this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return $this->redirectToRoute('user_dashboard');
}
//TODO redirection vers keycloak
// /** @var KeycloakClient $client */
// $client = $clientRegistry->getClient('keycloak');
// return $client->redirect(['openid','kinalgo-user']);
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
/*Custom message error if bad credential*/
if ($error instanceof BadCredentialsException) {
$error = new \stdClass();
$error->message = 'Email ou mot de passe non valide';
}
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/screen/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
/**
* @Route("/open-id/check-auth", name="openid_check_auth")
*/
public function redirectUri(){}
/**
* @Route("/logout", name="logout", methods={"GET"})
*/
public function logout()
{
// controller can be blank: it will never be executed!
throw new \Exception('Don\'t forget to activate logout in security.yaml');
}
/**
* Envoie d'un email pour réinitialisation mot de passe ou création de compte
* @Route("/security/password/{context}", requirements={"context":"reset|create"}, name="security-reset",methods={"POST","GET"})
*/
public function reset(Request $request, string $context, EventDispatcherInterface $eventDispatcher,ManagerRegistry $em)
{
/*Create form*/
$form = $this->createFormBuilder()
->add('email', EmailType::class, array('required' => true, 'label' => false,
'attr' => array('class' => 'user-form__input')))
->getForm();
$form->handleRequest($request);
/*form is submitted*/
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
//check email
/* @var $user User*/
$user = $em->getRepository(User::class)->findOneBy(['email' => $data['email']]);
if (!$user || empty($user)) {
$this->addFlash('notice-warning', 'Aucun compte associé à cet email n\'a été trouvé.');
return $this->redirectToRoute('security-reset',["context"=>$context]);
}
if($context === 'reset' && $user->getPassword() === null){
$createPassHref = $this->generateUrl('security-reset',['context'=>'create']);
$link = "<a class='text-decoration-underline' href='${createPassHref}'>Créer mon compte maintenant</a>";
$message = sprintf('Vous ne pouvez pas réinitialiser votre mot de passe car votre compte n’est pas encore finalisé. Cliquez sur %s ou contactez le référent prévention de votre établissement.',$link);
$this->addFlash('notice-warning', $message);
return $this->redirectToRoute('security-reset',["context"=>$context]);
}
if($context === 'create' && $user->getPassword() !== null){
$forgotPassHref = $this->generateUrl('security-reset',['context'=>'reset']);
$link = "<a class='text-decoration-underline' href='${forgotPassHref}'>mot de passe oublié</a>";
$message = sprintf('Vous avez déjà créé votre mot de passe. Cliquez sur %s pour le réinitialiser.',$link);
$this->addFlash('notice-warning', $message);
return $this->redirectToRoute('security-reset',["context"=>$context]);
}
/*==============>Email exist*/
$event = new GenericEvent(['user'=>$user,'context'=>$context]);
$eventDispatcher->dispatch($event, Events::EMAIL_FORGOT_PWD);
$message = $context === "reset" ? "Un email a été envoyé a l'adresse {$user->getEmail()}, suivez le lien pour changer votre mot de passe." :
"Un email a été envoyé a l'adresse {$user->getEmail()}, suivez le lien pour créer votre mot de passe.";
$this->addFlash('notice-success', $message);
return $this->redirectToRoute('app_login', array(
'last_username' => $user->getEmail(),
)
);
}
return $this->render('security/screen/reset.html.twig', array(
'form' => $form->createView(),
'title_page' => $context === 'reset' ? 'Mot de passe oublié' : "Création de compte",
'context' => $context
));
}
/**
* @Route("/reset-password/{user}", name="reset-password", methods={"GET", "POST"})
*/
public function resetPassword(Request $request, User $user, JwtHandler $jwt, UserPasswordHasherInterface $encoder,ManagerRegistry $managerRegistry)
{
$token = $request->query->get('token');
$decoded = $jwt->verifyToken($token);
if (!$decoded || !$jwt->verifyUserToken($user->getId(), $decoded)) {
throw $this->createAccessDeniedException();
}
$form = $this->createForm(PwdType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$encoded = $encoder->hashPassword($user, $user->getPlainPassword());
$user->setPassword($encoded);
$entityManager = $managerRegistry->getManager();
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash('notice-success', "Votre mot de passe a été créé, vous pouvez vous connecter.");
return $this->redirectToRoute('app_login');
}
return $this->render('security/screen/reset-pwd.html.twig', array(
'form' => $form->createView(),
'title_page' => 'Réinitialisation du mot de passe'
));
}
/**
* @Route("/create-account/{user}", name="create-account", methods={"GET", "POST"})
*/
public function createAccount(Request $request, User $user, JwtHandler $jwt, UserPasswordHasherInterface $encoder, ManagerRegistry $managerRegistry)
{
$token = $request->query->get('token');
$decoded = $jwt->verifyToken($token);
if (
!$decoded || !$jwt->verifyUserToken($user->getId(), $decoded) ||
$user->getPassword() // déjà un compte avec mot de passe
) {
throw $this->createAccessDeniedException();
}
$form = $this->createForm(PwdType::class, $user)
->add('agreeTerms', CheckboxType::class, [
'label' =>false,
'label_html' => true,
'mapped' => false,
'constraints' => [
new IsTrue([
'message' => 'Vous devez accepter les conditions générales.',
]),
],
'required' => true,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$encoded = $encoder->hashPassword($user, $user->getPlainPassword());
$user->setPassword($encoded);
$user->setCgu(true);
$user->setAgreeTermsAt(new \DateTime("now", new \DateTimeZone("Europe/Paris")));
$entityManager = $managerRegistry->getManager();
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash('notice-success', "Votre mot de passe a été créé, vous pouvez vous connecter.");
return $this->redirectToRoute('app_login');
}
return $this->render('security/screen/create-account.html.twig', array(
'form' => $form->createView(),
'title_page' => 'Création du mot de passe'
));
}
}