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\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\MainBundle\Form\UserPasswordType; use Chill\MainBundle\Form\UserPasswordType;
use Chill\MainBundle\Entity\User; 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 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 * @param Request $request
@ -18,7 +48,6 @@ class PasswordController extends Controller
*/ */
public function UserPasswordAction(Request $request) public function UserPasswordAction(Request $request)
{ {
// get authentified user // get authentified user
$user = $this->getUser(); $user = $this->getUser();
@ -29,21 +58,27 @@ class PasswordController extends Controller
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$password = $form->get('new_password')->getData();
$password = $form->getData()->getPassword();
// logging for prod // logging for prod
$this->get('logger')->info('update password for an user', $this
array('method' => __METHOD__, 'user' => $user->getUsername())); ->chillLogger
->notice(
'update password for an user',
array(
'method' => $request->getMethod(),
'user' => $user->getUsername()
)
);
$user->setPassword($this->get('security.password_encoder') $user->setPassword($this->passwordEncoder->encodePassword($user, $password));
->encodePassword($user, $password));
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$em->flush(); $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) private function passwordForm(User $user)
{ {
return $this->createForm(UserPasswordType::class, $user, array( return $this->createForm(
'method' => 'PUT', UserPasswordType::class,
[],
)) [ 'user' => $this->getUser() ]
->add('submit', SubmitType::class, array('label' => 'Change password')) )
->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\Validator\Constraints\Regex;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType; 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 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 FormBuilderInterface $builder
* @param array $options * @param array $options
@ -20,7 +45,7 @@ class UserPasswordType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
->add('password', RepeatedType::class, array( ->add('new_password', RepeatedType::class, array(
'type' => PasswordType::class, 'type' => PasswordType::class,
'required' => false, 'required' => false,
'options' => array(), '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) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver
'data_classds' => 'Chill\MainBundle\Entity\User' ->setRequired('user')
)); ->setAllowedTypes('user', \Chill\MainBundle\Entity\User::class)
;
} }
/** /**

View File

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

View File

@ -4,3 +4,9 @@ services:
autowire: true autowire: true
resource: '../../../Controller' resource: '../../../Controller'
tags: ['controller.service_arguments'] 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 class: Chill\MainBundle\Form\AdvancedSearchType
arguments: arguments:
- "@chill.main.search_provider" - "@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: tags:
- { name: form.type } - { name: form.type }

View File

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

View File

@ -187,4 +187,8 @@ Choose the format: Choisir le format
# select2 # select2
'select2.no_results': Aucun résultat 'select2.no_results': Aucun résultat
'select2.error_loading': Erreur de chargement des résultats '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 title %}{{"Change my password"|trans}}{% endblock %}
{% block content %} {% 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_start(form) }}
{{ form_row(form.password) }} {{ form_row(form.actual_password) }}
{{ form_widget(form.submit, { 'attr': { 'class': 'sc-button orange' } } ) }} {{ form_row(form.new_password) }}
{{ form_end(form) }}
<ul class="record_actions">
<li>
{{ form_widget(form.submit, { 'attr': { 'class': 'sc-button orange' } } ) }}
</li>
</ul>
{{ form_end(form) }}
</div>
{% endblock %} {% endblock %}

View File

@ -18,6 +18,8 @@
namespace Chill\MainBundle\Routing\MenuBuilder; namespace Chill\MainBundle\Routing\MenuBuilder;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface; 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 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) 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', 'Logout',
[ [
'route' => 'logout' 'route' => 'logout'
]) ])
->setExtras([ ->setExtras([
'order'=> 99999999999, 'order'=> 99999999999,
'icon' => 'power-off' 'icon' => 'power-off'
]); ]);
} }
public static function getMenuIds(): array public static function getMenuIds(): array