Passed
Pull Request — main (#308)
by Michiel
14:02 queued 06:58
created

SmsController::sendChallenge()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 42
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 27
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 42
rs 9.1768
1
<?php
2
3
declare(strict_types = 1);
4
5
/**
6
 * Copyright 2014 SURFnet bv
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @link tag in file comment
Loading history...
20
21
namespace Surfnet\StepupSelfService\SelfServiceBundle\Controller\Registration;
22
23
use Psr\Log\LoggerInterface;
24
use Surfnet\StepupSelfService\SelfServiceBundle\Service\InstitutionConfigurationOptionsService;
25
use Symfony\Bridge\Twig\Attribute\Template;
26
use Surfnet\StepupSelfService\SelfServiceBundle\Command\SendSmsChallengeCommand;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Command\VerifySmsChallengeCommand;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Controller\Controller;
29
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\SendSmsChallengeType;
30
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\VerifySmsChallengeType;
31
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SmsSecondFactorService;
32
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SmsSecondFactorServiceInterface;
33
use Symfony\Component\HttpFoundation\RedirectResponse;
34
use Symfony\Component\HttpFoundation\Request;
35
use Symfony\Component\HttpFoundation\RequestStack;
36
use Symfony\Component\Routing\Attribute\Route;
37
38
class SmsController extends Controller
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class SmsController
Loading history...
39
{
40
    public function __construct(
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
41
        LoggerInterface                         $logger,
42
        InstitutionConfigurationOptionsService  $configurationOptionsService,
43
        private readonly SmsSecondFactorService $smsSecondFactorService,
44
        private readonly RequestStack $requestStack,
45
    ) {
46
        parent::__construct($logger, $configurationOptionsService);
47
    }
48
49
    #[Template('registration/sms/send_challenge.html.twig')]
50
    #[Route(
51
        path: '/registration/sms/send-challenge',
52
        name: 'ss_registration_sms_send_challenge',
53
        methods: ['GET','POST'],
54
    )]
55
    public function sendChallenge(Request $request): array|RedirectResponse
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function sendChallenge()
Loading history...
56
    {
57
        $this->assertSecondFactorEnabled('sms');
58
59
        $identity = $this->getIdentity();
60
61
        $command = new SendSmsChallengeCommand();
62
        $form = $this->createForm(SendSmsChallengeType::class, $command)->handleRequest($request);
63
64
        $otpRequestsRemaining = $this->smsSecondFactorService->getOtpRequestsRemainingCount(
65
            SmsSecondFactorServiceInterface::REGISTRATION_SECOND_FACTOR_ID
66
        );
67
        $maximumOtpRequests = $this->smsSecondFactorService->getMaximumOtpRequestsCount();
68
        $viewVariables = [
69
            'otpRequestsRemaining' => $otpRequestsRemaining,
70
            'maximumOtpRequests' => $maximumOtpRequests,
71
            'verifyEmail' => $this->emailVerificationIsRequired(),
72
        ];
73
74
        if ($form->isSubmitted() && $form->isValid()) {
75
            $command->identity = $identity->id;
76
            $command->institution = $identity->institution;
77
78
            if ($otpRequestsRemaining === 0) {
79
                $this->addFlash('error', 'ss.prove_phone_possession.challenge_request_limit_reached');
80
                return ['form' => $form->createView(), ...$viewVariables];
81
            }
82
83
            if ($this->smsSecondFactorService->sendChallenge($command)) {
84
                return $this->redirect($this->generateUrl('ss_registration_sms_prove_possession'));
85
            } else {
86
                $this->addFlash('error', 'ss.prove_phone_possession.send_sms_challenge_failed');
87
            }
88
        }
89
90
        return ['form' => $form->createView(), ...$viewVariables];
91
    }
92
93
    #[Template('registration/sms/prove_possession.html.twig')]
94
    #[Route(
95
        path: '/registration/sms/prove-possession',
96
        name: 'ss_registration_sms_prove_possession',
97
        methods: ['GET','POST'],
98
    )]
99
    public function provePossession(Request $request): RedirectResponse|array
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function provePossession()
Loading history...
100
    {
101
        $this->assertSecondFactorEnabled('sms');
102
103
        if (!$this->smsSecondFactorService->hasSmsVerificationState(SmsSecondFactorServiceInterface::REGISTRATION_SECOND_FACTOR_ID)) {
104
            $this->addFlash('notice', 'ss.registration.sms.alert.no_verification_state');
105
106
            return $this->redirectToRoute('ss_registration_sms_send_challenge');
107
        }
108
109
        $identity = $this->getIdentity();
110
111
        $command = new VerifySmsChallengeCommand();
112
        $command->identity = $identity->id;
113
114
        $form = $this->createForm(VerifySmsChallengeType::class, $command)->handleRequest($request);
115
116
        if ($form->isSubmitted() && $form->isValid()) {
117
            $result = $this->smsSecondFactorService->provePossession($command);
118
119
            if ($result->isSuccessful()) {
120
                $this->smsSecondFactorService->clearSmsVerificationState(SmsSecondFactorServiceInterface::REGISTRATION_SECOND_FACTOR_ID);
121
122
                if ($this->emailVerificationIsRequired()) {
123
                    return $this->redirectToRoute(
124
                        'ss_registration_email_verification_email_sent',
125
                        ['secondFactorId' => $result->getSecondFactorId()]
126
                    );
127
                } else {
128
                    return $this->redirectToRoute(
129
                        'ss_second_factor_vetting_types',
130
                        ['secondFactorId' => $result->getSecondFactorId()]
131
                    );
132
                }
133
            } elseif ($result->wasIncorrectChallengeResponseGiven()) {
134
                $this->addFlash('error', 'ss.prove_phone_possession.incorrect_challenge_response');
135
            } elseif ($result->hasChallengeExpired()) {
136
                $this->addFlash('error', 'ss.prove_phone_possession.challenge_expired');
137
            } elseif ($result->wereTooManyAttemptsMade()) {
138
                $this->addFlash('error', 'ss.prove_phone_possession.too_many_attempts');
139
            } else {
140
                $this->addFlash('error', 'ss.prove_phone_possession.proof_of_possession_failed');
141
            }
142
        }
143
144
        return [
145
            'form' => $form->createView(),
146
            'verifyEmail' => $this->emailVerificationIsRequired(),
147
        ];
148
    }
149
}
150