SecurityController   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 22
eloc 69
c 2
b 0
f 0
dl 0
loc 133
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A logout() 0 3 1
A create() 0 29 5
B authenticate() 0 22 7
A sendAuthenticationEmail() 0 14 3
A loginAndRedirect() 0 14 2
A tryLogin() 0 28 4
1
<?php
2
3
/*
4
 * This file is part of the TheAlternativeZurich/events project.
5
 *
6
 * (c) Florian Moser <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace App\Controller;
13
14
use App\Controller\Base\BaseDoctrineController;
15
use App\Entity\User;
16
use App\Form\User\LoginType;
17
use App\Form\User\RegisterType;
18
use App\Helper\HashHelper;
19
use App\Security\UserToken;
20
use App\Service\Interfaces\EmailServiceInterface;
21
use LogicException;
22
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
23
use Symfony\Component\HttpFoundation\RedirectResponse;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
use Symfony\Component\Routing\Annotation\Route;
27
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
28
use Symfony\Contracts\Translation\TranslatorInterface;
29
30
class SecurityController extends BaseDoctrineController
31
{
32
    /**
33
     * @Route("/create", name="create")
34
     */
35
    public function create(Request $request, GuardAuthenticatorHandler $guardHandler, TranslatorInterface $translator): Response
36
    {
37
        if (null !== $this->getUser()) {
38
            return $this->redirectToRoute('index');
39
        }
40
41
        $user = new User();
42
        $form = $this->createForm(RegisterType::class, $user)
43
            ->add('submit', SubmitType::class, ['translation_domain' => 'security', 'label' => 'create.submit']);
44
        $form->handleRequest($request);
45
        if ($form->isSubmitted() && $form->isValid()) {
46
            $userRepository = $this->getDoctrine()->getRepository(User::class);
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Bundle\Framework...ntroller::getDoctrine() has been deprecated: since Symfony 5.4, inject an instance of ManagerRegistry in your controller instead ( Ignorable by Annotation )

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

46
            $userRepository = /** @scrutinizer ignore-deprecated */ $this->getDoctrine()->getRepository(User::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
47
            $existingUser = $userRepository->findOneBy(['email' => $user->getEmail()]);
48
            if ($existingUser) {
49
                $message = $translator->trans('create.error.already_registered', [], 'security');
50
                $this->displayError($message);
51
52
                return $this->redirectToRoute('authenticate');
53
            }
54
55
            $this->fastSave($user);
56
57
            $message = $translator->trans('create.success.welcome', [], 'security');
58
            $this->displaySuccess($message);
59
60
            return $this->loginAndRedirect($user, $guardHandler, $request);
61
        }
62
63
        return $this->render('security/create.html.twig', ['form' => $form->createView()]);
64
    }
65
66
    /**
67
     * @Route("/authenticate/{authenticationHash}", defaults={"authenticationHash"=null}, name="authenticate")
68
     */
69
    public function authenticate(?string $authenticationHash, Request $request, GuardAuthenticatorHandler $guardHandler, EmailServiceInterface $emailService, TranslatorInterface $translator): Response
70
    {
71
        if (null !== $authenticationHash && HashHelper::HASH_LENGTH === mb_strlen($authenticationHash)) {
72
            $response = $this->tryLogin($authenticationHash, $guardHandler, $request, $translator);
73
            if ($response instanceof Response) {
74
                return $response;
75
            }
76
        }
77
78
        if (null !== $this->getUser()) {
79
            return $this->redirectToRoute('index');
80
        }
81
82
        $user = new User();
83
        $form = $this->createForm(LoginType::class, $user)
84
            ->add('submit', SubmitType::class, ['translation_domain' => 'security', 'label' => 'authenticate.submit']);
85
        $form->handleRequest($request);
86
        if ($form->isSubmitted() && $form->isValid()) {
87
            $this->sendAuthenticationEmail($user, $emailService, $translator);
88
        }
89
90
        return $this->render('security/authenticate.html.twig', ['form' => $form->createView()]);
91
    }
92
93
    /**
94
     * @Route("/logout", name="logout")
95
     */
96
    public function logout()
97
    {
98
        throw new LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
99
    }
100
101
    private function sendAuthenticationEmail(User $user, EmailServiceInterface $emailService, TranslatorInterface $translator): void
102
    {
103
        $userRepository = $this->getDoctrine()->getRepository(User::class);
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Bundle\Framework...ntroller::getDoctrine() has been deprecated: since Symfony 5.4, inject an instance of ManagerRegistry in your controller instead ( Ignorable by Annotation )

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

103
        $userRepository = /** @scrutinizer ignore-deprecated */ $this->getDoctrine()->getRepository(User::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
104
        $existingUser = $userRepository->findOneBy(['email' => $user->getEmail()]);
105
        if (!$existingUser) {
106
            $message = $translator->trans('authenticate.errors.email_not_recognised', [], 'security');
107
            $this->displayError($message);
108
        } elseif (!$emailService->sendAuthenticateLink($existingUser)) {
109
            $message = $translator->trans('errors.email_could_not_be_sent', [], 'email');
110
            $this->displayError($message);
111
        } else {
112
            // also show success message if user is not found to make it intransparent who is registered
113
            $message = $translator->trans('authenticate.success.sent_authentication_link', [], 'security');
114
            $this->displaySuccess($message);
115
        }
116
    }
117
118
    private function tryLogin(string $authenticationHash, GuardAuthenticatorHandler $guardHandler, Request $request, TranslatorInterface $translator): ?RedirectResponse
119
    {
120
        $userRepository = $this->getDoctrine()->getRepository(User::class);
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Bundle\Framework...ntroller::getDoctrine() has been deprecated: since Symfony 5.4, inject an instance of ManagerRegistry in your controller instead ( Ignorable by Annotation )

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

120
        $userRepository = /** @scrutinizer ignore-deprecated */ $this->getDoctrine()->getRepository(User::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
121
        $user = $userRepository->findOneBy(['authenticationHash' => $authenticationHash]);
122
123
        if (null !== $user) {
124
            $message = $translator->trans('authenticate.success.authentication_successful', [], 'security');
125
            $this->displaySuccess($message);
126
127
            if (!$user->getIsEmailConfirmed()) {
128
                $user->setIsEmailConfirmed(true);
129
            }
130
131
            // show email confirmed message if user was already logged in
132
            if ($this->getUser()) {
133
                $message = $translator->trans('authenticate.success.email_confirmed', [], 'security');
134
                $this->displaySuccess($message);
135
            }
136
137
            $user->generateAuthenticationHash();
138
            $this->fastSave($user);
139
140
            return $this->loginAndRedirect($user, $guardHandler, $request);
141
        } else {
142
            $message = $translator->trans('authenticate.errors.authentication_code_invalid', [], 'security');
143
            $this->displayError($message);
144
145
            return null;
146
        }
147
    }
148
149
    private function loginAndRedirect(User $user, GuardAuthenticatorHandler $guardHandler, Request $request): RedirectResponse
150
    {
151
        $userToken = new UserToken($user);
152
        $guardHandler->authenticateWithToken($userToken, $request, 'main');
153
154
        $redirectPathKey = '_security.main.target_path';
155
        if ($request->getSession()->has($redirectPathKey)) {
156
            $value = $request->getSession()->get($redirectPathKey);
157
            $request->getSession()->remove($redirectPathKey);
158
159
            return $this->redirect($value);
160
        }
161
162
        return $this->redirectToRoute('index');
163
    }
164
}
165