SecurityController::logInOutCheckAction()   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
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/*
3
  ÁTICA - Aplicación web para la gestión documental de centros educativos
4
5
  Copyright (C) 2015-2017: Luis Ramón López López
6
7
  This program is free software: you can redistribute it and/or modify
8
  it under the terms of the GNU Affero General Public License as published by
9
  the Free Software Foundation, either version 3 of the License, or
10
  (at your option) any later version.
11
12
  This program is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
  GNU Affero General Public License for more details.
16
17
  You should have received a copy of the GNU Affero General Public License
18
  along with this program.  If not, see [http://www.gnu.org/licenses/].
19
*/
20
21
namespace AppBundle\Controller;
22
23
use AppBundle\Entity\Organization;
24
use AppBundle\Entity\User;
25
use AppBundle\Repository\OrganizationRepository;
26
use AppBundle\Service\MailerService;
27
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
28
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
29
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
30
use Symfony\Component\HttpFoundation\RedirectResponse;
31
use Symfony\Component\HttpFoundation\Request;
32
use Symfony\Component\HttpFoundation\Session\Session;
33
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
34
35
class SecurityController extends Controller
36
{
37
    /**
38
     * @Route("/entrar", name="login", methods={"GET"})
39
     */
40
    public function loginAction()
41
    {
42
        $authenticationUtils = $this->get('security.authentication_utils');
43
44
        // obtener el error de entrada, si existe alguno
45
        $error = $authenticationUtils->getLastAuthenticationError();
46
47
        // último nombre de usuario introducido
48
        $lastUsername = $authenticationUtils->getLastUsername();
49
50
        return $this->render(
51
            'security/login.html.twig',
52
            array(
53
                'last_username' => $lastUsername,
54
                'login_error' => $error,
55
            )
56
        );
57
    }
58
59
    /**
60
     * @Route("/comprobar", name="login_check", methods={"POST"})
61
     * @Route("/salir", name="logout", methods={"GET"})
62
     */
63
    public function logInOutCheckAction()
64
    {
65
    }
66
67
    /**
68
     * @Route("/restablecer", name="login_password_reset", methods={"GET", "POST"})
69
     */
70
    public function passwordResetRequestAction(Request $request)
71
    {
72
73
        $data = [
74
            'email' => ''
75
        ];
76
77
        $form = $this->createForm('AppBundle\Form\Type\PasswordResetType', $data);
78
79
        $form->handleRequest($request);
80
81
        $data = $form->getData();
82
        $email = $data['email'];
83
        $error = '';
84
85
        // ¿se ha enviado una dirección?
86
        if ($form->isSubmitted() && $form->isValid()) {
87
            $error = $this->passwordResetRequest($email);
88
89
            if (!is_string($error)) {
90
                return $error;
91
            }
92
        }
93
94
        return $this->render(
95
            'security/login_password_reset.html.twig', [
96
                'last_username' => $this->get('session')->get('_security.last_username', ''),
97
                'form' => $form->createView(),
98
                'error' => $error
99
            ]
100
        );
101
    }
102
103
    /**
104
     * @Route("/restablecer/correo/{userId}/{token}", name="email_reset_do", methods={"GET", "POST"})
105
     */
106
    public function emailResetAction(Request $request, $userId, $token)
107
    {
108
        /**
109
         * @var User
110
         */
111
        $user = $this->getDoctrine()->getManager()->getRepository('AppBundle:User')->findOneBy([
112
            'id' => $userId,
113
            'token' => $token
114
        ]);
115
116 View Code Duplication
        if (null === $user || $user->getTokenType() === 'password' || $user->getTokenExpiration() < new \DateTime()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
117
            $this->addFlash('error', $this->get('translator')->trans('form.change_email.notvalid', [], 'security'));
118
            return $this->redirectToRoute('login');
119
        }
120
121
        if ($request->getMethod() === 'POST') {
122
            $user
123
                ->setEmailAddress($user->getTokenType())
124
                ->setToken(null)
125
                ->setTokenExpiration(null)
126
                ->setTokenType(null);
127
128
            try {
129
                $this->getDoctrine()->getManager()->flush();
130
131
                // indicar que los cambios se han realizado con éxito y volver a la página de inicio
132
                $this->addFlash('success', $this->get('translator')->trans('form.change_email.message', [], 'security'));
133
            } catch (\Exception $e) {
134
                // indicar que no se ha podido cambiar
135
                $this->addFlash('error', $this->get('translator')->trans('form.change_email.error', [], 'security'));
136
            }
137
            return new RedirectResponse(
138
                $this->generateUrl('frontpage')
139
            );
140
        }
141
142
        return $this->render(
143
            'security/login_email_change.html.twig', [
144
                'user' => $user
145
            ]
146
        );
147
    }
148
149
    /**
150
     * @Route("/restablecer/{userId}/{token}", name="login_password_reset_do", methods={"GET", "POST"})
151
     */
152
    public function passwordResetAction(Request $request, $userId, $token)
153
    {
154
        /**
155
         * @var User
156
         */
157
        $user = $this->getDoctrine()->getManager()->getRepository('AppBundle:User')->findOneBy([
158
            'id' => $userId,
159
            'token' => $token,
160
            'tokenType' => 'password'
161
        ]);
162
163 View Code Duplication
        if (null === $user || ($user->getTokenExpiration() < new \DateTime())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
164
            $this->addFlash('error', $this->get('translator')->trans('form.reset.notvalid', [], 'security'));
165
            return $this->redirectToRoute('login');
166
        }
167
168
        $data = [
169
            'password' => '',
170
            'repeat' => ''
171
        ];
172
173
        $form = $this->createForm('AppBundle\Form\Type\NewPasswordType', $data);
174
175
        $form->handleRequest($request);
176
177
        $error = '';
178
        if ($form->isSubmitted() && $form->isValid()) {
179
180
            //codificar la nueva contraseña y asignarla al usuario
181
            $password = $this->get('security.password_encoder')
182
                ->encodePassword($user, $form->get('newPassword')->get('first')->getData());
183
184
            $user
185
                ->setPassword($password)
186
                ->setToken(null)
187
                ->setTokenExpiration(null)
188
                ->setTokenType(null);
189
190
            $this->getDoctrine()->getManager()->flush();
191
192
            // indicar que los cambios se han realizado con éxito y volver a la página de inicio
193
            $message = $this->get('translator')->trans('form.reset.message', [], 'security');
194
            $this->addFlash('success', $message);
195
            return new RedirectResponse(
196
                $this->generateUrl('frontpage')
197
            );
198
        }
199
200
        return $this->render(
201
            'security/login_password_new.html.twig', [
202
                'user' => $user,
203
                'form' => $form->createView(),
204
                'error' => $error
205
            ]
206
        );
207
    }
208
209
    /**
210
     * @Route("/organizacion", name="login_organization", methods={"GET", "POST"})
211
     */
212
    public function organizationAction(Request $request)
213
    {
214
        // si no hay usuario activo, volver
215
        if (null === $this->getUser()) {
216
            return $this->redirectToRoute('login');
217
        }
218
219
        /** @var Session $session */
220
        $session = $this->get('session');
221
222
        $data = ['organization' => $this->getUser()->getDefaultOrganization()];
223
224
        $count = $this->getDoctrine()->getManager()->getRepository('AppBundle:Organization')->countOrganizationsByUser($this->getUser(), new \DateTime());
225
226
        $form = $this->createFormBuilder($data)
227
            ->add('organization', EntityType::class, [
228
                'expanded' => $count < 5,
229
                'class' => Organization::class,
230
                'query_builder' => function(OrganizationRepository $er) {
231
                    return $er->getMembershipByUserQueryBuilder($this->getUser(), new \DateTime());
232
                },
233
                'required' => true
234
            ])
235
            ->getForm();
236
237
        $form->handleRequest($request);
238
239
        // ¿se ha seleccionado una organización?
240
        if ($form->isSubmitted() && $form->isValid() && $form->get('organization')->getData()) {
241
242
            $session->set('organization_id', $form->get('organization')->getData()->getId());
243
            $session->set('organization_selected', true);
244
            $this->getUser()->setDefaultOrganization($form->get('organization')->getData());
245
            $this->getDoctrine()->getManager()->flush();
246
247
            $url = $session->get('_security.organization.target_path', $this->generateUrl('frontpage'));
248
            $session->remove('_security.organization.target_path');
249
            return new RedirectResponse($url);
250
        }
251
        return $this->render('security/login_organization.html.twig', [
252
                'form' => $form->createView(),
253
                'count' => $count
254
            ]
255
        );
256
    }
257
258
    /**
259
     * @param $email
260
     * @return string|RedirectResponse
261
     */
262
    private function passwordResetRequest($email)
263
    {
264
        /** @var User $user */
265
        // comprobar que está asociada a un usuario
266
        $user = $this->getDoctrine()->getManager()->getRepository('AppBundle:User')->findOneBy(['emailAddress' => $email]);
267
268
        $error = '';
269
270
        if (null === $user) {
271
            $error = $this->get('translator')->trans('form.reset.notfound', [], 'security');
272
        } else {
273
            // almacenar como último correo electrónico el indicado
274
            $this->get('session')->set('_security.last_username', $user->getEmailAddress());
275
276
            // obtener tiempo de expiración del token
277
            $expire = (int) $this->getParameter('password_reset.expire');
278
279
            if ($this->getParameter('external.enabled') && $user->getExternalCheck()) {
280
                $this->addFlash('error', $this->get('translator')->trans('form.reset.external_login.error', [], 'security'));
281
            } else {
282
                // comprobar que no se ha generado un token hace poco
283
                if ($user->getToken() && $user->getTokenExpiration() > new \DateTime()) {
284
                    $error = $this->get('translator')->trans('form.reset.wait', ['%expiry%' => $expire], 'security');
285
                } else {
286
                    // generar un nuevo token
287
                    $token = bin2hex(random_bytes(16));
288
                    $user->setToken($token);
289
290
                    // calcular fecha de expiración del token
291
                    $validity = new \DateTime();
292
                    $validity->add(new \DateInterval('PT'.$expire.'M'));
293
                    $user->setTokenExpiration($validity)->setTokenType('password');
294
295
                    // enviar correo
296
                    if (0 === $this->get(MailerService::class)->sendEmail([$user],
297
                            ['id' => 'form.reset.email.subject', 'parameters' => []],
298
                            [
299
                                'id' => 'form.reset.email.body',
300
                                'parameters' => [
301
                                    '%name%' => $user->getFirstName(),
302
                                    '%link%' => $this->generateUrl('login_password_reset_do',
303
                                        ['userId' => $user->getId(), 'token' => $token],
304
                                        UrlGeneratorInterface::ABSOLUTE_URL),
305
                                    '%expiry%' => $expire
306
                                ]
307
                            ], 'security')
308
                    ) {
309
                        $this->addFlash('error', $this->get('translator')->trans('form.reset.error', [], 'security'));
310
                    } else {
311
                        // guardar token
312
                        $this->get('doctrine')->getManager()->flush();
313
314
                        $this->addFlash('success',
315
                            $this->get('translator')->trans('form.reset.sent', ['%email%' => $email], 'security'));
316
                        return $this->redirectToRoute('login');
317
                    }
318
                }
319
            }
320
        }
321
        return $error;
322
    }
323
324
}
325