BootstrapGsspSecondFactorCommand::__invoke()   B
last analyzed

Complexity

Conditions 8
Paths 27

Size

Total Lines 115
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 79
nc 27
nop 7
dl 0
loc 115
rs 7.2137
c 0
b 0
f 0

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 2020 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\StepupMiddleware\MiddlewareBundle\Console\Command;
20
21
use Exception;
22
use Ramsey\Uuid\Uuid;
23
use Surfnet\Stepup\Identity\Value\Institution;
24
use Surfnet\Stepup\Identity\Value\NameId;
25
use Surfnet\StepupMiddleware\MiddlewareBundle\Service\BootstrapCommandService;
26
use Surfnet\StepupMiddleware\MiddlewareBundle\Service\TransactionHelper;
0 ignored issues
show
Bug introduced by
The type Surfnet\StepupMiddleware...rvice\TransactionHelper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use Symfony\Component\Console\Attribute\Argument;
28
use Symfony\Component\Console\Attribute\AsCommand;
29
use Symfony\Component\Console\Output\OutputInterface;
30
31
#[AsCommand(
32
    name: 'middleware:bootstrap:gssp',
33
    description: 'Creates a Generic SAML Second Factor (GSSF) second factor for a specified user'
34
)]
35
final class BootstrapGsspSecondFactorCommand
36
{
37
    public function __construct(private readonly BootstrapCommandService $bootstrapService, private readonly TransactionHelper $transactionHelper)
38
    {
39
    }
40
41
    /**
42
     * @SuppressWarnings("PHPMD.ExcessiveMethodLength") Method length could be reduced by deconstructing the bootstrapping
43
     * of the required data and the vetting of the GSSP
44
     */
45
    public function __invoke(
46
        #[Argument(description: 'The NameID of the identity to create', name: 'name-id')]
47
        string $nameId,
48
        #[Argument(description: 'The institution of the identity to create', name: 'institution')]
49
        string $institution,
50
        #[Argument(description: 'The GSSP token type as defined in the GSSP config, for example tiqr or webauthn', name: 'gssp-token-type')]
51
        string $gsspTokenType,
52
        #[Argument(description: 'The identifier of the token as registered at the GSSP', name: 'gssp-token-identifier')]
53
        string $gsspTokenIdentifier,
54
        #[Argument(description: 'Valid arguments: unverified, verified, vetted', name: 'registration-status')]
55
        string $registrationStatus,
56
        #[Argument(description: 'The id of the vetting actor', name: 'actor-id')]
57
        string $actorId,
58
        OutputInterface $output
59
    ): int {
60
        $this->bootstrapService->validRegistrationStatus($registrationStatus);
61
62
        $nameId = new NameId($nameId);
63
        $institutionText = $institution;
64
        $institution = new Institution($institutionText);
65
        $mailVerificationRequired = $this->bootstrapService->requiresMailVerification($institutionText);
66
        $tokenType = $gsspTokenType;
67
        $tokenIdentifier = $gsspTokenIdentifier;
68
69
        $this->bootstrapService->enrichEventMetadata($actorId);
70
        if (!$this->bootstrapService->identityExists($nameId, $institution)) {
71
            $output->writeln(
72
                sprintf(
73
                    '<error>An identity with name ID "%s" from institution "%s" does not exist, create it first.</error>',
74
                    $nameId->getNameId(),
75
                    $institution->getInstitution(),
76
                ),
77
            );
78
79
            return 1;
80
        }
81
        $identity = $this->bootstrapService->getIdentity($nameId, $institution);
82
        $output->writeln(
83
            sprintf(
84
                '<comment>Adding a %s %s GSSP token for %s</comment>',
85
                $registrationStatus,
86
                $tokenType,
87
                $identity->commonName,
88
            ),
89
        );
90
        $this->transactionHelper->beginTransaction();
91
        $secondFactorId = Uuid::uuid4()->toString();
92
93
        try {
94
            switch ($registrationStatus) {
95
                case "unverified":
96
                    $output->writeln(sprintf('<comment>Creating an unverified %s token</comment>', $tokenType));
97
                    $this->bootstrapService->proveGsspPossession(
98
                        $secondFactorId,
99
                        $identity,
100
                        $tokenType,
101
                        $tokenIdentifier,
102
                    );
103
                    break;
104
                case "verified":
105
                    $output->writeln(sprintf('<comment>Creating an unverified %s token</comment>', $tokenType));
106
                    $this->bootstrapService->proveGsspPossession(
107
                        $secondFactorId,
108
                        $identity,
109
                        $tokenType,
110
                        $tokenIdentifier,
111
                    );
112
                    if ($mailVerificationRequired) {
113
                        $output->writeln(sprintf('<comment>Creating an verified %s token</comment>', $tokenType));
114
                        $this->bootstrapService->verifyEmail($identity, $tokenType);
115
                    }
116
                    break;
117
                case "vetted":
118
                    $output->writeln(sprintf('<comment>Creating an unverified %s token</comment>', $tokenType));
119
                    $this->bootstrapService->proveGsspPossession(
120
                        $secondFactorId,
121
                        $identity,
122
                        $tokenType,
123
                        $tokenIdentifier,
124
                    );
125
                    if ($mailVerificationRequired) {
126
                        $output->writeln(sprintf('<comment>Creating an verified %s token</comment>', $tokenType));
127
                        $this->bootstrapService->verifyEmail($identity, $tokenType);
128
                    }
129
                    $output->writeln(sprintf('<comment>Vetting the verified %s token</comment>', $tokenType));
130
                    $this->bootstrapService->vetSecondFactor(
131
                        $tokenType,
132
                        $actorId,
133
                        $identity,
134
                        $secondFactorId,
135
                        $tokenIdentifier,
136
                    );
137
                    break;
138
            }
139
            $this->transactionHelper->finishTransaction();
140
        } catch (Exception $e) {
141
            $output->writeln(
142
                sprintf(
143
                    '<error>An Error occurred when trying to bootstrap the %s token: "%s"</error>',
144
                    $tokenType,
145
                    $e->getMessage(),
146
                ),
147
            );
148
            $this->transactionHelper->rollback();
149
            return 1;
150
        }
151
        $output->writeln(
152
            sprintf(
153
                '<info>Successfully %s %s second factor with UUID %s</info>',
154
                $registrationStatus,
155
                $tokenType,
156
                $secondFactorId,
157
            ),
158
        );
159
        return 0;
160
    }
161
}
162