These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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\Dto\CollectionDto; |
||
25 | use Surfnet\StepupMiddlewareClientBundle\Identity\Command\RevokeOwnSecondFactorCommand; |
||
26 | use Surfnet\StepupMiddlewareClientBundle\Identity\Command\VerifyEmailCommand; |
||
27 | use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\UnverifiedSecondFactor; |
||
28 | use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\UnverifiedSecondFactorCollection; |
||
29 | use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactor; |
||
30 | use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactorCollection; |
||
31 | use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VettedSecondFactor; |
||
32 | use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VettedSecondFactorCollection; |
||
33 | use Surfnet\StepupMiddlewareClientBundle\Identity\Service\SecondFactorService as MiddlewareSecondFactorService; |
||
34 | use Surfnet\StepupSelfService\SelfServiceBundle\Command\RevokeCommand; |
||
35 | use Surfnet\StepupSelfService\SelfServiceBundle\Exception\LogicException; |
||
36 | |||
37 | /** |
||
38 | * @SuppressWarnings(PHPMD.TooManyPublicMethods) |
||
39 | * @SuppressWarnings(PHPMD.CouplingBetweenObjects) |
||
40 | */ |
||
41 | class SecondFactorService |
||
42 | { |
||
43 | /** |
||
44 | * @var \Surfnet\StepupMiddlewareClientBundle\Identity\Service\SecondFactorService |
||
45 | */ |
||
46 | private $secondFactors; |
||
47 | |||
48 | /** |
||
49 | * @var \Surfnet\StepupSelfService\SelfServiceBundle\Service\CommandService |
||
50 | */ |
||
51 | private $commandService; |
||
52 | |||
53 | /** |
||
54 | * @var \Surfnet\StepupSelfService\SelfServiceBundle\Service\U2fSecondFactorService |
||
55 | */ |
||
56 | private $u2fSecondFactorService; |
||
57 | |||
58 | /** |
||
59 | * @param MiddlewareSecondFactorService $secondFactors |
||
60 | * @param CommandService $commandService |
||
61 | * @param U2fSecondFactorService $u2fSecondFactorService |
||
62 | */ |
||
63 | public function __construct( |
||
64 | MiddlewareSecondFactorService $secondFactors, |
||
65 | CommandService $commandService, |
||
66 | U2fSecondFactorService $u2fSecondFactorService |
||
67 | ) { |
||
68 | $this->secondFactors = $secondFactors; |
||
69 | $this->commandService = $commandService; |
||
70 | $this->u2fSecondFactorService = $u2fSecondFactorService; |
||
71 | } |
||
72 | |||
73 | /** |
||
74 | * @param string $identityId |
||
75 | * @param string $nonce |
||
76 | * @return bool |
||
77 | */ |
||
78 | public function verifyEmail($identityId, $nonce) |
||
79 | { |
||
80 | $command = new VerifyEmailCommand(); |
||
81 | $command->identityId = $identityId; |
||
82 | $command->verificationNonce = $nonce; |
||
83 | |||
84 | $result = $this->commandService->execute($command); |
||
85 | |||
86 | return $result->isSuccessful(); |
||
87 | } |
||
88 | |||
89 | /** |
||
90 | * @param RevokeCommand $command |
||
91 | * @return bool |
||
92 | */ |
||
93 | public function revoke(RevokeCommand $command) |
||
94 | { |
||
95 | /** @var UnverifiedSecondFactor|VerifiedSecondFactor|VettedSecondFactor $secondFactor */ |
||
96 | $secondFactor = $command->secondFactor; |
||
97 | |||
98 | $apiCommand = new RevokeOwnSecondFactorCommand(); |
||
99 | $apiCommand->identityId = $command->identity->id; |
||
100 | $apiCommand->secondFactorId = $secondFactor->id; |
||
101 | |||
102 | $result = $this->commandService->execute($apiCommand); |
||
103 | |||
104 | if ($secondFactor->type === 'u2f') { |
||
105 | $this->u2fSecondFactorService->revokeRegistration( |
||
106 | $command->identity, |
||
107 | $secondFactor->secondFactorIdentifier |
||
108 | ); |
||
109 | } |
||
110 | |||
111 | return $result->isSuccessful(); |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * Returns whether the given registrant has registered second factors with Step-up. The state of the second factor |
||
116 | * is irrelevant. |
||
117 | * |
||
118 | * @param string $identityId |
||
119 | * @param string $institution |
||
120 | * @return bool |
||
121 | */ |
||
122 | public function doSecondFactorsExistForIdentity($identityId, $institution) |
||
123 | { |
||
124 | $unverifiedSecondFactors = $this->findUnverifiedByIdentity($identityId); |
||
125 | $verifiedSecondFactors = $this->findVerifiedByIdentity($identityId, $institution); |
||
126 | $vettedSecondFactors = $this->findVettedByIdentity($identityId); |
||
127 | |||
128 | return $unverifiedSecondFactors->getTotalItems() + |
||
129 | $verifiedSecondFactors->getTotalItems() + |
||
130 | $vettedSecondFactors->getTotalItems() > 0; |
||
131 | } |
||
132 | |||
133 | public function identityHasSecondFactorOfStateWithId($identityId, $state, $secondFactorId, $institution) |
||
134 | { |
||
135 | switch ($state) { |
||
136 | case 'unverified': |
||
137 | $secondFactors = $this->findUnverifiedByIdentity($identityId); |
||
138 | break; |
||
139 | case 'verified': |
||
140 | $secondFactors = $this->findVerifiedByIdentity($identityId, $institution); |
||
141 | break; |
||
142 | case 'vetted': |
||
143 | $secondFactors = $this->findVettedByIdentity($identityId); |
||
144 | break; |
||
145 | default: |
||
146 | throw new LogicException(sprintf('Invalid second factor state "%s" given.', $state)); |
||
147 | } |
||
148 | |||
149 | if (count($secondFactors->getElements()) === 0) { |
||
150 | return false; |
||
151 | } |
||
152 | |||
153 | foreach ($secondFactors->getElements() as $secondFactor) { |
||
154 | if ($secondFactor->id === $secondFactorId) { |
||
155 | return true; |
||
156 | } |
||
157 | } |
||
158 | |||
159 | return false; |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * Returns the given registrant's unverified second factors. |
||
164 | * |
||
165 | * @param string $identityId |
||
166 | * @return UnverifiedSecondFactorCollection |
||
0 ignored issues
–
show
|
|||
167 | */ |
||
168 | public function findUnverifiedByIdentity($identityId) |
||
169 | { |
||
170 | return $this->secondFactors->searchUnverified( |
||
171 | (new UnverifiedSecondFactorSearchQuery())->setIdentityId($identityId) |
||
172 | ); |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * Returns the given registrant's verified second factors. |
||
177 | * |
||
178 | * @param string $identityId |
||
179 | * @param string $actorInstitution |
||
180 | * @return VerifiedSecondFactorCollection |
||
0 ignored issues
–
show
|
|||
181 | */ |
||
182 | public function findVerifiedByIdentity($identityId, $actorInstitution) |
||
183 | { |
||
184 | $query = new VerifiedSecondFactorSearchQuery(); |
||
185 | $query->setIdentityId($identityId); |
||
186 | // In self service the actor equals the identity of the user. |
||
187 | $query->setActorId($identityId); |
||
188 | $query->setActorInstitution($actorInstitution); |
||
189 | $query->setInstitution($actorInstitution); |
||
190 | // Actor and identity are equal in SelfService. |
||
191 | $query->setActorId($identityId); |
||
192 | return $this->secondFactors->searchVerified($query); |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Returns the given registrant's verified second factors. |
||
197 | * |
||
198 | * @param string $identityId |
||
199 | * @return VettedSecondFactorCollection |
||
0 ignored issues
–
show
|
|||
200 | */ |
||
201 | public function findVettedByIdentity($identityId) |
||
202 | { |
||
203 | return $this->secondFactors->searchVetted( |
||
204 | (new VettedSecondFactorSearchQuery())->setIdentityId($identityId) |
||
205 | ); |
||
206 | } |
||
207 | |||
208 | /** |
||
209 | * @param string $secondFactorId |
||
210 | * @return null|UnverifiedSecondFactor |
||
211 | */ |
||
212 | public function findOneUnverified($secondFactorId) |
||
213 | { |
||
214 | return $this->secondFactors->getUnverified($secondFactorId); |
||
215 | } |
||
216 | |||
217 | /** |
||
218 | * @param string $secondFactorId |
||
219 | * @return null|VerifiedSecondFactor |
||
220 | */ |
||
221 | public function findOneVerified($secondFactorId) |
||
222 | { |
||
223 | return $this->secondFactors->getVerified($secondFactorId); |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * @param string $secondFactorId |
||
228 | * @return null|VettedSecondFactor |
||
229 | */ |
||
230 | public function findOneVetted($secondFactorId) |
||
231 | { |
||
232 | return $this->secondFactors->getVetted($secondFactorId); |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * @param string $identityId |
||
237 | * @param string $verificationNonce |
||
238 | * @return UnverifiedSecondFactor|null |
||
239 | */ |
||
240 | public function findUnverifiedByVerificationNonce($identityId, $verificationNonce) |
||
241 | { |
||
242 | $secondFactors = $this->secondFactors->searchUnverified( |
||
243 | (new UnverifiedSecondFactorSearchQuery()) |
||
244 | ->setIdentityId($identityId) |
||
245 | ->setVerificationNonce($verificationNonce) |
||
246 | ); |
||
247 | |||
248 | $elements = $secondFactors->getElements(); |
||
249 | |||
250 | switch (count($elements)) { |
||
251 | case 0: |
||
252 | return null; |
||
253 | case 1: |
||
254 | return reset($elements); |
||
255 | default: |
||
256 | throw new LogicException('There cannot be more than one unverified second factor with the same nonce'); |
||
257 | } |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * @param array $allSecondFactors |
||
262 | * @param UnverifiedSecondFactorCollection $unverifiedCollection |
||
263 | * @param VerifiedSecondFactorCollection $verifiedCollection |
||
264 | * @param VettedSecondFactorCollection $vettedCollection |
||
265 | * @return array |
||
266 | */ |
||
267 | private function determineAvailable( |
||
268 | array $allSecondFactors, |
||
269 | UnverifiedSecondFactorCollection $unverifiedCollection, |
||
270 | VerifiedSecondFactorCollection $verifiedCollection, |
||
271 | VettedSecondFactorCollection $vettedCollection |
||
272 | ) { |
||
273 | $allSecondFactors = $this->filterAvailableSecondFactors($allSecondFactors, $unverifiedCollection); |
||
274 | $allSecondFactors = $this->filterAvailableSecondFactors($allSecondFactors, $verifiedCollection); |
||
275 | $allSecondFactors = $this->filterAvailableSecondFactors($allSecondFactors, $vettedCollection); |
||
276 | return $allSecondFactors; |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * @param array $allSecondFactors |
||
281 | * @param CollectionDto $collection |
||
282 | * @return array |
||
283 | */ |
||
284 | private function filterAvailableSecondFactors(array $allSecondFactors, CollectionDto $collection) |
||
285 | { |
||
286 | foreach ($collection->getElements() as $secondFactor) { |
||
287 | $keyFound = array_search($secondFactor->type, $allSecondFactors); |
||
288 | if (is_numeric($keyFound)) { |
||
289 | unset($allSecondFactors[$keyFound]); |
||
290 | } |
||
291 | } |
||
292 | return $allSecondFactors; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * @param $identity |
||
297 | * @param string $institution |
||
298 | * @param $allSecondFactors |
||
299 | * @param $allowedSecondFactors |
||
300 | * @param $maximumNumberOfRegistrations |
||
301 | * @return SecondFactorTypeCollection |
||
302 | */ |
||
303 | public function getSecondFactorsForIdentity( |
||
304 | $identity, |
||
305 | $institution, |
||
306 | $allSecondFactors, |
||
307 | $allowedSecondFactors, |
||
308 | $maximumNumberOfRegistrations |
||
309 | ) { |
||
310 | $unverified = $this->findUnverifiedByIdentity($identity->id); |
||
311 | $verified = $this->findVerifiedByIdentity($identity->id, $institution); |
||
312 | $vetted = $this->findVettedByIdentity($identity->id); |
||
313 | // Determine which Second Factors are still available for registration. |
||
314 | $available = $this->determineAvailable($allSecondFactors, $unverified, $verified, $vetted); |
||
0 ignored issues
–
show
It seems like
$unverified defined by $this->findUnverifiedByIdentity($identity->id) on line 310 can be null ; however, Surfnet\StepupSelfServic...e::determineAvailable() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
It seems like
$verified defined by $this->findVerifiedByIde...tity->id, $institution) on line 311 can be null ; however, Surfnet\StepupSelfServic...e::determineAvailable() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
It seems like
$vetted defined by $this->findVettedByIdentity($identity->id) on line 312 can be null ; however, Surfnet\StepupSelfServic...e::determineAvailable() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
|
|||
315 | |||
316 | if (!empty($allowedSecondFactors)) { |
||
317 | $available = array_intersect( |
||
318 | $available, |
||
319 | $allowedSecondFactors |
||
320 | ); |
||
321 | } |
||
322 | |||
323 | $collection = new SecondFactorTypeCollection(); |
||
324 | $collection->unverified = $unverified; |
||
325 | $collection->verified = $verified; |
||
326 | $collection->vetted = $vetted; |
||
327 | $collection->available = array_combine($available, $available); |
||
328 | $collection->maxNumberOfRegistrations = $maximumNumberOfRegistrations; |
||
329 | |||
330 | return $collection; |
||
331 | } |
||
332 | } |
||
333 |
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.