From e54337d1c0d6865c32b04ab698c1989fea4e3b66 Mon Sep 17 00:00:00 2001 From: Johannes Date: Thu, 10 Oct 2024 10:10:04 +0200 Subject: [PATCH 1/2] fix: DoctrineTokenProvider not oracle compatible Oracle converts all not quoted names to uppercase --- Security/RememberMe/DoctrineTokenProvider.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Security/RememberMe/DoctrineTokenProvider.php b/Security/RememberMe/DoctrineTokenProvider.php index 5b6b3752..834826c6 100644 --- a/Security/RememberMe/DoctrineTokenProvider.php +++ b/Security/RememberMe/DoctrineTokenProvider.php @@ -55,15 +55,17 @@ public function __construct(Connection $conn) */ public function loadTokenBySeries(string $series) { - // the alias for lastUsed works around case insensitivity in PostgreSQL - $sql = 'SELECT class, username, value, lastUsed AS last_used FROM rememberme_token WHERE series=:series'; + $sql = 'SELECT class, username, value, lastUsed FROM rememberme_token WHERE series=:series'; $paramValues = ['series' => $series]; $paramTypes = ['series' => ParameterType::STRING]; $stmt = $this->conn->executeQuery($sql, $paramValues, $paramTypes); - $row = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAssociative() : $stmt->fetch(\PDO::FETCH_ASSOC); + + // fetching numeric because column name casing depends on platform, eg. Oracle converts all not quoted names to uppercase + $row = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchNumeric() : $stmt->fetch(\PDO::FETCH_NUM); if ($row) { - return new PersistentToken($row['class'], $row['username'], $series, $row['value'], new \DateTime($row['last_used'])); + [$class, $username, $value, $last_used] = $row; + return new PersistentToken($class, $username, $series, $value, new \DateTime($last_used)); } throw new TokenNotFoundException('No token found.'); From 96f5d70e6a31305fc24ae044e625ab67116689e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 10 Oct 2024 12:15:05 +0200 Subject: [PATCH 2/2] Add integration test for RememberMe with pg connection --- .../DoctrineTokenProviderPostgresTest.php | 55 +++++++++++++++++++ .../RememberMe/DoctrineTokenProviderTest.php | 4 +- 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 Tests/Security/RememberMe/DoctrineTokenProviderPostgresTest.php diff --git a/Tests/Security/RememberMe/DoctrineTokenProviderPostgresTest.php b/Tests/Security/RememberMe/DoctrineTokenProviderPostgresTest.php new file mode 100644 index 00000000..866c1ce0 --- /dev/null +++ b/Tests/Security/RememberMe/DoctrineTokenProviderPostgresTest.php @@ -0,0 +1,55 @@ +setSchemaManagerFactory(new DefaultSchemaManagerFactory()); + } + + $connection = DriverManager::getConnection([ + 'driver' => 'pdo_pgsql', + 'host' => getenv('POSTGRES_HOST'), + 'user' => 'postgres', + 'password' => 'password', + ], $config); + $connection->{method_exists($connection, 'executeStatement') ? 'executeStatement' : 'executeUpdate'}(<<<'SQL' + DROP TABLE IF EXISTS rememberme_token; +SQL + ); + + $connection->{method_exists($connection, 'executeStatement') ? 'executeStatement' : 'executeUpdate'}(<<<'SQL' + CREATE TABLE rememberme_token ( + series CHAR(88) UNIQUE PRIMARY KEY NOT NULL, + value VARCHAR(88) NOT NULL, -- CHAR(88) adds spaces at the end + lastUsed TIMESTAMP NOT NULL, + class VARCHAR(100) NOT NULL, + username VARCHAR(200) NOT NULL + ); +SQL + ); + + return new DoctrineTokenProvider($connection); + } +} diff --git a/Tests/Security/RememberMe/DoctrineTokenProviderTest.php b/Tests/Security/RememberMe/DoctrineTokenProviderTest.php index eb387e42..d210abc6 100644 --- a/Tests/Security/RememberMe/DoctrineTokenProviderTest.php +++ b/Tests/Security/RememberMe/DoctrineTokenProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Security\RememberMe; +namespace Symfony\Bridge\Doctrine\Tests\Security\RememberMe; use Doctrine\DBAL\Configuration; use Doctrine\DBAL\DriverManager; @@ -121,7 +121,7 @@ public function testVerifyOutdatedTokenAfterParallelRequestFailsAfter60Seconds() /** * @return DoctrineTokenProvider */ - private function bootstrapProvider() + protected function bootstrapProvider() { $config = class_exists(ORMSetup::class) ? ORMSetup::createConfiguration(true) : new Configuration(); if (class_exists(DefaultSchemaManagerFactory::class)) {