Completed
Push — feature/ra-optional-vetting ( 18d375...2f991f )
by
unknown
02:10
created

VettingService::startGssfVerification()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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\Service;
20
21
use DateInterval;
22
use RuntimeException;
23
use Surfnet\StepupBundle\Command\SendSmsChallengeCommand;
24
use Surfnet\StepupBundle\Command\VerifyPossessionOfPhoneCommand;
25
use Surfnet\StepupBundle\Service\SecondFactorTypeService;
26
use Surfnet\StepupBundle\Service\SmsSecondFactor\OtpVerification;
27
use Surfnet\StepupBundle\Service\SmsSecondFactorServiceInterface;
28
use Surfnet\StepupBundle\Value\PhoneNumber\InternationalPhoneNumber;
29
use Surfnet\StepupBundle\Value\SecondFactorType;
30
use Surfnet\StepupMiddlewareClientBundle\Identity\Service\SecondFactorService;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Surfnet\StepupRa\RaBundl...ice\SecondFactorService.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
31
use Surfnet\StepupMiddlewareClientBundle\Identity\Command\VetSecondFactorCommand;
32
use Surfnet\StepupRa\RaBundle\Command\CreateU2fSignRequestCommand;
33
use Surfnet\StepupRa\RaBundle\Command\StartVettingProcedureCommand;
34
use Surfnet\StepupRa\RaBundle\Command\VerifyIdentityCommand;
35
use Surfnet\StepupRa\RaBundle\Command\VerifyU2fAuthenticationCommand;
36
use Surfnet\StepupRa\RaBundle\Command\VerifyYubikeyPublicIdCommand;
37
use Surfnet\StepupRa\RaBundle\Exception\DomainException;
38
use Surfnet\StepupRa\RaBundle\Exception\InvalidArgumentException;
39
use Surfnet\StepupRa\RaBundle\Exception\LoaTooLowException;
40
use Surfnet\StepupRa\RaBundle\Exception\UnknownVettingProcedureException;
41
use Surfnet\StepupRa\RaBundle\Repository\VettingProcedureRepository;
42
use Surfnet\StepupRa\RaBundle\Service\Gssf\VerificationResult as GssfVerificationResult;
43
use Surfnet\StepupRa\RaBundle\Service\U2f\AuthenticationVerificationResult;
44
use Surfnet\StepupRa\RaBundle\Service\U2f\SignRequestCreationResult;
45
use Surfnet\StepupRa\RaBundle\Value\DateTime;
46
use Surfnet\StepupRa\RaBundle\VettingProcedure;
47
use Surfnet\StepupU2fBundle\Dto\SignRequest;
48
use Surfnet\StepupU2fBundle\Dto\SignResponse;
49
use Symfony\Component\Translation\TranslatorInterface;
50
51
/**
52
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
53
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
54
 */
55
class VettingService
56
{
57
    const REGISTRATION_CODE_EXPIRED_ERROR =
58
        'Surfnet\Stepup\Exception\DomainException: Cannot vet second factor, the registration window is closed.';
59
60
    /**
61
     * @var \Surfnet\StepupBundle\Service\SmsSecondFactorServiceInterface
62
     */
63
    private $smsSecondFactorService;
64
65
    /**
66
     * @var \Surfnet\StepupRa\RaBundle\Service\YubikeySecondFactorService
67
     */
68
    private $yubikeySecondFactorService;
69
70
    /**
71
     * @var \Surfnet\StepupRa\RaBundle\Service\GssfService
72
     */
73
    private $gssfService;
74
75
    /**
76
     * @var \Surfnet\StepupRa\RaBundle\Service\U2fService
77
     */
78
    private $u2fService;
79
80
    /**
81
     * @var \Surfnet\StepupRa\RaBundle\Service\CommandService
82
     */
83
    private $commandService;
84
85
    /**
86
     * @var \Surfnet\StepupRa\RaBundle\Repository\VettingProcedureRepository
87
     */
88
    private $vettingProcedureRepository;
89
90
    /**
91
     * @var \Symfony\Component\Translation\TranslatorInterface
92
     */
93
    private $translator;
94
95
    /**
96
     * @var \Surfnet\StepupRa\RaBundle\Service\IdentityService
97
     */
98
    private $identityService;
99
100
    /**
101
     * @var \Surfnet\StepupBundle\Service\SecondFactorTypeService
102
     */
103
    private $secondFactorTypeService;
104
105
    /**
106
     * @var SecondFactorService
107
     */
108
    private $secondFactorService;
109
110
    public function __construct(
111
        SmsSecondFactorServiceInterface $smsSecondFactorService,
112
        YubikeySecondFactorService $yubikeySecondFactorService,
113
        GssfService $gssfService,
114
        U2fService $u2fService,
115
        CommandService $commandService,
116
        VettingProcedureRepository $vettingProcedureRepository,
117
        TranslatorInterface $translator,
118
        IdentityService $identityService,
119
        SecondFactorTypeService $secondFactorTypeService,
120
        SecondFactorService $secondFactorService
121
    ) {
122
        $this->smsSecondFactorService = $smsSecondFactorService;
123
        $this->yubikeySecondFactorService = $yubikeySecondFactorService;
124
        $this->gssfService = $gssfService;
125
        $this->u2fService = $u2fService;
126
        $this->commandService = $commandService;
127
        $this->vettingProcedureRepository = $vettingProcedureRepository;
128
        $this->translator = $translator;
129
        $this->identityService = $identityService;
130
        $this->secondFactorTypeService = $secondFactorTypeService;
131
        $this->secondFactorService = $secondFactorService;
132
    }
133
134
    /**
135
     * @param StartVettingProcedureCommand $command
136
     * @return bool
137
     */
138
    public function isLoaSufficientToStartProcedure(StartVettingProcedureCommand $command)
139
    {
140
        $secondFactorType = new SecondFactorType($command->secondFactor->type);
141
142
        return $this->secondFactorTypeService->isSatisfiedBy($secondFactorType, $command->authorityLoa);
143
    }
144
145
    /**
146
     * @param StartVettingProcedureCommand $command
147
     * @return bool
148
     */
149
    public function isExpiredRegistrationCode(StartVettingProcedureCommand $command)
150
    {
151
        return DateTime::now()->comesAfter(
152
            new DateTime(
153
                $command->secondFactor->registrationRequestedAt
154
                    ->add(new DateInterval('P14D'))
155
                    ->setTime(23, 59, 59)
156
            )
157
        );
158
    }
159
160
    /**
161
     * @param $procedureId
162
     * @param StartVettingProcedureCommand $command
163
     * @return bool
164
     */
165
    public function provePossessionImplicitly($procedureId, StartVettingProcedureCommand $command)
166
    {
167
        $result = $this->secondFactorService->getVerifiedSkipVetting($command->secondFactor->id);
168
        if ($result) {
169
            $procedure = $this->getProcedure($procedureId);
170
171
            $procedure->verifySecondFactorIdentifier($command->secondFactor->secondFactorIdentifier);
172
173
            $this->vettingProcedureRepository->store($procedure);
0 ignored issues
show
Bug introduced by
It seems like $procedure defined by $this->getProcedure($procedureId) on line 169 can be null; however, Surfnet\StepupRa\RaBundl...dureRepository::store() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
174
175
            return true;
176
        }
177
178
        return false;
179
    }
180
181
    /**
182
     * @param StartVettingProcedureCommand $command
183
     * @return string The procedure ID.
184
     */
185
    public function startProcedure(StartVettingProcedureCommand $command)
186
    {
187
        $this->smsSecondFactorService->clearSmsVerificationState();
188
189
        if (!$this->isLoaSufficientToStartProcedure($command)) {
190
            throw new LoaTooLowException(
191
                sprintf(
192
                    "Registration authority has LoA '%s', which is not enough to allow vetting of a '%s' second factor",
193
                    $command->authorityLoa,
194
                    $command->secondFactor->type
195
                )
196
            );
197
        }
198
199
        $procedure = VettingProcedure::start(
200
            $command->secondFactor->id,
201
            $command->authorityId,
202
            $command->registrationCode,
203
            $command->secondFactor
204
        );
205
206
        $this->vettingProcedureRepository->store($procedure);
207
208
        return $procedure->getId();
209
    }
210
211
    /**
212
     * @param string $procedureId
213
     * @throws UnknownVettingProcedureException
214
     */
215 View Code Duplication
    public function cancelProcedure($procedureId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
216
    {
217
        if (!is_string($procedureId)) {
218
            throw InvalidArgumentException::invalidType('string', 'procedureId', $procedureId);
219
        }
220
221
        $procedure = $this->vettingProcedureRepository->retrieve($procedureId);
222
223
        if (!$procedure) {
224
            throw new UnknownVettingProcedureException(
225
                sprintf("No vetting procedure with id '%s' is known.", $procedureId)
226
            );
227
        }
228
229
        $this->vettingProcedureRepository->remove($procedureId);
230
    }
231
232
    /**
233
     * @return int
234
     */
235
    public function getSmsOtpRequestsRemainingCount()
236
    {
237
        return $this->smsSecondFactorService->getOtpRequestsRemainingCount();
238
    }
239
240
    /**
241
     * @return int
242
     */
243
    public function getSmsMaximumOtpRequestsCount()
244
    {
245
        return $this->smsSecondFactorService->getMaximumOtpRequestsCount();
246
    }
247
248
    /**
249
     * @param string $procedureId
250
     * @param SendSmsChallengeCommand $command
251
     * @return bool
252
     * @throws UnknownVettingProcedureException
253
     * @throws RuntimeException
254
     */
255
    public function sendSmsChallenge($procedureId, SendSmsChallengeCommand $command)
256
    {
257
        $procedure = $this->getProcedure($procedureId);
258
259
        $phoneNumber = InternationalPhoneNumber::fromStringFormat(
260
            $procedure->getSecondFactor()->secondFactorIdentifier
261
        );
262
263
        $identity = $this->identityService->findById($procedure->getSecondFactor()->identityId);
264
265
        if (!$identity) {
266
            throw new RuntimeException("Second factor is coupled to an identity that doesn't exist");
267
        }
268
269
        $command->phoneNumber = $phoneNumber;
270
        $command->body        = $this->translator->trans('ra.vetting.sms.challenge_body', [], 'messages', $identity->preferredLocale);
271
        $command->identity    = $procedure->getSecondFactor()->identityId;
272
        $command->institution = $procedure->getSecondFactor()->institution;
273
274
        return $this->smsSecondFactorService->sendChallenge($command);
275
    }
276
277
    /**
278
     * @param string                   $procedureId
279
     * @param VerifyPossessionOfPhoneCommand $command
280
     * @return OtpVerification
281
     * @throws UnknownVettingProcedureException
282
     * @throws DomainException
283
     */
284
    public function verifyPhoneNumber($procedureId, VerifyPossessionOfPhoneCommand $command)
285
    {
286
        $procedure = $this->getProcedure($procedureId);
287
288
        $verification = $this->smsSecondFactorService->verifyPossession($command);
289
290
        if (!$verification->wasSuccessful()) {
291
            return $verification;
292
        }
293
294
        $procedure->verifySecondFactorIdentifier($verification->getPhoneNumber());
295
        $this->vettingProcedureRepository->store($procedure);
0 ignored issues
show
Bug introduced by
It seems like $procedure defined by $this->getProcedure($procedureId) on line 286 can be null; however, Surfnet\StepupRa\RaBundl...dureRepository::store() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
296
297
        return $verification;
298
    }
299
300
    /**
301
     * @param string                       $procedureId
302
     * @param VerifyYubikeyPublicIdCommand $command
303
     * @return YubikeySecondFactor\VerificationResult
304
     */
305
    public function verifyYubikeyPublicId($procedureId, VerifyYubikeyPublicIdCommand $command)
306
    {
307
        $procedure = $this->getProcedure($procedureId);
308
309
        $command->expectedPublicId = $procedure->getSecondFactor()->secondFactorIdentifier;
310
        $command->identityId = $procedure->getSecondFactor()->identityId;
311
        $command->institution = $procedure->getSecondFactor()->institution;
312
313
        $result = $this->yubikeySecondFactorService->verifyYubikeyPublicId($command);
314
315
        if ($result->didPublicIdMatch()) {
316
            $procedure->verifySecondFactorIdentifier($result->getPublicId()->getYubikeyPublicId());
317
318
            $this->vettingProcedureRepository->store($procedure);
0 ignored issues
show
Bug introduced by
It seems like $procedure defined by $this->getProcedure($procedureId) on line 307 can be null; however, Surfnet\StepupRa\RaBundl...dureRepository::store() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
319
        }
320
321
        return $result;
322
    }
323
324
    /**
325
     * @param string $procedureId
326
     */
327
    public function startGssfVerification($procedureId)
328
    {
329
        $procedure = $this->getProcedure($procedureId);
330
331
        $this->gssfService->startVerification($procedure->getSecondFactor()->secondFactorIdentifier, $procedureId);
332
    }
333
334
    /**
335
     * @param string $gssfId
336
     * @return GssfVerificationResult
337
     */
338
    public function verifyGssfId($gssfId)
339
    {
340
        $result = $this->gssfService->verify($gssfId);
341
342
        if (!$result->isSuccess()) {
343
            return $result;
344
        }
345
346
        $procedure = $this->getProcedure($result->getProcedureId());
347
        $procedure->verifySecondFactorIdentifier($gssfId);
348
349
        $this->vettingProcedureRepository->store($procedure);
0 ignored issues
show
Bug introduced by
It seems like $procedure defined by $this->getProcedure($result->getProcedureId()) on line 346 can be null; however, Surfnet\StepupRa\RaBundl...dureRepository::store() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
350
351
        return $result;
352
    }
353
354
    /**
355
     * @param string $procedureId
356
     * @return SignRequestCreationResult
357
     */
358
    public function createU2fSignRequest($procedureId)
359
    {
360
        $procedure = $this->getProcedure($procedureId);
361
362
        $command = new CreateU2fSignRequestCommand();
363
        $command->keyHandle = $procedure->getSecondFactor()->secondFactorIdentifier;
364
        $command->identityId = $procedure->getSecondFactor()->identityId;
365
        $command->institution = $procedure->getSecondFactor()->institution;
366
367
        return $this->u2fService->createSignRequest($command);
368
    }
369
370
    /**
371
     * @param string       $procedureId
372
     * @param SignRequest  $signRequest
373
     * @param SignResponse $signResponse
374
     * @return AuthenticationVerificationResult
375
     */
376
    public function verifyU2fAuthentication($procedureId, SignRequest $signRequest, SignResponse $signResponse)
377
    {
378
        $procedure = $this->getProcedure($procedureId);
379
380
        $command = new VerifyU2fAuthenticationCommand();
381
        $command->identityId = $procedure->getSecondFactor()->identityId;
382
        $command->institution = $procedure->getSecondFactor()->institution;
383
        $command->signRequest = $signRequest;
384
        $command->signResponse = $signResponse;
385
386
        $result = $this->u2fService->verifyAuthentication($command);
387
388
        if ($result->wasSuccessful()) {
389
            $procedure->verifySecondFactorIdentifier($signResponse->keyHandle);
390
            $this->vettingProcedureRepository->store($procedure);
0 ignored issues
show
Bug introduced by
It seems like $procedure defined by $this->getProcedure($procedureId) on line 378 can be null; however, Surfnet\StepupRa\RaBundl...dureRepository::store() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
391
        }
392
393
        return $result;
394
    }
395
396
    /**
397
     * @param string $procedureId
398
     * @param VerifyIdentityCommand $command
399
     * @return void
400
     * @throws UnknownVettingProcedureException
401
     * @throws DomainException
402
     */
403
    public function verifyIdentity($procedureId, VerifyIdentityCommand $command)
404
    {
405
        $procedure = $this->getProcedure($procedureId);
406
        $procedure->verifyIdentity($command->documentNumber, $command->identityVerified);
407
408
        $this->vettingProcedureRepository->store($procedure);
0 ignored issues
show
Bug introduced by
It seems like $procedure defined by $this->getProcedure($procedureId) on line 405 can be null; however, Surfnet\StepupRa\RaBundl...dureRepository::store() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
409
    }
410
411
    /**
412
     * @param string $procedureId
413
     * @return \Surfnet\StepupMiddlewareClient\Service\ExecutionResult
414
     * @throws UnknownVettingProcedureException
415
     * @throws DomainException
416
     */
417
    public function vet($procedureId)
418
    {
419
        $procedure = $this->getProcedure($procedureId);
420
        $procedure->vet();
421
422
        $command = new VetSecondFactorCommand();
423
        $command->authorityId = $procedure->getAuthorityId();
424
        $command->identityId = $procedure->getSecondFactor()->identityId;
425
        $command->secondFactorId = $procedure->getSecondFactor()->id;
426
        $command->registrationCode = $procedure->getRegistrationCode();
427
        $command->secondFactorType = $procedure->getSecondFactor()->type;
428
        $command->secondFactorIdentifier = $procedure->getInputSecondFactorIdentifier();
429
        $command->documentNumber = $procedure->getDocumentNumber();
430
        $command->identityVerified = $procedure->isIdentityVerified();
431
432
        $result = $this->commandService->execute($command);
433
434
        if ($result->isSuccessful()) {
435
            $this->vettingProcedureRepository->remove($procedureId);
436
        }
437
438
        return $result;
439
    }
440
441
    /**
442
     * @param string $procedureId
443
     * @return string
444
     * @throws UnknownVettingProcedureException
445
     */
446
    public function getIdentityCommonName($procedureId)
447
    {
448
        return $this->getProcedure($procedureId)->getSecondFactor()->commonName;
449
    }
450
451
    /**
452
     * @param $procedureId
453
     * @return string
454
     * @throws UnknownVettingProcedureException
455
     */
456
    public function getSecondFactorIdentifier($procedureId)
457
    {
458
        return $this->getProcedure($procedureId)->getSecondFactor()->secondFactorIdentifier;
459
    }
460
461
    /**
462
     * @param string $procedureId
463
     * @return null|VettingProcedure
464
     * @throws UnknownVettingProcedureException
465
     */
466 View Code Duplication
    private function getProcedure($procedureId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
467
    {
468
        if (!is_string($procedureId)) {
469
            throw InvalidArgumentException::invalidType('string', 'procedureId', $procedureId);
470
        }
471
472
        $procedure = $this->vettingProcedureRepository->retrieve($procedureId);
473
474
        if (!$procedure) {
475
            throw new UnknownVettingProcedureException(
476
                sprintf("No vetting procedure with id '%s' is known.", $procedureId)
477
            );
478
        }
479
480
        return $procedure;
481
    }
482
483
    /**
484
     * @param string $procedureId
485
     * @return bool
486
     */
487
    public function hasProcedure($procedureId)
488
    {
489
        if (!is_string($procedureId)) {
490
            throw InvalidArgumentException::invalidType('string', 'procedureId', $procedureId);
491
        }
492
493
        return $this->vettingProcedureRepository->retrieve($procedureId) !== null;
494
    }
495
}
496