<?php
namespace App\Controller;
use App\Form\EventListener\ReCaptchaValidatorListener;
use App\Service\PasswordChecker;
use App\Service\UserManager;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @Route("/cambiar", name="password_change_",
* requirements={"_locale":"%app.supported_locales%"},
* defaults={"_locale" = "es", "_title"="Pasarela cambia clave de la Universidad de Murcia"})
*/
class PasswordChangeController extends AbstractController
{
const PANEL_STEPS = 4;
const PASSWORD_MIN_LEN = 12;
const DEFAULT_ERRORS = [
500 => 'error.default.500', // Se ha producido un error inesperado, vuelva a intentarlo más tarde.
];
/**
* @Route("/validatepasswd/{_locale}", name="check", requirements={"_locale"="[a-zA-Z]+"}, methods="POST")
*/
public function checkPassword(Request $request, PasswordChecker $passwordChecker, UserManager $userManager) : JsonResponse
{
// REVIEW no se puede hacer autowire del UserManager en PasswordChecker, por que el primero usa al primero en el constructor para log fortaleza
$passwordChecker->setUserManager($userManager);
return new JsonResponse($passwordChecker->validate(
$request->get('password', ''),
$request->get('username')
));
}
/**
* @Route("/{_locale}", name="index", requirements={"_locale"="[a-zA-Z]+"})
*/
public function index(Request $request, ReCaptchaValidatorListener $recaptchaValidator, UserManager $userManager, TranslatorInterface $translator, LoggerInterface $logger): Response
{
// Si se pasa GET['pose'] se ocultará el iframe y se inyectará el correo
// Si se pasa GET['email'] se inyectará el correo
$pose_email = $request->get('pose', null);
$myaccount_email = $request->get('micuenta', null);
$iframe = false;
$email = null;
if (filter_var($pose_email, FILTER_VALIDATE_EMAIL) !== false) {
$iframe = true;
$email = $pose_email;
}
elseif (filter_var($myaccount_email, FILTER_VALIDATE_EMAIL) !== false) {
$email = $myaccount_email;
}
$passwdForm = $this->createPasswdForm($recaptchaValidator, $email);
$passwdForm->handleRequest($request);
if ($passwdForm->isSubmitted() && $passwdForm->isValid()) {
$data = $passwdForm->getData();
$logger->info('[cambiar] solicitud cambio clave para '.$data['username']);
try {
// Validar usuario haciendo login y comprobando que la cuenta no esté bloqueada
$userManager->infoAccount($data['username'], true);
$userManager->login($data['username'], $data['password'], UserManager::ALLOW_PPOLICY_EXPIRED);
$userManager->changePassword($data['username'], $data['newpassword']);
$logger->info('[cambiar] cambio de clave realizado para '.$data['username']);
return $this->render('success.html.twig', [
'iframe' => $iframe,
'show_chpwd_help' => true
]);
} catch (\Throwable $th) {
// Nueva clave no válida
if (400 == $th->getCode() || 406 == $th->getCode()) {
$passwdForm->get('newpassword')['first']->addError(new FormError($th->getMessage()));
// Usuario no vaĺido
} else if (404 == $th->getCode()) {
if ($iframe)
$passwdForm->get('password')->addError(new FormError($th->getMessage()));
else
$passwdForm->get('username')->addError(new FormError($th->getMessage()));
// Enviar a pantalla de error
} else
return $this->render('error.html.twig', [
'error_code' => $th->getCode(),
'error_body' => $th->getMessage(),
'iframe' => $iframe
]);
}
}
// Establecer token del formulario y renderizar
return $this->renderForm('password_change.html.twig', [
'passwd_form' => $passwdForm,
'iframe' => $iframe,
]);
}
/**
* Crea un formulario de restauración de clave.
*/
private function createPasswdForm(ReCaptchaValidatorListener $recaptchaValidator, ?string $username = '', string $name = 'passwdForm', string $formid = 'changePassword') {
//return $this->get('form.factory')->createNamedBuilder($name, FormType::class, [ 'formid' => $formid ])
return $this->createFormBuilder()->getFormFactory()->createNamedBuilder($name, FormType::class, [ 'formid' => $formid ])
->add('username', EmailType::class, [
'required' => true,
'constraints' => [
new NotBlank(),
new Email()
],
'label' => 'Correo electrónico',
'attr' => [
'autofocus' => empty($username) ? 'autofocus' : false,
'readonly' => ! empty($username),
'value' => $username
],
'row_attr' => [ 'class' => 'form-floating'],
])->add('password', PasswordType::class, [
'required' => true,
'constraints' => [ new NotBlank() ],
'label' => 'Clave actual',
'attr' => [
'autofocus' => empty($username) ? false : 'autofocus',
],
'row_attr' => [ 'class' => 'form-floating form-caps-lock'],
])->add('newpassword', RepeatedType::class, [
'required' => true,
'type' => PasswordType::class,
'constraints' => [
new NotBlank(),
new Length([ 'min' => self::PASSWORD_MIN_LEN ]),
],
'options' => [
'attr' => [ 'minglength' => 12 ],
'row_attr' => [ 'class' => 'form-floating form-caps-lock'],
],
'first_options' => [ 'label' => 'Nueva clave' ],
'second_options' => [ 'label' => 'Repita la clave' ],
'invalid_message' => 'Las claves deben coincidir.',
'error_bubbling' => false,
])->add('next', SubmitType::class, [
'label' => 'Cambiar clave',
])->addEventSubscriber($recaptchaValidator)
->getForm();
}
}
?>