OpenConext /
Stepup-Gateway
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Copyright 2014 SURFnet bv |
||
| 5 | * |
||
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||
| 7 | * you may not use this file except in compliance with the License. |
||
| 8 | * You may obtain a copy of the License at |
||
| 9 | * |
||
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
| 11 | * |
||
| 12 | * Unless required by applicable law or agreed to in writing, software |
||
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
| 15 | * See the License for the specific language governing permissions and |
||
| 16 | * limitations under the License. |
||
| 17 | */ |
||
| 18 | |||
| 19 | namespace Surfnet\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\Exception\RuntimeException; |
||
| 30 | use Surfnet\StepupGateway\GatewayBundle\Saml\ResponseContext; |
||
| 31 | use Surfnet\StepupGateway\U2fVerificationBundle\Value\KeyHandle; |
||
| 32 | use Surfnet\StepupU2fBundle\Dto\SignResponse; |
||
| 33 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
||
| 34 | use Symfony\Component\Form\FormError; |
||
| 35 | use Symfony\Component\HttpFoundation\Request; |
||
| 36 | use Symfony\Component\HttpFoundation\Response; |
||
| 37 | use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface; |
||
| 38 | use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * @SuppressWarnings(PHPMD.CouplingBetweenObjects) |
||
| 42 | */ |
||
| 43 | class SecondFactorController extends Controller |
||
| 44 | { |
||
| 45 | public function selectSecondFactorForVerificationAction() |
||
| 46 | { |
||
| 47 | $context = $this->getResponseContext(); |
||
| 48 | $originalRequestId = $context->getInResponseTo(); |
||
| 49 | |||
| 50 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 51 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 52 | $logger->notice('Determining which second factor to use...'); |
||
| 53 | |||
| 54 | $requiredLoa = $this |
||
| 55 | ->getStepupService() |
||
| 56 | ->resolveHighestRequiredLoa( |
||
| 57 | $context->getRequiredLoa(), |
||
| 58 | $context->getIdentityNameId(), |
||
| 59 | $context->getServiceProvider() |
||
| 60 | ); |
||
| 61 | |||
| 62 | if ($requiredLoa === null) { |
||
| 63 | $logger->notice( |
||
| 64 | 'No valid required Loa can be determined, no authentication is possible, Loa cannot be given' |
||
| 65 | ); |
||
| 66 | |||
| 67 | return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendLoaCannotBeGiven'); |
||
| 68 | } else { |
||
| 69 | $logger->notice(sprintf('Determined that the required Loa is "%s"', $requiredLoa)); |
||
| 70 | } |
||
| 71 | |||
| 72 | if ($this->getStepupService()->isIntrinsicLoa($requiredLoa)) { |
||
| 73 | $this->get('gateway.authentication_logger')->logIntrinsicLoaAuthentication($originalRequestId); |
||
| 74 | |||
| 75 | return $this->forward($context->getResponseAction()); |
||
| 76 | } |
||
| 77 | |||
| 78 | $secondFactorCollection = $this |
||
| 79 | ->getStepupService() |
||
| 80 | ->determineViableSecondFactors($context->getIdentityNameId(), $requiredLoa); |
||
| 81 | |||
| 82 | if (count($secondFactorCollection) === 0) { |
||
| 83 | $logger->notice('No second factors can give the determined Loa'); |
||
| 84 | |||
| 85 | return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendLoaCannotBeGiven'); |
||
| 86 | } |
||
| 87 | |||
| 88 | // will be replaced by a second factor selection screen once we support multiple |
||
| 89 | /** @var \Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor $secondFactor */ |
||
| 90 | $secondFactor = $secondFactorCollection->first(); |
||
| 91 | // when multiple second factors are supported this should be moved into the |
||
| 92 | // StepUpAuthenticationService::determineViableSecondFactors and handled in a performant way |
||
| 93 | // currently keeping this here for visibility |
||
| 94 | if (!$this->get('gateway.service.whitelist')->contains($secondFactor->institution)) { |
||
| 95 | $logger->notice(sprintf( |
||
| 96 | 'Second factor "%s" is listed for institution "%s" which is not on the whitelist, sending Loa ' |
||
| 97 | . 'cannot be given response', |
||
| 98 | $secondFactor->secondFactorId, |
||
| 99 | $secondFactor->institution |
||
| 100 | )); |
||
| 101 | |||
| 102 | return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendLoaCannotBeGiven'); |
||
| 103 | } |
||
| 104 | |||
| 105 | $logger->notice(sprintf( |
||
| 106 | 'Found "%d" second factors, using second factor of type "%s"', |
||
| 107 | count($secondFactorCollection), |
||
| 108 | $secondFactor->secondFactorType |
||
| 109 | )); |
||
| 110 | |||
| 111 | $context->saveSelectedSecondFactor($secondFactor); |
||
| 112 | |||
| 113 | $this->getStepupService()->clearSmsVerificationState(); |
||
| 114 | |||
| 115 | $route = 'gateway_verify_second_factor_'; |
||
| 116 | if ($secondFactor->isGssf()) { |
||
|
0 ignored issues
–
show
|
|||
| 117 | $route .= 'gssf'; |
||
| 118 | } else { |
||
| 119 | $route .= strtolower($secondFactor->secondFactorType); |
||
| 120 | } |
||
| 121 | |||
| 122 | return $this->redirect($this->generateUrl($route)); |
||
| 123 | } |
||
| 124 | |||
| 125 | public function verifyGssfAction() |
||
| 126 | { |
||
| 127 | $context = $this->getResponseContext(); |
||
| 128 | $originalRequestId = $context->getInResponseTo(); |
||
| 129 | |||
| 130 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 131 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 132 | $logger->info('Received request to verify GSSF'); |
||
| 133 | |||
| 134 | $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger); |
||
| 135 | |||
| 136 | $logger->info(sprintf( |
||
| 137 | 'Selected GSSF "%s" for verfication, forwarding to Saml handling', |
||
| 138 | $selectedSecondFactor |
||
| 139 | )); |
||
| 140 | |||
| 141 | /** @var \Surfnet\StepupGateway\GatewayBundle\Service\SecondFactorService $secondFactorService */ |
||
| 142 | $secondFactorService = $this->get('gateway.service.second_factor_service'); |
||
| 143 | /** @var \Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor $secondFactor */ |
||
| 144 | $secondFactor = $secondFactorService->findByUuid($selectedSecondFactor); |
||
| 145 | if (!$secondFactor) { |
||
| 146 | $logger->critical(sprintf( |
||
| 147 | 'Requested verification of GSSF "%s", however that Second Factor no longer exists', |
||
| 148 | $selectedSecondFactor |
||
| 149 | )); |
||
| 150 | |||
| 151 | throw new RuntimeException('Verification of selected second factor that no longer exists'); |
||
| 152 | } |
||
| 153 | |||
| 154 | return $this->forward( |
||
| 155 | 'SurfnetStepupGatewaySamlStepupProviderBundle:SamlProxy:sendSecondFactorVerificationAuthnRequest', |
||
| 156 | [ |
||
| 157 | 'provider' => $secondFactor->secondFactorType, |
||
| 158 | 'subjectNameId' => $secondFactor->secondFactorIdentifier |
||
| 159 | ] |
||
| 160 | ); |
||
| 161 | } |
||
| 162 | |||
| 163 | public function gssfVerifiedAction() |
||
| 164 | { |
||
| 165 | $context = $this->getResponseContext(); |
||
| 166 | $originalRequestId = $context->getInResponseTo(); |
||
| 167 | |||
| 168 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 169 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 170 | $logger->info('Attempting to mark GSSF as verified'); |
||
| 171 | |||
| 172 | $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger); |
||
| 173 | |||
| 174 | /** @var \Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor $secondFactor */ |
||
| 175 | $secondFactor = $this->get('gateway.service.second_factor_service')->findByUuid($selectedSecondFactor); |
||
| 176 | if (!$secondFactor) { |
||
| 177 | $logger->critical(sprintf( |
||
| 178 | 'Verification of GSSF "%s" succeeded, however that Second Factor no longer exists', |
||
| 179 | $selectedSecondFactor |
||
| 180 | )); |
||
| 181 | |||
| 182 | throw new RuntimeException('Verification of selected second factor that no longer exists'); |
||
| 183 | } |
||
| 184 | |||
| 185 | $context->markSecondFactorVerified(); |
||
| 186 | $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId); |
||
| 187 | |||
| 188 | $logger->info(sprintf( |
||
| 189 | 'Marked GSSF "%s" as verified, forwarding to Gateway controller to respond', |
||
| 190 | $selectedSecondFactor |
||
| 191 | )); |
||
| 192 | |||
| 193 | return $this->forward($context->getResponseAction()); |
||
| 194 | } |
||
| 195 | |||
| 196 | /** |
||
| 197 | * @Template |
||
| 198 | * @param Request $request |
||
| 199 | * @return array|Response |
||
| 200 | */ |
||
| 201 | public function verifyYubiKeySecondFactorAction(Request $request) |
||
| 202 | { |
||
| 203 | $context = $this->getResponseContext(); |
||
| 204 | $originalRequestId = $context->getInResponseTo(); |
||
| 205 | |||
| 206 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 207 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 208 | |||
| 209 | $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger); |
||
| 210 | |||
| 211 | $logger->notice('Verifying possession of Yubikey second factor'); |
||
| 212 | |||
| 213 | $command = new VerifyYubikeyOtpCommand(); |
||
| 214 | $command->secondFactorId = $selectedSecondFactor; |
||
| 215 | |||
| 216 | $form = $this->createForm('gateway_verify_yubikey_otp', $command)->handleRequest($request); |
||
| 217 | |||
| 218 | if ($form->get('cancel')->isClicked()) { |
||
| 219 | return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendAuthenticationCancelledByUser'); |
||
| 220 | } |
||
| 221 | |||
| 222 | if (!$form->isValid()) { |
||
| 223 | // OTP field is rendered empty in the template. |
||
| 224 | return ['form' => $form->createView()]; |
||
| 225 | } |
||
| 226 | |||
| 227 | $result = $this->getStepupService()->verifyYubikeyOtp($command); |
||
| 228 | |||
| 229 | if ($result->didOtpVerificationFail()) { |
||
| 230 | $form->addError(new FormError('gateway.form.verify_yubikey.otp_verification_failed')); |
||
| 231 | |||
| 232 | // OTP field is rendered empty in the template. |
||
| 233 | return ['form' => $form->createView()]; |
||
| 234 | } elseif (!$result->didPublicIdMatch()) { |
||
| 235 | $form->addError(new FormError('gateway.form.verify_yubikey.public_id_mismatch')); |
||
| 236 | |||
| 237 | // OTP field is rendered empty in the template. |
||
| 238 | return ['form' => $form->createView()]; |
||
| 239 | } |
||
| 240 | |||
| 241 | $this->getResponseContext()->markSecondFactorVerified(); |
||
| 242 | $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId); |
||
| 243 | |||
| 244 | $logger->info( |
||
| 245 | sprintf( |
||
| 246 | 'Marked Yubikey Second Factor "%s" as verified, forwarding to Saml Proxy to respond', |
||
| 247 | $selectedSecondFactor |
||
| 248 | ) |
||
| 249 | ); |
||
| 250 | |||
| 251 | return $this->forward($context->getResponseAction()); |
||
| 252 | } |
||
| 253 | |||
| 254 | /** |
||
| 255 | * @Template |
||
| 256 | * @param Request $request |
||
| 257 | * @return array|Response |
||
| 258 | */ |
||
| 259 | public function verifySmsSecondFactorAction(Request $request) |
||
| 260 | { |
||
| 261 | $context = $this->getResponseContext(); |
||
| 262 | $originalRequestId = $context->getInResponseTo(); |
||
| 263 | |||
| 264 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 265 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 266 | |||
| 267 | $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger); |
||
| 268 | |||
| 269 | $logger->notice('Verifying possession of SMS second factor, preparing to send'); |
||
| 270 | |||
| 271 | $command = new SendSmsChallengeCommand(); |
||
| 272 | $command->secondFactorId = $selectedSecondFactor; |
||
| 273 | |||
| 274 | $form = $this->createForm('gateway_send_sms_challenge', $command)->handleRequest($request); |
||
| 275 | |||
| 276 | $stepupService = $this->getStepupService(); |
||
| 277 | $phoneNumber = InternationalPhoneNumber::fromStringFormat( |
||
| 278 | $stepupService->getSecondFactorIdentifier($selectedSecondFactor) |
||
| 279 | ); |
||
| 280 | |||
| 281 | $otpRequestsRemaining = $stepupService->getSmsOtpRequestsRemainingCount(); |
||
| 282 | $maximumOtpRequests = $stepupService->getSmsMaximumOtpRequestsCount(); |
||
| 283 | $viewVariables = ['otpRequestsRemaining' => $otpRequestsRemaining, 'maximumOtpRequests' => $maximumOtpRequests]; |
||
| 284 | |||
| 285 | if ($form->get('cancel')->isClicked()) { |
||
| 286 | return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendAuthenticationCancelledByUser'); |
||
| 287 | } |
||
| 288 | |||
| 289 | if (!$form->isValid()) { |
||
| 290 | return array_merge($viewVariables, ['phoneNumber' => $phoneNumber, 'form' => $form->createView()]); |
||
| 291 | } |
||
| 292 | |||
| 293 | $logger->notice('Verifying possession of SMS second factor, sending challenge per SMS'); |
||
| 294 | |||
| 295 | if (!$stepupService->sendSmsChallenge($command)) { |
||
| 296 | $form->addError(new FormError('gateway.form.send_sms_challenge.sms_sending_failed')); |
||
| 297 | |||
| 298 | return array_merge($viewVariables, ['phoneNumber' => $phoneNumber, 'form' => $form->createView()]); |
||
| 299 | } |
||
| 300 | |||
| 301 | return $this->redirect($this->generateUrl('gateway_verify_second_factor_sms_verify_challenge')); |
||
| 302 | } |
||
| 303 | |||
| 304 | /** |
||
| 305 | * @Template |
||
| 306 | * @param Request $request |
||
| 307 | * @return array|Response |
||
| 308 | */ |
||
| 309 | public function verifySmsSecondFactorChallengeAction(Request $request) |
||
| 310 | { |
||
| 311 | $context = $this->getResponseContext(); |
||
| 312 | $originalRequestId = $context->getInResponseTo(); |
||
| 313 | |||
| 314 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 315 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 316 | |||
| 317 | $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger); |
||
| 318 | |||
| 319 | $command = new VerifyPossessionOfPhoneCommand(); |
||
| 320 | $form = $this->createForm('gateway_verify_sms_challenge', $command)->handleRequest($request); |
||
| 321 | |||
| 322 | if ($form->get('cancel')->isClicked()) { |
||
|
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Symfony\Component\Form\FormInterface as the method isClicked() does only exist in the following implementations of said interface: Symfony\Component\Form\SubmitButton.
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
| 323 | return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendAuthenticationCancelledByUser'); |
||
| 324 | } |
||
| 325 | |||
| 326 | if (!$form->isValid()) { |
||
| 327 | return ['form' => $form->createView()]; |
||
| 328 | } |
||
| 329 | |||
| 330 | $logger->notice('Verifying input SMS challenge matches'); |
||
| 331 | |||
| 332 | $verification = $this->getStepupService()->verifySmsChallenge($command); |
||
| 333 | |||
| 334 | if ($verification->wasSuccessful()) { |
||
| 335 | $this->getStepupService()->clearSmsVerificationState(); |
||
| 336 | |||
| 337 | $this->getResponseContext()->markSecondFactorVerified(); |
||
| 338 | $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId); |
||
| 339 | |||
| 340 | $logger->info( |
||
| 341 | sprintf( |
||
| 342 | 'Marked Sms Second Factor "%s" as verified, forwarding to Saml Proxy to respond', |
||
| 343 | $selectedSecondFactor |
||
| 344 | ) |
||
| 345 | ); |
||
| 346 | |||
| 347 | return $this->forward($context->getResponseAction()); |
||
| 348 | } elseif ($verification->didOtpExpire()) { |
||
| 349 | $logger->notice('SMS challenge expired'); |
||
| 350 | $form->addError(new FormError('gateway.form.send_sms_challenge.challenge_expired')); |
||
| 351 | } elseif ($verification->wasAttemptedTooManyTimes()) { |
||
| 352 | $logger->notice('SMS challenge verification was attempted too many times'); |
||
| 353 | $form->addError(new FormError('gateway.form.send_sms_challenge.too_many_attempts')); |
||
| 354 | } else { |
||
| 355 | $logger->notice('SMS challenge did not match'); |
||
| 356 | $form->addError(new FormError('gateway.form.send_sms_challenge.sms_challenge_incorrect')); |
||
| 357 | } |
||
| 358 | |||
| 359 | return ['form' => $form->createView()]; |
||
| 360 | } |
||
| 361 | |||
| 362 | /** |
||
| 363 | * @Template |
||
| 364 | */ |
||
| 365 | public function initiateU2fAuthenticationAction() |
||
| 366 | { |
||
| 367 | $context = $this->getResponseContext(); |
||
| 368 | $originalRequestId = $context->getInResponseTo(); |
||
| 369 | |||
| 370 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 371 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 372 | |||
| 373 | $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger); |
||
| 374 | $stepupService = $this->getStepupService(); |
||
| 375 | |||
| 376 | $cancelFormAction = $this->generateUrl('gateway_verify_second_factor_u2f_cancel_authentication'); |
||
| 377 | $cancelForm = |
||
| 378 | $this->createForm('gateway_cancel_second_factor_verification', null, ['action' => $cancelFormAction]); |
||
| 379 | |||
| 380 | $logger->notice('Verifying possession of U2F second factor, looking for registration matching key handle'); |
||
| 381 | |||
| 382 | $service = $this->get('surfnet_stepup_u2f_verification.service.u2f_verification'); |
||
| 383 | $keyHandle = new KeyHandle($stepupService->getSecondFactorIdentifier($selectedSecondFactor)); |
||
| 384 | $registration = $service->findRegistrationByKeyHandle($keyHandle); |
||
| 385 | |||
| 386 | if ($registration === null) { |
||
| 387 | $logger->critical( |
||
| 388 | sprintf('No known registration for key handle of second factor "%s"', $selectedSecondFactor) |
||
| 389 | ); |
||
| 390 | $this->addFlash('error', 'gateway.u2f.alert.unknown_registration'); |
||
| 391 | |||
| 392 | return ['authenticationFailed' => true, 'cancelForm' => $cancelForm->createView()]; |
||
| 393 | } |
||
| 394 | |||
| 395 | $logger->notice('Creating sign request'); |
||
| 396 | |||
| 397 | $signRequest = $service->createSignRequest($registration); |
||
| 398 | $signResponse = new SignResponse(); |
||
| 399 | |||
| 400 | /** @var AttributeBagInterface $session */ |
||
| 401 | $session = $this->get('gateway.session.u2f'); |
||
| 402 | $session->set('request', $signRequest); |
||
| 403 | |||
| 404 | $formAction = $this->generateUrl('gateway_verify_second_factor_u2f_verify_authentication'); |
||
| 405 | $form = $this->createForm( |
||
| 406 | 'surfnet_stepup_u2f_verify_device_authentication', |
||
| 407 | $signResponse, |
||
| 408 | ['sign_request' => $signRequest, 'action' => $formAction] |
||
| 409 | ); |
||
| 410 | |||
| 411 | return ['form' => $form->createView(), 'cancelForm' => $cancelForm->createView()]; |
||
| 412 | } |
||
| 413 | |||
| 414 | /** |
||
| 415 | * @Template("SurfnetStepupGatewayGatewayBundle:SecondFactor:initiateU2fAuthentication.html.twig") |
||
| 416 | * |
||
| 417 | * @param Request $request |
||
| 418 | * @return array|Response |
||
| 419 | */ |
||
| 420 | public function verifyU2fAuthenticationAction(Request $request) |
||
| 421 | { |
||
| 422 | $context = $this->getResponseContext(); |
||
| 423 | $originalRequestId = $context->getInResponseTo(); |
||
| 424 | |||
| 425 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
| 426 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
| 427 | |||
| 428 | $selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger); |
||
| 429 | |||
| 430 | $logger->notice('Received sign response from device'); |
||
| 431 | |||
| 432 | /** @var AttributeBagInterface $session */ |
||
| 433 | $session = $this->get('gateway.session.u2f'); |
||
| 434 | $signRequest = $session->get('request'); |
||
| 435 | $signResponse = new SignResponse(); |
||
| 436 | |||
| 437 | $formAction = $this->generateUrl('gateway_verify_second_factor_u2f_verify_authentication'); |
||
| 438 | $form = $this |
||
| 439 | ->createForm( |
||
| 440 | 'surfnet_stepup_u2f_verify_device_authentication', |
||
| 441 | $signResponse, |
||
| 442 | ['sign_request' => $signRequest, 'action' => $formAction] |
||
| 443 | ) |
||
| 444 | ->handleRequest($request); |
||
| 445 | |||
| 446 | $cancelFormAction = $this->generateUrl('gateway_verify_second_factor_u2f_cancel_authentication'); |
||
| 447 | $cancelForm = |
||
| 448 | $this->createForm('gateway_cancel_second_factor_verification', null, ['action' => $cancelFormAction]); |
||
| 449 | |||
| 450 | if (!$form->isValid()) { |
||
| 451 | $logger->error('U2F authentication verification could not be started because device send illegal data'); |
||
| 452 | $this->addFlash('error', 'gateway.u2f.alert.error'); |
||
| 453 | |||
| 454 | return ['authenticationFailed' => true, 'cancelForm' => $cancelForm->createView()]; |
||
| 455 | } |
||
| 456 | |||
| 457 | $service = $this->get('surfnet_stepup_u2f_verification.service.u2f_verification'); |
||
| 458 | $result = $service->verifyAuthentication($signRequest, $signResponse); |
||
| 459 | |||
| 460 | if ($result->wasSuccessful()) { |
||
| 461 | $context->markSecondFactorVerified(); |
||
| 462 | $this->getAuthenticationLogger()->logSecondFactorAuthentication($originalRequestId); |
||
| 463 | |||
| 464 | $logger->info( |
||
| 465 | sprintf( |
||
| 466 | 'Marked U2F second factor "%s" as verified, forwarding to Saml Proxy to respond', |
||
| 467 | $selectedSecondFactor |
||
| 468 | ) |
||
| 469 | ); |
||
| 470 | |||
| 471 | return $this->forward($context->getResponseAction()); |
||
| 472 | } elseif ($result->didDeviceReportError()) { |
||
| 473 | $logger->error('U2F device reported error during authentication'); |
||
| 474 | $this->addFlash('error', 'gateway.u2f.alert.device_reported_an_error'); |
||
| 475 | } else { |
||
| 476 | $logger->error('U2F authentication verification failed'); |
||
| 477 | $this->addFlash('error', 'gateway.u2f.alert.error'); |
||
| 478 | } |
||
| 479 | |||
| 480 | return ['authenticationFailed' => true, 'cancelForm' => $cancelForm->createView()]; |
||
| 481 | } |
||
| 482 | |||
| 483 | public function cancelU2fAuthenticationAction() |
||
| 484 | { |
||
| 485 | return $this->forward('SurfnetStepupGatewayGatewayBundle:Gateway:sendAuthenticationCancelledByUser'); |
||
| 486 | } |
||
| 487 | |||
| 488 | /** |
||
| 489 | * @return \Surfnet\StepupGateway\GatewayBundle\Service\StepupAuthenticationService |
||
| 490 | */ |
||
| 491 | private function getStepupService() |
||
| 492 | { |
||
| 493 | return $this->get('gateway.service.stepup_authentication'); |
||
| 494 | } |
||
| 495 | |||
| 496 | /** |
||
| 497 | * @return ResponseContext |
||
| 498 | */ |
||
| 499 | private function getResponseContext() |
||
| 500 | { |
||
| 501 | return $this->get($this->get('gateway.proxy.state_handler')->getResponseContextServiceId()); |
||
| 502 | } |
||
| 503 | |||
| 504 | /** |
||
| 505 | * @return \Surfnet\StepupGateway\GatewayBundle\Monolog\Logger\AuthenticationLogger |
||
| 506 | */ |
||
| 507 | private function getAuthenticationLogger() |
||
| 508 | { |
||
| 509 | return $this->get('gateway.authentication_logger'); |
||
| 510 | } |
||
| 511 | |||
| 512 | /** |
||
| 513 | * @param ResponseContext $context |
||
| 514 | * @param LoggerInterface $logger |
||
| 515 | * @return string |
||
| 516 | */ |
||
| 517 | private function getSelectedSecondFactor(ResponseContext $context, LoggerInterface $logger) |
||
| 518 | { |
||
| 519 | $selectedSecondFactor = $context->getSelectedSecondFactor(); |
||
| 520 | |||
| 521 | if (!$selectedSecondFactor) { |
||
| 522 | $logger->error('Cannot verify possession of an unknown second factor'); |
||
| 523 | |||
| 524 | throw new BadRequestHttpException('Cannot verify possession of an unknown second factor.'); |
||
| 525 | } |
||
| 526 | |||
| 527 | return $selectedSecondFactor; |
||
| 528 | } |
||
| 529 | |||
| 530 | private function selectAndRedirectTo(SecondFactor $secondFactor, ResponseContext $context) |
||
|
0 ignored issues
–
show
|
|||
| 531 | { |
||
| 532 | $context->saveSelectedSecondFactor($secondFactor); |
||
| 533 | |||
| 534 | $this->getStepupService()->clearSmsVerificationState(); |
||
| 535 | |||
| 536 | $secondFactorTypeService = $this->get('surfnet_stepup.service.second_factor_type'); |
||
| 537 | $secondFactorType = new SecondFactorType($this->secondFactorType); |
||
|
0 ignored issues
–
show
The property
secondFactorType does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
| 538 | |||
| 539 | $route = 'gateway_verify_second_factor_'; |
||
| 540 | if ($secondFactorTypeService->isGssf($secondFactorType)) { |
||
| 541 | $route .= 'gssf'; |
||
| 542 | } else { |
||
| 543 | $route .= strtolower($secondFactor->secondFactorType); |
||
| 544 | } |
||
| 545 | |||
| 546 | return $this->redirect($this->generateUrl($route)); |
||
| 547 | } |
||
| 548 | } |
||
| 549 |
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.