Completed
Pull Request — feature/fine-grained-authoriza... (#246)
by
unknown
56:03 queued 45:22
created

RaCandidateProjector::addCandidateToProjection()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 9.0168
c 0
b 0
f 0
cc 5
nc 8
nop 5
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\StepupMiddleware\ApiBundle\Identity\Projector;
20
21
use Broadway\ReadModel\Projector;
22
use Surfnet\Stepup\Configuration\Event\InstitutionConfigurationRemovedEvent;
23
use Surfnet\Stepup\Configuration\Event\SelectRaaOptionChangedEvent;
24
use Surfnet\Stepup\Configuration\Event\SraaUpdatedEvent;
25
use Surfnet\Stepup\Identity\Collection\InstitutionCollection;
26
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaaForInstitutionEvent;
27
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaForInstitutionEvent;
28
use Surfnet\Stepup\Identity\Event\RegistrationAuthorityRetractedForInstitutionEvent;
29
use Surfnet\Stepup\Identity\Value\CommonName;
30
use Surfnet\Stepup\Identity\Value\Email;
31
use Surfnet\Stepup\Identity\Value\IdentityId;
32
use Surfnet\Stepup\Identity\Value\Institution;
33
use Surfnet\Stepup\Configuration\Value\Institution as ConfigurationInstitution;
34
use Surfnet\Stepup\Identity\Event\CompliedWithVettedSecondFactorRevocationEvent;
35
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaaEvent;
36
use Surfnet\Stepup\Identity\Event\IdentityAccreditedAsRaEvent;
37
use Surfnet\Stepup\Identity\Event\IdentityForgottenEvent;
38
use Surfnet\Stepup\Identity\Event\RegistrationAuthorityRetractedEvent;
39
use Surfnet\Stepup\Identity\Event\SecondFactorVettedEvent;
40
use Surfnet\Stepup\Identity\Event\VettedSecondFactorRevokedEvent;
41
use Surfnet\Stepup\Identity\Event\YubikeySecondFactorBootstrappedEvent;
42
use Surfnet\Stepup\Identity\Value\NameId;
43
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Repository\InstitutionAuthorizationRepository;
44
use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\RaCandidate;
45
use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentityRepository;
46
use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\RaCandidateRepository;
47
use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\RaListingRepository;
48
49
/**
50
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
51
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
52
 */
53
class RaCandidateProjector extends Projector
54
{
55
    /**
56
     * @var RaCandidateRepository
57
     */
58
    private $raCandidateRepository;
59
60
    /**
61
     * @var RaListingRepository
62
     */
63
    private $raListingRepository;
64
65
    /**
66
     * @var institutionAuthorizationRepository
67
     */
68
    private $institutionAuthorizationRepository;
69
    /**
70
     * @var IdentityRepository
71
     */
72
    private $identityRepository;
73
74
    public function __construct(
75
        RaCandidateRepository $raCandidateRepository,
76
        RaListingRepository $raListingRepository,
77
        InstitutionAuthorizationRepository $institutionAuthorizationRepository,
78
        IdentityRepository $identityRepository
79
    ) {
80
        $this->raCandidateRepository = $raCandidateRepository;
81
        $this->raListingRepository = $raListingRepository;
82
        $this->institutionAuthorizationRepository = $institutionAuthorizationRepository;
0 ignored issues
show
Documentation Bug introduced by
It seems like $institutionAuthorizationRepository of type object<Surfnet\StepupMid...uthorizationRepository> is incompatible with the declared type object<Surfnet\StepupMid...uthorizationRepository> of property $institutionAuthorizationRepository.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
83
        $this->identityRepository = $identityRepository;
84
    }
85
86
    /**
87
     * @param SecondFactorVettedEvent $event
88
     * @return void
89
     */
90
    public function applySecondFactorVettedEvent(SecondFactorVettedEvent $event)
91
    {
92
        $this->addCandidateToProjection(
93
            $event->identityInstitution,
94
            $event->identityId,
95
            $event->nameId,
96
            $event->commonName,
97
            $event->email
98
        );
99
    }
100
101
    /**
102
     * @param YubikeySecondFactorBootstrappedEvent $event
103
     * @return void
104
     */
105
    public function applyYubikeySecondFactorBootstrappedEvent(YubikeySecondFactorBootstrappedEvent $event)
106
    {
107
        $this->addCandidateToProjection(
108
            $event->identityInstitution,
109
            $event->identityId,
110
            $event->nameId,
111
            $event->commonName,
112
            $event->email
113
        );
114
    }
115
116
    /**
117
     * @param VettedSecondFactorRevokedEvent $event
118
     * @return void
119
     */
120
    public function applyVettedSecondFactorRevokedEvent(VettedSecondFactorRevokedEvent $event)
121
    {
122
        $this->raCandidateRepository->removeByIdentityId($event->identityId);
123
    }
124
125
    /**
126
     * @param CompliedWithVettedSecondFactorRevocationEvent $event
127
     * @return void
128
     */
129
    public function applyCompliedWithVettedSecondFactorRevocationEvent(
130
        CompliedWithVettedSecondFactorRevocationEvent $event
131
    ) {
132
        $this->raCandidateRepository->removeByIdentityId($event->identityId);
133
    }
134
135
    /**
136
     * @param SraaUpdatedEvent $event
137
     *
138
     * Removes all RaCandidates that have a nameId matching an SRAA, as they cannot be made RA(A) as they
139
     * already are SRAA.
140
     */
141
    public function applySraaUpdatedEvent(SraaUpdatedEvent $event)
142
    {
143
        $this->raCandidateRepository->removeByNameIds($event->sraaList);
144
    }
145
146
    /**
147
     * @param IdentityAccreditedAsRaForInstitutionEvent $event
148
     * @return void
149
     */
150
    public function applyIdentityAccreditedAsRaForInstitutionEvent(IdentityAccreditedAsRaForInstitutionEvent $event)
151
    {
152
        $this->raCandidateRepository->removeByIdentityIdAndRaInstitution($event->identityId, $event->raInstitution);
153
    }
154
155
    /**
156
     * @param IdentityAccreditedAsRaaForInstitutionEvent $event
157
     * @return void
158
     */
159
    public function applyIdentityAccreditedAsRaaForInstitutionEvent(IdentityAccreditedAsRaaForInstitutionEvent $event)
160
    {
161
        $this->raCandidateRepository->removeByIdentityIdAndRaInstitution($event->identityId, $event->raInstitution);
162
    }
163
164
    /**
165
     * @param RegistrationAuthorityRetractedForInstitutionEvent $event
166
     * @return void
167
     */
168
    public function applyRegistrationAuthorityRetractedForInstitutionEvent(RegistrationAuthorityRetractedForInstitutionEvent $event)
169
    {
170
        $this->addCandidateToProjection(
171
            $event->identityInstitution,
172
            $event->identityId,
173
            $event->nameId,
174
            $event->commonName,
175
            $event->email
176
        );
177
    }
178
179
    protected function applyIdentityForgottenEvent(IdentityForgottenEvent $event)
180
    {
181
        $this->raCandidateRepository->removeByIdentityId($event->identityId);
182
    }
183
184
    protected function applySelectRaaOptionChangedEvent(SelectRaaOptionChangedEvent $event)
185
    {
186
        $authorizedInstitutions = $event->selectRaaOption->getInstitutions($event->institution);
187
        $this->updateInstitutionCandidatesFromCollection(new Institution($event->institution->getInstitution()), $authorizedInstitutions);
188
    }
189
190
    protected function applyInstitutionConfigurationRemovedEvent(InstitutionConfigurationRemovedEvent $event)
191
    {
192
        $this->raCandidateRepository->removeByRaInstitution(new Institution($event->institution->getInstitution()));
193
    }
194
195
    /**
196
     * This method is kept to be backwards compatible for changes before FGA
197
     *
198
     * @param IdentityAccreditedAsRaEvent $event
199
     * @return void
200
     */
201
    public function applyIdentityAccreditedAsRaEvent(IdentityAccreditedAsRaEvent $event)
202
    {
203
        $this->raCandidateRepository->removeByIdentityIdAndRaInstitution($event->identityId, $event->identityInstitution);
204
    }
205
206
    /**
207
     * This method is kept to be backwards compatible for changes before FGA
208
     *
209
     * @param IdentityAccreditedAsRaaEvent $event
210
     * @return void
211
     */
212
    public function applyIdentityAccreditedAsRaaEvent(IdentityAccreditedAsRaaEvent $event)
213
    {
214
        $this->raCandidateRepository->removeByIdentityIdAndRaInstitution($event->identityId, $event->identityInstitution);
215
    }
216
217
    /**
218
     * This method is kept to be backwards compatible for changes before FGA
219
     *
220
     * @param RegistrationAuthorityRetractedEvent $event
221
     * @return void
222
     */
223
    public function applyRegistrationAuthorityRetractedEvent(RegistrationAuthorityRetractedEvent $event)
224
    {
225
        $candidate = RaCandidate::nominate(
226
            $event->identityId,
227
            $event->identityInstitution,
228
            $event->nameId,
229
            $event->commonName,
230
            $event->email,
231
            $event->identityInstitution
232
        );
233
234
        $this->raCandidateRepository->merge($candidate);
235
    }
236
237
    /**
238
     * @param Institution $institution
239
     * @param ConfigurationInstitution[] $authorizedInstitutions
240
     * @throws \Doctrine\ORM\NonUniqueResultException
241
     */
242
    private function updateInstitutionCandidatesFromCollection(Institution $institution, array $authorizedInstitutions)
243
    {
244
        // convert configuration to value institutions
245
        $raInstitutions = new InstitutionCollection();
246
        foreach ($authorizedInstitutions as $authorizedInstitution) {
247
            $raInstitutions->add(new Institution($authorizedInstitution->getInstitution()));
248
        }
249
250
        // Remove candidates from removed institutions
251
        $this->raCandidateRepository->removeInstitutionsNotInList($institution, $raInstitutions);
252
253
        // loop through authorized institutions
254
        foreach ($raInstitutions as $raInstitution) {
255
256
            // add new identities
257
            $identities = $this->identityRepository->findByInstitution($raInstitution);
258
            foreach ($identities as $identity) {
259
                $identityId = new IdentityId($identity->id);
260
261
                // check if persistent in ra listing
262
                if ($this->raListingRepository->findByIdentityIdAndInstitution($identityId, $raInstitution)) {
263
                    continue;
264
                }
265
266
                // create candidate if not exists
267
                $candidate = $this->raCandidateRepository->findByIdentityIdAndRaInstitution($identityId, $raInstitution);
268
                if (!$candidate) {
269
                    $candidate = RaCandidate::nominate(
270
                        $identityId,
271
                        $identity->institution,
272
                        $identity->nameId,
273
                        $identity->commonName,
274
                        $identity->email,
275
                        $raInstitution
276
                    );
277
                }
278
279
                // store
280
                $this->raCandidateRepository->merge($candidate);
281
            }
282
        }
283
    }
284
285
    /**
286
     * @param Institution $identityInstitution
287
     * @param IdentityId $identityId
288
     * @param NameId $identityNameId
289
     * @param CommonName $identityCommonName
290
     * @param Email $identityEmail
291
     * @throws \Doctrine\ORM\NonUniqueResultException
292
     */
293
    private function addCandidateToProjection(
294
        Institution $identityInstitution,
295
        IdentityId $identityId,
296
        NameId $identityNameId,
297
        CommonName $identityCommonName,
298
        Email $identityEmail
299
    ) {
300
        $institutionAuthorizations = $this->institutionAuthorizationRepository
301
            ->findAuthorizationOptionsForInstitution(new ConfigurationInstitution($identityInstitution->getInstitution()));
302
303
        $institutions = [];
304
        foreach ($institutionAuthorizations as $authorization) {
305
            $raInstitutionName = $authorization->institutionRelation->getInstitution();
306
            $institutions[$raInstitutionName] = new Institution($raInstitutionName);
307
        }
308
309
        foreach ($institutions as $institution) {
310
            if ($this->raListingRepository->findByIdentityIdAndInstitution($identityId, $institution)) {
311
                continue;
312
            }
313
314
            // create candidate if not exists
315
            $candidate = $this->raCandidateRepository->findByIdentityIdAndRaInstitution($identityId, $institution);
316
            if (!$candidate) {
317
                $candidate = RaCandidate::nominate(
318
                    $identityId,
319
                    $identityInstitution,
320
                    $identityNameId,
321
                    $identityCommonName,
322
                    $identityEmail,
323
                    $institution
324
                );
325
            }
326
327
            $this->raCandidateRepository->merge($candidate);
328
        }
329
    }
330
}
331