require actual password for change + insert link in menu

This commit is contained in:
Julien Fastré 2018-08-16 13:41:32 +02:00
parent af803cc87d
commit 5b1ba71a8a
9 changed files with 169 additions and 36 deletions

View File

@ -5,12 +5,42 @@ namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\MainBundle\Form\UserPasswordType;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Psr\Log\LoggerInterface;
class PasswordController extends Controller
{
/**
*
* @var UserPasswordEncoderInterface
*/
protected $passwordEncoder;
/**
*
* @var TranslatorInterface
*/
protected $translator;
/**
*
* @var LoggerInterface
*/
protected $chillLogger;
public function __construct(
LoggerInterface $chillLogger,
UserPasswordEncoderInterface $passwordEncoder,
TranslatorInterface $translator
) {
$this->chillLogger = $chillLogger;
$this->passwordEncoder = $passwordEncoder;
$this->translator = $translator;
}
/**
*
* @param Request $request
@ -18,7 +48,6 @@ class PasswordController extends Controller
*/
public function UserPasswordAction(Request $request)
{
// get authentified user
$user = $this->getUser();
@ -29,21 +58,27 @@ class PasswordController extends Controller
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$password = $form->getData()->getPassword();
$password = $form->get('new_password')->getData();
// logging for prod
$this->get('logger')->info('update password for an user',
array('method' => __METHOD__, 'user' => $user->getUsername()));
$this
->chillLogger
->notice(
'update password for an user',
array(
'method' => $request->getMethod(),
'user' => $user->getUsername()
)
);
$user->setPassword($this->get('security.password_encoder')
->encodePassword($user, $password));
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
$em = $this->getDoctrine()->getManager();
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('Password successfully updated!'));
$this->addFlash('success', $this->translator->trans('Password successfully updated!'));
return $this->redirectToRoute('change_my_password');
}
@ -62,11 +97,12 @@ class PasswordController extends Controller
*/
private function passwordForm(User $user)
{
return $this->createForm(UserPasswordType::class, $user, array(
'method' => 'PUT',
))
->add('submit', SubmitType::class, array('label' => 'Change password'))
return $this->createForm(
UserPasswordType::class,
[],
[ 'user' => $this->getUser() ]
)
->add('submit', SubmitType::class, array('label' => 'Change password'))
;
}

View File

@ -10,9 +10,34 @@ use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Psr\Log\LoggerInterface;
class UserPasswordType extends AbstractType
{
/**
*
* @var UserPasswordEncoderInterface
*/
protected $passwordEncoder;
/**
*
* @var LoggerInterface
*/
protected $chillLogger;
public function __construct(
UserPasswordEncoderInterface $passwordEncoder,
LoggerInterface $chillLogger
) {
$this->passwordEncoder = $passwordEncoder;
$this->chillLogger = $chillLogger;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
@ -20,7 +45,7 @@ class UserPasswordType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('password', RepeatedType::class, array(
->add('new_password', RepeatedType::class, array(
'type' => PasswordType::class,
'required' => false,
'options' => array(),
@ -45,17 +70,35 @@ class UserPasswordType extends AbstractType
))
)
))
->add('actual_password', PasswordType::class, [
'label' => 'Your actual password',
'mapped' => false,
'constraints' => [
new Callback([
'callback' => function($password, ExecutionContextInterface $context, $payload) use ($options) {
if (TRUE === $this->passwordEncoder->isPasswordValid($options['user'], $password)) {
return;
}
// password problem :-)
$this->chillLogger
->notice("incorrect password when trying to change password", [
'username' => $options['user']->getUsername()
]);
$context->addViolation('Incorrect password');
}
])
]
])
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_classds' => 'Chill\MainBundle\Entity\User'
));
$resolver
->setRequired('user')
->setAllowedTypes('user', \Chill\MainBundle\Entity\User::class)
;
}
/**

View File

@ -79,6 +79,6 @@ login_check:
logout:
path: /logout
password:
path: /password
change_my_password:
path: /{_locale}/password/edit
defaults: { _controller: ChillMainBundle:Password:userPassword }

View File

@ -4,3 +4,9 @@ services:
autowire: true
resource: '../../../Controller'
tags: ['controller.service_arguments']
Chill\MainBundle\Controller\PasswordController:
autowire: true
arguments:
$chillLogger: '@monolog.logger.chill'
tags: ['controller.service_arguments']

View File

@ -123,5 +123,12 @@ services:
class: Chill\MainBundle\Form\AdvancedSearchType
arguments:
- "@chill.main.search_provider"
tags:
- { name: form.type }
Chill\MainBundle\Form\UserPasswordType:
arguments:
$chillLogger: '@monolog.logger.chill'
$passwordEncoder: '@Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface'
tags:
- { name: form.type }

View File

@ -1,5 +1,7 @@
services:
Chill\MainBundle\Routing\MenuBuilder\UserMenuBuilder:
arguments:
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
tags:
- { name: 'chill.menu_builder' }

View File

@ -187,4 +187,8 @@ Choose the format: Choisir le format
# select2
'select2.no_results': Aucun résultat
'select2.error_loading': Erreur de chargement des résultats
'select2.searching': Recherche en cours...
'select2.searching': Recherche en cours...
# page changement mot de passe
Change my password: Modification du mot de passe
Your actual password: Mot de passe actuel

View File

@ -23,12 +23,22 @@
{% block title %}{{"Change my password"|trans}}{% endblock %}
{% block content %}
<div class="grid-10 grid-mobile-10 grid-tablet-10 centered">
<h1>{{ 'Choose a new password'|trans }}</h1>
<h1>{{ 'Change my password'|trans }}</h1>
{{ form_start(form) }}
{{ form_row(form.password) }}
{{ form_widget(form.submit, { 'attr': { 'class': 'sc-button orange' } } ) }}
{{ form_end(form) }}
{{ form_start(form) }}
{{ form_row(form.actual_password) }}
{{ form_row(form.new_password) }}
<ul class="record_actions">
<li>
{{ form_widget(form.submit, { 'attr': { 'class': 'sc-button orange' } } ) }}
</li>
</ul>
{{ form_end(form) }}
</div>
{% endblock %}

View File

@ -18,6 +18,8 @@
namespace Chill\MainBundle\Routing\MenuBuilder;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
/**
*
@ -26,17 +28,40 @@ use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
*/
class UserMenuBuilder implements LocalMenuBuilderInterface
{
/**
*
* @var TokenStorageInterface
*/
protected $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters)
{
$menu->addChild(
if ($this->tokenStorage->getToken()->getUser() instanceof User) {
$menu
->addChild(
'Change password',
[ 'route' => 'change_my_password']
)
->setExtras([
'order' => 99999999998
]);
}
$menu
->addChild(
'Logout',
[
'route' => 'logout'
])
->setExtras([
'order'=> 99999999999,
'icon' => 'power-off'
]);
->setExtras([
'order'=> 99999999999,
'icon' => 'power-off'
]);
}
public static function getMenuIds(): array