Completed
Push — feature/upgrade-remote-vetting ( bf22f6 )
by
unknown
02:39
created

applyRegistrationAuthorityInformationAmendedEvent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
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\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
        $secondFactor->vet(DocumentNumber::unknown(), false);
515
    }
516
517
    public function complyWithVettingOfSecondFactor(
518
        SecondFactorId $secondFactorId,
519
        SecondFactorType $secondFactorType,
520
        SecondFactorIdentifier $secondFactorIdentifier,
521
        $registrationCode,
522
        DocumentNumber $documentNumber,
523
        $provePossessionSkipped
524
    ) {
525
        $this->assertNotForgotten();
526
527
        $secondFactorToVet = null;
528
        foreach ($this->verifiedSecondFactors as $secondFactor) {
529
            /** @var VerifiedSecondFactor $secondFactor */
530
            if ($secondFactor->hasRegistrationCodeAndIdentifier($registrationCode, $secondFactorIdentifier)) {
531
                $secondFactorToVet = $secondFactor;
532
            }
533
        }
534
535
        if (!$secondFactorToVet) {
536
            throw new DomainException(
537
                'Cannot vet second factor, no verified second factor can be vetted using the given registration code ' .
538
                'and second factor identifier'
539
            );
540
        }
541
542
        if (!$secondFactorToVet->canBeVettedNow()) {
543
            throw new DomainException('Cannot vet second factor, the registration window is closed.');
544
        }
545
546
        $secondFactorToVet->vet($documentNumber, $provePossessionSkipped);
547
    }
548
549
    public function revokeSecondFactor(SecondFactorId $secondFactorId)
550
    {
551
        $this->assertNotForgotten();
552
553
        /** @var UnverifiedSecondFactor|null $unverifiedSecondFactor */
554
        $unverifiedSecondFactor = $this->unverifiedSecondFactors->get((string)$secondFactorId);
555
        /** @var VerifiedSecondFactor|null $verifiedSecondFactor */
556
        $verifiedSecondFactor = $this->verifiedSecondFactors->get((string)$secondFactorId);
557
        /** @var VettedSecondFactor|null $vettedSecondFactor */
558
        $vettedSecondFactor = $this->vettedSecondFactors->get((string)$secondFactorId);
559
560
        if (!$unverifiedSecondFactor && !$verifiedSecondFactor && !$vettedSecondFactor) {
561
            throw new DomainException('Cannot revoke second factor: no second factor with given id exists.');
562
        }
563
564
        if ($unverifiedSecondFactor) {
565
            $unverifiedSecondFactor->revoke();
566
567
            return;
568
        }
569
570
        if ($verifiedSecondFactor) {
571
            $verifiedSecondFactor->revoke();
572
573
            return;
574
        }
575
576
        $vettedSecondFactor->revoke();
577
578
        if ($this->vettedSecondFactors->isEmpty()) {
579
            $this->allVettedSecondFactorsRemoved();
580
        }
581
    }
582
583
    public function complyWithSecondFactorRevocation(SecondFactorId $secondFactorId, IdentityId $authorityId)
584
    {
585
        $this->assertNotForgotten();
586
587
        /** @var UnverifiedSecondFactor|null $unverifiedSecondFactor */
588
        $unverifiedSecondFactor = $this->unverifiedSecondFactors->get((string)$secondFactorId);
589
        /** @var VerifiedSecondFactor|null $verifiedSecondFactor */
590
        $verifiedSecondFactor = $this->verifiedSecondFactors->get((string)$secondFactorId);
591
        /** @var VettedSecondFactor|null $vettedSecondFactor */
592
        $vettedSecondFactor = $this->vettedSecondFactors->get((string)$secondFactorId);
593
594
        if (!$unverifiedSecondFactor && !$verifiedSecondFactor && !$vettedSecondFactor) {
595
            throw new DomainException('Cannot revoke second factor: no second factor with given id exists.');
596
        }
597
598
        if ($unverifiedSecondFactor) {
599
            $unverifiedSecondFactor->complyWithRevocation($authorityId);
600
601
            return;
602
        }
603
604
        if ($verifiedSecondFactor) {
605
            $verifiedSecondFactor->complyWithRevocation($authorityId);
606
607
            return;
608
        }
609
610
        $vettedSecondFactor->complyWithRevocation($authorityId);
611
612
        if ($this->vettedSecondFactors->isEmpty()) {
613
            $this->allVettedSecondFactorsRemoved();
614
        }
615
    }
616
617
    /**
618
     * @param RegistrationAuthorityRole $role
619
     * @param Institution $institution
620
     * @param Location $location
621
     * @param ContactInformation $contactInformation
622
     * @param InstitutionConfiguration $institutionConfiguration
623
     * @return void
624
     */
625
    public function accreditWith(
626
        RegistrationAuthorityRole $role,
627
        Institution $institution,
628
        Location $location,
629
        ContactInformation $contactInformation,
630
        InstitutionConfiguration $institutionConfiguration
631
    ) {
632
        $this->assertNotForgotten();
633
634
        if (!$institutionConfiguration->isInstitutionAllowedToAccreditRoles(new ConfigurationInstitution($this->institution->getInstitution()))) {
635
            throw new DomainException('An Identity may only be accredited by configured institutions.');
636
        }
637
638
        if (!$this->vettedSecondFactors->count()) {
639
            throw new DomainException(
640
                'An Identity must have at least one vetted second factor before it can be accredited'
641
            );
642
        }
643
644
        if ($this->registrationAuthorities->exists($institution)) {
645
            throw new DomainException('Cannot accredit Identity as it has already been accredited for institution');
646
        }
647
648
        if ($role->equals(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA))) {
649
            $this->apply(new IdentityAccreditedAsRaForInstitutionEvent(
650
                $this->id,
651
                $this->nameId,
652
                $this->institution,
653
                $role,
654
                $location,
655
                $contactInformation,
656
                $institution
657
            ));
658 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...
659
            $this->apply(new IdentityAccreditedAsRaaForInstitutionEvent(
660
                $this->id,
661
                $this->nameId,
662
                $this->institution,
663
                $role,
664
                $location,
665
                $contactInformation,
666
                $institution
667
            ));
668
        } else {
669
            throw new DomainException('An Identity can only be accredited with either the RA or RAA role');
670
        }
671
    }
672
673
    public function amendRegistrationAuthorityInformation(Institution $institution, Location $location, ContactInformation $contactInformation)
674
    {
675
        $this->assertNotForgotten();
676
677
        if (!$this->registrationAuthorities->exists($institution)) {
678
            throw new DomainException(
679
                'Cannot amend registration authority information: identity is not a registration authority for institution'
680
            );
681
        }
682
683
        $this->apply(
684
            new RegistrationAuthorityInformationAmendedForInstitutionEvent(
685
                $this->id,
686
                $this->institution,
687
                $this->nameId,
688
                $location,
689
                $contactInformation,
690
                $institution
691
            )
692
        );
693
    }
694
695
    /**
696
     * This method will appoint an institution to become ra or raa for another institution
697
     *
698
     * @param Institution $institution
699
     * @param RegistrationAuthorityRole $role
700
     * @param InstitutionConfiguration $institutionConfiguration
701
     */
702
    public function appointAs(
703
        Institution $institution,
704
        RegistrationAuthorityRole $role,
705
        InstitutionConfiguration $institutionConfiguration
706
    ) {
707
        $this->assertNotForgotten();
708
709
        if (!$institutionConfiguration->isInstitutionAllowedToAccreditRoles(new ConfigurationInstitution($this->institution->getInstitution()))) {
710
            throw new DomainException(
711
                'Cannot appoint as different RegistrationAuthorityRole: identity is not a registration authority for institution'
712
            );
713
        }
714
715
        $registrationAuthority = $this->registrationAuthorities->get($institution);
716
717
        if ($registrationAuthority->isAppointedAs($role)) {
718
            return;
719
        }
720
721
        if ($role->equals(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA))) {
722
            $this->apply(new AppointedAsRaForInstitutionEvent($this->id, $this->institution, $this->nameId, $institution));
723 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...
724
            $this->apply(new AppointedAsRaaForInstitutionEvent($this->id, $this->institution, $this->nameId, $institution));
725
        } else {
726
            throw new DomainException('An Identity can only be appointed as either RA or RAA');
727
        }
728
    }
729
730
    public function retractRegistrationAuthority(Institution $institution)
731
    {
732
        $this->assertNotForgotten();
733
734
        if (!$this->registrationAuthorities->exists($institution)) {
735
            throw new DomainException(
736
                'Cannot Retract Registration Authority as the Identity is not a registration authority'
737
            );
738
        }
739
740
        $this->apply(new RegistrationAuthorityRetractedForInstitutionEvent(
741
            $this->id,
742
            $this->institution,
743
            $this->nameId,
744
            $this->commonName,
745
            $this->email,
746
            $institution
747
        ));
748
    }
749
750
    public function expressPreferredLocale(Locale $preferredLocale)
751
    {
752
        $this->assertNotForgotten();
753
754
        if ($this->preferredLocale === $preferredLocale) {
755
            return;
756
        }
757
758
        $this->apply(new LocalePreferenceExpressedEvent($this->id, $this->institution, $preferredLocale));
759
    }
760
761
    public function forget()
762
    {
763
        $this->assertNotForgotten();
764
765
        if ($this->registrationAuthorities->count()) {
766
            throw new DomainException('Cannot forget an identity that is currently accredited as an RA(A)');
767
        }
768
769
        $this->apply(new IdentityForgottenEvent($this->id, $this->institution));
770
    }
771
772
    public function allVettedSecondFactorsRemoved()
773
    {
774
        $this->apply(
775
            new VettedSecondFactorsAllRevokedEvent(
776
                $this->id,
777
                $this->institution
778
            )
779
        );
780
    }
781
782
    protected function applyIdentityCreatedEvent(IdentityCreatedEvent $event)
783
    {
784
        $this->id = $event->identityId;
785
        $this->institution = $event->identityInstitution;
786
        $this->nameId = $event->nameId;
787
        $this->commonName = $event->commonName;
788
        $this->email = $event->email;
789
        $this->preferredLocale = $event->preferredLocale;
790
        $this->forgotten = false;
791
792
        $this->unverifiedSecondFactors = new SecondFactorCollection();
793
        $this->verifiedSecondFactors = new SecondFactorCollection();
794
        $this->vettedSecondFactors = new SecondFactorCollection();
795
        $this->registrationAuthorities = new RegistrationAuthorityCollection();
796
    }
797
798
    public function applyIdentityRenamedEvent(IdentityRenamedEvent $event)
799
    {
800
        $this->commonName = $event->commonName;
801
    }
802
803
    public function applyIdentityEmailChangedEvent(IdentityEmailChangedEvent $event)
804
    {
805
        $this->email = $event->email;
806
    }
807
808
    protected function applyYubikeySecondFactorBootstrappedEvent(YubikeySecondFactorBootstrappedEvent $event)
809
    {
810
        $secondFactor = VettedSecondFactor::create(
811
            $event->secondFactorId,
812
            $this,
813
            new SecondFactorType('yubikey'),
814
            $event->yubikeyPublicId
815
        );
816
817
        $this->vettedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
818
    }
819
820 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...
821
    {
822
        $secondFactor = UnverifiedSecondFactor::create(
823
            $event->secondFactorId,
824
            $this,
825
            new SecondFactorType('yubikey'),
826
            $event->yubikeyPublicId,
827
            $event->emailVerificationWindow,
828
            $event->emailVerificationNonce
829
        );
830
831
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
832
    }
833
834 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...
835
    {
836
        $secondFactor = VerifiedSecondFactor::create(
837
            $event->secondFactorId,
838
            $this,
839
            new SecondFactorType('yubikey'),
840
            $event->yubikeyPublicId,
841
            $event->registrationRequestedAt,
842
            $event->registrationCode
843
        );
844
845
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
846
    }
847
848 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...
849
    {
850
        $secondFactor = UnverifiedSecondFactor::create(
851
            $event->secondFactorId,
852
            $this,
853
            new SecondFactorType('sms'),
854
            $event->phoneNumber,
855
            $event->emailVerificationWindow,
856
            $event->emailVerificationNonce
857
        );
858
859
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
860
    }
861
862 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...
863
    {
864
        $secondFactor = VerifiedSecondFactor::create(
865
            $event->secondFactorId,
866
            $this,
867
            new SecondFactorType('sms'),
868
            $event->phoneNumber,
869
            $event->registrationRequestedAt,
870
            $event->registrationCode
871
        );
872
873
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
874
    }
875
876 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...
877
    {
878
        $secondFactor = UnverifiedSecondFactor::create(
879
            $event->secondFactorId,
880
            $this,
881
            new SecondFactorType((string)$event->stepupProvider),
882
            $event->gssfId,
883
            $event->emailVerificationWindow,
884
            $event->emailVerificationNonce
885
        );
886
887
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
888
    }
889
890 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...
891
    {
892
        $secondFactor = VerifiedSecondFactor::create(
893
            $event->secondFactorId,
894
            $this,
895
            new SecondFactorType((string)$event->stepupProvider),
896
            $event->gssfId,
897
            $event->registrationRequestedAt,
898
            $event->registrationCode
899
        );
900
901
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
902
    }
903
904 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...
905
    {
906
        $secondFactor = UnverifiedSecondFactor::create(
907
            $event->secondFactorId,
908
            $this,
909
            new SecondFactorType('u2f'),
910
            $event->keyHandle,
911
            $event->emailVerificationWindow,
912
            $event->emailVerificationNonce
913
        );
914
915
        $this->unverifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
916
    }
917
918 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...
919
    {
920
        $secondFactor = VerifiedSecondFactor::create(
921
            $event->secondFactorId,
922
            $this,
923
            new SecondFactorType('u2f'),
924
            $event->keyHandle,
925
            $event->registrationRequestedAt,
926
            $event->registrationCode
927
        );
928
929
        $this->verifiedSecondFactors->set((string)$secondFactor->getId(), $secondFactor);
930
    }
931
932
    protected function applyEmailVerifiedEvent(EmailVerifiedEvent $event)
933
    {
934
        $secondFactorId = (string)$event->secondFactorId;
935
936
        /** @var UnverifiedSecondFactor $unverified */
937
        $unverified = $this->unverifiedSecondFactors->get($secondFactorId);
938
        $verified = $unverified->asVerified($event->registrationRequestedAt, $event->registrationCode);
939
940
        $this->unverifiedSecondFactors->remove($secondFactorId);
941
        $this->verifiedSecondFactors->set($secondFactorId, $verified);
942
    }
943
944 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...
945
    {
946
        $secondFactorId = (string)$event->secondFactorId;
947
948
        /** @var VerifiedSecondFactor $verified */
949
        $verified = $this->verifiedSecondFactors->get($secondFactorId);
950
        $vetted = $verified->asVetted();
951
952
        $this->verifiedSecondFactors->remove($secondFactorId);
953
        $this->vettedSecondFactors->set($secondFactorId, $vetted);
954
    }
955
956 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...
957
    {
958
        $secondFactorId = (string)$event->secondFactorId;
959
960
        /** @var VerifiedSecondFactor $verified */
961
        $verified = $this->verifiedSecondFactors->get($secondFactorId);
962
        $vetted = $verified->asVetted();
963
964
        $this->verifiedSecondFactors->remove($secondFactorId);
965
        $this->vettedSecondFactors->set($secondFactorId, $vetted);
966
    }
967
968
    protected function applyUnverifiedSecondFactorRevokedEvent(UnverifiedSecondFactorRevokedEvent $event)
969
    {
970
        $this->unverifiedSecondFactors->remove((string)$event->secondFactorId);
971
    }
972
973
    protected function applyCompliedWithUnverifiedSecondFactorRevocationEvent(
974
        CompliedWithUnverifiedSecondFactorRevocationEvent $event
975
    ) {
976
        $this->unverifiedSecondFactors->remove((string)$event->secondFactorId);
977
    }
978
979
    protected function applyVerifiedSecondFactorRevokedEvent(VerifiedSecondFactorRevokedEvent $event)
980
    {
981
        $this->verifiedSecondFactors->remove((string)$event->secondFactorId);
982
    }
983
984
    protected function applyCompliedWithVerifiedSecondFactorRevocationEvent(
985
        CompliedWithVerifiedSecondFactorRevocationEvent $event
986
    ) {
987
        $this->verifiedSecondFactors->remove((string)$event->secondFactorId);
988
    }
989
990
    protected function applyVettedSecondFactorRevokedEvent(VettedSecondFactorRevokedEvent $event)
991
    {
992
        $this->vettedSecondFactors->remove((string)$event->secondFactorId);
993
    }
994
995
    protected function applyCompliedWithVettedSecondFactorRevocationEvent(
996
        CompliedWithVettedSecondFactorRevocationEvent $event
997
    ) {
998
        $this->vettedSecondFactors->remove((string)$event->secondFactorId);
999
    }
1000
1001 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...
1002
    {
1003
        $this->registrationAuthorities->set($event->raInstitution, RegistrationAuthority::accreditWith(
1004
            $event->registrationAuthorityRole,
1005
            $event->location,
1006
            $event->contactInformation,
1007
            $event->raInstitution
1008
        ));
1009
    }
1010
1011 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...
1012
    {
1013
        $this->registrationAuthorities->set($event->raInstitution, RegistrationAuthority::accreditWith(
1014
            $event->registrationAuthorityRole,
1015
            $event->location,
1016
            $event->contactInformation,
1017
            $event->raInstitution
1018
        ));
1019
    }
1020
1021
    protected function applyRegistrationAuthorityInformationAmendedForInstitutionEvent(
1022
        RegistrationAuthorityInformationAmendedForInstitutionEvent $event
1023
    ) {
1024
        $this->registrationAuthorities->get($event->raInstitution)->amendInformation($event->location, $event->contactInformation);
1025
    }
1026
1027
    protected function applyAppointedAsRaaForInstitutionEvent(AppointedAsRaaForInstitutionEvent $event)
1028
    {
1029
        $this->registrationAuthorities->get($event->raInstitution)->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RAA));
1030
    }
1031
1032
    protected function applyRegistrationAuthorityRetractedForInstitutionEvent(RegistrationAuthorityRetractedForInstitutionEvent $event)
1033
    {
1034
        $this->registrationAuthorities->remove($event->raInstitution);
1035
    }
1036
1037
    protected function applyLocalePreferenceExpressedEvent(LocalePreferenceExpressedEvent $event)
1038
    {
1039
        $this->preferredLocale = $event->preferredLocale;
1040
    }
1041
1042
    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...
1043
    {
1044
        $this->commonName = CommonName::unknown();
1045
        $this->email = Email::unknown();
1046
        $this->forgotten = true;
1047
    }
1048
1049
    /**
1050
     * This method is kept to be backwards compatible for changes before FGA
1051
     *
1052
     * @param AppointedAsRaEvent $event
1053
     */
1054
    protected function applyAppointedAsRaEvent(AppointedAsRaEvent $event)
1055
    {
1056
        $this->registrationAuthorities->get($event->identityInstitution)
1057
            ->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA));
1058
    }
1059
1060
    /**
1061
     * This method is kept to be backwards compatible for changes before FGA
1062
     *
1063
     * @param AppointedAsRaaEvent $event
1064
     */
1065
    protected function applyAppointedAsRaaEvent(AppointedAsRaaEvent $event)
1066
    {
1067
        $this->registrationAuthorities->get($event->identityInstitution)
1068
            ->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RAA));
1069
    }
1070
1071
    /**
1072
     * This method is kept to be backwards compatible for changes before FGA
1073
     *
1074
     * @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...
1075
     */
1076 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...
1077
    {
1078
        $this->registrationAuthorities->set($event->identityInstitution, RegistrationAuthority::accreditWith(
1079
            $event->registrationAuthorityRole,
1080
            $event->location,
1081
            $event->contactInformation,
1082
            $event->identityInstitution
1083
        ));
1084
    }
1085
1086
    /**
1087
     * This method is kept to be backwards compatible for changes before FGA
1088
     *
1089
     * @param IdentityAccreditedAsRaaEvent $event
1090
     */
1091 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...
1092
    {
1093
        $this->registrationAuthorities->set($event->identityInstitution, RegistrationAuthority::accreditWith(
1094
            $event->registrationAuthorityRole,
1095
            $event->location,
1096
            $event->contactInformation,
1097
            $event->identityInstitution
1098
        ));
1099
    }
1100
1101
    /**
1102
     * This method is kept to be backwards compatible for changes before FGA
1103
     *
1104
     * @param AppointedAsRaForInstitutionEvent $event
1105
     */
1106
    protected function applyAppointedAsRaForInstitutionEvent(AppointedAsRaForInstitutionEvent $event)
1107
    {
1108
        $this->registrationAuthorities->get($event->identityInstitution)
1109
            ->appointAs(new RegistrationAuthorityRole(RegistrationAuthorityRole::ROLE_RA));
1110
    }
1111
1112
    /**
1113
     * This method is kept to be backwards compatible for changes before FGA
1114
     *
1115
     * @param RegistrationAuthorityInformationAmendedEvent $event
1116
     */
1117
    protected function applyRegistrationAuthorityInformationAmendedEvent(
1118
        RegistrationAuthorityInformationAmendedEvent $event
1119
    ) {
1120
        $this->registrationAuthorities->get($event->identityInstitution)->amendInformation($event->location, $event->contactInformation);
1121
    }
1122
1123
    /**
1124
     * This method is kept to be backwards compatible for changes before FGA
1125
     *
1126
     * @param RegistrationAuthorityRetractedEvent $event
1127
     */
1128
    protected function applyRegistrationAuthorityRetractedEvent(RegistrationAuthorityRetractedEvent $event)
1129
    {
1130
        $this->registrationAuthorities->remove($event->identityInstitution);
1131
    }
1132
1133
1134
    public function getAggregateRootId(): string
1135
    {
1136
        return $this->id->getIdentityId();
1137
    }
1138
1139
    protected function getChildEntities(): array
1140
    {
1141
        return array_merge(
1142
            $this->unverifiedSecondFactors->getValues(),
1143
            $this->verifiedSecondFactors->getValues(),
1144
            $this->vettedSecondFactors->getValues(),
1145
            $this->registrationAuthorities->getValues()
1146
        );
1147
    }
1148
1149
    /**
1150
     * @throws DomainException
1151
     */
1152
    private function assertNotForgotten()
1153
    {
1154
        if ($this->forgotten) {
1155
            throw new DomainException('Operation on this Identity is not allowed: it has been forgotten');
1156
        }
1157
    }
1158
1159
    /**
1160
     * @throws DomainException
1161
     */
1162
    private function assertUserMayAddSecondFactor()
1163
    {
1164
        if (count($this->unverifiedSecondFactors) +
1165
            count($this->verifiedSecondFactors) +
1166
            count($this->vettedSecondFactors) >= $this->maxNumberOfTokens
1167
        ) {
1168
            throw new DomainException(
1169
                sprintf('User may not have more than %d token(s)', $this->maxNumberOfTokens)
1170
            );
1171
        }
1172
    }
1173
1174
    public function getId()
1175
    {
1176
        return $this->id;
1177
    }
1178
1179
    /**
1180
     * @return NameId
1181
     */
1182
    public function getNameId()
1183
    {
1184
        return $this->nameId;
1185
    }
1186
1187
    /**
1188
     * @return Institution
1189
     */
1190
    public function getInstitution()
1191
    {
1192
        return $this->institution;
1193
    }
1194
1195
    public function getCommonName()
1196
    {
1197
        return $this->commonName;
1198
    }
1199
1200
    public function getEmail()
1201
    {
1202
        return $this->email;
1203
    }
1204
1205
    public function getPreferredLocale()
1206
    {
1207
        return $this->preferredLocale;
1208
    }
1209
1210
    /**
1211
     * @param SecondFactorId $secondFactorId
1212
     * @return VerifiedSecondFactor|null
1213
     */
1214
    public function getVerifiedSecondFactor(SecondFactorId $secondFactorId)
1215
    {
1216
        return $this->verifiedSecondFactors->get((string)$secondFactorId);
1217
    }
1218
}
1219