diff --git a/src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Controller/SecondFactorOnlyController.php b/src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Controller/SecondFactorOnlyController.php index 21417f4e..32742847 100644 --- a/src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Controller/SecondFactorOnlyController.php +++ b/src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Controller/SecondFactorOnlyController.php @@ -124,7 +124,7 @@ public function respondAction(Request $request) } try { - $response = $this->getSecondFactorRespondService()->respond($responseContext); + $response = $this->getSecondFactorRespondService()->respond($responseContext, $request); } catch (InvalidSecondFactorMethodException $e) { throw new BadRequestHttpException($e->getMessage()); } diff --git a/src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Exception/RuntimeException.php b/src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Exception/RuntimeException.php new file mode 100644 index 00000000..f6e75924 --- /dev/null +++ b/src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Exception/RuntimeException.php @@ -0,0 +1,26 @@ +samlLogger = $samlLogger; $this->loaResolutionService = $loaResolutionService; @@ -71,6 +75,8 @@ public function __construct( $this->responseFactory = $responseFactory; $this->secondFactorService = $secondFactorService; $this->secondFactorTypeService = $secondFactorTypeService; + $this->providerRepository = $providerRepository; + $this->postBinding = $postBinding; } @@ -84,7 +90,7 @@ public function __construct( * @param ResponseContext $responseContext * @return Response */ - public function respond(ResponseContext $responseContext) + public function respond(ResponseContext $responseContext, Request $request) { $originalRequestId = $responseContext->getInResponseTo(); $logger = $this->samlLogger->forAuthentication($originalRequestId); @@ -105,6 +111,31 @@ public function respond(ResponseContext $responseContext) } $secondFactor = $this->secondFactorService->findByUuid($selectedSecondFactorUuid); + + $secondFactorType = new SecondFactorType($secondFactor->secondFactorType); + // When dealing with a GSSP response. It is advised to receive the SAML response through POST Binding, + // testing the preconditions. + if ($this->secondFactorTypeService->isGssf($secondFactorType)) { + $provider = $this->providerRepository->get($secondFactorType->getSecondFactorType()); + // Receive the response via POST Binding, this will test all the regular pre-conditions + $samlResponse = $this->postBinding->processResponse( + $request, + $provider->getRemoteIdentityProvider(), + $provider->getServiceProvider() + ); + $nameIdFromResponse = $samlResponse->getNameId()->getValue(); + // Additionally test if the name id from the gssp matches the SF identifier that we have in state + if ($nameIdFromResponse !== $secondFactor->secondFactorIdentifier) { + throw new RuntimeException( + sprintf( + 'The NameId from the GSSP (%s) did not match that of the Identity that vetted the selected ' . + 'Second Factor (%s). This might be an indication someone is tampering with a GSSP', + $nameIdFromResponse, + $secondFactor->secondFactorIdentifier + ) + ); + } + } $grantedLoa = $this->loaResolutionService ->getLoaByLevel($secondFactor->getLoaLevel($this->secondFactorTypeService));