|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* This file is part of Webcook security bundle. |
|
5
|
|
|
* |
|
6
|
|
|
* See LICENSE file in the root of the bundle. Webcook |
|
7
|
|
|
*/ |
|
8
|
|
|
|
|
9
|
|
|
namespace Webcook\Cms\SecurityBundle\Controller; |
|
10
|
|
|
|
|
11
|
|
|
use Webcook\Cms\CoreBundle\Base\BaseRestController; |
|
12
|
|
|
use Symfony\Component\HttpFoundation\Request; |
|
13
|
|
|
use Symfony\Component\HttpFoundation\Response; |
|
14
|
|
|
use Webcook\Cms\SecurityBundle\Entity\User; |
|
15
|
|
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
|
16
|
|
|
use FOS\RestBundle\Controller\Annotations\Post; |
|
17
|
|
|
use FOS\RestBundle\Controller\Annotations\Get; |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Login controller. |
|
21
|
|
|
*/ |
|
22
|
|
|
class LoginController extends BaseRestController |
|
23
|
|
|
{ |
|
24
|
|
|
|
|
25
|
|
|
/** |
|
26
|
|
|
* Send an email with a link to reset user's password. |
|
27
|
|
|
* |
|
28
|
|
|
* @ApiDoc( |
|
29
|
|
|
* description="Send an email with a link to reset user's password." |
|
30
|
|
|
* ) |
|
31
|
|
|
* @Post("password/email/reset", options={"i18n"=false}) |
|
32
|
|
|
*/ |
|
33
|
|
|
public function resetPasswordEmailAction(Request $request): Response |
|
34
|
7 |
|
{ |
|
35
|
|
|
$email = $request->request->get('email'); |
|
36
|
7 |
|
$user = $this->getEntityManager()->getRepository('Webcook\Cms\SecurityBundle\Entity\User')->findOneBy(array('email'=> $email)); |
|
37
|
7 |
|
|
|
38
|
|
View Code Duplication |
if ($user === null) { |
|
|
|
|
|
|
39
|
7 |
|
$view = $this->getViewWithMessage(null, 404, 'This email does not exist. Please enter a valid email.'); |
|
|
|
|
|
|
40
|
1 |
|
return $this->handleView($view); |
|
41
|
1 |
|
} |
|
42
|
|
|
|
|
43
|
|
|
$resetLink = $this->setResetToken($user); |
|
44
|
6 |
|
$message = \Swift_Message::newInstance() |
|
45
|
6 |
|
->setSubject('Password Reset') |
|
46
|
6 |
|
->setFrom('[email protected]') |
|
47
|
6 |
|
->setTo($email) |
|
48
|
6 |
|
->setBody($this->render( |
|
49
|
6 |
|
'WebcookCmsSecurityBundle:Auth:emailTemplate.html.twig', |
|
50
|
6 |
|
array( |
|
51
|
|
|
'user' => $user->getUsername(), |
|
52
|
6 |
|
'resetLink' => $resetLink |
|
53
|
6 |
|
) |
|
54
|
|
|
)) |
|
55
|
|
|
->setContentType("text/html"); |
|
56
|
6 |
|
|
|
57
|
|
|
$result = $this->get('mailer')->send($message); |
|
58
|
6 |
|
if ($result) { |
|
59
|
6 |
|
$view = $this->getViewWithMessage(null, 200, 'Your password reset link was sent to your e-mail address.'); |
|
|
|
|
|
|
60
|
5 |
|
} else { |
|
61
|
|
|
$view = $this->getViewWithMessage(null, 400, 'Cannot send an email.'); |
|
|
|
|
|
|
62
|
1 |
|
} |
|
63
|
|
|
|
|
64
|
|
|
return $this->handleView($view); |
|
65
|
6 |
|
} |
|
66
|
|
|
|
|
67
|
|
|
/** |
|
68
|
|
|
* Reset password view. |
|
69
|
|
|
* |
|
70
|
|
|
* @ApiDoc( |
|
71
|
|
|
* description="Reset password view." |
|
72
|
|
|
* ) |
|
73
|
|
|
* @Get("password/reset", options={"i18n"=false}) |
|
74
|
|
|
*/ |
|
75
|
|
|
public function resetPasswordGetAction(Request $request): Response |
|
76
|
3 |
|
{ |
|
77
|
|
|
$token = $request->query->get('token'); |
|
78
|
3 |
|
$user = $this->getEntityManager()->getRepository('Webcook\Cms\SecurityBundle\Entity\User')->findOneBy(array('passwordResetToken'=> $token)); |
|
79
|
3 |
View Code Duplication |
if ($user === null || empty($token)) { |
|
|
|
|
|
|
80
|
3 |
|
$view = $this->getViewWithMessage(null, 404, 'This token is invalid.'); |
|
|
|
|
|
|
81
|
1 |
|
return $this->handleView($view); |
|
82
|
1 |
|
} |
|
83
|
|
|
|
|
84
|
|
|
$dateDiff = date_diff( |
|
85
|
2 |
|
new \DateTime(), |
|
86
|
2 |
|
$user->getPasswordResetExpiration() |
|
87
|
2 |
|
); |
|
88
|
|
|
|
|
89
|
|
|
$view = $this->getViewWithMessage(null, 400, 'This token has expired.'); |
|
|
|
|
|
|
90
|
2 |
|
$diffInSeconds = $dateDiff->i * 60 + $dateDiff->s; |
|
91
|
2 |
|
if ($diffInSeconds < 600 && $dateDiff->y == 0 && $dateDiff->m == 0 && $dateDiff->d == 0 && $dateDiff->h == 0) { |
|
92
|
2 |
|
$view = $this->getViewWithMessage(null, 200, 'Please enter your new password.'); |
|
|
|
|
|
|
93
|
1 |
|
} |
|
94
|
|
|
|
|
95
|
|
|
return $this->handleView($view); |
|
96
|
2 |
|
} |
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* Reset password action. |
|
100
|
|
|
* |
|
101
|
|
|
* @ApiDoc( |
|
102
|
|
|
* description="Reset password action." |
|
103
|
|
|
* ) |
|
104
|
|
|
* @Post("password/reset", options={"i18n"=false}) |
|
105
|
|
|
*/ |
|
106
|
|
|
public function resetPasswordPostAction(Request $request): Response |
|
107
|
2 |
|
{ |
|
108
|
|
|
$password = $request->request->get('password'); |
|
109
|
2 |
|
$repeatPassword = $request->request->get('repeatPassword'); |
|
110
|
2 |
|
$token = $request->request->get('token'); |
|
111
|
2 |
View Code Duplication |
if (empty($password) || empty($repeatPassword) || empty($token)) { |
|
|
|
|
|
|
112
|
2 |
|
$view = $this->getViewWithMessage(null, 400, 'Passwords and token can\'t be empty.'); |
|
|
|
|
|
|
113
|
1 |
|
return $this->handleView($view); |
|
114
|
1 |
|
} |
|
115
|
|
|
|
|
116
|
|
|
if ($password == $repeatPassword) { |
|
117
|
1 |
|
$user = $this->getEntityManager()->getRepository('Webcook\Cms\SecurityBundle\Entity\User')->findOneBy(array('passwordResetToken'=> $token)); |
|
118
|
|
View Code Duplication |
if ($user === null) { |
|
|
|
|
|
|
119
|
|
|
$view = $this->getViewWithMessage(null, 404, 'This token is invalid.'); |
|
|
|
|
|
|
120
|
|
|
return $this->handleView($view); |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
$this->setUserPassword($user, $password); |
|
124
|
|
|
|
|
125
|
|
|
$view = $this->getViewWithMessage(null, 200, 'Password has been changed.'); |
|
|
|
|
|
|
126
|
|
|
return $this->handleView($view); |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
$view = $this->getViewWithMessage(null, 400, 'Passwords dont\'t match.'); |
|
|
|
|
|
|
130
|
1 |
|
return $this->handleView($view); |
|
131
|
1 |
|
} |
|
132
|
|
|
|
|
133
|
|
|
private function setUserPassword(User $user, String $password) |
|
134
|
|
|
{ |
|
135
|
|
|
$factory = $this->container->get('security.encoder_factory'); |
|
136
|
|
|
$encoder = $factory->getEncoder($user); |
|
137
|
|
|
$password = $encoder->encodePassword($password, $user->getSalt()); |
|
138
|
|
|
|
|
139
|
|
|
$user->setPassword($password); |
|
140
|
|
|
$user->setPasswordResetToken(null); |
|
141
|
|
|
$user->setPasswordResetExpiration(null); |
|
142
|
|
|
|
|
143
|
|
|
$this->getEntityManager()->flush(); |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
private function setResetToken(User $user): string |
|
147
|
6 |
|
{ |
|
148
|
|
|
$token = md5(uniqid(mt_rand(), true)); |
|
149
|
6 |
|
$resetLink = $this->generateUrl('reset_password_get', array('token' => $token), true); |
|
|
|
|
|
|
150
|
6 |
|
$date = new \DateTime(); |
|
151
|
6 |
|
|
|
152
|
|
|
$user->setPasswordResetToken($token); |
|
153
|
6 |
|
$user->setPasswordResetExpiration($date); |
|
154
|
6 |
|
|
|
155
|
|
|
$this->getEntityManager()->flush(); |
|
156
|
6 |
|
|
|
157
|
|
|
return $resetLink; |
|
158
|
6 |
|
} |
|
159
|
|
|
} |
|
160
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.