diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index ad4d272f..93336bf9 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -25,6 +25,7 @@ namespace App\Controller; use App\Entity\UserSystem\User; use App\Events\SecurityEvent; use App\Events\SecurityEvents; +use App\Form\Security\LoginFormType; use App\Services\UserSystem\PasswordResetManager; use Doctrine\ORM\EntityManagerInterface; use Gregwar\CaptchaBundle\Type\CaptchaType; @@ -61,7 +62,12 @@ class SecurityController extends AbstractController // last username entered by the user $lastUsername = $authenticationUtils->getLastUsername(); + $form = $this->createForm(LoginFormType::class, [ + '_username' => $lastUsername, + ]); + return $this->render('security/login.html.twig', [ + 'form' => $form, 'last_username' => $lastUsername, 'error' => $error, ]); diff --git a/src/Form/Security/LoginFormType.php b/src/Form/Security/LoginFormType.php new file mode 100644 index 00000000..184f68ac --- /dev/null +++ b/src/Form/Security/LoginFormType.php @@ -0,0 +1,83 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Security; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\OptionsResolver\OptionsResolver; + +use function Symfony\Component\Translation\t; + +class LoginFormType extends AbstractType +{ + public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options): void + { + $builder + ->add('_username', TextType::class, [ + 'label' => t('login.username.label'), + 'attr' => [ + 'autofocus' => 'autofocus', + 'autocomplete' => 'username', + 'placeholder' => t('login.username.placeholder'), + ] + ]) + ->add('_password', PasswordType::class, [ + 'label' => t('login.password.label'), + 'attr' => [ + 'autocomplete' => 'current-password', + 'placeholder' => t('login.password.placeholder'), + ] + ]) + ->add('_remember_me', CheckboxType::class, [ + 'label' => t('login.rememberme'), + 'required' => false, + ]) + ->add('submit', \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, [ + 'label' => t('login.btn'), + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + // This ensures CSRF protection is active for the login + 'csrf_protection' => true, + 'csrf_field_name' => '_csrf_token', + 'csrf_token_id' => 'authenticate', + 'attr' => [ + 'data-turbo' => 'false', // Disable Turbo for the login form to ensure proper redirection after login + ] + ]); + } + + public function getBlockPrefix(): string + { + // This removes the "login_form_" prefix from field names + // so that Security can find "_username" directly. + return ''; + } +} diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig index b8a0df1d..c09b3669 100644 --- a/templates/security/login.html.twig +++ b/templates/security/login.html.twig @@ -20,53 +20,23 @@ {% endblock %} {% block card_content %} -
- + {% if saml_enabled %} +
+ {% trans %}login.sso_saml_login{% endtrans %} - - - {% if saml_enabled %} -
- {% trans %}login.sso_saml_login{% endtrans %} - -

{% trans %}login.local_login_hint{% endtrans %}

-
- - {% endif %} - -
- -
- -
-
-
- -
- -
+

{% trans %}login.local_login_hint{% endtrans %}

+ {% endif %} -
-
-
- - -
-
-
+ {{ form_start(form) }} -
-
- -
-
- + {{ form_row(form._username) }} + {{ form_row(form._password) }} + {{ form_row(form._remember_me) }} + {{ form_row(form.submit) }} + + {{ form_end(form) }} {% if allow_email_pw_reset %} {% trans %}pw_reset.password_forget{% endtrans %}