getForgotPasswordEmail()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Smart\AuthenticationBundle\Controller;
4
5
use Smart\AuthenticationBundle\Email\ForgotPasswordEmail;
6
use Smart\AuthenticationBundle\Security\Form\Type\ResetPasswordType;
7
use Smart\AuthenticationBundle\Security\Form\Type\UserProfileType;
8
use Smart\AuthenticationBundle\Form\Type\Security\ForgotPasswordType;
9
use Smart\AuthenticationBundle\Security\SmartUserInterface;
10
use Smart\AuthenticationBundle\Security\Token;
11
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
12
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\HttpFoundation\Response;
16
use Symfony\Component\Mailer\MailerInterface;
17
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
18
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
19
use Yokai\SecurityTokenBundle\Exception\TokenNotFoundException;
20
use Yokai\SecurityTokenBundle\Exception\TokenConsumedException;
21
use Yokai\SecurityTokenBundle\Exception\TokenExpiredException;
22
use Yokai\SecurityTokenBundle\Manager\TokenManagerInterface;
23
24
/**
25
 * @author Nicolas Bastien <[email protected]>
26
 *
27
 * Fix phpstan error cf. https://github.com/phpstan/phpstan/issues/3200
28
 * @property ContainerInterface $container
29
 */
30
class AbstractSecurityController extends Controller
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...e\Controller\Controller has been deprecated: since Symfony 4.2, use "Symfony\Bundle\FrameworkBundle\Controller\AbstractController" instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

30
class AbstractSecurityController extends /** @scrutinizer ignore-deprecated */ Controller
Loading history...
31
{
32
    /**
33
     * Define application context, override this in your controller
34
     * @var string
35
     */
36
    protected $context;
37
38
    /**
39
     * @var TokenManagerInterface
40
     */
41
    protected $tokenManager;
42
43
    /**
44
     * @var MailerInterface
45
     */
46
    protected $mailer;
47
48
    public function __construct(TokenManagerInterface $tokenManager, MailerInterface $mailer)
49
    {
50
        $this->tokenManager = $tokenManager;
51
        $this->mailer = $mailer;
52
    }
53
54
    /**
55
     * @deprecated
56
     * @return Response
57
     */
58
    public function loginAction()
59
    {
60
        return $this->login();
61
    }
62
63
    /**
64
     * @deprecated
65
     * @param Request $request
66
     *
67
     * @return Response
68
     */
69
    public function forgotPasswordAction(Request $request)
70
    {
71
        return $this->forgotPassword($request);
72
    }
73
74
    /**
75
     * @deprecated
76
     * @param Request $request
77
     *
78
     * @return Response
79
     */
80
    public function resetPasswordAction(Request $request)
81
    {
82
        return $this->resetPassword($request);
83
    }
84
85
    /**
86
     * @deprecated
87
     * @param Request $request
88
     *
89
     * @return Response
90
     */
91
    public function profileAction(Request $request)
92
    {
93
        return $this->profile($request);
94
    }
95
96
    /**
97
     * @return Response
98
     */
99
    public function login()
100
    {
101
        $helper = $this->getAuthenticationUtils();
102
103
        return $this->render($this->context . '/security/login.html.twig', [
104
            'last_username' => $helper->getLastUsername(),
105
            'error'         => $helper->getLastAuthenticationError(),
106
            'layout_template' => $this->context . '/empty_layout.html.twig',
107
            'security_login_check_url' => $this->generateUrl($this->context . '_security_login_check'),
108
            'security_forgot_password_url' => $this->generateUrl($this->context . '_security_forgot_password'),
109
        ]);
110
    }
111
112
    /**
113
     * @param Request $request
114
     *
115
     * @return Response
116
     */
117
    public function forgotPassword(Request $request)
118
    {
119
        $form =  $this->createForm(ForgotPasswordType::class);
120
        $form->handleRequest($request);
121
122
        if (!$form->isSubmitted() || !$form->isValid()) {
123
            return $this->render(
124
                $this->context . '/security/forgot_password.html.twig',
125
                [
126
                    'form' => $form->createView(),
127
                    'security_login_form_url' => $this->generateUrl($this->context . '_security_login_form'),
128
                    'security_forgot_password_url' => $this->generateUrl($this->context . '_security_forgot_password'),
129
                ]
130
            );
131
        }
132
133
        try {
134
            $user = $this->get($this->context . '_user_provider')->loadUserByUsername($form->get('email')->getData());
135
136
            if ($user instanceof SmartUserInterface) {
137
                $token = $this->tokenManager->create(Token::RESET_PASSWORD, $user);
138
139
                $this->mailer->send($this->getForgotPasswordEmail([
140
                    'from' => $this->container->getParameter('app.mail_from'),
141
                    'subject' => $this->translate('security.forgot_password.subject', [], 'email'),
142
                    'context' => $this->context,
143
                    'token' => $token->getValue(),
144
                    'domain' => $this->getDomain(),
145
                    'security_reset_password_route' => $this->context . '_security_reset_password'
146
                ], $user->getEmail()));
147
148
                $this->addFlash('success', 'flash.forgot_password.success');
149
            }
150
        } catch (UsernameNotFoundException $e) {
151
            $this->addFlash('error', 'flash.forgot_password.unknown');
152
153
            return $this->redirectToRoute($this->context . '_security_forgot_password');
154
        }
155
156
        return $this->redirectToRoute($this->context . '_security_login_form');
157
    }
158
159
    /**
160
     * This provide a default email for the forgot password
161
     *
162
     * @param array<mixed> $parameters
163
     * @param string $email
164
     *
165
     * @return TemplatedEmail
166
     */
167
    protected function getForgotPasswordEmail(array $parameters, $email)
168
    {
169
        return new ForgotPasswordEmail($parameters, $email);
170
    }
171
172
    /**
173
     * @param Request $request
174
     *
175
     * @return Response
176
     */
177
    public function resetPassword(Request $request)
178
    {
179
        if ($this->getUser()) {
180
            return $this->redirectToRoute($this->context . '_dashboard');
181
        }
182
183
        if (!$request->query->has('token')) {
184
            $this->addFlash('error', 'flash.security.invalid_token');
185
186
            return $this->redirectToRoute($this->context . '_security_login_form');
187
        }
188
189
        try {
190
            $token = $this->tokenManager->get(Token::RESET_PASSWORD, $request->query->get('token'));
191
        } catch (TokenNotFoundException $e) {
192
            $this->addFlash('error', 'flash.security.token_not_found');
193
            return $this->redirectToRoute($this->context . '_security_login_form');
194
        } catch (TokenExpiredException $e) {
195
            $this->addFlash('error', 'flash.security.token_expired');
196
            return $this->redirectToRoute($this->context . '_security_login_form');
197
        } catch (TokenConsumedException $e) {
198
            $this->addFlash('error', 'flash.security.token_used');
199
            return $this->redirectToRoute($this->context . '_security_login_form');
200
        }
201
202
        /** @var SmartUserInterface $user */
203
        $user = $this->tokenManager->getUser($token);
204
205
        $form =  $this->createForm(ResetPasswordType::class, $user);
206
        $form->handleRequest($request);
207
208
        if (!$form->isSubmitted() || !$form->isValid()) {
209
            return $this->render(
210
                $this->context . '/security/reset_password.html.twig',
211
                [
212
                    'token' => $token->getValue(),
213
                    'form' => $form->createView(),
214
                    'security_reset_password_route' => $this->context . '_security_reset_password'
215
                ]
216
            );
217
        }
218
219
        try {
220
            if (null !== $user->getPlainPassword()) {
0 ignored issues
show
introduced by
The condition null !== $user->getPlainPassword() is always true.
Loading history...
221
                $this->updateUser($user);
222
                $this->tokenManager->consume($token);
223
            }
224
            $this->addFlash('success', 'flash.reset_password.success');
225
        } catch (\Exception $e) {
226
            $this->addFlash('error', 'flash.reset_password.error');
227
        }
228
229
        return $this->redirectToRoute($this->context . '_security_login_form');
230
    }
231
232
    /**
233
     * @param Request $request
234
     *
235
     * @return Response
236
     */
237
    public function profile(Request $request)
238
    {
239
        /** @var SmartUserInterface $user */
240
        $user = $this->getUser();
241
242
        $form = $this->createForm(UserProfileType::class, $user, []);
243
244
        $form->handleRequest($request);
245
246
        if (!$form->isSubmitted() || !$form->isValid()) {
247
            return $this->render($this->context . '/security/profile.html.twig', [
248
                'base_template' => $this->get('sonata.admin.pool')->getTemplate('layout'),
249
                'admin_pool'    => $this->get('sonata.admin.pool'),
250
                'form'          => $form->createView(),
251
                'security_profile_url' => $this->generateUrl('admin_security_profile'),
252
            ]);
253
        }
254
255
        $this->updateUser($user);
256
257
        $this->addFlash('success', $this->translate('profile_edit.processed', [], 'security'));
258
259
        return $this->redirectToRoute('sonata_admin_dashboard');
260
    }
261
262
    /**
263
     * @return AuthenticationUtils
264
     */
265
    private function getAuthenticationUtils()
266
    {
267
        return $this->get('security.authentication_utils');
268
    }
269
270
    /**
271
     * @param string      $id         The message id (may also be an object that can be cast to string)
272
     * @param array<array>       $parameters An array of parameters for the message
273
     * @param string|null $domain     The domain for the message or null to use the default
274
     *
275
     * @return string
276
     */
277
    protected function translate($id, array $parameters = array(), $domain = null)
278
    {
279
        return $this->get('translator')->trans($id, $parameters, $domain);
280
    }
281
282
    /**
283
     * @param SmartUserInterface $user
284
     *
285
     * @return void
286
     */
287
    protected function updateUser(SmartUserInterface $user)
288
    {
289
        if (null !== $user->getPlainPassword()) {
0 ignored issues
show
introduced by
The condition null !== $user->getPlainPassword() is always true.
Loading history...
290
            $encoder = $this->get('security.password_encoder');
291
            $user->setPassword(
292
                $encoder->encodePassword($user, $user->getPlainPassword())
293
            );
294
        }
295
296
        $manager = $this->getDoctrine()->getManager();
297
        $manager->persist($user);
298
        $manager->flush();
299
    }
300
301
    /**
302
     * Override this method if your application use custom domain
303
     *
304
     * @return string
305
     */
306
    protected function getDomain()
307
    {
308
        return $this->container->getParameter('domain');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->container->getParameter('domain') also could return the type array|boolean which is incompatible with the documented return type string.
Loading history...
309
    }
310
}
311