Completed
Push — master ( 53601d...990ac1 )
by
unknown
07:37 queued 28s
created

SecondFactorService::determineAvailable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 4
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\VerifiedSecondFactorSearchQuery;
23
use Surfnet\StepupMiddlewareClient\Identity\Dto\VettedSecondFactorSearchQuery;
24
use Surfnet\StepupMiddlewareClientBundle\Identity\Command\RevokeOwnSecondFactorCommand;
25
use Surfnet\StepupMiddlewareClientBundle\Identity\Command\VerifyEmailCommand;
26
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\UnverifiedSecondFactor;
27
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\UnverifiedSecondFactorCollection;
28
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactor;
29
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactorCollection;
30
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VettedSecondFactor;
31
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VettedSecondFactorCollection;
32
use Surfnet\StepupMiddlewareClientBundle\Identity\Service\SecondFactorService as MiddlewareSecondFactorService;
33
use Surfnet\StepupSelfService\SelfServiceBundle\Command\RevokeCommand;
34
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\LogicException;
35
36
/**
37
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
38
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
39
 */
40
class SecondFactorService
41
{
42
    /**
43
     * @var \Surfnet\StepupMiddlewareClientBundle\Identity\Service\SecondFactorService
44
     */
45
    private $secondFactors;
46
47
    /**
48
     * @var \Surfnet\StepupSelfService\SelfServiceBundle\Service\CommandService
49
     */
50
    private $commandService;
51
52
    /**
53
     * @var \Surfnet\StepupSelfService\SelfServiceBundle\Service\U2fSecondFactorService
54
     */
55
    private $u2fSecondFactorService;
56
57
    /**
58
     * @param MiddlewareSecondFactorService $secondFactors
59
     * @param CommandService                $commandService
60
     * @param U2fSecondFactorService        $u2fSecondFactorService
61
     */
62
    public function __construct(
63
        MiddlewareSecondFactorService $secondFactors,
64
        CommandService $commandService,
65
        U2fSecondFactorService $u2fSecondFactorService
66
    ) {
67
        $this->secondFactors = $secondFactors;
68
        $this->commandService = $commandService;
69
        $this->u2fSecondFactorService = $u2fSecondFactorService;
70
    }
71
72
    /**
73
     * @param string $identityId
74
     * @param string $nonce
75
     * @return bool
76
     */
77
    public function verifyEmail($identityId, $nonce)
78
    {
79
        $command                    = new VerifyEmailCommand();
80
        $command->identityId        = $identityId;
81
        $command->verificationNonce = $nonce;
82
83
        $result = $this->commandService->execute($command);
84
85
        return $result->isSuccessful();
86
    }
87
88
    /**
89
     * @param RevokeCommand $command
90
     * @return bool
91
     */
92
    public function revoke(RevokeCommand $command)
93
    {
94
        /** @var UnverifiedSecondFactor|VerifiedSecondFactor|VettedSecondFactor $secondFactor */
95
        $secondFactor = $command->secondFactor;
96
97
        $apiCommand = new RevokeOwnSecondFactorCommand();
98
        $apiCommand->identityId = $command->identity->id;
99
        $apiCommand->secondFactorId = $secondFactor->id;
100
101
        $result = $this->commandService->execute($apiCommand);
102
103
        if ($secondFactor->type === 'u2f') {
104
            $this->u2fSecondFactorService->revokeRegistration(
105
                $command->identity,
106
                $secondFactor->secondFactorIdentifier
107
            );
108
        }
109
110
        return $result->isSuccessful();
111
    }
112
113
    /**
114
     * Returns whether the given registrant has registered second factors with Step-up. The state of the second factor
115
     * is irrelevant.
116
     *
117
     * @param string $identityId
118
     * @return bool
119
     */
120
    public function doSecondFactorsExistForIdentity($identityId)
121
    {
122
        $unverifiedSecondFactors = $this->findUnverifiedByIdentity($identityId);
123
        $verifiedSecondFactors = $this->findVerifiedByIdentity($identityId);
124
        $vettedSecondFactors = $this->findVettedByIdentity($identityId);
125
126
        return $unverifiedSecondFactors->getTotalItems() +
127
               $verifiedSecondFactors->getTotalItems() +
128
               $vettedSecondFactors->getTotalItems() > 0;
129
    }
130
131
    public function identityHasSecondFactorOfStateWithId($identityId, $state, $secondFactorId)
132
    {
133
        switch ($state) {
134
            case 'unverified':
135
                $secondFactors = $this->findUnverifiedByIdentity($identityId);
136
                break;
137
            case 'verified':
138
                $secondFactors = $this->findVerifiedByIdentity($identityId);
139
                break;
140
            case 'vetted':
141
                $secondFactors = $this->findVettedByIdentity($identityId);
142
                break;
143
            default:
144
                throw new LogicException(sprintf('Invalid second factor state "%s" given.', $state));
145
        }
146
147
        if (count($secondFactors->getElements()) === 0) {
148
            return false;
149
        }
150
151
        foreach ($secondFactors->getElements() as $secondFactor) {
152
            if ($secondFactor->id === $secondFactorId) {
153
                return true;
154
            }
155
        }
156
157
        return false;
158
    }
159
160
    /**
161
     * Returns the given registrant's unverified second factors.
162
     *
163
     * @param string $identityId
164
     * @return UnverifiedSecondFactorCollection
0 ignored issues
show
Documentation introduced by
Should the return type not be UnverifiedSecondFactorCollection|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
165
     */
166
    public function findUnverifiedByIdentity($identityId)
167
    {
168
        return $this->secondFactors->searchUnverified(
169
            (new UnverifiedSecondFactorSearchQuery())->setIdentityId($identityId)
170
        );
171
    }
172
173
    /**
174
     * Returns the given registrant's verified second factors.
175
     *
176
     * @param string $identityId
177
     * @return VerifiedSecondFactorCollection
0 ignored issues
show
Documentation introduced by
Should the return type not be VerifiedSecondFactorCollection|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
178
     */
179
    public function findVerifiedByIdentity($identityId)
180
    {
181
        return $this->secondFactors->searchVerified(
182
            (new VerifiedSecondFactorSearchQuery())->setIdentityId($identityId)
183
        );
184
    }
185
186
    /**
187
     * Returns the given registrant's verified second factors.
188
     *
189
     * @param string $identityId
190
     * @return VettedSecondFactorCollection
0 ignored issues
show
Documentation introduced by
Should the return type not be VettedSecondFactorCollection|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
191
     */
192
    public function findVettedByIdentity($identityId)
193
    {
194
        return $this->secondFactors->searchVetted(
195
            (new VettedSecondFactorSearchQuery())->setIdentityId($identityId)
196
        );
197
    }
198
199
    /**
200
     * @param string $secondFactorId
201
     * @return null|UnverifiedSecondFactor
202
     */
203
    public function findOneUnverified($secondFactorId)
204
    {
205
        return $this->secondFactors->getUnverified($secondFactorId);
206
    }
207
208
    /**
209
     * @param string $secondFactorId
210
     * @return null|VerifiedSecondFactor
211
     */
212
    public function findOneVerified($secondFactorId)
213
    {
214
        return $this->secondFactors->getVerified($secondFactorId);
215
    }
216
217
    /**
218
     * @param string $secondFactorId
219
     * @return null|VettedSecondFactor
220
     */
221
    public function findOneVetted($secondFactorId)
222
    {
223
        return $this->secondFactors->getVetted($secondFactorId);
224
    }
225
226
    /**
227
     * @param string $identityId
228
     * @param string $verificationNonce
229
     * @return UnverifiedSecondFactor|null
230
     */
231 View Code Duplication
    public function findUnverifiedByVerificationNonce($identityId, $verificationNonce)
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
    {
233
        $secondFactors = $this->secondFactors->searchUnverified(
234
            (new UnverifiedSecondFactorSearchQuery())
235
                ->setIdentityId($identityId)
236
                ->setVerificationNonce($verificationNonce)
237
        );
238
239
        $elements = $secondFactors->getElements();
240
241
        switch (count($elements)) {
242
            case 0:
243
                return null;
244
            case 1:
245
                return reset($elements);
246
            default:
247
                throw new LogicException('There cannot be more than one unverified second factor with the same nonce');
248
        }
249
    }
250
251
    /**
252
     * @param string $secondFactorId
253
     * @param string $identityId
254
     * @return null|string
255
     */
256 View Code Duplication
    public function getRegistrationCode($secondFactorId, $identityId)
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...
257
    {
258
        $query = (new VerifiedSecondFactorSearchQuery())
259
            ->setIdentityId($identityId)
260
            ->setSecondFactorId($secondFactorId);
261
262
        /** @var VerifiedSecondFactor[] $verifiedSecondFactors */
263
        $verifiedSecondFactors = $this->secondFactors->searchVerified($query)->getElements();
264
265
        switch (count($verifiedSecondFactors)) {
266
            case 0:
267
                return null;
268
            case 1:
269
                return reset($verifiedSecondFactors)->registrationCode;
270
            default:
271
                throw new LogicException('Searching by second factor ID cannot result in multiple results.');
272
        }
273
    }
274
}
275