Passed
Pull Request — main (#308)
by Paul
16:16 queued 09:55
created

SecondFactorController::revoke()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 54
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 35
c 1
b 0
f 0
nc 5
nop 3
dl 0
loc 54
rs 8.7377

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
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;
22
23
use LogicException;
24
use Surfnet\StepupBundle\DateTime\RegistrationExpirationHelper;
25
use Psr\Log\LoggerInterface;
26
use Surfnet\StepupBundle\Service\SecondFactorTypeService;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Command\RevokeCommand;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\RevokeSecondFactorType;
29
use Surfnet\StepupSelfService\SelfServiceBundle\Service\AuthorizationService;
30
use Surfnet\StepupSelfService\SelfServiceBundle\Service\InstitutionConfigurationOptionsService;
31
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SecondFactorService;
32
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\RecoveryTokenService;
33
use Symfony\Bridge\Twig\Attribute\Template;
34
use Symfony\Component\HttpFoundation\Request;
35
use Symfony\Component\HttpFoundation\Response;
36
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
37
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
38
use Symfony\Component\Routing\Attribute\Route;
39
40
class SecondFactorController extends Controller
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class SecondFactorController
Loading history...
41
{
42
    public function __construct(
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
43
        private readonly LoggerInterface $logger,
44
        private readonly InstitutionConfigurationOptionsService $configurationOptionsService,
45
        private readonly RecoveryTokenService    $recoveryTokenService,
46
        private readonly AuthorizationService    $authorizationService,
47
        private readonly SecondFactorTypeService $secondFactorTypeService,
48
        private readonly SecondFactorService $secondFactorService,
49
        private readonly RegistrationExpirationHelper $registrationExpirationHelper,
50
    ) {
51
        parent::__construct($logger, $configurationOptionsService);
52
    }
53
    #[Template('second_factor/list.html.twig')]
54
    #[Route(path: '/overview', name: 'ss_second_factor_list', methods:  ['GET'])]
55
    public function list(): array
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function list()
Loading history...
56
    {
57
        $identity = $this->getIdentity();
58
        $institution = $this->getIdentity()->institution;
59
        $options = $this->configurationOptionsService
60
            ->getInstitutionConfigurationOptionsFor($institution);
61
62
        // Get all available second factors from the config.
63
        $allSecondFactors = $this->getParameter('ss.enabled_second_factors');
64
65
        $secondFactors = $this->secondFactorService->getSecondFactorsForIdentity(
66
            $identity,
67
            $allSecondFactors,
68
            $options->allowedSecondFactors,
69
            $options->numberOfTokensPerIdentity
70
        );
71
72
        $recoveryTokensAllowed = $this->authorizationService->mayRegisterRecoveryTokens($identity);
73
        $selfAssertedTokenRegistration = $options->allowSelfAssertedTokens === true && $recoveryTokensAllowed;
74
        $hasRemainingTokenTypes = $this->recoveryTokenService->getRemainingTokenTypes($identity) !== [];
75
        $recoveryTokens = [];
76
        if ($selfAssertedTokenRegistration && $recoveryTokensAllowed) {
77
            $recoveryTokens = $this->recoveryTokenService->getRecoveryTokensForIdentity($identity);
78
        }
79
        $loaService = $this->secondFactorTypeService;
80
81
        return [
82
            'loaService' => $loaService,
83
            'email' => $identity->email,
84
            'maxNumberOfTokens' => $secondFactors->getMaximumNumberOfRegistrations(),
85
            'registrationsLeft' => $secondFactors->getRegistrationsLeft(),
86
            'unverifiedSecondFactors' => $secondFactors->unverified,
87
            'verifiedSecondFactors' => $secondFactors->verified,
88
            'vettedSecondFactors' => $secondFactors->vetted,
89
            'availableSecondFactors' => $secondFactors->available,
90
            'expirationHelper' => $this->registrationExpirationHelper,
91
            'selfAssertedTokenRegistration' => $selfAssertedTokenRegistration,
92
            'recoveryTokens' => $recoveryTokens,
93
            'hasRemainingRecoveryTokens' => $hasRemainingTokenTypes,
94
        ];
95
    }
96
97
    #[Template('second_factor/revoke.html.twig')]
98
    #[Route(
99
        path: '/second-factor/{state}/{secondFactorId}/revoke',
100
        name: 'ss_second_factor_revoke',
101
        requirements: ['state' => '^(unverified|verified|vetted)$'],
102
        methods: ['GET','POST']
103
    )]
104
    public function revoke(Request $request, string $state, string $secondFactorId): array|Response
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function revoke()
Loading history...
105
    {
106
        $identity = $this->getIdentity();
107
108
        if (!$this->secondFactorService->identityHasSecondFactorOfStateWithId($identity->id, $state, $secondFactorId)) {
0 ignored issues
show
Bug introduced by
It seems like $identity->id can also be of type null; however, parameter $identityId of Surfnet\StepupSelfServic...ndFactorOfStateWithId() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

108
        if (!$this->secondFactorService->identityHasSecondFactorOfStateWithId(/** @scrutinizer ignore-type */ $identity->id, $state, $secondFactorId)) {
Loading history...
109
            $this->logger->error(sprintf(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
110
                'Identity "%s" tried to revoke "%s" second factor "%s", but does not own that second factor',
111
                $identity->id,
112
                $state,
113
                $secondFactorId
114
            ));
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
115
            throw new NotFoundHttpException();
116
        }
117
118
        $secondFactor = match ($state) {
119
            'unverified' => $this->secondFactorService->findOneUnverified($secondFactorId),
120
            'verified' => $this->secondFactorService->findOneVerified($secondFactorId),
121
            'vetted' => $this->secondFactorService->findOneVetted($secondFactorId),
122
            default => throw new LogicException('There are no other types of second factor.'),
123
        };
124
125
        if ($secondFactor === null) {
126
            throw new NotFoundHttpException(
127
                sprintf("No %s second factor with id '%s' exists.", $state, $secondFactorId)
128
            );
129
        }
130
131
        $command = new RevokeCommand();
132
        $command->identity = $identity;
133
        $command->secondFactor = $secondFactor;
134
135
        $form = $this->createForm(RevokeSecondFactorType::class, $command)->handleRequest($request);
136
137
        if ($form->isSubmitted() && $form->isValid()) {
138
            
139
            if ($this->secondFactorService->revoke($command)) {
140
                $this->addFlash('success', 'ss.second_factor.revoke.alert.revocation_successful');
141
            } else {
142
                $this->addFlash('error', 'ss.second_factor.revoke.alert.revocation_failed');
143
            }
144
145
            return $this->redirectToRoute('ss_second_factor_list');
146
        }
147
148
        return [
149
            'form'         => $form->createView(),
150
            'secondFactor' => $secondFactor,
151
        ];
152
    }
153
}
154