1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* This file is part of the Superdesk Web Publisher User Bundle. |
7
|
|
|
* |
8
|
|
|
* Copyright 2021 Sourcefabric z.ú. and contributors. |
9
|
|
|
* |
10
|
|
|
* For the full copyright and license information, please see the |
11
|
|
|
* AUTHORS and LICENSE files distributed with this source code. |
12
|
|
|
* |
13
|
|
|
* @Copyright 2021 Sourcefabric z.ú |
14
|
|
|
* @license http://www.superdesk.org/license |
15
|
|
|
*/ |
16
|
|
|
|
17
|
|
|
namespace SWP\Bundle\UserBundle\Controller; |
18
|
|
|
|
19
|
|
|
use SWP\Bundle\CoreBundle\Model\User; |
20
|
|
|
use SWP\Bundle\UserBundle\Form\ChangePasswordFormType; |
21
|
|
|
use SWP\Bundle\UserBundle\Form\ResetPasswordRequestFormType; |
22
|
|
|
use SWP\Bundle\UserBundle\Mailer\MailerInterface; |
23
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; |
24
|
|
|
use Symfony\Component\HttpFoundation\RedirectResponse; |
25
|
|
|
use Symfony\Component\HttpFoundation\Request; |
26
|
|
|
use Symfony\Component\HttpFoundation\Response; |
27
|
|
|
use Symfony\Component\Routing\Annotation\Route; |
28
|
|
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; |
29
|
|
|
use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait; |
30
|
|
|
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface; |
31
|
|
|
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @Route("/reset-password") |
35
|
|
|
*/ |
36
|
|
|
class ResetPasswordController extends AbstractController |
37
|
|
|
{ |
38
|
|
|
use ResetPasswordControllerTrait; |
39
|
|
|
|
40
|
|
|
private $resetPasswordHelper; |
41
|
|
|
|
42
|
|
|
public function __construct(ResetPasswordHelperInterface $resetPasswordHelper) |
43
|
|
|
{ |
44
|
|
|
$this->resetPasswordHelper = $resetPasswordHelper; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Display & process form to request a password reset. |
49
|
|
|
* |
50
|
|
|
* @Route("", name="swp_user_forgot_password_request") |
51
|
|
|
*/ |
52
|
|
|
public function request(Request $request, MailerInterface $mailer): Response |
53
|
|
|
{ |
54
|
|
|
$form = $this->createForm(ResetPasswordRequestFormType::class); |
55
|
|
|
$form->handleRequest($request); |
56
|
|
|
|
57
|
|
|
if ($form->isSubmitted() && $form->isValid()) { |
58
|
|
|
return $this->processSendingPasswordResetEmail( |
59
|
|
|
$form->get('email')->getData(), |
60
|
|
|
$mailer |
61
|
|
|
); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
return $this->render('@SWPUser/reset_password/request.html.twig', [ |
65
|
|
|
'requestForm' => $form->createView(), |
66
|
|
|
]); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Confirmation page after a user has requested a password reset. |
71
|
|
|
* |
72
|
|
|
* @Route("/check-email", name="swp_user_check_email") |
73
|
|
|
*/ |
74
|
|
|
public function checkEmail(): Response |
75
|
|
|
{ |
76
|
|
|
// We prevent users from directly accessing this page |
77
|
|
|
if (!$this->canCheckEmail()) { |
|
|
|
|
78
|
|
|
return $this->redirectToRoute('swp_user_forgot_password_request'); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
return $this->render('@SWPUser/reset_password/check_email.html.twig', [ |
82
|
|
|
'tokenLifetime' => $this->resetPasswordHelper->getTokenLifetime(), |
83
|
|
|
]); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Validates and process the reset URL that the user clicked in their email. |
88
|
|
|
* |
89
|
|
|
* @Route("/reset/{token}", name="swp_user_reset_password") |
90
|
|
|
*/ |
91
|
|
|
public function reset(Request $request, UserPasswordEncoderInterface $passwordEncoder, string $token = null): Response |
92
|
|
|
{ |
93
|
|
|
if ($token) { |
|
|
|
|
94
|
|
|
// We store the token in session and remove it from the URL, to avoid the URL being |
95
|
|
|
// loaded in a browser and potentially leaking the token to 3rd party JavaScript. |
96
|
|
|
$this->storeTokenInSession($token); |
97
|
|
|
|
98
|
|
|
return $this->redirectToRoute('swp_user_reset_password'); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
$token = $this->getTokenFromSession(); |
102
|
|
|
if (null === $token) { |
103
|
|
|
throw $this->createNotFoundException('No reset password token found in the URL or in the session.'); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
try { |
107
|
|
|
$user = $this->resetPasswordHelper->validateTokenAndFetchUser($token); |
108
|
|
|
} catch (ResetPasswordExceptionInterface $e) { |
109
|
|
|
$this->addFlash('reset_password_error', sprintf( |
110
|
|
|
'There was a problem validating your reset request - %s', |
111
|
|
|
$e->getReason() |
112
|
|
|
)); |
113
|
|
|
|
114
|
|
|
return $this->redirectToRoute('swp_user_forgot_password_request'); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
// The token is valid; allow the user to change their password. |
118
|
|
|
$form = $this->createForm(ChangePasswordFormType::class); |
119
|
|
|
$form->handleRequest($request); |
120
|
|
|
|
121
|
|
|
if ($form->isSubmitted() && $form->isValid()) { |
122
|
|
|
// A password reset token should be used only once, remove it. |
123
|
|
|
$this->resetPasswordHelper->removeResetRequest($token); |
124
|
|
|
|
125
|
|
|
// Encode the plain password, and set it. |
126
|
|
|
$encodedPassword = $passwordEncoder->encodePassword( |
127
|
|
|
$user, |
128
|
|
|
$form->get('plainPassword')->getData() |
129
|
|
|
); |
130
|
|
|
|
131
|
|
|
$user->setPassword($encodedPassword); |
132
|
|
|
$this->getDoctrine()->getManager()->flush(); |
133
|
|
|
|
134
|
|
|
// The session is cleaned up after the password has been changed. |
135
|
|
|
$this->cleanSessionAfterReset(); |
136
|
|
|
|
137
|
|
|
return $this->redirectToRoute('homepage'); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $this->render('@SWPUser/reset_password/reset.html.twig', [ |
141
|
|
|
'resetForm' => $form->createView(), |
142
|
|
|
]); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer): RedirectResponse |
146
|
|
|
{ |
147
|
|
|
$user = $this->getDoctrine()->getRepository(User::class)->findOneBy([ |
148
|
|
|
'email' => $emailFormData, |
149
|
|
|
]); |
150
|
|
|
|
151
|
|
|
// Marks that you are allowed to see the swp_user_check_email page. |
152
|
|
|
$this->setCanCheckEmailInSession(); |
|
|
|
|
153
|
|
|
|
154
|
|
|
// Do not reveal whether a user account was found or not. |
155
|
|
|
if (!$user) { |
156
|
|
|
return $this->redirectToRoute('swp_user_check_email'); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
try { |
160
|
|
|
$resetToken = $this->resetPasswordHelper->generateResetToken($user); |
161
|
|
|
} catch (ResetPasswordExceptionInterface $e) { |
162
|
|
|
$this->addFlash('reset_password_error', sprintf( |
163
|
|
|
'There was a problem handling your password reset request - %s', |
164
|
|
|
$e->getReason() |
165
|
|
|
)); |
166
|
|
|
|
167
|
|
|
return $this->redirectToRoute('swp_user_check_email'); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
$mailer->sendResetPasswordEmail($user, $resetToken); |
171
|
|
|
|
172
|
|
|
return $this->redirectToRoute('swp_user_check_email'); |
173
|
|
|
} |
174
|
|
|
} |
175
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.