applyVettedSecondFactorRevokedEvent()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
 */
0 ignored issues
show
Coding Style introduced by
Missing @link tag in file comment
Loading history...
18
19
namespace Surfnet\StepupMiddleware\ApiBundle\Identity\Projector;
20
21
use Surfnet\Stepup\Projector\Projector;
22
use Surfnet\Stepup\Identity\Event\CompliedWithUnverifiedSecondFactorRevocationEvent;
23
use Surfnet\Stepup\Identity\Event\CompliedWithVerifiedSecondFactorRevocationEvent;
24
use Surfnet\Stepup\Identity\Event\CompliedWithVettedSecondFactorRevocationEvent;
25
use Surfnet\Stepup\Identity\Event\EmailVerifiedEvent;
26
use Surfnet\Stepup\Identity\Event\GssfPossessionProvenAndVerifiedEvent;
27
use Surfnet\Stepup\Identity\Event\GssfPossessionProvenEvent;
28
use Surfnet\Stepup\Identity\Event\IdentityEmailChangedEvent;
29
use Surfnet\Stepup\Identity\Event\IdentityForgottenEvent;
30
use Surfnet\Stepup\Identity\Event\IdentityRenamedEvent;
31
use Surfnet\Stepup\Identity\Event\PhonePossessionProvenAndVerifiedEvent;
32
use Surfnet\Stepup\Identity\Event\PhonePossessionProvenEvent;
33
use Surfnet\Stepup\Identity\Event\SecondFactorMigratedEvent;
34
use Surfnet\Stepup\Identity\Event\SecondFactorVettedEvent;
35
use Surfnet\Stepup\Identity\Event\SecondFactorVettedWithoutTokenProofOfPossession;
36
use Surfnet\Stepup\Identity\Event\U2fDevicePossessionProvenAndVerifiedEvent;
37
use Surfnet\Stepup\Identity\Event\U2fDevicePossessionProvenEvent;
38
use Surfnet\Stepup\Identity\Event\UnverifiedSecondFactorRevokedEvent;
39
use Surfnet\Stepup\Identity\Event\VerifiedSecondFactorRevokedEvent;
40
use Surfnet\Stepup\Identity\Event\VettedSecondFactorRevokedEvent;
41
use Surfnet\Stepup\Identity\Event\YubikeyPossessionProvenAndVerifiedEvent;
42
use Surfnet\Stepup\Identity\Event\YubikeyPossessionProvenEvent;
43
use Surfnet\Stepup\Identity\Event\YubikeySecondFactorBootstrappedEvent;
44
use Surfnet\Stepup\Identity\Value\CommonName;
45
use Surfnet\Stepup\Identity\Value\DocumentNumber;
46
use Surfnet\Stepup\Identity\Value\Email;
47
use Surfnet\Stepup\Identity\Value\OnPremiseVettingType;
48
use Surfnet\Stepup\Identity\Value\SecondFactorId;
49
use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\RaSecondFactor;
50
use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentityRepository;
51
use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\RaSecondFactorRepository;
52
use Surfnet\StepupMiddleware\ApiBundle\Identity\Value\SecondFactorStatus;
0 ignored issues
show
Bug introduced by
The type Surfnet\StepupMiddleware...alue\SecondFactorStatus was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
53
54
/**
55
 * @SuppressWarnings(PHPMD.TooManyMethods)
56
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
57
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
58
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
59
class RaSecondFactorProjector extends Projector
60
{
61
    public function __construct(
62
        private readonly RaSecondFactorRepository $raSecondFactorRepository,
63
        private readonly IdentityRepository $identityRepository,
64
    ) {
65
    }
66
67
    public function applyIdentityRenamedEvent(IdentityRenamedEvent $event): void
68
    {
69
        $secondFactors = $this->raSecondFactorRepository->findByIdentityId((string)$event->identityId);
70
71
        if ($secondFactors === []) {
72
            return;
73
        }
74
75
        $commonName = $event->commonName;
76
77
        foreach ($secondFactors as $secondFactor) {
78
            $secondFactor->name = $commonName;
79
        }
80
81
        $this->raSecondFactorRepository->saveAll($secondFactors);
82
    }
83
84
    public function applyIdentityEmailChangedEvent(IdentityEmailChangedEvent $event): void
85
    {
86
        $secondFactors = $this->raSecondFactorRepository->findByIdentityId((string)$event->identityId);
87
88
        if ($secondFactors === []) {
89
            return;
90
        }
91
92
        $email = $event->email;
93
94
        foreach ($secondFactors as $secondFactor) {
95
            $secondFactor->email = $email;
96
        }
97
98
        $this->raSecondFactorRepository->saveAll($secondFactors);
99
    }
100
101
    public function applyYubikeySecondFactorBootstrappedEvent(YubikeySecondFactorBootstrappedEvent $event): void
102
    {
103
        $identity = $this->identityRepository->find((string)$event->identityId);
104
105
        $secondFactor = new RaSecondFactor(
106
            (string)$event->secondFactorId,
107
            'yubikey',
108
            (string)$event->yubikeyPublicId,
109
            $identity->id,
110
            $identity->institution,
111
            $event->commonName,
112
            $event->email,
113
        );
114
        $secondFactor->status = SecondFactorStatus::vetted();
115
116
        $this->raSecondFactorRepository->save($secondFactor);
117
    }
118
119
    public function applyYubikeyPossessionProvenEvent(YubikeyPossessionProvenEvent $event): void
120
    {
121
        $this->saveRaSecondFactor(
122
            (string)$event->identityId,
123
            (string)$event->secondFactorId,
124
            'yubikey',
125
            (string)$event->yubikeyPublicId,
126
            $event->commonName,
127
            $event->email,
128
        );
129
    }
130
131
    public function applyYubikeyPossessionProvenAndVerifiedEvent(YubikeyPossessionProvenAndVerifiedEvent $event): void
132
    {
133
        $this->saveRaSecondFactor(
134
            (string)$event->identityId,
135
            (string)$event->secondFactorId,
136
            'yubikey',
137
            (string)$event->yubikeyPublicId,
138
            $event->commonName,
139
            $event->email,
140
        );
141
    }
142
143
    public function applyPhonePossessionProvenEvent(PhonePossessionProvenEvent $event): void
144
    {
145
        $this->saveRaSecondFactor(
146
            (string)$event->identityId,
147
            (string)$event->secondFactorId,
148
            'sms',
149
            (string)$event->phoneNumber,
150
            $event->commonName,
151
            $event->email,
152
        );
153
    }
154
155
    public function applyPhonePossessionProvenAndVerifiedEvent(PhonePossessionProvenAndVerifiedEvent $event): void
156
    {
157
        $this->saveRaSecondFactor(
158
            (string)$event->identityId,
159
            (string)$event->secondFactorId,
160
            'sms',
161
            (string)$event->phoneNumber,
162
            $event->commonName,
163
            $event->email,
164
        );
165
    }
166
167
    public function applyGssfPossessionProvenEvent(GssfPossessionProvenEvent $event): void
168
    {
169
        $this->saveRaSecondFactor(
170
            (string)$event->identityId,
171
            (string)$event->secondFactorId,
172
            (string)$event->stepupProvider,
173
            (string)$event->gssfId,
174
            $event->commonName,
175
            $event->email,
176
        );
177
    }
178
179
    public function applyGssfPossessionProvenAndVerifiedEvent(GssfPossessionProvenAndVerifiedEvent $event): void
180
    {
181
        $this->saveRaSecondFactor(
182
            (string)$event->identityId,
183
            (string)$event->secondFactorId,
184
            (string)$event->stepupProvider,
185
            (string)$event->gssfId,
186
            $event->commonName,
187
            $event->email,
188
        );
189
    }
190
191
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $event should have a doc-comment as per coding-style.
Loading history...
192
     * @deprecated Built in U2F support is dropped from StepUp, this was not removed to support event replay
193
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
194
    public function applyU2fDevicePossessionProvenEvent(U2fDevicePossessionProvenEvent $event): void
195
    {
196
        $this->saveRaSecondFactor(
197
            (string)$event->identityId,
198
            (string)$event->secondFactorId,
199
            'u2f',
200
            $event->keyHandle->getValue(),
201
            $event->commonName,
202
            $event->email,
203
        );
204
    }
205
206
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $event should have a doc-comment as per coding-style.
Loading history...
207
     * @deprecated Built in U2F support is dropped from StepUp, this was not removed to support event replay
208
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
209
    public function applyU2fDevicePossessionProvenAndVerifiedEvent(U2fDevicePossessionProvenAndVerifiedEvent $event,): void
210
    {
211
        $this->saveRaSecondFactor(
212
            (string)$event->identityId,
213
            (string)$event->secondFactorId,
214
            'u2f',
215
            $event->keyHandle->getValue(),
216
            $event->commonName,
217
            $event->email,
218
        );
219
    }
220
221
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $identityId should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorType should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorIdentifier should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $commonName should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $email should have a doc-comment as per coding-style.
Loading history...
222
     * @param SecondFactorStatus|null $status
0 ignored issues
show
Coding Style introduced by
Doc comment for parameter $status does not match actual variable name $identityId
Loading history...
223
     * @param DocumentNumber|null $documentNumber
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Doc comment for parameter $documentNumber does not match actual variable name $secondFactorId
Loading history...
224
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
225
    private function saveRaSecondFactor(
0 ignored issues
show
Coding Style introduced by
Private method name "RaSecondFactorProjector::saveRaSecondFactor" must be prefixed with an underscore
Loading history...
226
        string             $identityId,
227
        string             $secondFactorId,
228
        string             $secondFactorType,
229
        string             $secondFactorIdentifier,
230
        CommonName         $commonName,
231
        Email              $email,
232
        SecondFactorStatus $status = null,
233
        DocumentNumber     $documentNumber = null,
234
    ): void {
235
        $identity = $this->identityRepository->find($identityId);
236
237
        $secondFactor = new RaSecondFactor(
238
            $secondFactorId,
239
            $secondFactorType,
240
            $secondFactorIdentifier,
241
            $identity->id,
242
            $identity->institution,
243
            $commonName,
244
            $email,
245
            $documentNumber,
246
        );
247
248
        if ($status instanceof SecondFactorStatus) {
249
            $secondFactor->status = $status;
250
        }
251
252
        $this->raSecondFactorRepository->save($secondFactor);
253
    }
254
255
    public function applyEmailVerifiedEvent(EmailVerifiedEvent $event): void
256
    {
257
        $this->updateStatus($event->secondFactorId, SecondFactorStatus::verified());
258
    }
259
260
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $event should have a doc-comment as per coding-style.
Loading history...
261
     * The RA second factor projection is updated with a new Second factor based on the 'source' second factor
262
     * from the original identity.
263
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
264
    public function applySecondFactorMigratedEvent(SecondFactorMigratedEvent $event): void
265
    {
266
        $oldSecondFactor = $this->raSecondFactorRepository->find((string)$event->secondFactorId);
267
268
        $this->saveRaSecondFactor(
269
            (string)$event->identityId,
270
            (string)$event->newSecondFactorId,
271
            (string)$event->secondFactorType,
272
            (string)$event->secondFactorIdentifier,
273
            $event->commonName,
274
            $event->email,
275
            $oldSecondFactor->status,
276
            $oldSecondFactor->documentNumber,
277
        );
278
    }
279
280
    public function applySecondFactorVettedEvent(SecondFactorVettedEvent $event): void
281
    {
282
        $secondFactor = $this->raSecondFactorRepository->find((string)$event->secondFactorId);
283
        $secondFactor->documentNumber = $event->vettingType->getDocumentNumber();
0 ignored issues
show
Bug introduced by
The method getDocumentNumber() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

283
        /** @scrutinizer ignore-call */ 
284
        $secondFactor->documentNumber = $event->vettingType->getDocumentNumber();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
284
        $secondFactor->status = SecondFactorStatus::vetted();
285
286
        $this->raSecondFactorRepository->save($secondFactor);
0 ignored issues
show
Bug introduced by
It seems like $secondFactor can also be of type null; however, parameter $secondFactor of Surfnet\StepupMiddleware...actorRepository::save() does only seem to accept Surfnet\StepupMiddleware...y\Entity\RaSecondFactor, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

286
        $this->raSecondFactorRepository->save(/** @scrutinizer ignore-type */ $secondFactor);
Loading history...
287
    }
288
289
    public function applySecondFactorVettedWithoutTokenProofOfPossession(
290
        SecondFactorVettedWithoutTokenProofOfPossession $event,
291
    ): void {
292
        $secondFactor = $this->raSecondFactorRepository->find((string)$event->secondFactorId);
293
294
        $documentNumber = null;
295
        if ($event->vettingType instanceof OnPremiseVettingType) {
296
            $documentNumber = $event->vettingType->getDocumentNumber();
297
        }
298
        $secondFactor->documentNumber = $documentNumber;
299
        $secondFactor->status = SecondFactorStatus::vetted();
300
301
        $this->raSecondFactorRepository->save($secondFactor);
0 ignored issues
show
Bug introduced by
It seems like $secondFactor can also be of type null; however, parameter $secondFactor of Surfnet\StepupMiddleware...actorRepository::save() does only seem to accept Surfnet\StepupMiddleware...y\Entity\RaSecondFactor, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

301
        $this->raSecondFactorRepository->save(/** @scrutinizer ignore-type */ $secondFactor);
Loading history...
302
    }
303
304
    protected function applyUnverifiedSecondFactorRevokedEvent(UnverifiedSecondFactorRevokedEvent $event): void
305
    {
306
        $this->updateStatus($event->secondFactorId, SecondFactorStatus::revoked());
307
    }
308
309
    protected function applyCompliedWithUnverifiedSecondFactorRevocationEvent(
310
        CompliedWithUnverifiedSecondFactorRevocationEvent $event,
311
    ): void {
312
        $this->updateStatus($event->secondFactorId, SecondFactorStatus::revoked());
313
    }
314
315
    protected function applyVerifiedSecondFactorRevokedEvent(VerifiedSecondFactorRevokedEvent $event): void
316
    {
317
        $this->updateStatus($event->secondFactorId, SecondFactorStatus::revoked());
318
    }
319
320
    protected function applyCompliedWithVerifiedSecondFactorRevocationEvent(
321
        CompliedWithVerifiedSecondFactorRevocationEvent $event,
322
    ): void {
323
        $this->updateStatus($event->secondFactorId, SecondFactorStatus::revoked());
324
    }
325
326
    protected function applyVettedSecondFactorRevokedEvent(VettedSecondFactorRevokedEvent $event): void
327
    {
328
        $this->updateStatus($event->secondFactorId, SecondFactorStatus::revoked());
329
    }
330
331
    protected function applyCompliedWithVettedSecondFactorRevocationEvent(
332
        CompliedWithVettedSecondFactorRevocationEvent $event,
333
    ): void {
334
        $this->updateStatus($event->secondFactorId, SecondFactorStatus::revoked());
335
    }
336
337
    protected function applyIdentityForgottenEvent(IdentityForgottenEvent $event): void
338
    {
339
        $this->raSecondFactorRepository->updateStatusByIdentityIdToForgotten($event->identityId);
340
    }
341
342
    private function updateStatus(SecondFactorId $secondFactorId, SecondFactorStatus $status): void
0 ignored issues
show
Coding Style introduced by
Private method name "RaSecondFactorProjector::updateStatus" must be prefixed with an underscore
Loading history...
343
    {
344
        $secondFactor = $this->raSecondFactorRepository->find((string)$secondFactorId);
345
        $secondFactor->status = $status;
346
347
        $this->raSecondFactorRepository->save($secondFactor);
0 ignored issues
show
Bug introduced by
It seems like $secondFactor can also be of type null; however, parameter $secondFactor of Surfnet\StepupMiddleware...actorRepository::save() does only seem to accept Surfnet\StepupMiddleware...y\Entity\RaSecondFactor, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

347
        $this->raSecondFactorRepository->save(/** @scrutinizer ignore-type */ $secondFactor);
Loading history...
348
    }
349
}
350