Completed
Pull Request — develop (#294)
by
unknown
05:31 queued 02:48
created

Identity::remoteVetSecondFactor()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.568
c 0
b 0
f 0
cc 3
nc 3
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\Stepup\Identity;
20
21
use Broadway\EventSourcing\EventSourcedAggregateRoot;
22
use Surfnet\Stepup\Configuration\InstitutionConfiguration;
23
use Surfnet\Stepup\Configuration\Value\Institution as ConfigurationInstitution;
24
use Surfnet\Stepup\DateTime\DateTime;
25
use Surfnet\Stepup\Exception\DomainException;
26
use Surfnet\Stepup\Helper\SecondFactorProvePossessionHelper;
27
use Surfnet\Stepup\Identity\Api\Identity as IdentityApi;
28
use Surfnet\Stepup\Identity\Entity\RegistrationAuthority;
29
use Surfnet\Stepup\Identity\Entity\RegistrationAuthorityCollection;
30
use Surfnet\Stepup\Identity\Entity\SecondFactorCollection;
31
use Surfnet\Stepup\Identity\Entity\UnverifiedSecondFactor;
32
use Surfnet\Stepup\Identity\Entity\VerifiedSecondFactor;
33
use Surfnet\Stepup\Identity\Entity\VettedSecondFactor;
34
use Surfnet\Stepup\Identity\Event\AppointedAsRaaEvent;
35
use Surfnet\Stepup\Identity\Event\AppointedAsRaEvent;
36
use Surfnet\Stepup\Identity\Event\AppointedAsRaaForInstitutionEvent;
37
use Surfnet\Stepup\Identity\Event\AppointedAsRaForInstitutionEvent;
38
use Surfnet\Stepup\Identity\Event\CompliedWithUnverifiedSecondFactorRevocationEvent;
39
use Surfnet\Stepup\Identity\Event\CompliedWithVerifiedSecondFactorRevocationEvent;
40
use Surfnet\Stepup\Identity\Event\CompliedWithVettedSecondFactorRevocationEvent;
41
use Surfnet\Stepup\Identity\Event\EmailVerifiedEvent;
42
use Surfnet\Stepup\Identity\Event\GssfPossessionProvenAndVerifiedEvent;
43
use Surfnet\Stepup\Identity\Event\GssfPossessionProvenEvent;
44
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaaEvent;
45
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaaForInstitutionEvent;
46
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaEvent;
47
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaForInstitutionEvent;
48
use Surfnet\Stepup\Identity\Event\IdentityCreatedEvent;
49
use Surfnet\Stepup\Identity\Event\IdentityEmailChangedEvent;
50
use Surfnet\Stepup\Identity\Event\IdentityForgottenEvent;
51
use Surfnet\Stepup\Identity\Event\IdentityRenamedEvent;
52
use Surfnet\Stepup\Identity\Event\LocalePreferenceExpressedEvent;
53
use Surfnet\Stepup\Identity\Event\PhonePossessionProvenAndVerifiedEvent;
54
use Surfnet\Stepup\Identity\Event\PhonePossessionProvenEvent;
55
use Surfnet\Stepup\Identity\Event\RegistrationAuthorityInformationAmendedEvent;
56
use Surfnet\Stepup\Identity\Event\RegistrationAuthorityInformationAmendedForInstitutionEvent;
57
use Surfnet\Stepup\Identity\Event\RegistrationAuthorityRetractedEvent;
58
use Surfnet\Stepup\Identity\Event\RegistrationAuthorityRetractedForInstitutionEvent;
59
use Surfnet\Stepup\Identity\Event\SecondFactorVettedWithoutTokenProofOfPossession;
60
use Surfnet\Stepup\Identity\Event\SecondFactorVettedEvent;
61
use Surfnet\Stepup\Identity\Event\U2fDevicePossessionProvenAndVerifiedEvent;
62
use Surfnet\Stepup\Identity\Event\U2fDevicePossessionProvenEvent;
63
use Surfnet\Stepup\Identity\Event\UnverifiedSecondFactorRevokedEvent;
64
use Surfnet\Stepup\Identity\Event\VerifiedSecondFactorRevokedEvent;
65
use Surfnet\Stepup\Identity\Event\VettedSecondFactorRevokedEvent;
66
use Surfnet\Stepup\Identity\Event\VettedSecondFactorsAllRevokedEvent;
67
use Surfnet\Stepup\Identity\Event\YubikeyPossessionProvenAndVerifiedEvent;
68
use Surfnet\Stepup\Identity\Event\YubikeyPossessionProvenEvent;
69
use Surfnet\Stepup\Identity\Event\YubikeySecondFactorBootstrappedEvent;
70
use Surfnet\Stepup\Identity\Value\CommonName;
71
use Surfnet\Stepup\Identity\Value\ContactInformation;
72
use Surfnet\Stepup\Identity\Value\DocumentNumber;
73
use Surfnet\Stepup\Identity\Value\Email;
74
use Surfnet\Stepup\Identity\Value\EmailVerificationWindow;
75
use Surfnet\Stepup\Identity\Value\GssfId;
76
use Surfnet\Stepup\Identity\Value\IdentityId;
77
use Surfnet\Stepup\Identity\Value\Institution;
78
use Surfnet\Stepup\Identity\Value\Locale;
79
use Surfnet\Stepup\Identity\Value\Location;
80
use Surfnet\Stepup\Identity\Value\NameId;
81
use Surfnet\Stepup\Identity\Value\PhoneNumber;
82
use Surfnet\Stepup\Identity\Value\RegistrationAuthorityRole;
83
use Surfnet\Stepup\Identity\Value\SecondFactorId;
84
use Surfnet\Stepup\Identity\Value\SecondFactorIdentifier;
85
use Surfnet\Stepup\Identity\Value\StepupProvider;
86
use Surfnet\Stepup\Identity\Value\U2fKeyHandle;
87
use Surfnet\Stepup\Identity\Value\YubikeyPublicId;
88
use Surfnet\Stepup\Token\TokenGenerator;
89
use Surfnet\StepupBundle\Security\OtpGenerator;
90
use Surfnet\StepupBundle\Service\SecondFactorTypeService;
91
use Surfnet\StepupBundle\Value\SecondFactorType;
92
93
/**
94
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
95
 * @SuppressWarnings(PHPMD.TooManyMethods)
96
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
97
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
98
 * @SuppressWarnings(PHPMD.ExcessiveClassLength)
99
 */
100
class Identity extends EventSourcedAggregateRoot implements IdentityApi
101
{
102
    /**
103
     * @var IdentityId
104
     */
105
    private $id;
106
107
    /**
108
     * @var Institution
109
     */
110
    private $institution;
111
112
    /**
113
     * @var NameId
114
     */
115
    private $nameId;
116
117
    /**
118
     * @var \Surfnet\Stepup\Identity\Value\CommonName
119
     */
120
    private $commonName;
121
122
    /**
123
     * @var \Surfnet\Stepup\Identity\Value\Email
124
     */
125
    private $email;
126
127
    /**
128
     * @var SecondFactorCollection|UnverifiedSecondFactor[]
129
     */
130
    private $unverifiedSecondFactors;
131
132
    /**
133
     * @var SecondFactorCollection|VerifiedSecondFactor[]
134
     */
135
    private $verifiedSecondFactors;
136
137
    /**
138
     * @var SecondFactorCollection|VettedSecondFactor[]
139
     */
140
    private $vettedSecondFactors;
141
142
    /**
143
     * @var RegistrationAuthorityCollection
144
     */
145
    private $registrationAuthorities;
146
147
    /**
148
     * @var Locale
149
     */
150
    private $preferredLocale;
151
152
    /**
153
     * @var boolean
154
     */
155
    private $forgotten;
156
157
    /**
158
     * @var int
159
     */
160
    private $maxNumberOfTokens = 1;
161
162
    public static function create(
163
        IdentityId $id,
164
        Institution $institution,
165
        NameId $nameId,
166
        CommonName $commonName,
167
        Email $email,
168
        Locale $preferredLocale
169
    ) {
170
        $identity = new self();
171
        $identity->apply(new IdentityCreatedEvent($id, $institution, $nameId, $commonName, $email, $preferredLocale));
172
173
        return $identity;
174
    }
175
176
    final public function __construct()
177
    {
178
    }
179
180
    public function rename(CommonName $commonName)
181
    {
182
        $this->assertNotForgotten();
183
184
        if ($this->commonName->equals($commonName)) {
185
            return;
186
        }
187
188
        $this->commonName = $commonName;
189
        $this->apply(new IdentityRenamedEvent($this->id, $this->institution, $commonName));
190
    }
191
192
    public function changeEmail(Email $email)
193
    {
194
        $this->assertNotForgotten();
195
196
        if ($this->email->equals($email)) {
197
            return;
198
        }
199
200
        $this->email = $email;
201
        $this->apply(new IdentityEmailChangedEvent($this->id, $this->institution, $email));
202
    }
203
204
    /**
205
     * @param int $numberOfTokens
206
     */
207
    public function setMaxNumberOfTokens($numberOfTokens)
208
    {
209
        $this->maxNumberOfTokens = $numberOfTokens;
210
    }
211
212
    public function bootstrapYubikeySecondFactor(SecondFactorId $secondFactorId, YubikeyPublicId $yubikeyPublicId)
213
    {
214
        $this->assertNotForgotten();
215
        $this->assertUserMayAddSecondFactor();
216
217
        $this->apply(
218
            new YubikeySecondFactorBootstrappedEvent(
219
                $this->id,
220
                $this->nameId,
221
                $this->institution,
222
                $this->commonName,
223
                $this->email,
224
                $this->preferredLocale,
225
                $secondFactorId,
226
                $yubikeyPublicId
227
            )
228
        );
229
    }
230
231 View Code Duplication
    public function provePossessionOfYubikey(
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...
232
        SecondFactorId $secondFactorId,
233
        YubikeyPublicId $yubikeyPublicId,
234
        $emailVerificationRequired,
235
        EmailVerificationWindow $emailVerificationWindow
236
    ) {
237
        $this->assertNotForgotten();
238
        $this->assertUserMayAddSecondFactor();
239
240
        if ($emailVerificationRequired) {
241
            $emailVerificationNonce = TokenGenerator::generateNonce();
242
243
            $this->apply(
244
                new YubikeyPossessionProvenEvent(
245
                    $this->id,
246
                    $this->institution,
247
                    $secondFactorId,
248
                    $yubikeyPublicId,
249
                    $emailVerificationRequired,
250
                    $emailVerificationWindow,
251
                    $emailVerificationNonce,
252
                    $this->commonName,
253
                    $this->email,
254
                    $this->preferredLocale
255
                )
256
            );
257
        } else {
258
            $this->apply(
259
                new YubikeyPossessionProvenAndVerifiedEvent(
260
                    $this->id,
261
                    $this->institution,
262
                    $secondFactorId,
263
                    $yubikeyPublicId,
264
                    $this->commonName,
265
                    $this->email,
266
                    $this->preferredLocale,
267
                    DateTime::now(),
268
                    OtpGenerator::generate(8)
269
                )
270
            );
271
        }
272
    }
273
274 View Code Duplication
    public function provePossessionOfPhone(
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...
275
        SecondFactorId $secondFactorId,
276
        PhoneNumber $phoneNumber,
277
        $emailVerificationRequired,
278
        EmailVerificationWindow $emailVerificationWindow
279
    ) {
280
        $this->assertNotForgotten();
281
        $this->assertUserMayAddSecondFactor();
282
283
        if ($emailVerificationRequired) {
284
            $emailVerificationNonce = TokenGenerator::generateNonce();
285
286
            $this->apply(
287
                new PhonePossessionProvenEvent(
288
                    $this->id,
289
                    $this->institution,
290
                    $secondFactorId,
291
                    $phoneNumber,
292
                    $emailVerificationRequired,
293
                    $emailVerificationWindow,
294
                    $emailVerificationNonce,
295
                    $this->commonName,
296
                    $this->email,
297
                    $this->preferredLocale
298
                )
299
            );
300
        } else {
301
            $this->apply(
302
                new PhonePossessionProvenAndVerifiedEvent(
303
                    $this->id,
304
                    $this->institution,
305
                    $secondFactorId,
306
                    $phoneNumber,
307
                    $this->commonName,
308
                    $this->email,
309
                    $this->preferredLocale,
310
                    DateTime::now(),
311
                    OtpGenerator::generate(8)
312
                )
313
            );
314
        }
315
    }
316
317 View Code Duplication
    public function provePossessionOfGssf(
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...
318
        SecondFactorId $secondFactorId,
319
        StepupProvider $provider,
320
        GssfId $gssfId,
321
        $emailVerificationRequired,
322
        EmailVerificationWindow $emailVerificationWindow
323
    ) {
324
        $this->assertNotForgotten();
325
        $this->assertUserMayAddSecondFactor();
326
327
        if ($emailVerificationRequired) {
328
            $emailVerificationNonce = TokenGenerator::generateNonce();
329
330
            $this->apply(
331
                new GssfPossessionProvenEvent(
332
                    $this->id,
333
                    $this->institution,
334
                    $secondFactorId,
335
                    $provider,
336
                    $gssfId,
337
                    $emailVerificationRequired,
338
                    $emailVerificationWindow,
339
                    $emailVerificationNonce,
340
                    $this->commonName,
341
                    $this->email,
342
                    $this->preferredLocale
343
                )
344
            );
345
        } else {
346
            $this->apply(
347
                new GssfPossessionProvenAndVerifiedEvent(
348
                    $this->id,
349
                    $this->institution,
350
                    $secondFactorId,
351
                    $provider,
352
                    $gssfId,
353
                    $this->commonName,
354
                    $this->email,
355
                    $this->preferredLocale,
356
                    DateTime::now(),
357
                    OtpGenerator::generate(8)
358
                )
359
            );
360
        }
361
    }
362
363 View Code Duplication
    public function provePossessionOfU2fDevice(
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...
364
        SecondFactorId $secondFactorId,
365
        U2fKeyHandle $keyHandle,
366
        $emailVerificationRequired,
367
        EmailVerificationWindow $emailVerificationWindow
368
    ) {
369
        $this->assertNotForgotten();
370
        $this->assertUserMayAddSecondFactor();
371
372
        if ($emailVerificationRequired) {
373
            $emailVerificationNonce = TokenGenerator::generateNonce();
374
375
            $this->apply(
376
                new U2fDevicePossessionProvenEvent(
377
                    $this->id,
378
                    $this->institution,
379
                    $secondFactorId,
380
                    $keyHandle,
381
                    $emailVerificationRequired,
382
                    $emailVerificationWindow,
383
                    $emailVerificationNonce,
384
                    $this->commonName,
385
                    $this->email,
386
                    $this->preferredLocale
387
                )
388
            );
389
        } else {
390
            $this->apply(
391
                new U2fDevicePossessionProvenAndVerifiedEvent(
392
                    $this->id,
393
                    $this->institution,
394
                    $secondFactorId,
395
                    $keyHandle,
396
                    $this->commonName,
397
                    $this->email,
398
                    $this->preferredLocale,
399
                    DateTime::now(),
400
                    OtpGenerator::generate(8)
401
                )
402
            );
403
        }
404
    }
405
406
    public function verifyEmail($verificationNonce)
407
    {
408
        $this->assertNotForgotten();
409
410
        $secondFactorToVerify = null;
411
        foreach ($this->unverifiedSecondFactors as $secondFactor) {
412
            /** @var Entity\UnverifiedSecondFactor $secondFactor */
413
            if ($secondFactor->hasNonce($verificationNonce)) {
414
                $secondFactorToVerify = $secondFactor;
415
            }
416
        }
417
418
        if (!$secondFactorToVerify) {
419
            throw new DomainException(
420
                'Cannot verify second factor, no unverified second factor can be verified using the given nonce'
421
            );
422
        }
423
424
        /** @var Entity\UnverifiedSecondFactor $secondFactorToVerify */
425
        if (!$secondFactorToVerify->canBeVerifiedNow()) {
426
            throw new DomainException('Cannot verify second factor, the verification window is closed.');
427
        }
428
429
        $secondFactorToVerify->verifyEmail();
430
    }
431
432
    /**
433
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
434
     */
435
    public function vetSecondFactor(
436
        IdentityApi $registrant,
437
        SecondFactorId $registrantsSecondFactorId,
438
        SecondFactorType $registrantsSecondFactorType,
439
        SecondFactorIdentifier $registrantsSecondFactorIdentifier,
440
        $registrationCode,
441
        DocumentNumber $documentNumber,
442
        $identityVerified,
443
        SecondFactorTypeService $secondFactorTypeService,
444
        SecondFactorProvePossessionHelper $secondFactorProvePossessionHelper,
445
        $provePossessionSkipped
446
    ) {
447
        $this->assertNotForgotten();
448
449
        /** @var VettedSecondFactor|null $secondFactorWithHighestLoa */
450
        $secondFactorWithHighestLoa = $this->vettedSecondFactors->getSecondFactorWithHighestLoa($secondFactorTypeService);
451
        $registrantsSecondFactor = $registrant->getVerifiedSecondFactor($registrantsSecondFactorId);
452
453
        if ($registrantsSecondFactor === null) {
454
            throw new DomainException(
455
                sprintf('Registrant second factor with ID %s does not exist', $registrantsSecondFactorId)
456
            );
457
        }
458
459
        if ($secondFactorWithHighestLoa === null) {
460
            throw new DomainException(
461
                sprintf(
462
                    'Vetting failed: authority %s has %d vetted second factors!',
463
                    $this->id,
464
                    count($this->vettedSecondFactors)
465
                )
466
            );
467
        }
468
469
        if (!$secondFactorWithHighestLoa->hasEqualOrHigherLoaComparedTo(
470
            $registrantsSecondFactor,
471
            $secondFactorTypeService
472
        )) {
473
            throw new DomainException("Authority does not have the required LoA to vet the registrant's second factor");
474
        }
475
476
        if (!$identityVerified) {
477
            throw new DomainException('Will not vet second factor when physical identity has not been verified.');
478
        }
479
480
        if ($provePossessionSkipped && !$secondFactorProvePossessionHelper->canSkipProvePossession($registrantsSecondFactorType)) {
481
            throw new DomainException(sprintf(
482
                "The possession of registrants second factor with ID '%s' of type '%s' has to be physically proven",
483
                $registrantsSecondFactorId,
484
                $registrantsSecondFactorType->getSecondFactorType()
485
            ));
486
        }
487
488
        $registrant->complyWithVettingOfSecondFactor(
489
            $registrantsSecondFactorId,
490
            $registrantsSecondFactorType,
491
            $registrantsSecondFactorIdentifier,
492
            $registrationCode,
493
            $documentNumber,
494
            $provePossessionSkipped
495
        );
496
    }
497
498
    public function remoteVetSecondFactor(
499
        SecondFactorId $secondFactorId
500
    ) {
501
        $this->assertNotForgotten();
502
503
        // TODO: Do we need configuration to whitelist remote vetting?
504
505
        /** @var UnverifiedSecondFactor|null $secondFactorWithHighestLoa */
506
        $secondFactor = $this->getVerifiedSecondFactor($secondFactorId);
507
508
        if ($secondFactor === null) {
509
            throw new DomainException(
510
                sprintf('Registrant second factor with ID %s does not exist', $secondFactorId)
511
            );
512
        }
513
514
        if (!$secondFactor->canBeVettedNow()) {
515
            throw new DomainException('Cannot vet second factor, the registration window is closed.');
516
        }
517
518
        $secondFactor->vet(DocumentNumber::unknown(), false);
519
    }
520
521
    public function complyWithVettingOfSecondFactor(
522
        SecondFactorId $secondFactorId,
523
        SecondFactorType $secondFactorType,
524
        SecondFactorIdentifier $secondFactorIdentifier,
525
        $registrationCode,
526
        DocumentNumber $documentNumber,
527
        $provePossessionSkipped
528
    ) {
529
        $this->assertNotForgotten();
530
531
        $secondFactorToVet = null;
532
        foreach ($this->verifiedSecondFactors as $secondFactor) {
533
            /** @var VerifiedSecondFactor $secondFactor */
534
            if ($secondFactor->hasRegistrationCodeAndIdentifier($registrationCode, $secondFactorIdentifier)) {
535
                $secondFactorToVet = $secondFactor;
536
            }
537
        }
538
539
        if (!$secondFactorToVet) {
540
            throw new DomainException(
541
                'Cannot vet second factor, no verified second factor can be vetted using the given registration code ' .
542
                'and second factor identifier'
543
            );
544
        }
545
546
        if (!$secondFactorToVet->canBeVettedNow()) {
547
            throw new DomainException('Cannot vet second factor, the registration window is closed.');
548
        }
549
550
        $secondFactorToVet->vet($documentNumber, $provePossessionSkipped);
551
    }
552
553
    public function revokeSecondFactor(SecondFactorId $secondFactorId)
554
    {
555
        $this->assertNotForgotten();
556
557
        /** @var UnverifiedSecondFactor|null $unverifiedSecondFactor */
558
        $unverifiedSecondFactor = $this->unverifiedSecondFactors->get((string)$secondFactorId);
559
        /** @var VerifiedSecondFactor|null $verifiedSecondFactor */
560
        $verifiedSecondFactor = $this->verifiedSecondFactors->get((string)$secondFactorId);
561
        /** @var VettedSecondFactor|null $vettedSecondFactor */
562
        $vettedSecondFactor = $this->vettedSecondFactors->get((string)$secondFactorId);
563
564
        if (!$unverifiedSecondFactor && !$verifiedSecondFactor && !$vettedSecondFactor) {
565
            throw new DomainException('Cannot revoke second factor: no second factor with given id exists.');
566
        }
567
568
        if ($unverifiedSecondFactor) {
569
            $unverifiedSecondFactor->revoke();
570
571
            return;
572
        }
573
574
        if ($verifiedSecondFactor) {
575
            $verifiedSecondFactor->revoke();
576
577
            return;
578
        }
579
580
        $vettedSecondFactor->revoke();
581
582
        if ($this->vettedSecondFactors->isEmpty()) {
583
            $this->allVettedSecondFactorsRemoved();
584
        }
585
    }
586
587
    public function complyWithSecondFactorRevocation(SecondFactorId $secondFactorId, IdentityId $authorityId)
588
    {
589
        $this->assertNotForgotten();
590
591
        /** @var UnverifiedSecondFactor|null $unverifiedSecondFactor */
592
        $unverifiedSecondFactor = $this->unverifiedSecondFactors->get((string)$secondFactorId);
593
        /** @var VerifiedSecondFactor|null $verifiedSecondFactor */
594
        $verifiedSecondFactor = $this->verifiedSecondFactors->get((string)$secondFactorId);
595
        /** @var VettedSecondFactor|null $vettedSecondFactor */
596
        $vettedSecondFactor = $this->vettedSecondFactors->get((string)$secondFactorId);
597
598
        if (!$unverifiedSecondFactor && !$verifiedSecondFactor && !$vettedSecondFactor) {
599
            throw new DomainException('Cannot revoke second factor: no second factor with given id exists.');
600
        }
601
602
        if ($unverifiedSecondFactor) {
603
            $unverifiedSecondFactor->complyWithRevocation($authorityId);
604
605
            return;
606
        }
607
608
        if ($verifiedSecondFactor) {
609
            $verifiedSecondFactor->complyWithRevocation($authorityId);
610
611
            return;
612
        }
613
614
        $vettedSecondFactor->complyWithRevocation($authorityId);
615
616
        if ($this->vettedSecondFactors->isEmpty()) {
617
            $this->allVettedSecondFactorsRemoved();
618
        }
619
    }
620
621
    /**
622
     * @param RegistrationAuthorityRole $role
623
     * @param Institution $institution
624
     * @param Location $location
625
     * @param ContactInformation $contactInformation
626
     * @param InstitutionConfiguration $institutionConfiguration
627
     * @return void
628
     */
629
    public function accreditWith(
630
        RegistrationAuthorityRole $role,
631
        Institution $institution,
632
        Location $location,
633
        ContactInformation $contactInformation,
634
        InstitutionConfiguration $institutionConfiguration
635
    ) {
636
        $this->assertNotForgotten();
637
638
        if (!$institutionConfiguration->isInstitutionAllowedToAccreditRoles(new ConfigurationInstitution($this->institution->getInstitution()))) {
639
            throw new DomainException('An Identity may only be accredited by configured institutions.');
640
        }
641
642
        if (!$this->vettedSecondFactors->count()) {
643
            throw new DomainException(
644
                'An Identity must have at least one vetted second factor before it can be accredited'
645
            );
646
        }
647
648
        if ($this->registrationAuthorities->exists($institution)) {
649
            throw new DomainException('Cannot accredit Identity as it has already been accredited for institution');
650
        }
651
652
        if ($role->equals(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA))) {
653
            $this->apply(new IdentityAccreditedAsRaForInstitutionEvent(
654
                $this->id,
655
                $this->nameId,
656
                $this->institution,
657
                $role,
658
                $location,
659
                $contactInformation,
660
                $institution
661
            ));
662 View Code Duplication
        } elseif ($role->equals(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RAA))) {
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...
663
            $this->apply(new IdentityAccreditedAsRaaForInstitutionEvent(
664
                $this->id,
665
                $this->nameId,
666
                $this->institution,
667
                $role,
668
                $location,
669
                $contactInformation,
670
                $institution
671
            ));
672
        } else {
673
            throw new DomainException('An Identity can only be accredited with either the RA or RAA role');
674
        }
675
    }
676
677
    public function amendRegistrationAuthorityInformation(Institution $institution, Location $location, ContactInformation $contactInformation)
678
    {
679
        $this->assertNotForgotten();
680
681
        if (!$this->registrationAuthorities->exists($institution)) {
682
            throw new DomainException(
683
                'Cannot amend registration authority information: identity is not a registration authority for institution'
684
            );
685
        }
686
687
        $this->apply(
688
            new RegistrationAuthorityInformationAmendedForInstitutionEvent(
689
                $this->id,
690
                $this->institution,
691
                $this->nameId,
692
                $location,
693
                $contactInformation,
694
                $institution
695
            )
696
        );
697
    }
698
699
    /**
700
     * This method will appoint an institution to become ra or raa for another institution
701
     *
702
     * @param Institution $institution
703
     * @param RegistrationAuthorityRole $role
704
     * @param InstitutionConfiguration $institutionConfiguration
705
     */
706
    public function appointAs(
707
        Institution $institution,
708
        RegistrationAuthorityRole $role,
709
        InstitutionConfiguration $institutionConfiguration
710
    ) {
711
        $this->assertNotForgotten();
712
713
        if (!$institutionConfiguration->isInstitutionAllowedToAccreditRoles(new ConfigurationInstitution($this->institution->getInstitution()))) {
714
            throw new DomainException(
715
                'Cannot appoint as different RegistrationAuthorityRole: identity is not a registration authority for institution'
716
            );
717
        }
718
719
        $registrationAuthority = $this->registrationAuthorities->get($institution);
720
721
        if ($registrationAuthority->isAppointedAs($role)) {
722
            return;
723
        }
724
725
        if ($role->equals(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA))) {
726
            $this->apply(new AppointedAsRaForInstitutionEvent($this->id, $this->institution, $this->nameId, $institution));
727 View Code Duplication
        } elseif ($role->equals(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RAA))) {
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...
728
            $this->apply(new AppointedAsRaaForInstitutionEvent($this->id, $this->institution, $this->nameId, $institution));
729
        } else {
730
            throw new DomainException('An Identity can only be appointed as either RA or RAA');
731
        }
732
    }
733
734
    public function retractRegistrationAuthority(Institution $institution)
735
    {
736
        $this->assertNotForgotten();
737
738
        if (!$this->registrationAuthorities->exists($institution)) {
739
            throw new DomainException(
740
                'Cannot Retract Registration Authority as the Identity is not a registration authority'
741
            );
742
        }
743
744
        $this->apply(new RegistrationAuthorityRetractedForInstitutionEvent(
745
            $this->id,
746
            $this->institution,
747
            $this->nameId,
748
            $this->commonName,
749
            $this->email,
750
            $institution
751
        ));
752
    }
753
754
    public function expressPreferredLocale(Locale $preferredLocale)
755
    {
756
        $this->assertNotForgotten();
757
758
        if ($this->preferredLocale === $preferredLocale) {
759
            return;
760
        }
761
762
        $this->apply(new LocalePreferenceExpressedEvent($this->id, $this->institution, $preferredLocale));
763
    }
764
765
    public function forget()
766
    {
767
        $this->assertNotForgotten();
768
769
        if ($this->registrationAuthorities->count()) {
770
            throw new DomainException('Cannot forget an identity that is currently accredited as an RA(A)');
771
        }
772
773
        $this->apply(new IdentityForgottenEvent($this->id, $this->institution));
774
    }
775
776
    public function allVettedSecondFactorsRemoved()
777
    {
778
        $this->apply(
779
            new VettedSecondFactorsAllRevokedEvent(
780
                $this->id,
781
                $this->institution
782
            )
783
        );
784
    }
785
786
    protected function applyIdentityCreatedEvent(IdentityCreatedEvent $event)
787
    {
788
        $this->id = $event->identityId;
789
        $this->institution = $event->identityInstitution;
790
        $this->nameId = $event->nameId;
791
        $this->commonName = $event->commonName;
792
        $this->email = $event->email;
793
        $this->preferredLocale = $event->preferredLocale;
794
        $this->forgotten = false;
795
796
        $this->unverifiedSecondFactors = new SecondFactorCollection();
797
        $this->verifiedSecondFactors = new SecondFactorCollection();
798
        $this->vettedSecondFactors = new SecondFactorCollection();
799
        $this->registrationAuthorities = new RegistrationAuthorityCollection();
800
    }
801
802
    public function applyIdentityRenamedEvent(IdentityRenamedEvent $event)
803
    {
804
        $this->commonName = $event->commonName;
805
    }
806
807
    public function applyIdentityEmailChangedEvent(IdentityEmailChangedEvent $event)
808
    {
809
        $this->email = $event->email;
810
    }
811
812
    protected function applyYubikeySecondFactorBootstrappedEvent(YubikeySecondFactorBootstrappedEvent $event)
813
    {
814
        $secondFactor = VettedSecondFactor::create(
815
            $event->secondFactorId,
816
            $this,
817
            new SecondFactorType('yubikey'),
818
            $event->yubikeyPublicId
819
        );
820
821
        $this->vettedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
822
    }
823
824 View Code Duplication
    protected function applyYubikeyPossessionProvenEvent(YubikeyPossessionProvenEvent $event)
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...
825
    {
826
        $secondFactor = UnverifiedSecondFactor::create(
827
            $event->secondFactorId,
828
            $this,
829
            new SecondFactorType('yubikey'),
830
            $event->yubikeyPublicId,
831
            $event->emailVerificationWindow,
832
            $event->emailVerificationNonce
833
        );
834
835
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
836
    }
837
838 View Code Duplication
    protected function applyYubikeyPossessionProvenAndVerifiedEvent(YubikeyPossessionProvenAndVerifiedEvent $event)
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...
839
    {
840
        $secondFactor = VerifiedSecondFactor::create(
841
            $event->secondFactorId,
842
            $this,
843
            new SecondFactorType('yubikey'),
844
            $event->yubikeyPublicId,
845
            $event->registrationRequestedAt,
846
            $event->registrationCode
847
        );
848
849
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
850
    }
851
852 View Code Duplication
    protected function applyPhonePossessionProvenEvent(PhonePossessionProvenEvent $event)
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...
853
    {
854
        $secondFactor = UnverifiedSecondFactor::create(
855
            $event->secondFactorId,
856
            $this,
857
            new SecondFactorType('sms'),
858
            $event->phoneNumber,
859
            $event->emailVerificationWindow,
860
            $event->emailVerificationNonce
861
        );
862
863
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
864
    }
865
866 View Code Duplication
    protected function applyPhonePossessionProvenAndVerifiedEvent(PhonePossessionProvenAndVerifiedEvent $event)
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...
867
    {
868
        $secondFactor = VerifiedSecondFactor::create(
869
            $event->secondFactorId,
870
            $this,
871
            new SecondFactorType('sms'),
872
            $event->phoneNumber,
873
            $event->registrationRequestedAt,
874
            $event->registrationCode
875
        );
876
877
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
878
    }
879
880 View Code Duplication
    protected function applyGssfPossessionProvenEvent(GssfPossessionProvenEvent $event)
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...
881
    {
882
        $secondFactor = UnverifiedSecondFactor::create(
883
            $event->secondFactorId,
884
            $this,
885
            new SecondFactorType((string)$event->stepupProvider),
886
            $event->gssfId,
887
            $event->emailVerificationWindow,
888
            $event->emailVerificationNonce
889
        );
890
891
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
892
    }
893
894 View Code Duplication
    protected function applyGssfPossessionProvenAndVerifiedEvent(GssfPossessionProvenAndVerifiedEvent $event)
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...
895
    {
896
        $secondFactor = VerifiedSecondFactor::create(
897
            $event->secondFactorId,
898
            $this,
899
            new SecondFactorType((string)$event->stepupProvider),
900
            $event->gssfId,
901
            $event->registrationRequestedAt,
902
            $event->registrationCode
903
        );
904
905
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
906
    }
907
908 View Code Duplication
    protected function applyU2fDevicePossessionProvenEvent(U2fDevicePossessionProvenEvent $event)
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...
909
    {
910
        $secondFactor = UnverifiedSecondFactor::create(
911
            $event->secondFactorId,
912
            $this,
913
            new SecondFactorType('u2f'),
914
            $event->keyHandle,
915
            $event->emailVerificationWindow,
916
            $event->emailVerificationNonce
917
        );
918
919
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
920
    }
921
922 View Code Duplication
    protected function applyU2fDevicePossessionProvenAndVerifiedEvent(U2fDevicePossessionProvenAndVerifiedEvent $event)
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...
923
    {
924
        $secondFactor = VerifiedSecondFactor::create(
925
            $event->secondFactorId,
926
            $this,
927
            new SecondFactorType('u2f'),
928
            $event->keyHandle,
929
            $event->registrationRequestedAt,
930
            $event->registrationCode
931
        );
932
933
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
934
    }
935
936
    protected function applyEmailVerifiedEvent(EmailVerifiedEvent $event)
937
    {
938
        $secondFactorId = (string)$event->secondFactorId;
939
940
        /** @var UnverifiedSecondFactor $unverified */
941
        $unverified = $this->unverifiedSecondFactors->get($secondFactorId);
942
        $verified = $unverified->asVerified($event->registrationRequestedAt, $event->registrationCode);
943
944
        $this->unverifiedSecondFactors->remove($secondFactorId);
945
        $this->verifiedSecondFactors->set($secondFactorId, $verified);
946
    }
947
948 View Code Duplication
    protected function applySecondFactorVettedEvent(SecondFactorVettedEvent $event)
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...
949
    {
950
        $secondFactorId = (string)$event->secondFactorId;
951
952
        /** @var VerifiedSecondFactor $verified */
953
        $verified = $this->verifiedSecondFactors->get($secondFactorId);
954
        $vetted = $verified->asVetted();
955
956
        $this->verifiedSecondFactors->remove($secondFactorId);
957
        $this->vettedSecondFactors->set($secondFactorId, $vetted);
958
    }
959
960 View Code Duplication
    protected function applySecondFactorVettedWithoutTokenProofOfPossession(SecondFactorVettedWithoutTokenProofOfPossession $event)
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...
961
    {
962
        $secondFactorId = (string)$event->secondFactorId;
963
964
        /** @var VerifiedSecondFactor $verified */
965
        $verified = $this->verifiedSecondFactors->get($secondFactorId);
966
        $vetted = $verified->asVetted();
967
968
        $this->verifiedSecondFactors->remove($secondFactorId);
969
        $this->vettedSecondFactors->set($secondFactorId, $vetted);
970
    }
971
972
    protected function applyUnverifiedSecondFactorRevokedEvent(UnverifiedSecondFactorRevokedEvent $event)
973
    {
974
        $this->unverifiedSecondFactors->remove((string)$event->secondFactorId);
975
    }
976
977
    protected function applyCompliedWithUnverifiedSecondFactorRevocationEvent(
978
        CompliedWithUnverifiedSecondFactorRevocationEvent $event
979
    ) {
980
        $this->unverifiedSecondFactors->remove((string)$event->secondFactorId);
981
    }
982
983
    protected function applyVerifiedSecondFactorRevokedEvent(VerifiedSecondFactorRevokedEvent $event)
984
    {
985
        $this->verifiedSecondFactors->remove((string)$event->secondFactorId);
986
    }
987
988
    protected function applyCompliedWithVerifiedSecondFactorRevocationEvent(
989
        CompliedWithVerifiedSecondFactorRevocationEvent $event
990
    ) {
991
        $this->verifiedSecondFactors->remove((string)$event->secondFactorId);
992
    }
993
994
    protected function applyVettedSecondFactorRevokedEvent(VettedSecondFactorRevokedEvent $event)
995
    {
996
        $this->vettedSecondFactors->remove((string)$event->secondFactorId);
997
    }
998
999
    protected function applyCompliedWithVettedSecondFactorRevocationEvent(
1000
        CompliedWithVettedSecondFactorRevocationEvent $event
1001
    ) {
1002
        $this->vettedSecondFactors->remove((string)$event->secondFactorId);
1003
    }
1004
1005 View Code Duplication
    protected function applyIdentityAccreditedAsRaForInstitutionEvent(IdentityAccreditedAsRaForInstitutionEvent $event)
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...
1006
    {
1007
        $this->registrationAuthorities->set($event->raInstitution, RegistrationAuthority::accreditWith(
1008
            $event->registrationAuthorityRole,
1009
            $event->location,
1010
            $event->contactInformation,
1011
            $event->raInstitution
1012
        ));
1013
    }
1014
1015 View Code Duplication
    protected function applyIdentityAccreditedAsRaaForInstitutionEvent(IdentityAccreditedAsRaaForInstitutionEvent $event)
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...
1016
    {
1017
        $this->registrationAuthorities->set($event->raInstitution, RegistrationAuthority::accreditWith(
1018
            $event->registrationAuthorityRole,
1019
            $event->location,
1020
            $event->contactInformation,
1021
            $event->raInstitution
1022
        ));
1023
    }
1024
1025
    protected function applyRegistrationAuthorityInformationAmendedForInstitutionEvent(
1026
        RegistrationAuthorityInformationAmendedForInstitutionEvent $event
1027
    ) {
1028
        $this->registrationAuthorities->get($event->raInstitution)->amendInformation($event->location, $event->contactInformation);
1029
    }
1030
1031
    protected function applyAppointedAsRaaForInstitutionEvent(AppointedAsRaaForInstitutionEvent $event)
1032
    {
1033
        $this->registrationAuthorities->get($event->raInstitution)->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RAA));
1034
    }
1035
1036
    protected function applyRegistrationAuthorityRetractedForInstitutionEvent(RegistrationAuthorityRetractedForInstitutionEvent $event)
1037
    {
1038
        $this->registrationAuthorities->remove($event->raInstitution);
1039
    }
1040
1041
    protected function applyLocalePreferenceExpressedEvent(LocalePreferenceExpressedEvent $event)
1042
    {
1043
        $this->preferredLocale = $event->preferredLocale;
1044
    }
1045
1046
    protected function applyIdentityForgottenEvent(IdentityForgottenEvent $event)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1047
    {
1048
        $this->commonName = CommonName::unknown();
1049
        $this->email = Email::unknown();
1050
        $this->forgotten = true;
1051
    }
1052
1053
    /**
1054
     * This method is kept to be backwards compatible for changes before FGA
1055
     *
1056
     * @param AppointedAsRaEvent $event
1057
     */
1058
    protected function applyAppointedAsRaEvent(AppointedAsRaEvent $event)
1059
    {
1060
        $this->registrationAuthorities->get($event->identityInstitution)
1061
            ->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA));
1062
    }
1063
1064
    /**
1065
     * This method is kept to be backwards compatible for changes before FGA
1066
     *
1067
     * @param AppointedAsRaaEvent $event
1068
     */
1069
    protected function applyAppointedAsRaaEvent(AppointedAsRaaEvent $event)
1070
    {
1071
        $this->registrationAuthorities->get($event->identityInstitution)
1072
            ->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RAA));
1073
    }
1074
1075
    /**
1076
     * This method is kept to be backwards compatible for changes before FGA
1077
     *
1078
     * @param AppointedAsRaaEvent $event
0 ignored issues
show
Documentation introduced by
Should the type for parameter $event not be IdentityAccreditedAsRaEvent?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1079
     */
1080 View Code Duplication
    protected function applyIdentityAccreditedAsRaEvent(IdentityAccreditedAsRaEvent $event)
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...
1081
    {
1082
        $this->registrationAuthorities->set($event->identityInstitution, RegistrationAuthority::accreditWith(
1083
            $event->registrationAuthorityRole,
1084
            $event->location,
1085
            $event->contactInformation,
1086
            $event->identityInstitution
1087
        ));
1088
    }
1089
1090
    /**
1091
     * This method is kept to be backwards compatible for changes before FGA
1092
     *
1093
     * @param IdentityAccreditedAsRaaEvent $event
1094
     */
1095 View Code Duplication
    protected function applyIdentityAccreditedAsRaaEvent(IdentityAccreditedAsRaaEvent $event)
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...
1096
    {
1097
        $this->registrationAuthorities->set($event->identityInstitution, RegistrationAuthority::accreditWith(
1098
            $event->registrationAuthorityRole,
1099
            $event->location,
1100
            $event->contactInformation,
1101
            $event->identityInstitution
1102
        ));
1103
    }
1104
1105
    /**
1106
     * This method is kept to be backwards compatible for changes before FGA
1107
     *
1108
     * @param AppointedAsRaForInstitutionEvent $event
1109
     */
1110
    protected function applyAppointedAsRaForInstitutionEvent(AppointedAsRaForInstitutionEvent $event)
1111
    {
1112
        $this->registrationAuthorities->get($event->identityInstitution)
1113
            ->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA));
1114
    }
1115
1116
    /**
1117
     * This method is kept to be backwards compatible for changes before FGA
1118
     *
1119
     * @param RegistrationAuthorityInformationAmendedEvent $event
1120
     */
1121
    protected function applyRegistrationAuthorityInformationAmendedEvent(
1122
        RegistrationAuthorityInformationAmendedEvent $event
1123
    ) {
1124
        $this->registrationAuthorities->get($event->identityInstitution)->amendInformation($event->location, $event->contactInformation);
1125
    }
1126
1127
    /**
1128
     * This method is kept to be backwards compatible for changes before FGA
1129
     *
1130
     * @param RegistrationAuthorityRetractedEvent $event
1131
     */
1132
    protected function applyRegistrationAuthorityRetractedEvent(RegistrationAuthorityRetractedEvent $event)
1133
    {
1134
        $this->registrationAuthorities->remove($event->identityInstitution);
1135
    }
1136
1137
1138
    public function getAggregateRootId(): string
1139
    {
1140
        return $this->id->getIdentityId();
1141
    }
1142
1143
    protected function getChildEntities(): array
1144
    {
1145
        return array_merge(
1146
            $this->unverifiedSecondFactors->getValues(),
1147
            $this->verifiedSecondFactors->getValues(),
1148
            $this->vettedSecondFactors->getValues(),
1149
            $this->registrationAuthorities->getValues()
1150
        );
1151
    }
1152
1153
    /**
1154
     * @throws DomainException
1155
     */
1156
    private function assertNotForgotten()
1157
    {
1158
        if ($this->forgotten) {
1159
            throw new DomainException('Operation on this Identity is not allowed: it has been forgotten');
1160
        }
1161
    }
1162
1163
    /**
1164
     * @throws DomainException
1165
     */
1166
    private function assertUserMayAddSecondFactor()
1167
    {
1168
        if (count($this->unverifiedSecondFactors) +
1169
            count($this->verifiedSecondFactors) +
1170
            count($this->vettedSecondFactors) >= $this->maxNumberOfTokens
1171
        ) {
1172
            throw new DomainException(
1173
                sprintf('User may not have more than %d token(s)', $this->maxNumberOfTokens)
1174
            );
1175
        }
1176
    }
1177
1178
    public function getId()
1179
    {
1180
        return $this->id;
1181
    }
1182
1183
    /**
1184
     * @return NameId
1185
     */
1186
    public function getNameId()
1187
    {
1188
        return $this->nameId;
1189
    }
1190
1191
    /**
1192
     * @return Institution
1193
     */
1194
    public function getInstitution()
1195
    {
1196
        return $this->institution;
1197
    }
1198
1199
    public function getCommonName()
1200
    {
1201
        return $this->commonName;
1202
    }
1203
1204
    public function getEmail()
1205
    {
1206
        return $this->email;
1207
    }
1208
1209
    public function getPreferredLocale()
1210
    {
1211
        return $this->preferredLocale;
1212
    }
1213
1214
    /**
1215
     * @param SecondFactorId $secondFactorId
1216
     * @return VerifiedSecondFactor|null
1217
     */
1218
    public function getVerifiedSecondFactor(SecondFactorId $secondFactorId)
1219
    {
1220
        return $this->verifiedSecondFactors->get((string)$secondFactorId);
1221
    }
1222
}
1223