SelfAssertedTokensController   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 369
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 195
c 3
b 0
f 0
dl 0
loc 369
rs 9.6
wmc 35

9 Methods

Rating   Name   Duplication   Size   Complexity  
A registerCreateRecoveryTokenSafeStore() 0 35 4
B selfAssertedTokenRecoveryTokenSmsAuthentication() 0 63 9
A registerRecoveryTokenSms() 0 12 1
A selfAssertedTokenRegistration() 0 43 4
A registerRecoveryTokenSmsProofOfPossession() 0 12 1
A newRecoveryToken() 0 24 3
C selfAssertedTokenRegistrationRecoveryToken() 0 81 11
A __construct() 0 9 1
A invokeSelfAssertedTokenRegistrationCommand() 0 8 1
1
<?php
2
3
declare(strict_types = 1);
4
5
/**
6
 * Copyright 2022 SURFnet B.V.
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @link tag in file comment
Loading history...
20
21
namespace Surfnet\StepupSelfService\SelfServiceBundle\Controller;
22
23
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\LogicException;
24
use Psr\Log\LoggerInterface;
25
use Surfnet\StepupBundle\Service\LoaResolutionService;
26
use Surfnet\StepupBundle\Value\PhoneNumber\InternationalPhoneNumber;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Command\PromiseSafeStorePossessionCommand;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Command\SafeStoreAuthenticationCommand;
29
use Surfnet\StepupSelfService\SelfServiceBundle\Command\SelfAssertedTokenRegistrationCommand;
30
use Surfnet\StepupSelfService\SelfServiceBundle\Command\SendRecoveryTokenSmsAuthenticationChallengeCommand;
31
use Surfnet\StepupSelfService\SelfServiceBundle\Command\VerifySmsRecoveryTokenChallengeCommand;
32
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\AuthenticateSafeStoreType;
33
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\PromiseSafeStorePossessionType;
34
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\VerifySmsChallengeType;
35
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SecondFactorService;
36
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\AuthenticationRequestFactory;
37
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\RecoveryTokenService;
38
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\SafeStoreService;
39
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SmsRecoveryTokenService;
40
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
41
use Symfony\Component\HttpFoundation\Request;
42
use Symfony\Component\HttpFoundation\Response;
43
use Symfony\Component\Routing\Attribute\Route;
44
45
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
46
 *
47
 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
48
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
49
 * TODO: Split up into smaller controllers
50
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
51
class SelfAssertedTokensController extends AbstractController
52
{
53
    use RecoveryTokenControllerTrait;
0 ignored issues
show
Bug introduced by
The trait Surfnet\StepupSelfServic...eryTokenControllerTrait requires the property $id which is not provided by Surfnet\StepupSelfServic...ssertedTokensController.
Loading history...
54
55
    public function __construct(
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
56
        private readonly RecoveryTokenService $recoveryTokenService,
57
        private readonly SafeStoreService $safeStoreService,
58
        private readonly SecondFactorService $secondFactorService,
59
        private readonly SmsRecoveryTokenService $smsService,
60
        private readonly LoaResolutionService $loaResolutionService,
61
        private readonly AuthenticationRequestFactory $authnRequestFactory,
62
        private readonly LoggerInterface $logger
63
    ) {
64
    }
65
66
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
67
     * Self-asserted token registration: Registration entrypoint
68
     *
69
     * Select(s) the recovery token to perform the self-asserted second factor
70
     * token registration with.
71
     *
72
     * Possible outcomes:
73
     * 1. Shows a recovery token selection screen when more than one token are available
74
     * 2. Selects the one and only available recovery token and redirects to the recovery token authentication route
75
     * 3. Starts registration of a recovery token if non are in possession
76
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
77
    #[Route(
78
        path: '/second-factor/{secondFactorId}/self-asserted-token-registration',
79
        name: 'ss_second_factor_self_asserted_tokens',
80
        methods: ['GET'],
81
    )]
82
    public function selfAssertedTokenRegistration(string $secondFactorId): Response
83
    {
84
        $this->logger->info('Checking if Identity has a recovery token');
85
        $identity = $this->getUser()->getIdentity();
0 ignored issues
show
Bug introduced by
The method getIdentity() does not exist on Symfony\Component\Security\Core\User\UserInterface. It seems like you code against a sub-type of Symfony\Component\Security\Core\User\UserInterface such as Surfnet\StepupSelfServic...n\AuthenticatedIdentity. ( Ignorable by Annotation )

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

85
        $identity = $this->getUser()->/** @scrutinizer ignore-call */ getIdentity();
Loading history...
86
        $this->assertSecondFactorInPossession($secondFactorId, $identity);
87
        $secondFactor = $this->secondFactorService->findOneVerified($secondFactorId);
88
        if ($this->recoveryTokenService->hasRecoveryToken($identity)) {
89
            $tokens = $this->recoveryTokenService->getAvailableTokens($identity, $secondFactor);
0 ignored issues
show
Bug introduced by
It seems like $secondFactor can also be of type null; however, parameter $secondFactor of Surfnet\StepupSelfServic...e::getAvailableTokens() does only seem to accept Surfnet\StepupMiddleware...to\VerifiedSecondFactor, maybe add an additional type check? ( Ignorable by Annotation )

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

89
            $tokens = $this->recoveryTokenService->getAvailableTokens($identity, /** @scrutinizer ignore-type */ $secondFactor);
Loading history...
90
            if ($tokens === []) {
91
                // User is in possession of a recovery token, but it is not safe to use here (for example sms recovery
92
                // token is not available while activating a SMS second factor)
93
                $this->addFlash('error', 'ss.self_asserted_tokens.second_factor.no_available_recovery_token.alert.failed');
94
                return $this->redirectToRoute('ss_second_factor_list');
95
            }
96
            if (count($tokens) > 1) {
97
                $this->logger->info('Show recovery token selection screen');
98
                return $this->render(
99
                    'registration/self_asserted_tokens/select_available_recovery_token.html.twig',
100
                    [
101
                        'secondFactorId' => $secondFactorId,
102
                        'showAvailable' => true,
103
                        'availableRecoveryTokens' => $tokens,
104
                    ]
105
                );
106
            }
107
            $this->logger->info('Continue to recovery token authentication screen for the one available recovery token');
108
            $token = reset($tokens);
109
            return $this->redirect($this->generateUrl(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
110
                'ss_second_factor_self_asserted_tokens_recovery_token',
111
                [
112
                    'secondFactorId' => $secondFactorId,
113
                    'recoveryTokenId' => $token->recoveryTokenId
114
                ]
115
            ));
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
116
        }
117
        $this->logger->info('Start registration of a recovery token (none are available yet)');
118
        return $this->redirect(
119
            $this->generateUrl('ss_second_factor_new_recovery_token', ['secondFactorId' => $secondFactorId])
120
        );
121
    }
122
123
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $recoveryTokenId should have a doc-comment as per coding-style.
Loading history...
124
     * Self-asserted token registration: Authenticate recovery token
125
     *
126
     * Identity must authenticate the recovery token in order to perform a
127
     * self-asserted token registration. But only when this action is
128
     * performed while recovering a Second Factor token. During initial
129
     * registration of a recovery token in the self-asserted token registration
130
     * flow, authentication is not required.
131
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
132
    #[Route(
133
        path: '/second-factor/{secondFactorId}/self-asserted-token-registration/{recoveryTokenId}',
134
        name: 'ss_second_factor_self_asserted_tokens_recovery_token',
135
        methods: ['GET','POST']
136
    )]
137
    public function selfAssertedTokenRegistrationRecoveryToken(
138
        Request $request,
139
        string $secondFactorId,
140
        string $recoveryTokenId
141
    ): Response {
142
        $this->logger->info('Start authentication of recovery token to perform self-asserted token registration');
143
        $identity = $this->getUser()->getIdentity();
144
        $this->assertSecondFactorInPossession($secondFactorId, $identity);
145
        $this->assertRecoveryTokenInPossession($recoveryTokenId, $identity);
146
        $token = $this->recoveryTokenService->getRecoveryToken($recoveryTokenId);
147
148
        switch ($token->type) {
149
            case "sms":
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
150
                if ($this->smsService->wasTokenCreatedDuringSecondFactorRegistration()) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
151
                    // Forget we created the recovery token during token registration. Next time Identity
152
                    // must fill its password.
153
                    $this->smsService->forgetTokenCreatedDuringSecondFactorRegistration();
154
                    $secondFactor = $this->secondFactorService->findOneVerified($secondFactorId);
155
156
                    $command = new SelfAssertedTokenRegistrationCommand();
157
                    $command->identity = $this->getUser()->getIdentity();
158
                    $command->secondFactor = $secondFactor;
159
                    $command->recoveryTokenId = $recoveryTokenId;
160
161
                    if ($this->secondFactorService->registerSelfAssertedToken($command)) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
162
                        $this->addFlash('success', 'ss.self_asserted_tokens.second_factor.alert.successful');
163
                    } else {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
164
                        $this->addFlash('error', 'ss.self_asserted_tokens.second_factor.alert.failed');
165
                    }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
166
                    return $this->redirectToRoute('ss_second_factor_list');
167
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
168
                $number = InternationalPhoneNumber::fromStringFormat($token->identifier);
169
                $command = new SendRecoveryTokenSmsAuthenticationChallengeCommand();
170
                $command->identifier = $number;
171
                $command->institution = $identity->institution;
172
                $command->recoveryTokenId = $recoveryTokenId;
173
                $command->identity = $identity->id;
174
                $this->smsService->authenticate($command);
175
                return $this->redirectToRoute(
176
                    'ss_second_factor_self_asserted_tokens_recovery_token_sms',
177
                    ['secondFactorId' => $secondFactorId, 'recoveryTokenId' => $recoveryTokenId]
178
                );
179
            case "safe-store":
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
180
                // No authentication of the safe store token is required if created during SF token registration
181
                if ($this->safeStoreService->wasSafeStoreTokenCreatedDuringSecondFactorRegistration()) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
182
                    // Forget we created the safe-store recovery token during token registration. Next time Identity
183
                    // must fill its password.
184
                    $this->safeStoreService->forgetSafeStoreTokenCreatedDuringSecondFactorRegistration();
185
                    if ($this->invokeSelfAssertedTokenRegistrationCommand($secondFactorId, $recoveryTokenId)) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
186
                        $this->addFlash('success', 'ss.self_asserted_tokens.second_factor.vetting.alert.successful');
187
                    } else {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
188
                        $this->addFlash('error', 'ss.self_asserted_tokens.second_factor.vetting.alert.failed');
189
                    }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
190
                    return $this->redirectToRoute('ss_second_factor_list');
191
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
192
                $command = new SafeStoreAuthenticationCommand();
193
                $command->recoveryToken = $token;
194
                $command->identity = $identity->id;
195
                $form = $this->createForm(AuthenticateSafeStoreType::class, $command)->handleRequest($request);
196
                if ($form->isSubmitted() && $form->isValid()) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
197
                    if ($this->recoveryTokenService->authenticateSafeStore($command)) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
198
                        if ($this->invokeSelfAssertedTokenRegistrationCommand($secondFactorId, $recoveryTokenId)) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 20 spaces, found 24
Loading history...
199
                            $this->addFlash('success', 'ss.self_asserted_tokens.second_factor.vetting.alert.successful');
200
                            return $this->redirectToRoute('ss_second_factor_list');
201
                        }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 20 spaces, found 24
Loading history...
202
                        $this->addFlash('error', 'ss.self_asserted_tokens.second_factor.vetting.alert.failed');
203
                    } else {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
204
                        $this->addFlash('error', 'ss.self_asserted_tokens.safe_store.authentication.alert.failed');
205
                    }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
206
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
207
                return $this->render(
208
                    'registration/self_asserted_tokens/authenticate_safe_store.html.twig',
209
                    ['form' => $form->createView()]
210
                );
211
            default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
212
                throw new LogicException("The token type {$token->type} is not implemented");
213
        }
214
    }
215
216
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
217
     * Self-asserted token registration: choose recovery token type
218
     *
219
     * The user can select which recovery token to add. Some limitations may
220
     * apply. For example, using a SMS Recovery Token for registration of an
221
     * SMS Second Factor is only allowed when different phone numbers are used.
222
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
223
    #[Route(
224
        path: '/second-factor/{secondFactorId}/new-recovery-token',
225
        name: 'ss_second_factor_new_recovery_token',
226
        methods: ['GET']
227
    )]
228
    public function newRecoveryToken(string $secondFactorId): Response
229
    {
230
        $this->logger->info('Determining which recovery token are available');
231
        $identity = $this->getUser()->getIdentity();
232
        $this->assertSecondFactorInPossession($secondFactorId, $identity);
233
        $this->assertNoRecoveryTokens($identity);
234
235
        $secondFactor = $this->secondFactorService->findOneVerified($secondFactorId);
236
        $availableRecoveryTokens = $this->recoveryTokenService->getRemainingTokenTypes($identity);
237
        if ($secondFactor && $secondFactor->type === 'sms') {
238
            $this->logger->notice('SMS recovery token type is not allowed as we are vetting a SMS second factor');
239
            unset($availableRecoveryTokens['sms']);
240
        }
241
242
        return $this->render(
243
            'registration/self_asserted_tokens/new_recovery_token.html.twig',
244
            [
245
                'secondFactorId' => $secondFactorId,
246
                'availableRecoveryTokens' => $availableRecoveryTokens
247
            ]
248
        );
249
    }
250
251
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $recoveryTokenId should have a doc-comment as per coding-style.
Loading history...
252
     * Self-asserted token registration: Authenticate a SMS recovery token
253
     *
254
     * The previous action (selfAssertedTokenRegistrationRecoveryTokenAction)
255
     * sent the Identity a OTP via SMS. The Identity must reproduce that OTP
256
     * in this action. Proving possession of the recovery token.
257
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
258
    #[Route(
259
        path: '/second-factor/{secondFactorId}/self-asserted-token-registration/{recoveryTokenId}/authenticate',
260
        name: 'ss_second_factor_self_asserted_tokens_recovery_token_sms',
261
        methods: ['GET','POST']
262
    )]
263
    public function selfAssertedTokenRecoveryTokenSmsAuthentication(
264
        Request $request,
265
        string $secondFactorId,
266
        string $recoveryTokenId
267
    ): Response {
268
        $identity = $this->getUser()->getIdentity();
269
        $this->assertSecondFactorInPossession($secondFactorId, $identity);
270
        $this->assertRecoveryTokenInPossession($recoveryTokenId, $identity);
271
272
        // Then render the authentication (proof of possession screen
273
        if (!$this->smsService->hasSmsVerificationState($recoveryTokenId)) {
274
            $this->addFlash('notice', 'ss.registration.sms.alert.no_verification_state');
275
            return $this->redirectToRoute(
276
                'ss_second_factor_self_asserted_tokens',
277
                ['secondFactorId' => $secondFactorId]
278
            );
279
        }
280
281
        $secondFactor = $this->secondFactorService->findOneVerified($secondFactorId);
282
283
        $command = new VerifySmsRecoveryTokenChallengeCommand();
284
        $command->identity = $identity->id;
285
        $command->resendRouteParameters = ['secondFactorId' => $secondFactorId, 'recoveryTokenId' => $recoveryTokenId];
286
287
        $form = $this->createForm(VerifySmsChallengeType::class, $command)->handleRequest($request);
288
289
        if ($form->isSubmitted() && $form->isValid()) {
290
            $command->recoveryTokenId = $recoveryTokenId;
291
            $result = $this->smsService->verifyAuthentication($command);
292
            if ($result->authenticated()) {
293
                $this->smsService->clearSmsVerificationState($recoveryTokenId);
294
295
                $command = new SelfAssertedTokenRegistrationCommand();
296
                $command->identity = $this->getUser()->getIdentity();
297
                $command->secondFactor = $secondFactor;
298
                $command->recoveryTokenId = $recoveryTokenId;
299
300
                if ($this->secondFactorService->registerSelfAssertedToken($command)) {
301
                    $this->addFlash('success', 'ss.self_asserted_tokens.second_factor.alert.successful');
302
                } else {
303
                    $this->addFlash('error', 'ss.self_asserted_tokens.second_factor.alert.failed');
304
                }
305
306
                return $this->redirectToRoute('ss_second_factor_list');
307
            } elseif ($result->wasIncorrectChallengeResponseGiven()) {
308
                $this->addFlash('error', 'ss.prove_phone_possession.incorrect_challenge_response');
309
            } elseif ($result->hasChallengeExpired()) {
310
                $this->addFlash('error', 'ss.prove_phone_possession.challenge_expired');
311
            } elseif ($result->wereTooManyAttemptsMade()) {
312
                $this->addFlash('error', 'ss.prove_phone_possession.too_many_attempts');
313
            } else {
314
                $this->addFlash('error', 'ss.prove_phone_possession.proof_of_possession_failed');
315
            }
316
        }
317
        return $this->render(
318
            'registration/self_asserted_tokens/registration_sms_prove_possession.html.twig',
319
            [
320
                'form' => $form->createView(),
321
            ]
322
        );
323
    }
324
325
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
326
     * Self-asserted token registration: Create Recovery Token (safe-store)
327
     *
328
     * Shows the one-time secret and asks the Identity to store the
329
     * password in a safe location.
330
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
331
    #[Route(
332
        path: '/second-factor/{secondFactorId}/safe-store',
333
        name: 'ss_registration_recovery_token_safe_store',
334
        methods: ['GET','POST']
335
    )]
336
    public function registerCreateRecoveryTokenSafeStore(Request $request, string $secondFactorId): Response
337
    {
338
        $identity = $this->getUser()->getIdentity();
339
        $this->assertSecondFactorInPossession($secondFactorId, $identity);
340
        $this->assertNoRecoveryTokenOfType('safe-store', $identity);
341
342
        $secret = $this->safeStoreService->produceSecret();
343
        $command = new PromiseSafeStorePossessionCommand();
344
345
        $form = $this->createForm(PromiseSafeStorePossessionType::class, $command)->handleRequest($request);
346
347
        if ($form->isSubmitted() && $form->isValid()) {
348
            $command->secret = $secret;
349
            $command->identity = $this->getUser()->getIdentity();
350
351
            $executionResult = $this->safeStoreService->promisePossession($command);
352
            if (!$executionResult->getErrors()) {
353
                return $this->redirect(
354
                    $this->generateUrl('ss_second_factor_self_asserted_tokens', ['secondFactorId' => $secondFactorId])
355
                );
356
            }
357
            $this->addFlash('error', 'ss.form.recovery_token.error.error_message');
358
        }
359
360
        return $this->render(
361
            'registration/self_asserted_tokens/recovery_token_safe_store.html.twig',
362
            [
363
                'form' => $form->createView(),
364
                'secondFactorId' => $secondFactorId,
365
                'secret' => $secret,
366
            ]
367
        );
368
    }
369
370
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
371
     * Self-asserted token registration: Create the SMS recovery token
372
     * Step 1: Send an OTP to phone of Identity
373
     *
374
     * Note: Shares logic with the recovery token SMS send challenge action
375
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
376
    #[Route(
377
        path: '/second-factor/{secondFactorId}/sms',
378
        name: 'ss_registration_recovery_token_sms',
379
        methods: ['GET','POST'],
380
    )]
381
    public function registerRecoveryTokenSms(Request $request, string $secondFactorId): Response
382
    {
383
        return $this->handleSmsChallenge(
384
            $request,
385
            'registration/self_asserted_tokens/recovery_token_sms.html.twig',
386
            'ss_registration_recovery_token_sms_proof_of_possession',
387
            $secondFactorId
388
        );
389
    }
390
391
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
392
     * Self-asserted token registration: Create the SMS recovery token
393
     * Step 2: Process proof of phone possession of Identity
394
     *
395
     * Note: Shares logic with the recovery token SMS send challenge action
396
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
397
    #[Route(
398
        path: '/recovery-token/{secondFactorId}/prove-sms-possession',
399
        name: 'ss_registration_recovery_token_sms_proof_of_possession',
400
        methods: ['GET', 'POST']
401
    )]
402
    public function registerRecoveryTokenSmsProofOfPossession(Request $request, string $secondFactorId): Response
403
    {
404
        return $this->handleSmsProofOfPossession(
405
            $request,
406
            'registration/self_asserted_tokens/registration_sms_prove_possession.html.twig',
407
            'ss_second_factor_self_asserted_tokens',
408
            $secondFactorId
409
        );
410
    }
411
412
    private function invokeSelfAssertedTokenRegistrationCommand(string $secondFactorId, string $recoveryTokenId): bool
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function invokeSelfAssertedTokenRegistrationCommand()
Loading history...
Coding Style introduced by
Private method name "SelfAssertedTokensController::invokeSelfAssertedTokenRegistrationCommand" must be prefixed with an underscore
Loading history...
413
    {
414
        $secondFactor = $this->secondFactorService->findOneVerified($secondFactorId);
415
        $command = new SelfAssertedTokenRegistrationCommand();
416
        $command->identity = $this->getUser()->getIdentity();
417
        $command->secondFactor = $secondFactor;
418
        $command->recoveryTokenId = $recoveryTokenId;
419
        return $this->secondFactorService->registerSelfAssertedToken($command);
420
    }
421
}
422