Skip to content
This repository has been archived by the owner on Dec 2, 2021. It is now read-only.

Commit

Permalink
Reset prepared provider on each login, to fix preparation issue when …
Browse files Browse the repository at this point in the history
…`invalidate_session` option is false #296
  • Loading branch information
scheb committed Aug 13, 2020
1 parent 0f757ff commit 5c2cbc4
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ public function __construct(
public function onLogin(AuthenticationEvent $event): void
{
$token = $event->getAuthenticationToken();

if ($token instanceof TwoFactorTokenInterface) {
$firewallName = $token->getProviderKey();
$this->preparationRecorder->startRecording($firewallName);
}

if ($this->prepareOnLogin && $this->supports($token)) {
/** @var TwoFactorTokenInterface $token */
// After login, when the token is a TwoFactorTokenInterface, execute preparation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ public function isProviderPrepared(string $firewallName, string $providerName):
return \in_array($providerName, $firewallCalledProviders, true);
}

public function startRecording(string $firewallName): void
{
$calledProviders = $this->session->get(self::CALLED_PROVIDERS_SESSION_KEY, []);
$calledProviders[$firewallName] = [];
$this->session->set(self::CALLED_PROVIDERS_SESSION_KEY, $calledProviders);
}

public function recordProviderIsPrepared(string $firewallName, string $providerName): void
{
$calledProviders = $this->session->get(self::CALLED_PROVIDERS_SESSION_KEY, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\TwoFactorProviderRegistry;
use Scheb\TwoFactorBundle\Tests\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;

class TwoFactorProviderPreparationListenerTest extends TestCase
Expand All @@ -35,17 +35,17 @@ class TwoFactorProviderPreparationListenerTest extends TestCase
private $request;

/**
* @var MockObject|SessionInterface
* @var MockObject|TwoFactorProviderPreparationRecorder
*/
private $preparationRecorder;

/**
* @var MockObject|TwoFactorToken
*/
private $token;
private $twoFactorToken;

/**
* @var
* @var \stdClass
*/
private $user;

Expand All @@ -58,16 +58,16 @@ protected function setUp(): void
{
$this->request = $this->createMock(Request::class);
$this->user = new \stdClass();
$this->token = $this->createMock(TwoFactorToken::class);
$this->token
$this->twoFactorToken = $this->createMock(TwoFactorToken::class);
$this->twoFactorToken
->expects($this->any())
->method('getProviderKey')
->willReturn(self::FIREWALL_NAME);
$this->token
$this->twoFactorToken
->expects($this->any())
->method('getCurrentTwoFactorProvider')
->willReturn(self::CURRENT_PROVIDER_NAME);
$this->token
$this->twoFactorToken
->expects($this->any())
->method('getUser')
->willReturn($this->user);
Expand All @@ -91,12 +91,12 @@ private function initTwoFactorProviderPreparationListener($prepareOnLogin, $prep

private function createTwoFactorAuthenticationEvent(): TwoFactorAuthenticationEvent
{
return new TwoFactorAuthenticationEvent($this->request, $this->token);
return new TwoFactorAuthenticationEvent($this->request, $this->twoFactorToken);
}

private function createAuthenticationEvent(): AuthenticationEvent
private function createAuthenticationEvent(TokenInterface $token): AuthenticationEvent
{
return new AuthenticationEvent($this->token);
return new AuthenticationEvent($token);
}

private function createFinishRequestEvent(): FinishRequestEvent
Expand Down Expand Up @@ -141,7 +141,7 @@ private function expectNotPrepareCurrentProvider(): void
{
$this->preparationRecorder
->expects($this->never())
->method($this->anything());
->method('recordProviderIsPrepared');

$this->providerRegistry
->expects($this->never())
Expand All @@ -154,7 +154,7 @@ private function expectNotPrepareCurrentProvider(): void
public function onLogin_optionPrepareOnLoginTrue_twoFactorProviderIsPrepared(): void
{
$this->initTwoFactorProviderPreparationListener(true, false);
$event = $this->createAuthenticationEvent();
$event = $this->createAuthenticationEvent($this->twoFactorToken);

$this->expectPrepareCurrentProvider();

Expand All @@ -168,14 +168,46 @@ public function onLogin_optionPrepareOnLoginTrue_twoFactorProviderIsPrepared():
public function onLogin_optionPrepareOnLoginFalse_twoFactorProviderIsNotPrepared(): void
{
$this->initTwoFactorProviderPreparationListener(false, false);
$event = $this->createAuthenticationEvent();
$event = $this->createAuthenticationEvent($this->twoFactorToken);

$this->expectNotPrepareCurrentProvider();

$this->listener->onLogin($event);
$this->listener->onKernelFinishRequest($this->createFinishRequestEvent());
}

/**
* @test
*/
public function onLogin_twoFactorToken_startRecording(): void
{
$this->initTwoFactorProviderPreparationListener(false, false);
$event = $this->createAuthenticationEvent($this->twoFactorToken);

$this->preparationRecorder
->expects($this->once())
->method('startRecording')
->with(self::FIREWALL_NAME);

$this->listener->onLogin($event);
}

/**
* @test
*/
public function onLogin_otherToken_doNothing(): void
{
$this->initTwoFactorProviderPreparationListener(false, false);
$token = $this->createMock(TokenInterface::class);
$event = $this->createAuthenticationEvent($token);

$this->preparationRecorder
->expects($this->never())
->method('startRecording');

$this->listener->onLogin($event);
}

/**
* @test
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,31 @@ protected function setUp(): void
$this->recorder = new TwoFactorProviderPreparationRecorder($this->session);
}

/**
* @test
*/
public function startRecording_wasPreparedBefore_noLongerPrepared(): void
{
$this->session
->expects($this->any())
->method('get')
->with('2fa_called_providers')
->willReturn([
'otherFirewallName' => [self::CURRENT_PROVIDER_NAME],
self::FIREWALL_NAME => [self::CURRENT_PROVIDER_NAME],
]);

$this->session
->expects($this->once())
->method('set')
->with('2fa_called_providers', [
'otherFirewallName' => [self::CURRENT_PROVIDER_NAME],
self::FIREWALL_NAME => [],
]);

$this->recorder->startRecording(self::FIREWALL_NAME);
}

/**
* @test
*/
Expand Down

0 comments on commit 5c2cbc4

Please sign in to comment.