Skip to content

Commit e9464b4

Browse files
committed
Move logic to dedicated GsspFallbackService
1 parent 39aafbe commit e9464b4

File tree

15 files changed

+164
-52
lines changed

15 files changed

+164
-52
lines changed

src/Surfnet/StepupGateway/GatewayBundle/Controller/SecondFactorController.php

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
use Surfnet\StepupGateway\GatewayBundle\Service\SecondFactorService;
4141
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\CookieService;
4242
use Surfnet\StepupGateway\SamlStepupProviderBundle\Controller\SamlProxyController;
43-
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\SecondfactorGsspFallback;
43+
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\GsspFallbackService;
4444
use Symfony\Component\Form\FormError;
4545
use Symfony\Component\Form\FormInterface;
4646
use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -125,7 +125,7 @@ public function selectSecondFactorForVerification(
125125
// Now read the SSO cookie
126126
$ssoCookie = $this->getCookieService()->read($request);
127127
// Test if the SSO cookie can satisfy the second factor authentication requirements
128-
if ($this->getCookieService()->maySkipAuthentication($requiredLoa->getLevel(), $identityNameId, $ssoCookie, $context)) {
128+
if ($this->getCookieService()->maySkipAuthentication($requiredLoa->getLevel(), $identityNameId, $ssoCookie)) {
129129
$logger->notice(
130130
'Skipping second factor authentication. Required LoA was met by the LoA recorded in the cookie',
131131
[
@@ -134,7 +134,7 @@ public function selectSecondFactorForVerification(
134134
],
135135
);
136136
// We use the SF from the cookie as the SF that was used for authenticating the second factor authentication
137-
$secondFactor = $this->getSecondFactorService()->findByUuid($ssoCookie->secondFactorId(), $context);
137+
$secondFactor = $this->getSecondFactorService()->findByUuid($ssoCookie->secondFactorId());
138138
$this->getResponseContext($authenticationMode)->saveSelectedSecondFactor($secondFactor);
139139
$this->getResponseContext($authenticationMode)->markSecondFactorVerified();
140140
$this->getResponseContext($authenticationMode)->markVerifiedBySsoOn2faCookie(
@@ -146,6 +146,17 @@ public function selectSecondFactorForVerification(
146146
}
147147
}
148148

149+
// Determine if the GSSP fallback flow is allowed so we can continue without a previous registered token
150+
if ($this->getGsspFallbackService()->determineGsspFallbackNeeded(
151+
$identityNameId,
152+
$authenticationMode,
153+
$requiredLoa,
154+
$this->get('gateway.service.whitelist'),
155+
)) {
156+
$secondFactor = $this->getGsspFallbackService()->createSecondFactor();
157+
return $this->selectAndRedirectTo($secondFactor, $context, $authenticationMode);
158+
}
159+
149160
$secondFactorCollection = $this
150161
->getStepupService()
151162
->determineViableSecondFactors(
@@ -156,24 +167,6 @@ public function selectSecondFactorForVerification(
156167
switch (count($secondFactorCollection)) {
157168
case 0:
158169
$logger->notice('No second factors can give the determined Loa');
159-
160-
// todo: handle sso registration bypass.
161-
if ($authenticationMode === self::MODE_SFO) {
162-
// - the user does not have an active token
163-
164-
// - a LoA1.5 (i.e. self asserted) authentication is requested
165-
// - a fallback GSSP is configured
166-
// - this "fallback" option is enabled for the institution that the user belongs to.
167-
// - the configured user attribute is present in the AuthnRequest
168-
// - handle authentication by forwarding it to a designated GSSP using the GSSP protocol instead of returning an error.
169-
170-
// var_dump($requiredLoa);
171-
// die();
172-
173-
$secondFactor = SecondfactorGsspFallback::create('azuremfa', $request->getLocale());
174-
return $this->selectAndRedirectTo($secondFactor, $context, $authenticationMode);
175-
}
176-
177170
return $this->forward(
178171
'Surfnet\StepupGateway\GatewayBundle\Controller\GatewayController::sendLoaCannotBeGiven',
179172
['authenticationMode' => $authenticationMode],
@@ -357,7 +350,7 @@ public function verifyGssf(Request $request): Response
357350

358351
/** @var SecondFactorService $secondFactorService */
359352
$secondFactorService = $this->get('gateway.service.second_factor_service');
360-
$secondFactor = $secondFactorService->findByUuid($selectedSecondFactor, $context);
353+
$secondFactor = $secondFactorService->findByUuid($selectedSecondFactor);
361354
if (!$secondFactor) {
362355
throw new RuntimeException(
363356
sprintf(
@@ -395,11 +388,11 @@ public function gssfVerified(Request $request): Response
395388

396389
$selectedSecondFactor = $this->getSelectedSecondFactor($context, $logger);
397390

398-
if (!$context->isSecondFactorFallback()) {
391+
if (!$this->getGsspFallbackService()->isSecondFactorFallback()) {
399392
/** @var SecondFactor $secondFactor */
400393
$secondFactor = $this->get('gateway.service.second_factor_service')->findByUuid($selectedSecondFactor);
401394
} else {
402-
$secondFactor = SecondfactorGsspFallback::create('azuremfa', $context->getSelectedLocale());
395+
$secondFactor = $this->getGsspFallbackService()->createSecondFactor();
403396
}
404397

405398
if (!$secondFactor) {
@@ -705,6 +698,11 @@ private function getSecondFactorService(): SecondFactorService
705698
return $this->get('gateway.service.second_factor_service');
706699
}
707700

701+
private function getGsspFallbackService(): GsspFallbackService
702+
{
703+
return $this->get('second_factor_only.gssp_fallback_service');
704+
}
705+
708706
private function getSelectedSecondFactor(ResponseContext $context, LoggerInterface $logger): string
709707
{
710708
$selectedSecondFactor = $context->getSelectedSecondFactor();

src/Surfnet/StepupGateway/GatewayBundle/EventListener/SecondFactorLocaleListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function getLocaleFromSelectedSecondFactor()
5858
return;
5959
}
6060

61-
$secondFactor = $this->secondFactorService->findByUuid($secondFactorId, $this->responseContext);
61+
$secondFactor = $this->secondFactorService->findByUuid($secondFactorId);
6262
if ($secondFactor) {
6363
return $secondFactor->displayLocale;
6464
}

src/Surfnet/StepupGateway/GatewayBundle/Monolog/Logger/AuthenticationLogger.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function logSecondFactorAuthentication(string $requestId, string $authent
6060
{
6161
$context = $this->getResponseContext($authenticationMode);
6262

63-
$secondFactor = $this->secondFactorService->findByUuid($context->getSelectedSecondFactor(), $context);
63+
$secondFactor = $this->secondFactorService->findByUuid($context->getSelectedSecondFactor());
6464
$loa = $this->secondFactorService->getLoaLevel($secondFactor);
6565

6666
$data = [
@@ -73,7 +73,7 @@ public function logSecondFactorAuthentication(string $requestId, string $authent
7373
];
7474

7575
if ($context->isVerifiedBySsoOn2faCookie()) {
76-
$context['sso_cookie_id'] = $context->getSsoOn2faCookieFingerprint();
76+
$data['sso_cookie_id'] = $context->getSsoOn2faCookieFingerprint();
7777
}
7878

7979
$this->log('Second Factor Authenticated', $data, $requestId, $authenticationMode);

src/Surfnet/StepupGateway/GatewayBundle/Resources/config/services.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ services:
7575
- "@gateway.repository.second_factor"
7676
- "@surfnet_stepup.service.loa_resolution"
7777
- "@surfnet_stepup.service.second_factor_type"
78+
- "@second_factor_only.gssp_fallback_service"
7879

7980
gateway.service.response_proxy:
8081
class: Surfnet\StepupGateway\GatewayBundle\Service\ProxyResponseService

src/Surfnet/StepupGateway/GatewayBundle/Saml/ResponseContext.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,6 @@ public function getSelectedLocale(): string
257257
return $this->stateHandler->getPreferredLocale();
258258
}
259259

260-
public function isSecondFactorFallback(): bool
261-
{
262-
return $this->stateHandler->isSecondFactorFallback();
263-
}
264-
265260
/**
266261
* @return null|string
267262
*/

src/Surfnet/StepupGateway/GatewayBundle/Service/Gateway/RespondService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function respond(ResponseContext $responseContext)
8383

8484
$grantedLoa = null;
8585
if ($responseContext->isSecondFactorVerified()) {
86-
$secondFactor = $this->secondFactorService->findByUuid($responseContext->getSelectedSecondFactor(), $responseContext);
86+
$secondFactor = $this->secondFactorService->findByUuid($responseContext->getSelectedSecondFactor());
8787
$grantedLoa = $this->secondFactorService->getLoaLevel($secondFactor);
8888
}
8989

src/Surfnet/StepupGateway/GatewayBundle/Service/SecondFactorService.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,37 @@
2424
use Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor;
2525
use Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactorRepository;
2626
use Surfnet\StepupGateway\GatewayBundle\Exception\RuntimeException;
27-
use Surfnet\StepupGateway\GatewayBundle\Saml\ResponseContext;
2827
use Surfnet\StepupGateway\GatewayBundle\Service\SecondFactor\SecondFactorInterface;
28+
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\GsspFallbackService;
2929
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\SecondfactorGsspFallback;
3030

3131
class SecondFactorService
3232
{
3333
private SecondFactorRepository $repository;
3434
private LoaResolutionService $loaResolutionService;
3535
private SecondFactorTypeService $secondFactorTypeService;
36+
private GsspFallbackService $gsspFallbackService;
3637

3738
public function __construct(
3839
SecondFactorRepository $repository,
3940
LoaResolutionService $loaResolutionService,
40-
SecondFactorTypeService $secondFactorTypeService
41+
SecondFactorTypeService $secondFactorTypeService,
42+
GsspFallbackService $gsspFallbackService
4143
) {
4244
$this->repository = $repository;
4345
$this->loaResolutionService = $loaResolutionService;
4446
$this->secondFactorTypeService = $secondFactorTypeService;
47+
$this->gsspFallbackService = $gsspFallbackService;
4548
}
4649

4750
/**
4851
* @param $uuid
4952
* @return null|SecondFactorInterface
5053
*/
51-
public function findByUuid($uuid, ResponseContext $responseContext)
54+
public function findByUuid($uuid)
5255
{
53-
if ($responseContext->isSecondFactorFallback()) {
54-
return SecondfactorGsspFallback::create('azuremfa', $responseContext->getSelectedLocale());
56+
if ($this->gsspFallbackService->isSecondFactorFallback()) {
57+
return $this->gsspFallbackService->createSecondFactor();
5558
}
5659

5760
return $this->repository->findOneBySecondFactorId($uuid);

src/Surfnet/StepupGateway/GatewayBundle/Sso2fa/CookieService.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function handleSsoOn2faCookieStorage(
106106

107107
// We can only set an SSO on 2FA cookie if a second factor authentication is being handled.
108108
if ($secondFactorId) {
109-
$secondFactor = $this->secondFactorService->findByUuid($secondFactorId, $responseContext);
109+
$secondFactor = $this->secondFactorService->findByUuid($secondFactorId);
110110
if (!$secondFactor) {
111111
throw new RuntimeException(sprintf('Second Factor token not found with ID: %s', $secondFactorId));
112112
}
@@ -141,16 +141,15 @@ public function handleSsoOn2faCookieStorage(
141141
public function maySkipAuthentication(
142142
float $requiredLoa,
143143
string $identityNameId,
144-
CookieValueInterface $ssoCookie,
145-
ResponseContext $responseContext
144+
CookieValueInterface $ssoCookie
146145
): bool {
147146

148147
// Perform validation on the cookie and its contents
149148
if (!$this->isCookieValid($ssoCookie, $requiredLoa, $identityNameId)) {
150149
return false;
151150
}
152151

153-
if (!$this->secondFactorService->findByUuid($ssoCookie->secondFactorId(), $responseContext)) {
152+
if (!$this->secondFactorService->findByUuid($ssoCookie->secondFactorId(),)) {
154153
$this->logger->notice(
155154
'The second factor stored in the SSO cookie was revoked or has otherwise became unknown to Gateway',
156155
[

src/Surfnet/StepupGateway/GatewayBundle/Tests/Service/Gateway/RespondServiceTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public function it_should_return_a_valid_saml_response_and_update_state_when_the
144144

145145
// Mock second factor service
146146
$this->secondFactorService->shouldReceive('findByUuid')
147-
->with('mocked-second-factor-id', $this->responseContext)
147+
->with('mocked-second-factor-id')
148148
->andReturn($secondFactor);
149149

150150
$this->secondFactorService->shouldReceive('getLoaLevel')

src/Surfnet/StepupGateway/GatewayBundle/Tests/Sso2fa/CookieServiceTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public function test_storing_a_session_cookie(): void
229229
->shouldReceive('finalizeAuthentication');
230230
$this->secondFactorService
231231
->shouldReceive('findByUuid')
232-
->with('sf-id-1234', $this->responseContext)
232+
->with('sf-id-1234')
233233
->andReturn($sfMock);
234234
$this->secondFactorService
235235
->shouldReceive('getLoaLevel')
@@ -290,7 +290,7 @@ public function test_storing_a_persistent_cookie(): void
290290
->shouldReceive('finalizeAuthentication');
291291
$this->secondFactorService
292292
->shouldReceive('findByUuid')
293-
->with('sf-id-1234', $this->responseContext)
293+
->with('sf-id-1234')
294294
->andReturn($sfMock);
295295
$this->secondFactorService
296296
->shouldReceive('getLoaLevel')
@@ -349,7 +349,7 @@ public function test_storing_a_session_cookie_new_authentication(): void
349349
->shouldReceive('finalizeAuthentication');
350350
$this->secondFactorService
351351
->shouldReceive('findByUuid')
352-
->with('sf-id-1234', $this->responseContext)
352+
->with('sf-id-1234')
353353
->andReturn($sfMock);
354354
$this->secondFactorService
355355
->shouldReceive('getLoaLevel')
@@ -402,7 +402,7 @@ public function test_storing_a_session_cookie_second_factor_not_found(): void
402402
->shouldReceive('finalizeAuthentication');
403403
$this->secondFactorService
404404
->shouldReceive('findByUuid')
405-
->with('non-existant', $this->responseContext)
405+
->with('non-existant')
406406
->andReturnNull();
407407

408408
self::expectException(RuntimeException::class);
@@ -471,7 +471,7 @@ public function test_storing_a_session_cookie_not_enabled_for_institution(): voi
471471
->andReturn(false);
472472
$this->secondFactorService
473473
->shouldReceive('findByUuid')
474-
->with('sf-id-1234', $this->responseContext)
474+
->with('sf-id-1234')
475475
->andReturn($sfMock);
476476
$this->institutionService
477477
->shouldReceive('ssoOn2faEnabled')
@@ -503,7 +503,7 @@ public function test_skipping_authentication_succeeds(): void
503503

504504
$this->secondFactorService
505505
->shouldReceive('findByUuid')
506-
->with('abcdef-1234', $this->responseContext)
506+
->with('abcdef-1234')
507507
->andReturn($yubikey);
508508

509509
self::assertTrue(

src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Controller/SecondFactorOnlyController.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Adfs\Exception\InvalidAdfsResponseException;
2525
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Exception\InvalidSecondFactorMethodException;
2626
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\AdfsService;
27+
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\GsspFallbackService;
2728
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\LoginService;
2829
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\RespondService;
2930
use Symfony\Component\HttpFoundation\Request;
@@ -88,6 +89,10 @@ public function sso(Request $httpRequest): Response
8889
return $responseRendering->renderRequesterFailureResponse($this->getResponseContext(), $httpRequest);
8990
}
9091

92+
// Handle SAML GSSP user attibutes extension
93+
$logger->notice('Determine if GSSP user attributes are present for processing later on');
94+
$this->getGsspFallbackService()->handleSamlGsspExtension($originalRequest);
95+
9196
$logger->notice('Forwarding to second factor controller for loa determination and handling');
9297

9398
// Forward to the selectSecondFactorForVerificationSsoAction,
@@ -200,4 +205,12 @@ public function getSecondFactorAdfsService()
200205
{
201206
return $this->get('second_factor_only.adfs_service');
202207
}
208+
209+
/**
210+
* @return AdfsService
211+
*/
212+
public function getGsspFallbackService(): GsspFallbackService
213+
{
214+
return $this->get('second_factor_only.gssp_fallback_service');
215+
}
203216
}

src/Surfnet/StepupGateway/SecondFactorOnlyBundle/Resources/config/services.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,11 @@ services:
170170
arguments:
171171
- "@second_factor_only.adfs.request_helper"
172172
- "@second_factor_only.adfs.response_helper"
173+
174+
175+
second_factor_only.gssp_fallback_service:
176+
class: Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\Gateway\GsspFallbackService
177+
arguments:
178+
- "@gateway.repository.second_factor"
179+
- "@gateway.proxy.sfo.state_handler"
180+
- "@surfnet_saml.logger"

0 commit comments

Comments
 (0)