Completed
Push — master ( f92548...5447f3 )
by Marcel
03:46
created

ForgotPasswordController   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Test Coverage

Coverage 46.67%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 50
c 1
b 0
f 0
dl 0
loc 88
ccs 21
cts 45
cp 0.4667
rs 10
wmc 14

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getCsrfTokenMessage() 0 2 1
A isCsrfTokenFromRequestValid() 0 5 1
A change() 0 26 5
A request() 0 22 6
1
<?php
2
3
namespace App\Controller;
4
5
use App\Entity\PasswordResetToken;
6
use App\Repository\UserRepositoryInterface;
7
use App\Security\ForgotPassword\ForgotPasswordManager;
8
use App\Security\PasswordStrengthHelper;
9
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
10
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
11
use Symfony\Component\HttpFoundation\Request;
12
use Symfony\Component\Routing\Annotation\Route;
13
use Symfony\Component\Security\Csrf\CsrfToken;
14
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
15
use Symfony\Contracts\Translation\TranslatorInterface;
16
17
class ForgotPasswordController extends AbstractController {
18
19
    private const CSRF_TOKEN_ID = 'forgot_pw';
20
21
    private const CSRF_TOKEN_KEY = '_csrf_token';
22
    private const USERNAME_KEY = '_username';
23
    private const PASSWORD_KEY = '_password';
24
    private const REPEAT_PASSWORD_KEY = '_repeat_password';
25
26
    private $manager;
27
    private $csrfTokenManager;
28
    private $translator;
29
30 1
    public function __construct(ForgotPasswordManager $manager, CsrfTokenManagerInterface $csrfTokenManager, TranslatorInterface $translator) {
31 1
        $this->manager = $manager;
32 1
        $this->csrfTokenManager = $csrfTokenManager;
33 1
        $this->translator = $translator;
34 1
    }
35
36 1
    private function isCsrfTokenFromRequestValid(Request $request): bool {
37 1
        $tokenValue = $request->request->get(static::CSRF_TOKEN_KEY);
38 1
        $token = new CsrfToken(static::CSRF_TOKEN_ID, $tokenValue);
39
40 1
        return $this->csrfTokenManager->isTokenValid($token);
41
    }
42
43
    private function getCsrfTokenMessage(): string {
44
        return $this->translator->trans('Invalid CSRF token.', [], 'security');
45
    }
46
47
    /**
48
     * @Route("/forgot_pw", name="forgot_password")
49
     */
50 1
    public function request(Request $request, CsrfTokenManagerInterface $csrfTokenManager, TranslatorInterface $translator, UserRepositoryInterface $userRepository) {
51 1
        if($request->isMethod('POST')) {
52 1
            $username = $request->request->get('_username');
53 1
            $user = $userRepository->findOneByUsername($username);
54
55 1
            if($this->isCsrfTokenFromRequestValid($request) !== true) {
56
                $this->addFlash('error', $this->getCsrfTokenMessage());
57 1
            } else if ($username === null) {
58
                $this->addFlash('error', 'forgot_pw.request.username_empty');
59 1
            } else if($user !== null && $this->manager->canResetPassword($user) !== true) {
60
                $this->addFlash('error', 'forgot_pw.request.cannot_change');
61
                return $this->redirectToRoute('login');
62
            } else {
63 1
                $this->manager->resetPassword($user);
64 1
                $this->addFlash('success', 'forgot_pw.request.success');
65
66 1
                return $this->redirectToRoute('login');
67
            }
68
        }
69
70 1
        return $this->render('auth/forgot_pw.html.twig', [
71 1
            'csrfTokenId' => static::CSRF_TOKEN_ID
72
        ]);
73
    }
74
75
    /**
76
     * @Route("/forgot_pw/{token}", name="change_password")
77
     * @ParamConverter("token", options={"mapping": {"token": "token"}})
78
     */
79
    public function change(PasswordResetToken $token, Request $request, PasswordStrengthHelper $passwordStrengthHelper) {
80
        if($request->isMethod('POST')) {
81
            $password = $request->request->get('_password');
82
            $repeatPassword = $request->request->get('_repeat_password');
83
84
            $violations = $passwordStrengthHelper->validatePassword($password);
85
86
            if($this->isCsrfTokenFromRequestValid($request) !== true) {
87
                $this->addFlash('error', $this->getCsrfTokenMessage());
88
            } else if($violations->count() > 0) {
89
                // flashes are added in twig template
90
            } else if($password !== $repeatPassword) {
91
                $this->addFlash('error', 'forgot_pw.change.password_error');
92
            } else {
93
                $this->manager->updatePassword($token, $password);
94
                $this->addFlash('success', 'forgot_pw.change.success');
95
96
                return $this->redirectToRoute('login');
97
            }
98
        }
99
100
        return $this->render('auth/change_pw.twig', [
101
            'user' => $token->getUser(),
102
            'csrfTokenId' => static::CSRF_TOKEN_ID,
103
            'token' => $token,
104
            'violations' => $violations ?? null
105
        ]);
106
    }
107
}