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); |
|
|
|
|
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); |
|
|
|
|
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); |
|
|
|
|
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
|
|
|
|
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.