SmsController::provePossessionAction()   B
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 51

Duplication

Lines 13
Ratio 25.49 %

Importance

Changes 0
Metric Value
dl 13
loc 51
rs 8.1357
c 0
b 0
f 0
cc 7
nc 6
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Copyright 2014 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupRa\RaBundle\Controller\Vetting;
20
21
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
22
use Surfnet\StepupBundle\Command\SendSmsChallengeCommand;
23
use Surfnet\StepupBundle\Command\VerifyPhoneNumberCommand;
24
use Surfnet\StepupBundle\Command\VerifyPossessionOfPhoneCommand;
25
use Surfnet\StepupBundle\Value\PhoneNumber\InternationalPhoneNumber;
26
use Surfnet\StepupRa\RaBundle\Form\Type\SendSmsChallengeType;
27
use Surfnet\StepupRa\RaBundle\Form\Type\VerifyPhoneNumberType;
28
use Surfnet\StepupRa\RaBundle\Service\VettingService;
29
use Symfony\Component\Form\FormError;
30
use Symfony\Component\Form\SubmitButton;
31
use Symfony\Component\HttpFoundation\Request;
32
use Symfony\Component\HttpFoundation\Response;
33
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
34
35
class SmsController extends SecondFactorController
36
{
37
    /**
38
     * @Template
39
     * @param Request $request
40
     * @param string $procedureId
41
     * @return array|Response
42
     */
43
    public function sendChallengeAction(Request $request, $procedureId)
44
    {
45
        $this->assertSecondFactorEnabled('sms');
46
47
        $this->denyAccessUnlessGranted(['ROLE_RA']);
48
49
        $logger = $this->get('ra.procedure_logger')->forProcedure($procedureId);
50
        $logger->notice('Received request for Send SMS Challenge page');
51
52 View Code Duplication
        if (!$this->getVettingService()->hasProcedure($procedureId)) {
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...
53
            $logger->notice(sprintf('Vetting procedure "%s" not found', $procedureId));
54
            throw new NotFoundHttpException(sprintf('Vetting procedure "%s" not found', $procedureId));
55
        }
56
57
        $command = new SendSmsChallengeCommand();
58
        $form = $this->createForm(SendSmsChallengeType::class, $command)->handleRequest($request);
59
60
        $vettingService = $this->getVettingService();
61
        $phoneNumber = InternationalPhoneNumber::fromStringFormat(
62
            $vettingService->getSecondFactorIdentifier($procedureId)
63
        );
64
65
        $otpRequestsRemaining = $vettingService->getSmsOtpRequestsRemainingCount();
66
        $maximumOtpRequests = $vettingService->getSmsMaximumOtpRequestsCount();
67
        $viewVariables = ['otpRequestsRemaining' => $otpRequestsRemaining, 'maximumOtpRequests' => $maximumOtpRequests];
68
69
        if (!$form->isSubmitted() || !$form->isValid()) {
70
            $logger->notice('Form has not been submitted, not sending SMS, rendering Send SMS Challenge page');
71
72
            return array_merge(
73
                $viewVariables,
74
                ['phoneNumber' => $phoneNumber, 'form' => $form->createView()]
75
            );
76
        }
77
78
        $logger->notice('Sending of SMS Challenge has been requested, sending OTP via SMS');
79
        if ($vettingService->sendSmsChallenge($procedureId, $command)) {
80
            $logger->notice(
81
                'SMS Challenge successfully sent, redirecting to Proof of Possession page to verify challenge'
82
            );
83
84
            return $this->redirectToRoute('ra_vetting_sms_prove_possession', ['procedureId' => $procedureId]);
85
        }
86
87
        $this->addFlash('error', 'ra.sms_send_challenge.send_sms_challenge_failed');
88
89
        $logger->notice(
90
            'SMS Challenge could not be sent, added error to page to notify user and re-rendering send challenge page'
91
        );
92
93
        return array_merge(
94
            $viewVariables,
95
            ['phoneNumber' => $phoneNumber, 'form' => $form->createView()]
96
        );
97
    }
98
99
    /**
100
     * @Template
101
     * @param Request $request
102
     * @param string $procedureId
103
     * @return array|Response
104
     */
105
    public function provePossessionAction(Request $request, $procedureId)
106
    {
107
        $this->assertSecondFactorEnabled('sms');
108
        $this->denyAccessUnlessGranted(['ROLE_RA']);
109
        $logger = $this->get('ra.procedure_logger')->forProcedure($procedureId);
110
111
        $logger->notice('Received request for Proof of Possession of SMS Second Factor page');
112
113
        $command = new VerifyPossessionOfPhoneCommand();
114
        $form = $this
115
            ->createForm(VerifyPhoneNumberType::class, $command, ['procedureId' => $procedureId])
116
            ->handleRequest($request);
117
118
        /** @var SubmitButton $cancelButton */
119
        $cancelButton = $form->get('cancel');
120 View Code Duplication
        if ($cancelButton->isClicked()) {
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...
121
            $this->getVettingService()->cancelProcedure($procedureId);
122
            $this->addFlash('info', $this->get('translator')->trans('ra.vetting.flash.cancelled'));
123
124
            return $this->redirectToRoute('ra_vetting_search');
125
        }
126
127 View Code Duplication
        if (!$form->isSubmitted() || !$form->isValid()) {
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...
128
            $logger->notice(
129
                'SMS OTP was not submitted through form, rendering Proof of Possession of SMS Second Factor page'
130
            );
131
132
            return ['form' => $form->createView()];
133
        }
134
135
        $logger->notice('SMS OTP has been entered, attempting to verify Proof of Possession');
136
        $verification = $this->getVettingService()->verifyPhoneNumber($procedureId, $command);
137
        if ($verification->wasSuccessful()) {
138
            $logger->notice('SMS OTP was valid, Proof of Possession given, redirecting to Identity Vetting page');
139
140
            return $this->redirectToRoute(
141
                'ra_vetting_verify_identity',
142
                ['procedureId' => $procedureId]
143
            );
144
        } elseif ($verification->didOtpExpire()) {
145
            $this->addFlash('error', 'ra.prove_phone_possession.challenge_expired');
146
        } elseif ($verification->wasAttemptedTooManyTimes()) {
147
            $this->addFlash('error', 'ra.prove_phone_possession.too_many_attempts');
148
        } else {
149
            $this->addFlash('error', 'ra.prove_phone_possession.challenge_response_incorrect');
150
        }
151
152
        $logger->notice('SMS OTP verification failed - Proof of Possession denied, added error to form');
153
154
        return ['form' => $form->createView()];
155
    }
156
157
    /**
158
     * @return VettingService
159
     */
160
    private function getVettingService()
161
    {
162
        return $this->get('ra.service.vetting');
163
    }
164
}
165