Passed
Push — master ( c4afc2...9cde23 )
by Pieter van der
27:49 queued 12:42
created

SecondFactorService::findOneVetted()   A

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
 */
18
19
namespace Surfnet\StepupSelfService\SelfServiceBundle\Service;
20
21
use Surfnet\StepupMiddlewareClient\Identity\Dto\UnverifiedSecondFactorSearchQuery;
22
use Surfnet\StepupMiddlewareClient\Identity\Dto\VerifiedSecondFactorOfIdentitySearchQuery;
23
use Surfnet\StepupMiddlewareClient\Identity\Dto\VettedSecondFactorSearchQuery;
24
use Surfnet\StepupMiddlewareClientBundle\Dto\CollectionDto;
25
use Surfnet\StepupMiddlewareClientBundle\Identity\Command\RegisterSelfAssertedSecondFactorCommand;
26
use Surfnet\StepupMiddlewareClientBundle\Identity\Command\SelfVetSecondFactorCommand;
27
use Surfnet\StepupMiddlewareClientBundle\Identity\Command\RevokeOwnSecondFactorCommand;
28
use Surfnet\StepupMiddlewareClientBundle\Identity\Command\VerifyEmailCommand;
29
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\UnverifiedSecondFactor;
30
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\UnverifiedSecondFactorCollection;
31
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactor;
32
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactorCollection;
33
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VettedSecondFactor;
34
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VettedSecondFactorCollection;
35
use Surfnet\StepupMiddlewareClientBundle\Identity\Service\SecondFactorService as MiddlewareSecondFactorService;
36
use Surfnet\StepupSelfService\SelfServiceBundle\Command\SelfAssertedTokenRegistrationCommand;
37
use Surfnet\StepupSelfService\SelfServiceBundle\Command\SelfVetCommand;
38
use Surfnet\StepupSelfService\SelfServiceBundle\Command\RevokeCommand;
39
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\LogicException;
40
41
/**
42
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
43
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
44
 */
45
class SecondFactorService
46
{
47
    /**
48
     * @var \Surfnet\StepupMiddlewareClientBundle\Identity\Service\SecondFactorService
49
     */
50
    private $secondFactors;
51
52
    /**
53
     * @var \Surfnet\StepupSelfService\SelfServiceBundle\Service\CommandService
54
     */
55
    private $commandService;
56
57
    /**
58
     * @param MiddlewareSecondFactorService $secondFactors
59
     * @param CommandService                $commandService
60
     */
61
    public function __construct(
62
        MiddlewareSecondFactorService $secondFactors,
63
        CommandService $commandService
64
    ) {
65
        $this->secondFactors = $secondFactors;
66
        $this->commandService = $commandService;
67
    }
68
69
    /**
70
     * @param string $identityId
71
     * @param string $nonce
72
     * @return bool
73
     */
74
    public function verifyEmail($identityId, $nonce)
75
    {
76
        $command                    = new VerifyEmailCommand();
77
        $command->identityId        = $identityId;
78
        $command->verificationNonce = $nonce;
79
80
        $result = $this->commandService->execute($command);
81
82
        return $result->isSuccessful();
83
    }
84
85
    /**
86
     * @param RevokeCommand $command
87
     * @return bool
88
     */
89
    public function revoke(RevokeCommand $command)
90
    {
91
        /** @var UnverifiedSecondFactor|VerifiedSecondFactor|VettedSecondFactor $secondFactor */
92
        $secondFactor = $command->secondFactor;
93
94
        $apiCommand = new RevokeOwnSecondFactorCommand();
95
        $apiCommand->identityId = $command->identity->id;
96
        $apiCommand->secondFactorId = $secondFactor->id;
97
98
        $result = $this->commandService->execute($apiCommand);
99
100
        return $result->isSuccessful();
101
    }
102
103
    public function selfVet(SelfVetCommand $command): bool
104
    {
105
        $apiCommand = new SelfVetSecondFactorCommand();
106
        $apiCommand->identityId = $command->identity->id;
107
        $apiCommand->registrationCode = $command->secondFactor->registrationCode;
108
        $apiCommand->secondFactorIdentifier = $command->secondFactor->id;
109
        $apiCommand->secondFactorId = $command->secondFactor->secondFactorIdentifier;
110
        $apiCommand->secondFactorType = $command->secondFactor->type;
111
        $apiCommand->authorityId = $command->identity->id;
112
        $apiCommand->authoringSecondFactorLoa = $command->authoringLoa;
113
114
        $result = $this->commandService->execute($apiCommand);
115
        return $result->isSuccessful();
116
    }
117
118
    public function registerSelfAssertedToken(SelfAssertedTokenRegistrationCommand $command): bool
119
    {
120
        $apiCommand = new RegisterSelfAssertedSecondFactorCommand();
121
        $apiCommand->identityId = $command->identity->id;
122
        $apiCommand->registrationCode = $command->secondFactor->registrationCode;
123
        $apiCommand->secondFactorIdentifier = $command->secondFactor->secondFactorIdentifier;
124
        $apiCommand->secondFactorId = $command->secondFactor->id;
125
        $apiCommand->secondFactorType = $command->secondFactor->type;
126
        $apiCommand->authorityId = $command->identity->id;
127
        $apiCommand->authoringRecoveryTokenId = $command->recoveryTokenId;
128
129
        return $this->commandService->execute($apiCommand)->isSuccessful();
130
    }
131
132
    /**
133
     * Returns whether the given registrant has registered second factors with Step-up. The state of the second factor
134
     * is irrelevant.
135
     *
136
     * @param string $identityId
137
     * @return bool
138
     */
139
    public function doSecondFactorsExistForIdentity($identityId)
140
    {
141
        $unverifiedSecondFactors = $this->findUnverifiedByIdentity($identityId);
142
        $verifiedSecondFactors = $this->findVerifiedByIdentity($identityId);
143
        $vettedSecondFactors = $this->findVettedByIdentity($identityId);
144
145
        return $unverifiedSecondFactors->getTotalItems() +
146
               $verifiedSecondFactors->getTotalItems() +
147
               $vettedSecondFactors->getTotalItems() > 0;
148
    }
149
150
    public function identityHasSecondFactorOfStateWithId($identityId, $state, $secondFactorId)
151
    {
152
        switch ($state) {
153
            case 'unverified':
154
                $secondFactors = $this->findUnverifiedByIdentity($identityId);
155
                break;
156
            case 'verified':
157
                $secondFactors = $this->findVerifiedByIdentity($identityId);
158
                break;
159
            case 'vetted':
160
                $secondFactors = $this->findVettedByIdentity($identityId);
161
                break;
162
            default:
163
                throw new LogicException(sprintf('Invalid second factor state "%s" given.', $state));
164
        }
165
166
        if (count($secondFactors->getElements()) === 0) {
167
            return false;
168
        }
169
170
        foreach ($secondFactors->getElements() as $secondFactor) {
171
            if ($secondFactor->id === $secondFactorId) {
172
                return true;
173
            }
174
        }
175
176
        return false;
177
    }
178
179
    /**
180
     * Returns the given registrant's unverified second factors.
181
     *
182
     * @param string $identityId
183
     * @return UnverifiedSecondFactorCollection
184
     */
185
    public function findUnverifiedByIdentity($identityId)
186
    {
187
        return $this->secondFactors->searchUnverified(
188
            (new UnverifiedSecondFactorSearchQuery())->setIdentityId($identityId)
189
        );
190
    }
191
192
    /**
193
     * Returns the given registrant's verified second factors.
194
     *
195
     * @param string $identityId
196
     * @return VerifiedSecondFactorCollection
197
     */
198
    public function findVerifiedByIdentity($identityId)
199
    {
200
        $query = new VerifiedSecondFactorOfIdentitySearchQuery();
201
        $query->setIdentityId($identityId);
202
        return $this->secondFactors->searchOwnVerified($query);
203
    }
204
205
    /**
206
     * Returns the given registrant's verified second factors.
207
     *
208
     * @param string $identityId
209
     * @return VettedSecondFactorCollection
210
     */
211
    public function findVettedByIdentity($identityId)
212
    {
213
        return $this->secondFactors->searchVetted(
214
            (new VettedSecondFactorSearchQuery())->setIdentityId($identityId)
215
        );
216
    }
217
218
    /**
219
     * @param string $secondFactorId
220
     * @return null|UnverifiedSecondFactor
221
     */
222
    public function findOneUnverified($secondFactorId)
223
    {
224
        return $this->secondFactors->getUnverified($secondFactorId);
225
    }
226
227
    /**
228
     * @param string $secondFactorId
229
     * @return null|VerifiedSecondFactor
230
     */
231
    public function findOneVerified($secondFactorId)
232
    {
233
        return $this->secondFactors->getVerified($secondFactorId);
234
    }
235
236
    /**
237
     * @param string $secondFactorId
238
     * @return null|VettedSecondFactor
239
     */
240
    public function findOneVetted($secondFactorId)
241
    {
242
        return $this->secondFactors->getVetted($secondFactorId);
243
    }
244
245
    /**
246
     * @param string $identityId
247
     * @param string $verificationNonce
248
     * @return UnverifiedSecondFactor|null
249
     */
250
    public function findUnverifiedByVerificationNonce($identityId, $verificationNonce)
251
    {
252
        $secondFactors = $this->secondFactors->searchUnverified(
253
            (new UnverifiedSecondFactorSearchQuery())
254
                ->setIdentityId($identityId)
255
                ->setVerificationNonce($verificationNonce)
256
        );
257
258
        $elements = $secondFactors->getElements();
259
260
        switch (count($elements)) {
261
            case 0:
262
                return null;
263
            case 1:
264
                return reset($elements);
265
            default:
266
                throw new LogicException('There cannot be more than one unverified second factor with the same nonce');
267
        }
268
    }
269
270
    /**
271
     * @param array $allSecondFactors
272
     * @param UnverifiedSecondFactorCollection $unverifiedCollection
273
     * @param VerifiedSecondFactorCollection $verifiedCollection
274
     * @param VettedSecondFactorCollection $vettedCollection
275
     * @return array
276
     */
277
    private function determineAvailable(
278
        array $allSecondFactors,
279
        UnverifiedSecondFactorCollection $unverifiedCollection,
280
        VerifiedSecondFactorCollection $verifiedCollection,
281
        VettedSecondFactorCollection $vettedCollection
282
    ) {
283
        $allSecondFactors = $this->filterAvailableSecondFactors($allSecondFactors, $unverifiedCollection);
284
        $allSecondFactors = $this->filterAvailableSecondFactors($allSecondFactors, $verifiedCollection);
285
        $allSecondFactors = $this->filterAvailableSecondFactors($allSecondFactors, $vettedCollection);
286
        return $allSecondFactors;
287
    }
288
289
    /**
290
     * @param array $allSecondFactors
291
     * @param CollectionDto $collection
292
     * @return array
293
     */
294
    private function filterAvailableSecondFactors(array $allSecondFactors, CollectionDto $collection)
295
    {
296
        foreach ($collection->getElements() as $secondFactor) {
297
            $keyFound = array_search($secondFactor->type, $allSecondFactors);
298
            if (is_numeric($keyFound)) {
299
                unset($allSecondFactors[$keyFound]);
300
            }
301
        }
302
        return $allSecondFactors;
303
    }
304
305
    /**
306
     * @param $identity
307
     * @param $allSecondFactors
308
     * @param $allowedSecondFactors
309
     * @param $maximumNumberOfRegistrations
310
     * @return SecondFactorTypeCollection
311
     */
312
    public function getSecondFactorsForIdentity(
313
        $identity,
314
        $allSecondFactors,
315
        $allowedSecondFactors,
316
        $maximumNumberOfRegistrations
317
    ) {
318
        $unverified = $this->findUnverifiedByIdentity($identity->id);
319
        $verified = $this->findVerifiedByIdentity($identity->id);
320
        $vetted = $this->findVettedByIdentity($identity->id);
321
        // Determine which Second Factors are still available for registration.
322
        $available = $this->determineAvailable($allSecondFactors, $unverified, $verified, $vetted);
323
324
        if (!empty($allowedSecondFactors)) {
325
            $available = array_intersect(
326
                $available,
327
                $allowedSecondFactors
328
            );
329
        }
330
331
        $collection = new SecondFactorTypeCollection();
332
        $collection->unverified = $unverified;
333
        $collection->verified   = $verified;
334
        $collection->vetted     = $vetted;
335
        $collection->available  = array_combine($available, $available);
336
        $collection->maxNumberOfRegistrations = $maximumNumberOfRegistrations;
337
338
        return $collection;
339
    }
340
}
341