diff --git a/Security/RememberMe/DoctrineTokenProvider.php b/Security/RememberMe/DoctrineTokenProvider.php index 206fda19..251b011b 100644 --- a/Security/RememberMe/DoctrineTokenProvider.php +++ b/Security/RememberMe/DoctrineTokenProvider.php @@ -48,14 +48,16 @@ public function __construct( public function loadTokenBySeries(string $series): PersistentTokenInterface { - // 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->fetchAssociative() ?: throw new TokenNotFoundException('No token found.'); - return new PersistentToken($row['class'], $row['username'], $series, $row['value'], new \DateTimeImmutable($row['last_used'])); + // fetching numeric because column name casing depends on platform, eg. Oracle converts all not quoted names to uppercase + $row = $stmt->fetchNumeric() ?: throw new TokenNotFoundException('No token found.'); + + [$class, $username, $value, $last_used] = $row; + return new PersistentToken($class, $username, $series, $value, new \DateTimeImmutable($last_used)); } public function deleteTokenBySeries(string $series): void 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 545d5926..f97a08cf 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\DriverManager; use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;