Passed
Pull Request — master (#23)
by Nicolas
10:35
created

AbstractSecurityController::profileAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
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\Form\Type\Security\ForgotPasswordType;
7
use Smart\AuthenticationBundle\Security\Form\Type\ResetPasswordType;
8
use Smart\AuthenticationBundle\Security\Form\Type\UserProfileType;
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\TokenConsumedException;
20
use Yokai\SecurityTokenBundle\Exception\TokenExpiredException;
21
use Yokai\SecurityTokenBundle\Exception\TokenNotFoundException;
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
 *
29
 * @property ContainerInterface $container
30
 */
31
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

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