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

excludeDisabledRecoveryTokens()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 6
nc 5
nop 1
dl 0
loc 11
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Copyright 2022 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\SelfAssertedTokens;
20
21
use Psr\Log\LoggerInterface;
22
use Surfnet\StepupMiddlewareClient\Identity\Dto\RecoveryToken;
23
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\Identity;
24
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactor;
25
use Surfnet\StepupMiddlewareClientBundle\Identity\Service\RecoveryTokenService as MiddlewareRecoveryTokenService;
26
use Surfnet\StepupSelfService\SelfServiceBundle\Command\SafeStoreAuthenticationCommand;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\Dto\ReturnTo;
28
29
class RecoveryTokenService
30
{
31
    /**
32
     * @var MiddlewareRecoveryTokenService
33
     */
34
    private $recoveryTokenService;
35
36
    /**
37
     * @var SafeStoreService
38
     */
39
    private $safeStoreService;
40
41
    /**
42
     * @var LoggerInterface
43
     */
44
    private $logger;
45
46
    /**
47
     * @var RecoveryTokenState
48
     */
49
    private $stateStore;
50
51
    /**
52
     * @var RecoveryTokenConfig
53
     */
54
    private $config;
55
56
    public function __construct(
57
        MiddlewareRecoveryTokenService $recoveryTokenService,
58
        SafeStoreService $safeStoreService,
59
        RecoveryTokenState $recoveryTokenState,
60
        RecoveryTokenConfig $config,
61
        LoggerInterface $logger
62
    ) {
63
        $this->recoveryTokenService = $recoveryTokenService;
64
        $this->safeStoreService = $safeStoreService;
65
        $this->stateStore = $recoveryTokenState;
66
        $this->config = $config;
67
        $this->logger = $logger;
68
    }
69
70
    public function hasRecoveryToken(Identity $identity): bool
71
    {
72
        return $this->recoveryTokenService->hasRecoveryToken($identity);
73
    }
74
75
    public function getRecoveryToken(string $recoveryTokenId): RecoveryToken
76
    {
77
        return $this->recoveryTokenService->findOne($recoveryTokenId);
78
    }
79
80
    /**
81
     * @return RecoveryToken[]
82
     */
83
    public function getRecoveryTokensForIdentity(Identity $identity): array
84
    {
85
        return $this->recoveryTokenService->findAllFor($identity);
86
    }
87
88
    public function getRemainingTokenTypes(Identity $identity): array
89
    {
90
        $tokens = $this->getRecoveryTokensForIdentity($identity);
91
        $tokenTypes = $this->excludeDisabledRecoveryTokens(
92
            $this->recoveryTokenService->getAvailableRecoveryTokenTypes()
93
        );
94
95
        /** @var RecoveryToken $token */
96
        foreach ($tokens as $token) {
97
            if (in_array($token->type, $tokenTypes)) {
98
                unset($tokenTypes[$token->type]);
99
            }
100
        }
101
        return $tokenTypes;
102
    }
103
104
    public function delete(RecoveryToken $recoveryToken)
105
    {
106
        $this->recoveryTokenService->delete($recoveryToken);
0 ignored issues
show
Bug introduced by
The method delete() does not exist on Surfnet\StepupMiddleware...ce\RecoveryTokenService. ( Ignorable by Annotation )

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

106
        $this->recoveryTokenService->/** @scrutinizer ignore-call */ 
107
                                     delete($recoveryToken);

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...
107
    }
108
109
    /**
110
     * Verify the password hash with the secret specified on the command.
111
     */
112
    public function authenticateSafeStore(SafeStoreAuthenticationCommand $command): bool
113
    {
114
        return $this->safeStoreService->authenticate($command->secret, $command->recoveryToken->identifier);
115
    }
116
117
    public function getAvailableTokens(Identity $identity, VerifiedSecondFactor $secondFactor): array
118
    {
119
        $tokens = $this->getRecoveryTokensForIdentity($identity);
120
        if ($secondFactor->type === 'sms' && array_key_exists('sms', $tokens)) {
121
            // Check if the phone number of the recovery token is the same as that of the second factor token
122
            $smsRecoveryToken = $tokens['sms'];
123
            if ($smsRecoveryToken->identifier === $secondFactor->secondFactorIdentifier) {
124
                $this->logger->info(
125
                    sprintf(
126
                        'Filtering the SMS recovery token from the available recovery tokens: [%s]. As the phone ' .
127
                        ' numbers are the same for both second factor and recovery tokens.',
128
                        implode(', ', array_keys($tokens))
129
                    )
130
                );
131
                unset($tokens['sms']);
132
            }
133
        }
134
        if (empty($tokens)) {
135
            $this->logger->info('No recovery tokens are available for second factor registration');
136
        }
137
        return $tokens;
138
    }
139
140
    public function startStepUpRequest(string $requestId): void
141
    {
142
        $this->stateStore->startStepUpRequest($requestId);
143
    }
144
145
    public function hasStepUpRequest(): bool
146
    {
147
        return $this->stateStore->hasStepUpRequest();
148
    }
149
150
    public function getStepUpRequest(): string
151
    {
152
        return $this->stateStore->getStepUpRequest();
153
    }
154
155
    public function deleteStepUpRequest(): void
156
    {
157
        $this->stateStore->deleteStepUpRequest();
158
    }
159
160
    public function wasStepUpGiven(): bool
161
    {
162
        return $this->stateStore->getStepUpGiven();
163
    }
164
165
    public function stepUpGiven(): void
166
    {
167
        $this->stateStore->setStepUpGiven(true);
168
    }
169
170
    public function setReturnTo(string $route, array $parameters = [])
171
    {
172
        $this->stateStore->setReturnTo($route, $parameters);
173
    }
174
175
    public function returnTo(): ReturnTo
176
    {
177
        return $this->stateStore->returnTo();
178
    }
179
180
    public function resetReturnTo() :void
181
    {
182
        $this->stateStore->resetReturnTo();
183
    }
184
185
    public function resetStepUpGiven()
186
    {
187
        $this->stateStore->resetStepUpGiven();
188
    }
189
190
    private function excludeDisabledRecoveryTokens(array $availableRecoveryTokenTypes): array
191
    {
192
        foreach ($availableRecoveryTokenTypes as $identifier => $token) {
193
            if ($token === 'sms' && $this->config->isSmsDisabled()) {
194
                unset($availableRecoveryTokenTypes[$identifier]);
195
            }
196
            if ($token === 'safe-store' && $this->config->isSafeStoreCodeDisabled()) {
197
                unset($availableRecoveryTokenTypes[$identifier]);
198
            }
199
        }
200
        return $availableRecoveryTokenTypes;
201
    }
202
}
203