Symfony2: Edit user without having password
php, security, symfony
Solution
Until I see a more elegant solution, here's what I came up with:
- Create a UserEditType form class with all fields but the password field(s)
- Assign UserEditType to a validation group other than Default
- Configure the password length constraint to the validation group in 2.
- Modify the edit and update actions to use UserEditType
And now users can be edited without having the password!
UserEditType:
class UserEditType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('enabled', 'choice', array(
'choices' => array('Yes' => 'Yes', 'No' => 'No'),
'expanded' => true,
'multiple' => false,
'label' => 'Enabled: ',
))
->add('fname')
->add('sname')
->add('email')
->add('username')
->add('role', 'choice', array(
'choices' => array('ROLE_USER' => 'User', 'ROLE_ADMIN' => 'Admin'),
'expanded' => true,
'multiple' => false,
'label' => 'Group: ',
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Mana\ClientBundle\Entity\User',
'validation_groups' => array('edit'),
));
}
Password in User entity:
* @ORM\Column(name="userpass", type="string", length=100, nullable=false)
* @Assert\NotBlank(message="Password may not be empty")
* @Assert\Length(
* min = "5",
* max = "12",
* minMessage = "Password must be at least 5 characters long",
* maxMessage = "Password cannot be longer than than 12 characters",
* groups = {"Default"}
* )
Update action:
public function updateAction(Request $request, $id) {
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('ManaClientBundle:User')->find($id);
$form = $this->createForm(new UserEditType(), $user);
$form->bind($request);
if ($form->isValid()) {
$em->persist($user);
$em->flush();
return $this->redirect($this->generateUrl('user_main', array()));
}
return array(
'form' => $form->createView(),
'user' => $user,
'title' => 'Edit user',
);
}
Problem
In my application, only the admin user can create and, theoretically, edit users. So far, using only the Symfony security system (no FOSUserBundle management - its complexity is not required), creating users with varying roles is just fine. The challenge that totally escapes me is how to edit a user without knowing the user's password. I keep running into the expected validation error Password cannot be empty . How can editing be accomplished? I'm surely missing something very fundamental here. Edit action: ``` public function editAction($id) { $em = $this->getDoctrine()->getManager(); $user = $em->getRepository('ManaClientBundle:User')->find($id); $form = $this->createForm(new UserType(), $user); return array( 'form' => $form->createView(), 'user' => $user, 'title' => 'Edit user', ); } ``` Update action: ``` public function updateAction(Request $request, $id) { $em = $this->getDoctrine()->getManager(); $user = $em->getRepository('ManaClientBundle:User')->find($id); $originalPassword = $user->getPassword(); $form = $this->createForm(new UserType(), $user); $form->bind($request); if ($form->isValid()) { $plainPassword = $form->get('password')->getData(); if (!empty($plainPassword)) { //encode the password $encoder = $this->container->get('security.encoder_factory')->getEncoder($entity); //get encoder for hashing pwd later $tempPassword = $encoder->encodePassword($entity->getPassword(), $entity->getSalt()); $user->setPassword($tempPassword); } else { $user->setPassword($originalPassword); } $em->persist($user); $em->flush(); return $this->redirect($this->generateUrl('user_main', array())); } ``` User form: ``` public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('enabled', 'choice', array( 'choices' => array('Yes' => 'Yes', 'No' => 'No'), 'expanded' => true, 'multiple' => false, 'label' => 'Enabled: ', )) ->add('fname') ->add('sname') ->add('email') ->add('username') ->add('password', 'repeated', array( 'type' => 'password', 'invalid_message' => 'Password fields do not match', 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat Password'), )) ->add('role', 'choice', array( 'choices' => array('ROLE_USER' => 'User', 'ROLE_ADMIN' => 'Admin'), 'expanded' => true, 'multiple' => false, 'label' => 'Group: ', )) ; } ```