Reset password symfony 4 (user not loggued) - symfony

I have a problem when i try to reset password on a non loggued user.
Entity users :
class Users implements AdvancedUserInterface, \Serializable, TwoFactorInterface, TrustedDeviceInterface {
[...]
}
Reset Password Action :
public function forgetPassword(Request $request, EntityManagerInterface $em, UserPasswordEncoderInterface $encoder)
{
$changePasswordModel = new ChangePassword();
$form = $this->createForm(ForgetPasswordType::class, $changePasswordModel);
$form->handleRequest($request);
$user = $em->getRepository("App:Users")->find(12);
if (!$request->get('token') || !$user || $user->getTokenExpire() <= new \DateTime())
{
return $this->redirectToRoute("404");
}
if ($form->isSubmitted() && $form->isValid())
{
$plainPassword = $form->getData()->getNewPassword();
$encoded = $encoder->encodePassword($user, $plainPassword);
$user->setPassword($encoded);
$em->persist($user);
$em->flush();
}
return $this->render('security/forget_password.html.twig', array(
'form' => $form->createView(),
'success' => $success
));
}
But i get this error :
The User object must implement the UserInterface interface.
Exact place of this error is on :
\vendor\symfony\security\Core\Validator\Constraints\UserPasswordValidator.php :
[...]
$user = $this->tokenStorage->getToken()->getUser();
if (!$user instanceof UserInterface) {
throw new ConstraintDefinitionException('The User object must
implement the UserInterface interface.');
}
[...]
When the user is loggued it work but when an user use a reset password it's because he lost his password. So it should work when the user is not loggued.
Thanks for your help !
Alex

Related

The "App\Security\UserAuthenticator::getUser()"method must return a UserInterface. You returned "Symfony\Component\HttpFoundation\RedirectResponse"

im trying to make a login method with symfony 4 , i have create this method public function
getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
if (!$user) {
return new RedirectResponse($this->urlGenerator->generate('app_login'));
}
return $user;
}
when i put a false user it display to me this error:
The "App\Security\UserAuthenticator::getUser()" method must return a UserInterface. You returned "Symfony\Component\HttpFoundation\RedirectResponse".
I'm guessing you are using a simple FormAuthenticator extending AbstractFormLoginAuthenticator (which is deprecated for symfony 5.3+ with the new authenticator system).
getUser() should only return an user or throw an exception so you should remove your redirect with:
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
if (!$user) {
throw new UserNotFoundException('User not found.');
}
return $user;
}
(You may want to use a less descriptive exception for security reason).
If I remember how it looked like in 4.4, your login method in your controller should look like:
use Symfony\Component\HttpFoundation\Request\AuthenticationUtils;
/**
* #Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig',
[
'last_username' => $lastUsername,
'error' => $error,
]
);
}

Binding entities to query parameters only allowed for entities have an identifier

I am using a Symfony 4 project, and I want to change the user password, so I created a method in my repository and called it to the controller, but this error it diplay to me,
Binding entities to query parameters only allowed for entities that have an identifier.
Repository
public function updateU($password,$email): ?Utilisateur
{
$dql = <<<DQL
SELECT u
FROM App\Entity\Utilisateur u
WHERE u.email = :email
AND u.password = :password
DQL;
return $this->getEntityManager()->createQuery($dql)
->setParameters(['email' => $email, 'password' => $password])
->getSingleScalarResult();
}
Controller
/**
* #Route("/Reset", name="Reset")
* Method({"GET"})
*/
public function New(
Request $request,
UtilisateurRepository $URe,
UserPasswordEncoderInterface $userPasswordEncoder,
EntityManagerInterface $entityManager,
MailerInterface $mailer
) {
$o = '';
$Varmail = $_GET['email'];
$user = new Utilisateur($o);
$form = $this->createFormBuilder($user)
->add('password', PasswordType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$to = $Varmail;
$sujet = 'Password Changed';
$Message = "Bonjour $Varmail Votre email est changé !";
$pass = $user->setPassword(
$userPasswordEncoder->encodePassword(
$user,
$form->get('password')->getData()
)
);
$URe->updateU($pass, $Varmail);
$Mai = new MailerController();
$Mai->sendEmail($mailer, $to, $sujet, $Message);
}
return $this->render('modifier_mdp/index.html.twig', [
'form' => $form->createView(),
]);
}
How can i solve it , And Thanks
In your updateU method, you are making a request to get, not update the data. It's better to use the ObjectManager to save the data, since you still have a updated instance of the Utilisateur object in the $user variable.
$user = $this->getDoctrine()->getManager()->getRepository(Event::class)->findOneBy(['email'=>$Varmail]);
$form = $this->createFormBuilder($user)->add('password', PasswordType::class)->getForm();
if ($form->isSubmitted() && $form->isValid()) {
// ...
$user->setPassword(
$userPasswordEncoder->encodePassword(
$user,
$form->get('password')->getData()
)
);
// save Utilisateur with new password
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
}

Symfony 4 - Good practice to remove your own user account while connected

I would like my users to be able to delete their own user account. I made a SecurityController where there is my 3 functions login, logout and deleteUser. When I delete the current user in database this error appears :
You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine.
When I delete another user, it works correctly because he's not connected.
Do I have to serialize the User and pass it through a Service, logout the user then remove it in a Service? Or can I clear the PHP session in the controller but I don't know how to do it with symfony4 I think it changed since version 4.
<?php
namespace App\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use App\Entity\User;
use App\Form\UserType;
class SecurityController extends Controller
{
/**
* #Route("/createAdmin", name="create_admin")
*/
public function createAdminUser(Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$usersRepo = $this->getDoctrine()->getRepository(User::class);
$uCount = $usersRepo->countAllUsers();
if ($uCount == 0)
{
$user = new User();
$form = $this->createForm(UserType::class, $user, array(
'is_fresh_install' => true,
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Encode the password
$password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
// save the User
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
// Do what you want here before redirecting the user
return $this->redirectToRoute('login');
}
return $this->render('security/register_admin_user.html.twig', array(
'form' => $form->createView(),
));
} else {
if ($this->getUser())
{
return $this->redirectToRoute('user_account');
} else {
return $this->redirectToRoute('login');
}
}
}
/**
* #Route("/login", name="login")
*/
public function login(Request $request, AuthenticationUtils $authUtils)
{
$usersRepo = $this->getDoctrine()->getRepository(User::class);
$uCount = $usersRepo->countAllUsers();
if ($uCount == 0)
{
return $this->redirectToRoute('create_admin');
} else {
$error = $authUtils->getLastAuthenticationError();
$lastUsername = $authUtils->getLastUsername();
return $this->render('security/login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
}
/**
* #Route("/logout", name="logout")
*/
public function logout()
{
}
/**
* #Route("/delete_user/{id}", name="delete_user")
*/
public function deleteUser($id)
{
$em = $this->getDoctrine()->getManager();
$usrRepo = $em->getRepository(User::class);
$user = $usrRepo->find($id);
$em->remove($user);
$em->flush();
return $this->redirectToRoute('user_registration');
}
}
SOLUTION :
You have to clear the Session before deleting user entry in DB with this method:
<?php
use Symfony\Component\HttpFoundation\Session\Session;
// In your deleteUser function...
$currentUserId = $this->getUser()->getId();
if ($currentUserId == $id)
{
$session = $this->get('session');
$session = new Session();
$session->invalidate();
}
I don't know why $this->get('session')->invalidate(); doesn't work directly... if someone knows :)
I find it also a good solution to do this what is an accepted answer but you can also simply redirect the user to the logout route.
This has worked for me without any problem in Symfony 4.4
I think you have to serialize the User and pass it through a service.Just check with the previous versions,you will find out the problem.

php - Symfony: Edit information of current user login with another user and reload page show error

I have two accounts one is client account and another is admin account. Client login to his account to edit profile and submit to admin approve. the problem when admin approve his updating then click submit then in client account reload page and have problem with message too many redirection.
Below is my code:
/**
* #Route("/client/personal-information", name="client_personal_info_page")
* #Template("FrontendBundle:ClientPanel:personal_info.html.twig")
*/
public function clientPersonalInfo(Request $request)
{
$user = $this->getUser();
$form = $this->createForm(ChangePersonalInfoFormType::class);
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
$user = $form->getData();
$idCardPictureFront = $form->get('idCardPictureFront')->getData();
$idCardPictureBack = $form->get('idCardPictureBack')->getData();
$accountDocument = $form->get('accountDocument')->getData();
if ($idCardPictureFront != null) {
$file = new Media($idCardPictureFront);
$this->persistAndFlush($file);
$user->setIdCardPictureFront($file);
}
if ($idCardPictureBack != null) {
$file = new Media($idCardPictureBack);
$this->persistAndFlush($file);
$user->setIdCardPictureBack($file);
}
if ($accountDocument != null) {
$file = new Media($accountDocument);
$this->persistAndFlush($file);
$user->setAccountDocument($file);
}
if ($form->get('otherCountryCode')->getData() != null) {
$phnoneNumber = $form->get('otherCountryCode')->getData().'-'.
$form->get('phoneNumber')->getData();
$user->setPhoneNumber($phnoneNumber);
}
$user->setStatus(AccountStatus::PENDING_OPENING);
$user->setPendingType(PendingType::ACCOUNT_UPDATE);
$this->addLog(
$this->moduleName,
LogAction::UPDATE,
'User update personal information',
$user->getId()
);
$this->msgSuccess('frontend.client.panel.personal_info_updated');
$this->persistAndFlush($user);
return $this->redirect($request->getUri());
}
return $this->getResponseParameters([
'form' => $form->createView(),
'user' => $user,
]);
}

How to write unit test in symfony3

I want to know how to write standard unit test code for the below controller. I believe PHPUNIT is installed by default in symfony3 but I'm not sure how to execute it as well. Can someone guide me how to write testcontroller and execution command for symfony3 as well.
class RegistrationController extends Controller
{
/**
* #Route("/register", name="user_registration")
* #Security("has_role('ROLE_SUPER_ADMIN')")
*/
public function userAction(Request $request)
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($request->isMethod('POST') && $form->isValid()) {
$password = $this->get('security.password_encoder')
->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->get('app.mailer')->sendUserCredentials($user);
$this->addFlash('notice', 'An account is created');
}
return $this->render('masteradmin/account/addUser.html.twig',
array('form' => $form->createView())
);
}
/**
* #Route(
* "/user/edit/{id}",
* requirements={"id" = "\d+"},
* name="user_edit"
* )
*/
public function editUserAction(User $user, Request $request)
{
if (!$this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN')) {
throw new AccessDeniedException();
}
$em = $this->getDoctrine()->getManager();
$id = $request->attributes->get('id');
if (!$user = $em->getRepository('AppBundle:User')->findOneById($id)) {
throw new NotFoundHttpException('user details not found.');
}
$form = $this->createForm(UserType::class, $user)
->remove('plainPassword');
$form->handleRequest($request);
$data = $form->getData();
if ($form->isValid()) {
$em->persist($user);
$em->flush();
$this->addFlash('notice', 'Account information is updated');
return $this->redirectToRoute('user_list');
}
return $this->render(
'masteradmin/account/editUser.html.twig', ['form' => $form->createView()]
);
}

Resources