Merge pull request #19272 from MauricioFauth/2fa-fix
Fix 2FA not getting checked
This commit is contained in:
commit
513c2ae7f5
@ -10002,11 +10002,6 @@
|
||||
<code><![CDATA[$_POST['u2f_registration_response']]]></code>
|
||||
</PossiblyInvalidCast>
|
||||
</file>
|
||||
<file src="src/Plugins/TwoFactor/Simple.php">
|
||||
<UnusedClass>
|
||||
<code><![CDATA[Simple]]></code>
|
||||
</UnusedClass>
|
||||
</file>
|
||||
<file src="src/Plugins/TwoFactorPlugin.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
|
||||
@ -26,7 +26,7 @@ class Simple extends TwoFactorPlugin
|
||||
*/
|
||||
public function check(ServerRequest $request): bool
|
||||
{
|
||||
return isset($_POST['2fa_confirm']);
|
||||
return $request->hasBodyParam('2fa_confirm');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -204,7 +204,11 @@ class TwoFactor
|
||||
return $this->backend->check($request);
|
||||
}
|
||||
|
||||
if (! isset($_SESSION['two_factor_check']) || ! is_bool($_SESSION['two_factor_check'])) {
|
||||
if (
|
||||
! isset($_SESSION['two_factor_check'])
|
||||
|| ! is_bool($_SESSION['two_factor_check'])
|
||||
|| ! $_SESSION['two_factor_check']
|
||||
) {
|
||||
$_SESSION['two_factor_check'] = $this->backend->check($request);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests\Plugins;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\ConfigStorage\RelationParameters;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Exceptions\AuthenticationFailure;
|
||||
use PhpMyAdmin\Exceptions\ExitException;
|
||||
@ -20,12 +23,21 @@ final class AuthenticationPluginTest extends AbstractTestCase
|
||||
{
|
||||
public function testCheckTwoFactor(): void
|
||||
{
|
||||
/** @psalm-suppress DeprecatedMethod */
|
||||
$config = Config::getInstance();
|
||||
/** @psalm-suppress InaccessibleProperty */
|
||||
$config->config->debug->simple2fa = true;
|
||||
|
||||
$GLOBALS['lang'] = 'en';
|
||||
$dbiDummy = $this->createDbiDummy();
|
||||
$dbiDummy->addResult('SHOW TABLES FROM `phpmyadmin`;', [['pma__userconfig'], ['Tables_in_phpmyadmin']]);
|
||||
$dbiDummy->addSelectDb('phpmyadmin');
|
||||
$dbi = $this->createDatabaseInterface($dbiDummy);
|
||||
DatabaseInterface::$instance = $dbi;
|
||||
$dbiDummy->addResult(
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
"SELECT `config_data`, UNIX_TIMESTAMP(`timevalue`) ts FROM `db_pma`.`pma__userconfig` WHERE `username` = 'test_user'",
|
||||
[['{"2fa":{"backend":"simple","settings":[]}}', '1724620722']],
|
||||
['config_data', 'ts'],
|
||||
);
|
||||
$dbiDummy->addResult('SELECT CURRENT_USER();', [['test_user@localhost']]);
|
||||
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy);
|
||||
|
||||
$object = new class extends AuthenticationPlugin {
|
||||
public function showLoginForm(): Response|null
|
||||
@ -46,6 +58,13 @@ final class AuthenticationPluginTest extends AbstractTestCase
|
||||
|
||||
$_SESSION['two_factor_check'] = false;
|
||||
|
||||
$relationParameters = RelationParameters::fromArray([
|
||||
'user' => 'test_user',
|
||||
'db' => 'db_pma',
|
||||
'userconfigwork' => true,
|
||||
'userconfig' => 'pma__userconfig',
|
||||
]);
|
||||
(new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters);
|
||||
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
|
||||
$responseRenderer = ResponseRenderer::getInstance();
|
||||
$responseRenderer->setAjax(false);
|
||||
@ -60,5 +79,67 @@ final class AuthenticationPluginTest extends AbstractTestCase
|
||||
'You have enabled two factor authentication, please confirm your login.',
|
||||
(string) $response->getBody(),
|
||||
);
|
||||
|
||||
$dbiDummy->assertAllQueriesConsumed();
|
||||
$dbiDummy->assertAllSelectsConsumed();
|
||||
}
|
||||
|
||||
public function testCheckTwoFactorConfirmation(): void
|
||||
{
|
||||
/** @psalm-suppress DeprecatedMethod */
|
||||
$config = Config::getInstance();
|
||||
/** @psalm-suppress InaccessibleProperty */
|
||||
$config->config->debug->simple2fa = true;
|
||||
|
||||
$GLOBALS['lang'] = 'en';
|
||||
$dbiDummy = $this->createDbiDummy();
|
||||
$dbiDummy->addResult(
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
"SELECT `config_data`, UNIX_TIMESTAMP(`timevalue`) ts FROM `db_pma`.`pma__userconfig` WHERE `username` = 'test_user'",
|
||||
[['{"2fa":{"backend":"simple","settings":[]}}', '1724620722']],
|
||||
['config_data', 'ts'],
|
||||
);
|
||||
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy);
|
||||
|
||||
$object = new class extends AuthenticationPlugin {
|
||||
public function showLoginForm(): Response|null
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function readCredentials(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function showFailure(AuthenticationFailure $failure): Response
|
||||
{
|
||||
throw new ExitException();
|
||||
}
|
||||
};
|
||||
|
||||
$_SESSION['two_factor_check'] = false;
|
||||
|
||||
$relationParameters = RelationParameters::fromArray([
|
||||
'user' => 'test_user',
|
||||
'db' => 'db_pma',
|
||||
'userconfigwork' => true,
|
||||
'userconfig' => 'pma__userconfig',
|
||||
]);
|
||||
(new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters);
|
||||
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
|
||||
$responseRenderer = ResponseRenderer::getInstance();
|
||||
$responseRenderer->setAjax(false);
|
||||
|
||||
$request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
|
||||
->withParsedBody(['2fa_confirm' => '1']);
|
||||
|
||||
$object->user = 'test_user';
|
||||
$response = $object->checkTwoFactor($request);
|
||||
|
||||
self::assertNull($response);
|
||||
|
||||
$dbiDummy->assertAllQueriesConsumed();
|
||||
$dbiDummy->assertAllSelectsConsumed();
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,8 +11,12 @@ use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\ConfigStorage\RelationParameters;
|
||||
use PhpMyAdmin\Current;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Http\Factory\ServerRequestFactory;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Plugins\TwoFactor\Application;
|
||||
use PhpMyAdmin\Plugins\TwoFactor\Invalid;
|
||||
use PhpMyAdmin\Plugins\TwoFactor\Key;
|
||||
use PhpMyAdmin\Plugins\TwoFactor\Simple;
|
||||
use PhpMyAdmin\Tests\Stubs\DbiDummy;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
@ -29,6 +33,10 @@ use function str_replace;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
|
||||
#[CoversClass(TwoFactor::class)]
|
||||
#[CoversClass(Application::class)]
|
||||
#[CoversClass(Invalid::class)]
|
||||
#[CoversClass(Key::class)]
|
||||
#[CoversClass(Simple::class)]
|
||||
class TwoFactorTest extends AbstractTestCase
|
||||
{
|
||||
protected DatabaseInterface $dbi;
|
||||
@ -161,6 +169,9 @@ class TwoFactorTest extends AbstractTestCase
|
||||
self::assertTrue($object->check($request));
|
||||
self::assertSame('', $object->render($request));
|
||||
|
||||
$_SESSION['two_factor_check'] = false;
|
||||
self::assertTrue($object->check($request));
|
||||
|
||||
$this->dummyDbi->assertAllQueriesConsumed();
|
||||
|
||||
$this->loadResultForConfig(['type' => 'db']);
|
||||
@ -170,9 +181,24 @@ class TwoFactorTest extends AbstractTestCase
|
||||
self::assertSame('', $object->setup($request));
|
||||
}
|
||||
|
||||
public function testInvalidBackend(): void
|
||||
{
|
||||
$object = $this->getTwoFactorAndLoadConfig('user', ['type' => 'db', 'backend' => 'unknown-backend']);
|
||||
$backend = $object->getBackend();
|
||||
self::assertSame('invalid', $backend::$id);
|
||||
self::assertSame('Invalid two-factor authentication', $backend::getName());
|
||||
self::assertSame('Error fallback only!', $backend::getDescription());
|
||||
$request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/');
|
||||
self::assertFalse($object->check($request, true));
|
||||
self::assertStringContainsString(
|
||||
'The configured two factor authentication is not available, please install missing dependencies.',
|
||||
$object->render($request),
|
||||
);
|
||||
self::assertSame('', $object->setup($request));
|
||||
}
|
||||
|
||||
public function testSimple(): void
|
||||
{
|
||||
$request = new ServerRequest(self::createStub(ServerRequestInterface::class));
|
||||
$config = Config::getInstance();
|
||||
$config->config->debug->simple2fa = true;
|
||||
$object = $this->getTwoFactorAndLoadConfig('user', ['type' => 'db', 'backend' => 'simple']);
|
||||
@ -180,12 +206,15 @@ class TwoFactorTest extends AbstractTestCase
|
||||
self::assertSame('simple', $backend::$id);
|
||||
$config->config->debug->simple2fa = false;
|
||||
|
||||
unset($_POST['2fa_confirm']);
|
||||
$serverRequestFactory = ServerRequestFactory::create();
|
||||
$request = $serverRequestFactory->createServerRequest('POST', 'https://example.com/');
|
||||
self::assertFalse($object->check($request, true));
|
||||
|
||||
$_POST['2fa_confirm'] = 1;
|
||||
$request = $serverRequestFactory->createServerRequest('POST', 'https://example.com/')
|
||||
->withParsedBody(['2fa_confirm' => '1']);
|
||||
self::assertTrue($object->check($request, true));
|
||||
unset($_POST['2fa_confirm']);
|
||||
|
||||
$request = $serverRequestFactory->createServerRequest('POST', 'https://example.com/');
|
||||
|
||||
/* Test rendering */
|
||||
self::assertNotEquals('', $object->render($request));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user