Passed
Pull Request — main (#557)
by Johan
10:46 queued 05:30
created

BootstrapGsspSecondFactorCommand::__invoke()   B

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