Passed
Pull Request — develop (#302)
by Michiel
26:45 queued 21:39
created

SecondFactorController::getSecondFactorService()   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 0
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
 */
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...
18
19
namespace Surfnet\StepupGateway\GatewayBundle\Controller;
20
21
use Psr\Log\LoggerInterface;
22
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
23
use Surfnet\StepupBundle\Command\VerifyPossessionOfPhoneCommand;
24
use Surfnet\StepupBundle\Value\PhoneNumber\InternationalPhoneNumber;
25
use Surfnet\StepupBundle\Value\SecondFactorType;
26
use Surfnet\StepupGateway\GatewayBundle\Command\ChooseSecondFactorCommand;
27
use Surfnet\StepupGateway\GatewayBundle\Command\SendSmsChallengeCommand;
28
use Surfnet\StepupGateway\GatewayBundle\Command\VerifyYubikeyOtpCommand;
29
use Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor;
30
use Surfnet\StepupGateway\GatewayBundle\Exception\InvalidArgumentException;
31
use Surfnet\StepupGateway\GatewayBundle\Exception\LoaCannotBeGivenException;
32
use Surfnet\StepupGateway\GatewayBundle\Exception\RuntimeException;
33
use Surfnet\StepupGateway\GatewayBundle\Form\Type\CancelAuthenticationType;
34
use Surfnet\StepupGateway\GatewayBundle\Form\Type\ChooseSecondFactorType;
35
use Surfnet\StepupGateway\GatewayBundle\Form\Type\SendSmsChallengeType;
36
use Surfnet\StepupGateway\GatewayBundle\Form\Type\VerifySmsChallengeType;
37
use Surfnet\StepupGateway\GatewayBundle\Form\Type\VerifyYubikeyOtpType;
38
use Surfnet\StepupGateway\GatewayBundle\Saml\ResponseContext;
39
use Surfnet\StepupGateway\GatewayBundle\Service\SecondFactorService;
40
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\CookieService;
41
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
42
use Symfony\Component\Form\FormError;
43
use Symfony\Component\Form\FormInterface;
44
use Symfony\Component\HttpFoundation\RedirectResponse;
45
use Symfony\Component\HttpFoundation\Request;
46
use Symfony\Component\HttpFoundation\Response;
47
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
48
49
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
50
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
51
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
52
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
53
 */
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...
54
class SecondFactorController extends Controller
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...e\Controller\Controller has been deprecated: since Symfony 4.2, use "Symfony\Bundle\FrameworkBundle\Controller\AbstractController" instead. ( Ignorable by Annotation )

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

54
class SecondFactorController extends /** @scrutinizer ignore-deprecated */ Controller
Loading history...
55
{
56
    const MODE_SFO = 'sfo';
57
    const MODE_SSO = 'sso';
58
59
    public function selectSecondFactorForVerificationSsoAction(Request $request)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function selectSecondFactorForVerificationSsoAction()
Loading history...
60
    {
61
        return $this->selectSecondFactorForVerificationAction(self::MODE_SSO, $request);
62
    }
63
64
    public function selectSecondFactorForVerificationSfoAction(Request $request)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function selectSecondFactorForVerificationSfoAction()
Loading history...
65
    {
66
        return $this->selectSecondFactorForVerificationAction(self::MODE_SFO, $request);
67
    }
68
69
    public function selectSecondFactorForVerificationAction($authenticationMode, Request $request)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function selectSecondFactorForVerificationAction()
Loading history...
70
    {
71
        $this->supportsAuthenticationMode($authenticationMode);
72
        $context = $this->getResponseContext($authenticationMode);
73
        $originalRequestId = $context->getInResponseTo();
74
        /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
75
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
76
        $logger->notice('Determining which second factor to use...');
77
        try {
78
            // Retrieve all requirements to determine the required LoA
79
            $requestedLoa = $context->getRequiredLoa();
80
            $spConfiguredLoas = $context->getServiceProvider()->get('configuredLoas');
81
            $identityNameId = $context->getIdentityNameId();
82
            $normalizedIdpSho = $context->getNormalizedSchacHomeOrganization();
83
            $normalizedUserSho = $this->getStepupService()->getNormalizedUserShoByIdentityNameId($identityNameId);
84
            $requiredLoa = $this
85
                ->getStepupService()
86
                ->resolveHighestRequiredLoa(
87
                    $requestedLoa,
88
                    $spConfiguredLoas,
0 ignored issues
show
Bug introduced by
It seems like $spConfiguredLoas can also be of type null; however, parameter $spConfiguredLoas of Surfnet\StepupGateway\Ga...lveHighestRequiredLoa() does only seem to accept array, 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

88
                    /** @scrutinizer ignore-type */ $spConfiguredLoas,
Loading history...
89
                    $normalizedIdpSho,
90
                    $normalizedUserSho
91
                );
92
        } catch (LoaCannotBeGivenException $e) {
93
            // Log the message of the domain exception, this contains a meaningful message.
94
            $logger->notice($e->getMessage());
95
            return $this->forward(
96
                'SurfnetStepupGatewayGatewayBundle:Gateway:sendLoaCannotBeGiven',
97
                ['authenticationMode' => $authenticationMode]
98
            );
99
        }
100
101
        $logger->notice(sprintf('Determined that the required Loa is "%s"', $requiredLoa));
102
        if ($this->getStepupService()->isIntrinsicLoa($requiredLoa)) {
103
            $this->get('gateway.authentication_logger')->logIntrinsicLoaAuthentication($originalRequestId);
104
            return $this->forward($context->getResponseAction());
0 ignored issues
show
Bug introduced by
It seems like $context->getResponseAction() can also be of type null; however, parameter $controller of Symfony\Bundle\Framework...r\Controller::forward() does only seem to accept string, 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

104
            return $this->forward(/** @scrutinizer ignore-type */ $context->getResponseAction());
Loading history...
105
        }
106
107
        $secondFactorCollection = $this
108
            ->getStepupService()
109
            ->determineViableSecondFactors(
110
                $context->getIdentityNameId(),
111
                $requiredLoa,
112
                $this->get('gateway.service.whitelist')
113
            );
114
115
        /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
116
         * @var CookieService $ssoCookieService
117
         */
118
        $ssoCookieService = $this->get('gateway.service.sso_2fa_cookie');
119
        $ssoCookie = $ssoCookieService->read($request);
120
        if ($ssoCookieService->shouldSkip2faAuthentication(
121
            $context,
122
            $requiredLoa->getLevel(),
123
            $identityNameId,
124
            $ssoCookie
125
        )) {
0 ignored issues
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
126
            $logger->notice('Skipping second factor authentication. Required LoA was met by the LoA recorded in the cookie');
127
            // We use the SF from the cookie as the SF that was used for authenticating the second factor authentication
128
            $secondFactor = $this->getSecondFactorService()->findByUuid($ssoCookie->secondFactorId());
129
            $this->getResponseContext($authenticationMode)->saveSelectedSecondFactor($secondFactor);
0 ignored issues
show
Bug introduced by
It seems like $secondFactor can also be of type null; however, parameter $secondFactor of Surfnet\StepupGateway\Ga...eSelectedSecondFactor() does only seem to accept Surfnet\StepupGateway\Ga...dle\Entity\SecondFactor, 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

129
            $this->getResponseContext($authenticationMode)->saveSelectedSecondFactor(/** @scrutinizer ignore-type */ $secondFactor);
Loading history...
130
            $this->getResponseContext($authenticationMode)->markSecondFactorVerified();
131
            $this->getResponseContext($authenticationMode)->markVerifiedBySsoOn2faCookie($ssoCookieService->getCookieFingerprint($request));
132
            $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId, $authenticationMode);
0 ignored issues
show
Bug introduced by
It seems like $originalRequestId can also be of type null; however, parameter $requestId of Surfnet\StepupGateway\Ga...dFactorAuthentication() does only seem to accept string, 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

132
            $this->getAuthenticationLogger()->logSecondFactorAuthentication(/** @scrutinizer ignore-type */ $originalRequestId, $authenticationMode);
Loading history...
133
            return $this->forward($context->getResponseAction());
134
        }
135
        switch (count($secondFactorCollection)) {
136
            case 0:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
137
                $logger->notice('No second factors can give the determined Loa');
138
                return $this->forward(
139
                    'SurfnetStepupGatewayGatewayBundle:Gateway:sendLoaCannotBeGiven',
140
                    ['authenticationMode' => $authenticationMode]
141
                );
142
            case 1:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
143
                $secondFactor = $secondFactorCollection->first();
144
                $logger->notice(sprintf(
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...
145
                    'Found "%d" second factors, using second factor of type "%s"',
146
                    count($secondFactorCollection),
147
                    $secondFactor->secondFactorType
148
                ));
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...
149
                return $this->selectAndRedirectTo($secondFactor, $context, $authenticationMode);
150
            default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
151
                return $this->forward(
152
                    'SurfnetStepupGatewayGatewayBundle:SecondFactor:chooseSecondFactor',
153
                    ['authenticationMode' => $authenticationMode, 'secondFactors' => $secondFactorCollection]
154
                );
155
        }
156
    }
157
158
    /**
159
     * The main WAYG screen
160
     * - Shows the token selection screen if you own > 1 token
161
     * - Directly goes to SF auth when identity owns 1 token
162
     *
163
     * @Template
0 ignored issues
show
Coding Style introduced by
Tag @Template cannot be grouped with parameter tags in a doc comment
Loading history...
164
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 41 spaces but found 1
Loading history...
165
     * @param string $authenticationMode
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 41 spaces but found 1
Loading history...
166
     * @return array|RedirectResponse|Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
Coding Style introduced by
Tag value for @return tag indented incorrectly; expected 40 spaces but found 1
Loading history...
167
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
0 ignored issues
show
Coding Style introduced by
Tag @SuppressWarnings(PHPMD.ExcessiveMethodLength) cannot be grouped with parameter tags in a doc comment
Loading history...
168
     */
169
    public function chooseSecondFactorAction(Request $request, $authenticationMode)
170
    {
171
        $this->supportsAuthenticationMode($authenticationMode);
172
        $context = $this->getResponseContext($authenticationMode);
173
        $originalRequestId = $context->getInResponseTo();
174
175
        /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
176
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
177
        $logger->notice('Ask the user which one of his suitable second factor tokens to use...');
178
179
        try {
180
            // Retrieve all requirements to determine the required LoA
181
            $requestedLoa = $context->getRequiredLoa();
182
            $spConfiguredLoas = $context->getServiceProvider()->get('configuredLoas');
183
184
            $normalizedIdpSho = $context->getNormalizedSchacHomeOrganization();
185
            $normalizedUserSho = $this->getStepupService()->getNormalizedUserShoByIdentityNameId($context->getIdentityNameId());
186
187
            $requiredLoa = $this
188
                ->getStepupService()
189
                ->resolveHighestRequiredLoa(
190
                    $requestedLoa,
191
                    $spConfiguredLoas,
0 ignored issues
show
Bug introduced by
It seems like $spConfiguredLoas can also be of type null; however, parameter $spConfiguredLoas of Surfnet\StepupGateway\Ga...lveHighestRequiredLoa() does only seem to accept array, 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

191
                    /** @scrutinizer ignore-type */ $spConfiguredLoas,
Loading history...
192
                    $normalizedIdpSho,
193
                    $normalizedUserSho
194
                );
195
        } catch (LoaCannotBeGivenException $e) {
196
            // Log the message of the domain exception, this contains a meaningful message.
197
            $logger->notice($e->getMessage());
198
            return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendLoaCannotBeGiven');
199
        }
200
201
        $logger->notice(sprintf('Determined that the required Loa is "%s"', $requiredLoa));
202
203
        $secondFactors = $this
204
            ->getStepupService()
205
            ->determineViableSecondFactors(
206
                $context->getIdentityNameId(),
207
                $requiredLoa,
208
                $this->get('gateway.service.whitelist')
209
            );
210
211
        $command = new ChooseSecondFactorCommand();
212
        $command->secondFactors = $secondFactors;
0 ignored issues
show
Documentation Bug introduced by
It seems like $secondFactors of type Doctrine\Common\Collections\Collection is incompatible with the declared type Surfnet\StepupGateway\Ga...e\Entity\SecondFactor[] of property $secondFactors.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
213
214
        $form = $this
215
            ->createForm(
216
                ChooseSecondFactorType::class,
217
                $command,
218
                ['action' => $this->generateUrl('gateway_verify_second_factor_choose_second_factor', ['authenticationMode' => $authenticationMode])]
219
            )
220
            ->handleRequest($request);
221
        $cancelForm = $this->buildCancelAuthenticationForm($authenticationMode)->handleRequest($request);
222
223
        if ($form->isSubmitted() && $form->isValid()) {
224
            $buttonName = $form->getClickedButton()->getName();
0 ignored issues
show
Bug introduced by
The method getClickedButton() does not exist on Symfony\Component\Form\FormInterface. It seems like you code against a sub-type of Symfony\Component\Form\FormInterface such as Symfony\Component\Form\Form. ( Ignorable by Annotation )

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

224
            $buttonName = $form->/** @scrutinizer ignore-call */ getClickedButton()->getName();
Loading history...
225
            $formResults = $request->request->get('gateway_choose_second_factor', false);
226
227
            if (!isset($formResults[$buttonName])) {
228
                throw new InvalidArgumentException(
229
                    sprintf(
230
                        'Second factor type "%s" could not be found in the posted form results.',
231
                        $buttonName
232
                    )
233
                );
234
            }
235
236
            $secondFactorType = $formResults[$buttonName];
237
238
            // Filter the selected second factor from the array collection
239
            $secondFactorFiltered = $secondFactors->filter(
240
                function ($secondFactor) use ($secondFactorType) {
241
                    return $secondFactorType === $secondFactor->secondFactorType;
242
                }
243
            );
244
245
            if ($secondFactorFiltered->isEmpty()) {
246
                throw new InvalidArgumentException(
247
                    sprintf(
248
                        'Second factor type "%s" could not be found in the collection of available second factors.',
249
                        $secondFactorType
250
                    )
251
                );
252
            }
253
254
            $secondFactor = $secondFactorFiltered->first();
255
256
            $logger->notice(sprintf('User chose "%s" to use as second factor', $secondFactorType));
257
258
            // Forward to action to verify possession of second factor
259
            return $this->selectAndRedirectTo($secondFactor, $context, $authenticationMode);
260
        } else if ($form->isSubmitted() && !$form->isValid()) {
261
            $form->addError(
262
                new FormError(
263
                    $this->get('translator')
264
                      ->trans('gateway.form.gateway_choose_second_factor.unknown_second_factor_type')
0 ignored issues
show
Coding Style introduced by
Object operator not indented correctly; expected 24 spaces but found 22
Loading history...
265
                )
266
            );
267
        }
268
269
        return [
270
            'form' => $form->createView(),
271
            'cancelForm' => $cancelForm->createView(),
272
            'secondFactors' => $secondFactors,
273
        ];
274
    }
275
276
    public function verifyGssfAction(Request $request)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function verifyGssfAction()
Loading history...
277
    {
278
        if (!$request->get('authenticationMode', false)) {
279
            throw new RuntimeException('Unable to determine the authentication mode in the GSSP verification action');
280
        }
281
        $authenticationMode = $request->get('authenticationMode');
282
        $this->supportsAuthenticationMode($authenticationMode);
283
        $context = $this->getResponseContext($authenticationMode);
284
285
        $originalRequestId = $context->getInResponseTo();
286
287
        /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
288
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
289
        $logger->info('Received request to verify GSSF');
290
291
        $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger);
292
293
        $logger->info(sprintf(
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...
294
            'Selected GSSF "%s" for verfication, forwarding to Saml handling',
295
            $selectedSecondFactor
296
        ));
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...
297
298
        /** @var \Surfnet\StepupGateway\GatewayBundle\Service\SecondFactorService $secondFactorService */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
299
        $secondFactorService = $this->get('gateway.service.second_factor_service');
300
        /** @var \Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor $secondFactor */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
301
        $secondFactor = $secondFactorService->findByUuid($selectedSecondFactor);
302
        if (!$secondFactor) {
0 ignored issues
show
introduced by
$secondFactor is of type Surfnet\StepupGateway\Ga...dle\Entity\SecondFactor, thus it always evaluated to true.
Loading history...
303
            throw new RuntimeException(sprintf(
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...
304
                'Requested verification of GSSF "%s", however that Second Factor no longer exists',
305
                $selectedSecondFactor
306
            ));
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...
307
        }
308
309
        // Also send the response context service id, as later we need to know if this is regular SSO or SFO authn.
310
        $responseContextServiceId = $context->getResponseContextServiceId();
311
312
        return $this->forward(
313
            'SurfnetStepupGatewaySamlStepupProviderBundle:SamlProxy:sendSecondFactorVerificationAuthnRequest',
314
            [
315
                'provider' => $secondFactor->secondFactorType,
316
                'subjectNameId' => $secondFactor->secondFactorIdentifier,
317
                'responseContextServiceId' => $responseContextServiceId,
318
            ]
319
        );
320
    }
321
322
    public function gssfVerifiedAction(Request $request)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function gssfVerifiedAction()
Loading history...
323
    {
324
        $authenticationMode = $request->get('authenticationMode');
325
        $this->supportsAuthenticationMode($authenticationMode);
326
        $context = $this->getResponseContext($authenticationMode);
327
328
        $originalRequestId = $context->getInResponseTo();
329
330
        /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
331
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
332
        $logger->info('Attempting to mark GSSF as verified');
333
334
        $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger);
335
336
        /** @var \Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor $secondFactor */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
337
        $secondFactor = $this->get('gateway.service.second_factor_service')->findByUuid($selectedSecondFactor);
338
        if (!$secondFactor) {
0 ignored issues
show
introduced by
$secondFactor is of type Surfnet\StepupGateway\Ga...dle\Entity\SecondFactor, thus it always evaluated to true.
Loading history...
339
            throw new RuntimeException(
340
                sprintf(
341
                    'Verification of GSSF "%s" succeeded, however that Second Factor no longer exists',
342
                    $selectedSecondFactor
343
                )
344
            );
345
        }
346
347
        $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId, $authenticationMode);
0 ignored issues
show
Bug introduced by
It seems like $originalRequestId can also be of type null; however, parameter $requestId of Surfnet\StepupGateway\Ga...dFactorAuthentication() does only seem to accept string, 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

347
        $this->getAuthenticationLogger()->logSecondFactorAuthentication(/** @scrutinizer ignore-type */ $originalRequestId, $authenticationMode);
Loading history...
348
        $context->markSecondFactorVerified();
349
350
        $logger->info(sprintf(
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...
351
            'Marked GSSF "%s" as verified, forwarding to Gateway controller to respond',
352
            $selectedSecondFactor
353
        ));
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...
354
        return $this->forward($context->getResponseAction());
0 ignored issues
show
Bug introduced by
It seems like $context->getResponseAction() can also be of type null; however, parameter $controller of Symfony\Bundle\Framework...r\Controller::forward() does only seem to accept string, 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

354
        return $this->forward(/** @scrutinizer ignore-type */ $context->getResponseAction());
Loading history...
355
    }
356
357
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
358
     * @Template
0 ignored issues
show
Coding Style introduced by
Tag @Template cannot be grouped with parameter tags in a doc comment
Loading history...
359
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 4 spaces but found 1
Loading history...
360
     * @return array|Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
Coding Style introduced by
Tag value for @return tag indented incorrectly; expected 3 spaces but found 1
Loading history...
361
     */
362
    public function verifyYubiKeySecondFactorAction(Request $request)
363
    {
364
        if (!$request->get('authenticationMode', false)) {
365
            throw new RuntimeException('Unable to determine the authentication mode in Yubikey verification action');
366
        }
367
        $authenticationMode = $request->get('authenticationMode');
368
        $this->supportsAuthenticationMode($authenticationMode);
369
        $context = $this->getResponseContext($authenticationMode);
370
        $originalRequestId = $context->getInResponseTo();
371
372
        /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
373
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
374
375
        $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger);
376
377
        $logger->notice('Verifying possession of Yubikey second factor');
378
379
        $command = new VerifyYubikeyOtpCommand();
380
        $command->secondFactorId = $selectedSecondFactor;
381
382
        $form = $this->createForm(VerifyYubikeyOtpType::class, $command)->handleRequest($request);
383
        $cancelForm = $this->buildCancelAuthenticationForm($authenticationMode)->handleRequest($request);
384
385
        if ($form->isSubmitted()  && $form->isValid()) {
386
            $result = $this->getStepupService()->verifyYubikeyOtp($command);
387
            if ($result->didOtpVerificationFail()) {
388
                $form->addError(
389
                    new FormError($this->get('translator')->trans('gateway.form.verify_yubikey.otp_verification_failed'))
390
                );
391
392
                // OTP field is rendered empty in the template.
393
                return ['form' => $form->createView(), 'cancelForm' => $cancelForm->createView()];
394
            } elseif (!$result->didPublicIdMatch()) {
395
                $form->addError(
396
                    new FormError($this->get('translator')->trans('gateway.form.verify_yubikey.public_id_mismatch'))
397
                );
398
399
                // OTP field is rendered empty in the template.
400
                return ['form' => $form->createView(), 'cancelForm' => $cancelForm->createView()];
401
            }
402
403
            $this->getResponseContext($authenticationMode)->markSecondFactorVerified();
404
            $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId, $authenticationMode);
0 ignored issues
show
Bug introduced by
It seems like $originalRequestId can also be of type null; however, parameter $requestId of Surfnet\StepupGateway\Ga...dFactorAuthentication() does only seem to accept string, 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

404
            $this->getAuthenticationLogger()->logSecondFactorAuthentication(/** @scrutinizer ignore-type */ $originalRequestId, $authenticationMode);
Loading history...
405
406
            $logger->info(
407
                sprintf(
408
                    'Marked Yubikey Second Factor "%s" as verified, forwarding to Saml Proxy to respond',
409
                    $selectedSecondFactor
410
                )
411
            );
412
            return $this->forward($context->getResponseAction());
0 ignored issues
show
Bug introduced by
It seems like $context->getResponseAction() can also be of type null; however, parameter $controller of Symfony\Bundle\Framework...r\Controller::forward() does only seem to accept string, 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

412
            return $this->forward(/** @scrutinizer ignore-type */ $context->getResponseAction());
Loading history...
413
        }
414
415
        // OTP field is rendered empty in the template.
416
        return ['form' => $form->createView(), 'cancelForm' => $cancelForm->createView()];
417
    }
418
419
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
420
     * @Template
0 ignored issues
show
Coding Style introduced by
Tag @Template cannot be grouped with parameter tags in a doc comment
Loading history...
421
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 4 spaces but found 1
Loading history...
422
     * @param string $authenticationMode
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Superfluous parameter comment
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 4 spaces but found 1
Loading history...
423
     * @return array|Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
Coding Style introduced by
Tag value for @return tag indented incorrectly; expected 3 spaces but found 1
Loading history...
424
     */
425
    public function verifySmsSecondFactorAction(Request $request)
426
    {
427
        if (!$request->get('authenticationMode', false)) {
428
            throw new RuntimeException('Unable to determine the authentication mode in the SMS verification action');
429
        }
430
        $authenticationMode = $request->get('authenticationMode');
431
        $this->supportsAuthenticationMode($authenticationMode);
432
        $context = $this->getResponseContext($authenticationMode);
433
        $originalRequestId = $context->getInResponseTo();
434
435
        /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
436
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
437
438
        $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger);
439
440
        $logger->notice('Verifying possession of SMS second factor, preparing to send');
441
442
        $command = new SendSmsChallengeCommand();
443
        $command->secondFactorId = $selectedSecondFactor;
444
445
        $form = $this->createForm(SendSmsChallengeType::class, $command)->handleRequest($request);
446
        $cancelForm = $this->buildCancelAuthenticationForm($authenticationMode)->handleRequest($request);
447
448
        $stepupService = $this->getStepupService();
449
        $phoneNumber = InternationalPhoneNumber::fromStringFormat(
450
            $stepupService->getSecondFactorIdentifier($selectedSecondFactor)
451
        );
452
453
        $otpRequestsRemaining = $stepupService->getSmsOtpRequestsRemainingCount($selectedSecondFactor);
454
        $maximumOtpRequests = $stepupService->getSmsMaximumOtpRequestsCount();
455
        $viewVariables = ['otpRequestsRemaining' => $otpRequestsRemaining, 'maximumOtpRequests' => $maximumOtpRequests];
456
457
        if ($form->isSubmitted() && !$form->isValid()) {
458
            return array_merge(
459
                $viewVariables,
460
                [
461
                    'phoneNumber' => $phoneNumber,
462
                    'form' => $form->createView(),
463
                    'cancelForm' => $cancelForm->createView()
464
                ]
465
            );
466
        }
467
468
        $logger->notice('Verifying possession of SMS second factor, sending challenge per SMS');
469
470
        if (!$stepupService->sendSmsChallenge($command)) {
471
            $form->addError(
472
                new FormError($this->get('translator')->trans('gateway.form.send_sms_challenge.sms_sending_failed'))
473
            );
474
475
            return array_merge(
476
                $viewVariables,
477
                [
478
                    'phoneNumber' => $phoneNumber,
479
                    'form' => $form->createView(),
480
                    'cancelForm' => $cancelForm->createView()
481
                ]
482
            );
483
        }
484
        return $this->redirect(
485
            $this->generateUrl(
486
                'gateway_verify_second_factor_sms_verify_challenge',
487
                ['authenticationMode' => $authenticationMode]
488
            )
489
        );
490
    }
491
492
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
493
     * @Template
0 ignored issues
show
Coding Style introduced by
Tag @Template cannot be grouped with parameter tags in a doc comment
Loading history...
494
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 4 spaces but found 1
Loading history...
495
     * @param string $authenticationMode
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Superfluous parameter comment
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 4 spaces but found 1
Loading history...
496
     * @return array|Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
Coding Style introduced by
Tag value for @return tag indented incorrectly; expected 3 spaces but found 1
Loading history...
497
     */
498
    public function verifySmsSecondFactorChallengeAction(Request $request)
499
    {
500
        if (!$request->get('authenticationMode', false)) {
501
            throw new RuntimeException('Unable to determine the authentication mode in the SMS challenge action');
502
        }
503
        $authenticationMode = $request->get('authenticationMode');
504
        $this->supportsAuthenticationMode($authenticationMode);
505
        $context = $this->getResponseContext($authenticationMode);
506
        $originalRequestId = $context->getInResponseTo();
507
508
        /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
509
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
510
511
        $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger);
512
513
        $command = new VerifyPossessionOfPhoneCommand();
514
        $form = $this->createForm(VerifySmsChallengeType::class, $command)->handleRequest($request);
515
        $cancelForm = $this->buildCancelAuthenticationForm($authenticationMode)->handleRequest($request);
516
517
        if ($form->isSubmitted() && $form->isValid()) {
518
            $logger->notice('Verifying input SMS challenge matches');
519
            $command->secondFactorId = $selectedSecondFactor;
520
            $verification = $this->getStepupService()->verifySmsChallenge($command);
521
522
            if ($verification->wasSuccessful()) {
523
                $this->getStepupService()->clearSmsVerificationState($selectedSecondFactor);
524
525
                $this->getResponseContext($authenticationMode)->markSecondFactorVerified();
526
                $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId, $authenticationMode);
0 ignored issues
show
Bug introduced by
It seems like $originalRequestId can also be of type null; however, parameter $requestId of Surfnet\StepupGateway\Ga...dFactorAuthentication() does only seem to accept string, 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

526
                $this->getAuthenticationLogger()->logSecondFactorAuthentication(/** @scrutinizer ignore-type */ $originalRequestId, $authenticationMode);
Loading history...
527
528
                $logger->info(
529
                    sprintf(
530
                        'Marked Sms Second Factor "%s" as verified, forwarding to Saml Proxy to respond',
531
                        $selectedSecondFactor
532
                    )
533
                );
534
                return $this->forward($context->getResponseAction());
0 ignored issues
show
Bug introduced by
It seems like $context->getResponseAction() can also be of type null; however, parameter $controller of Symfony\Bundle\Framework...r\Controller::forward() does only seem to accept string, 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

534
                return $this->forward(/** @scrutinizer ignore-type */ $context->getResponseAction());
Loading history...
535
            } elseif ($verification->didOtpExpire()) {
536
                $logger->notice('SMS challenge expired');
537
                $form->addError(
538
                    new FormError($this->get('translator')->trans('gateway.form.send_sms_challenge.challenge_expired'))
539
                );
540
            } elseif ($verification->wasAttemptedTooManyTimes()) {
541
                $logger->notice('SMS challenge verification was attempted too many times');
542
                $form->addError(
543
                    new FormError($this->get('translator')->trans('gateway.form.send_sms_challenge.too_many_attempts'))
544
                );
545
            } else {
546
                $logger->notice('SMS challenge did not match');
547
                $form->addError(
548
                    new FormError(
549
                        $this->get('translator')->trans('gateway.form.send_sms_challenge.sms_challenge_incorrect')
550
                    )
551
                );
552
            }
553
        }
554
        return ['form' => $form->createView(), 'cancelForm' => $cancelForm->createView()];
555
    }
556
557
    public function cancelAuthenticationAction()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function cancelAuthenticationAction()
Loading history...
558
    {
559
        return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendAuthenticationCancelledByUser');
560
    }
561
562
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
563
     * @return \Surfnet\StepupGateway\GatewayBundle\Service\StepupAuthenticationService
564
     */
565
    private function getStepupService()
0 ignored issues
show
Coding Style introduced by
Private method name "SecondFactorController::getStepupService" must be prefixed with an underscore
Loading history...
566
    {
567
        return $this->get('gateway.service.stepup_authentication');
568
    }
569
570
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $authenticationMode should have a doc-comment as per coding-style.
Loading history...
571
     * @return ResponseContext
572
     */
573
    private function getResponseContext($authenticationMode)
0 ignored issues
show
Coding Style introduced by
Private method name "SecondFactorController::getResponseContext" must be prefixed with an underscore
Loading history...
574
    {
575
        switch ($authenticationMode) {
576
            case self::MODE_SFO:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
577
                return $this->get($this->get('gateway.proxy.sfo.state_handler')->getResponseContextServiceId());
578
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
579
            case self::MODE_SSO:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
580
                return $this->get($this->get('gateway.proxy.sso.state_handler')->getResponseContextServiceId());
581
                break;
582
        }
583
    }
584
585
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
586
     * @return \Surfnet\StepupGateway\GatewayBundle\Monolog\Logger\AuthenticationLogger
587
     */
588
    private function getAuthenticationLogger()
0 ignored issues
show
Coding Style introduced by
Private method name "SecondFactorController::getAuthenticationLogger" must be prefixed with an underscore
Loading history...
589
    {
590
        return $this->get('gateway.authentication_logger');
591
    }
592
593
    private function getSecondFactorService(): SecondFactorService
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getSecondFactorService()
Loading history...
Coding Style introduced by
Private method name "SecondFactorController::getSecondFactorService" must be prefixed with an underscore
Loading history...
594
    {
595
        return $this->get('gateway.service.second_factor_service');
596
    }
597
598
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
599
     * @param ResponseContext $context
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
600
     * @param LoggerInterface $logger
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
601
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
602
     */
603
    private function getSelectedSecondFactor(ResponseContext $context, LoggerInterface $logger)
0 ignored issues
show
Coding Style introduced by
Private method name "SecondFactorController::getSelectedSecondFactor" must be prefixed with an underscore
Loading history...
604
    {
605
        $selectedSecondFactor = $context->getSelectedSecondFactor();
606
607
        if (!$selectedSecondFactor) {
608
            $logger->error('Cannot verify possession of an unknown second factor');
609
610
            throw new BadRequestHttpException('Cannot verify possession of an unknown second factor.');
611
        }
612
613
        return $selectedSecondFactor;
614
    }
615
616
    private function selectAndRedirectTo(SecondFactor $secondFactor, ResponseContext $context, $authenticationMode)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function selectAndRedirectTo()
Loading history...
Coding Style introduced by
Private method name "SecondFactorController::selectAndRedirectTo" must be prefixed with an underscore
Loading history...
617
    {
618
        $context->saveSelectedSecondFactor($secondFactor);
619
620
        $this->getStepupService()->clearSmsVerificationState($secondFactor->secondFactorId);
621
622
        $secondFactorTypeService = $this->get('surfnet_stepup.service.second_factor_type');
623
        $secondFactorType = new SecondFactorType($secondFactor->secondFactorType);
624
625
        $route = 'gateway_verify_second_factor_';
626
        if ($secondFactorTypeService->isGssf($secondFactorType)) {
627
            $route .= 'gssf';
628
        } else {
629
            $route .= strtolower($secondFactor->secondFactorType);
630
        }
631
632
        return $this->redirect($this->generateUrl($route, ['authenticationMode' => $authenticationMode]));
633
    }
634
635
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
636
     * @param string $authenticationMode
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
637
     * @return FormInterface
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
638
     */
639
    private function buildCancelAuthenticationForm($authenticationMode)
0 ignored issues
show
Coding Style introduced by
Private method name "SecondFactorController::buildCancelAuthenticationForm" must be prefixed with an underscore
Loading history...
640
    {
641
        $cancelFormAction = $this->generateUrl(
642
            'gateway_cancel_authentication',
643
            ['authenticationMode' => $authenticationMode]
644
        );
645
646
        return $this->createForm(
647
            CancelAuthenticationType::class,
648
            null,
649
            ['action' => $cancelFormAction]
650
        );
651
    }
652
653
    private function supportsAuthenticationMode($authenticationMode)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function supportsAuthenticationMode()
Loading history...
Coding Style introduced by
Private method name "SecondFactorController::supportsAuthenticationMode" must be prefixed with an underscore
Loading history...
654
    {
655
        if (!($authenticationMode === self::MODE_SSO || $authenticationMode === self::MODE_SFO)) {
656
            throw new InvalidArgumentException('Invalid authentication mode requested');
657
        }
658
    }
659
}
660