mirror of
https://github.com/wallabag/wallabag.git
synced 2025-08-11 17:51:02 +00:00
Add a two-step setup of OTP
Before this change, 2FA with OTP was enabled before the user was able to submit a code to validate the setup. Thus, this could lead to a situation where the user is locked out of her account if there was an issue setting up her application. Now we rely on a new boolean property that is set to true only after the user submits a valid code during the setup phase. Fixes #4867 Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
This commit is contained in:
parent
3f6c01103d
commit
b09224cac1
6 changed files with 125 additions and 17 deletions
|
@ -3,6 +3,7 @@
|
|||
namespace Tests\Wallabag\Controller;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
@ -1223,27 +1224,74 @@ class ConfigControllerTest extends WallabagTestCase
|
|||
|
||||
public function testUserEnable2faGoogle()
|
||||
{
|
||||
$googleAuthenticatorMock = $this->createMock(GoogleAuthenticatorInterface::class);
|
||||
$googleAuthenticatorMock
|
||||
->method('generateSecret')
|
||||
->willReturn('DUMMYSECRET');
|
||||
$googleAuthenticatorMock
|
||||
->method('checkCode')
|
||||
->willReturnCallback(function ($user, $code) {
|
||||
return '123456' === $code;
|
||||
});
|
||||
|
||||
$this->logInAs('admin');
|
||||
$client = $this->getTestClient();
|
||||
$client->disableReboot(); // Disable reboot to keep the mock in the container
|
||||
|
||||
// name::class notation does not work in this context
|
||||
self::getContainer()->set('scheb_two_factor.security.google_authenticator', $googleAuthenticatorMock);
|
||||
|
||||
$crawler = $client->request('GET', '/config');
|
||||
|
||||
$form = $crawler->filter('form[name=config_otp_app]')->form();
|
||||
$client->submit($form);
|
||||
$crawler = $client->submit($form);
|
||||
|
||||
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
// restore user
|
||||
$secret = $crawler->filter('div#config_otp_app_secret pre code')->innerText();
|
||||
$this->assertSame('DUMMYSECRET', $secret);
|
||||
|
||||
$em = $this->getEntityManager();
|
||||
$user = $em
|
||||
->getRepository(User::class)
|
||||
->findOneByUsername('admin');
|
||||
// At this phase, the user should not have 2FA enabled
|
||||
$this->assertFalse($user->isGoogleTwoFactor());
|
||||
|
||||
// First test: send invalid OTP code
|
||||
$form = $crawler->filter('form[name=config_otp_app_check]')->form();
|
||||
$data = [
|
||||
'_auth_code' => '000000',
|
||||
];
|
||||
$client->submit($form, $data);
|
||||
|
||||
$this->assertSame(307, $client->getResponse()->getStatusCode());
|
||||
$this->assertStringContainsString('flashes.config.notice.otp_code_invalid', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
|
||||
|
||||
// Follow the redirect to the OTP check form again
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
// Second test: send valid OTP code
|
||||
$form = $crawler->filter('form[name=config_otp_app_check]')->form();
|
||||
$data = [
|
||||
'_auth_code' => '123456',
|
||||
];
|
||||
$client->submit($form, $data);
|
||||
|
||||
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertStringContainsString('flashes.config.notice.otp_enabled', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
|
||||
|
||||
$em = $this->getEntityManager();
|
||||
$user = $em
|
||||
->getRepository(User::class)
|
||||
->findOneByUsername('admin');
|
||||
|
||||
$this->assertTrue($user->isGoogleTwoFactor());
|
||||
$this->assertGreaterThan(0, $user->getBackupCodes());
|
||||
$this->assertGreaterThan(0, \count($user->getBackupCodes()));
|
||||
|
||||
$user->setGoogleAuthenticatorSecret(false);
|
||||
$user->setBackupCodes(null);
|
||||
// Restore user
|
||||
$user->setGoogleAuthenticatorSecret('');
|
||||
$user->setGoogleAuthenticator(false);
|
||||
$user->setBackupCodes([]);
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
}
|
||||
|
@ -1259,6 +1307,7 @@ class ConfigControllerTest extends WallabagTestCase
|
|||
->findOneByUsername('admin');
|
||||
|
||||
$user->setGoogleAuthenticatorSecret('Google2FA');
|
||||
$user->setGoogleAuthenticator(true);
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
|
||||
|
@ -1271,7 +1320,6 @@ class ConfigControllerTest extends WallabagTestCase
|
|||
|
||||
$this->assertStringContainsString('flashes.config.notice.otp_disabled', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
|
||||
|
||||
// restore user
|
||||
$em = $this->getEntityManager();
|
||||
$user = $em
|
||||
->getRepository(User::class)
|
||||
|
@ -1279,6 +1327,7 @@ class ConfigControllerTest extends WallabagTestCase
|
|||
|
||||
$this->assertEmpty($user->getGoogleAuthenticatorSecret());
|
||||
$this->assertEmpty($user->getBackupCodes());
|
||||
$this->assertFalse($user->isGoogleTwoFactor());
|
||||
}
|
||||
|
||||
public function testExportTaggingRule()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue