Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit df166fa

Browse filesBrowse files
committed
Add DoctrineSchemaSubscriber to automatically create remember me table
1 parent e45b25f commit df166fa
Copy full SHA for df166fa

File tree

3 files changed

+120
-21
lines changed
Filter options

3 files changed

+120
-21
lines changed
+64Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\SchemaListener;
13+
14+
use Doctrine\Common\EventSubscriber;
15+
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
16+
use Doctrine\ORM\Tools\ToolEvents;
17+
use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider;
18+
use Symfony\Component\Security\Http\RememberMe\PersistentRememberMeHandler;
19+
use Symfony\Component\Security\Http\RememberMe\RememberMeHandlerInterface;
20+
21+
/**
22+
* Automatically adds the remember me table needed for the {@see DoctrineTokenProvider}.
23+
*
24+
* @author Wouter de Jong <wouter@wouterj.nl>
25+
*/
26+
final class RememberMeTokenProviderDoctrineSchemaSubscriber implements EventSubscriber
27+
{
28+
private $rememberMeHandlers;
29+
30+
/**
31+
* @param iterable|RememberMeHandlerInterface[] $doctrineTokenProviders
32+
*/
33+
public function __construct(iterable $rememberMeHandlers)
34+
{
35+
$this->rememberMeHandlers = $rememberMeHandlers;
36+
}
37+
38+
public function postGenerateSchema(GenerateSchemaEventArgs $event): void
39+
{
40+
$dbalConnection = $event->getEntityManager()->getConnection();
41+
42+
foreach ($this->rememberMeHandlers as $rememberMeHandler) {
43+
if (
44+
!$rememberMeHandler instanceof PersistentRememberMeHandler
45+
|| !$rememberMeHandler->getTokenProvider() instanceof DoctrineTokenProvider
46+
) {
47+
continue;
48+
}
49+
50+
$rememberMeHandler->getTokenProvider()->configureSchema($event->getSchema(), $dbalConnection);
51+
}
52+
}
53+
54+
public function getSubscribedEvents(): array
55+
{
56+
if (!class_exists(ToolEvents::class)) {
57+
return [];
58+
}
59+
60+
return [
61+
ToolEvents::postGenerateSchema,
62+
];
63+
}
64+
}

‎src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php
+48-21Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Doctrine\DBAL\Connection;
1515
use Doctrine\DBAL\Driver\Result as DriverResult;
1616
use Doctrine\DBAL\Result;
17+
use Doctrine\DBAL\Schema\Schema;
1718
use Doctrine\DBAL\Types\Types;
1819
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
1920
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentTokenInterface;
@@ -40,11 +41,13 @@
4041
*/
4142
class DoctrineTokenProvider implements TokenProviderInterface
4243
{
43-
private $conn;
44+
private const TABLE = 'rememberme_token';
4445

45-
public function __construct(Connection $conn)
46+
private $connection;
47+
48+
public function __construct(Connection $connection)
4649
{
47-
$this->conn = $conn;
50+
$this->connection = $connection;
4851
}
4952

5053
/**
@@ -53,11 +56,10 @@ public function __construct(Connection $conn)
5356
public function loadTokenBySeries(string $series)
5457
{
5558
// the alias for lastUsed works around case insensitivity in PostgreSQL
56-
$sql = 'SELECT class, username, value, lastUsed AS last_used'
57-
.' FROM rememberme_token WHERE series=:series';
59+
$sql = 'SELECT class, username, value, lastUsed AS last_used FROM '.self::TABLE.' WHERE series=:series';
5860
$paramValues = ['series' => $series];
5961
$paramTypes = ['series' => \PDO::PARAM_STR];
60-
$stmt = $this->conn->executeQuery($sql, $paramValues, $paramTypes);
62+
$stmt = $this->connection->executeQuery($sql, $paramValues, $paramTypes);
6163
$row = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAssociative() : $stmt->fetch(\PDO::FETCH_ASSOC);
6264

6365
if ($row) {
@@ -72,13 +74,13 @@ public function loadTokenBySeries(string $series)
7274
*/
7375
public function deleteTokenBySeries(string $series)
7476
{
75-
$sql = 'DELETE FROM rememberme_token WHERE series=:series';
77+
$sql = 'DELETE FROM '.self::TABLE.' WHERE series=:series';
7678
$paramValues = ['series' => $series];
7779
$paramTypes = ['series' => \PDO::PARAM_STR];
78-
if (method_exists($this->conn, 'executeStatement')) {
79-
$this->conn->executeStatement($sql, $paramValues, $paramTypes);
80+
if (method_exists($this->connection, 'executeStatement')) {
81+
$this->connection->executeStatement($sql, $paramValues, $paramTypes);
8082
} else {
81-
$this->conn->executeUpdate($sql, $paramValues, $paramTypes);
83+
$this->connection->executeUpdate($sql, $paramValues, $paramTypes);
8284
}
8385
}
8486

@@ -87,8 +89,7 @@ public function deleteTokenBySeries(string $series)
8789
*/
8890
public function updateToken(string $series, string $tokenValue, \DateTime $lastUsed)
8991
{
90-
$sql = 'UPDATE rememberme_token SET value=:value, lastUsed=:lastUsed'
91-
.' WHERE series=:series';
92+
$sql = 'UPDATE '.self::TABLE.' SET value=:value, lastUsed=:lastUsed WHERE series=:series';
9293
$paramValues = [
9394
'value' => $tokenValue,
9495
'lastUsed' => $lastUsed,
@@ -99,10 +100,10 @@ public function updateToken(string $series, string $tokenValue, \DateTime $lastU
99100
'lastUsed' => Types::DATETIME_MUTABLE,
100101
'series' => \PDO::PARAM_STR,
101102
];
102-
if (method_exists($this->conn, 'executeStatement')) {
103-
$updated = $this->conn->executeStatement($sql, $paramValues, $paramTypes);
103+
if (method_exists($this->connection, 'executeStatement')) {
104+
$updated = $this->connection->executeStatement($sql, $paramValues, $paramTypes);
104105
} else {
105-
$updated = $this->conn->executeUpdate($sql, $paramValues, $paramTypes);
106+
$updated = $this->connection->executeUpdate($sql, $paramValues, $paramTypes);
106107
}
107108
if ($updated < 1) {
108109
throw new TokenNotFoundException('No token found.');
@@ -114,9 +115,7 @@ public function updateToken(string $series, string $tokenValue, \DateTime $lastU
114115
*/
115116
public function createNewToken(PersistentTokenInterface $token)
116117
{
117-
$sql = 'INSERT INTO rememberme_token'
118-
.' (class, username, series, value, lastUsed)'
119-
.' VALUES (:class, :username, :series, :value, :lastUsed)';
118+
$sql = 'INSERT INTO '.self::TABLE.' (class, username, series, value, lastUsed) VALUES (:class, :username, :series, :value, :lastUsed)';
120119
$paramValues = [
121120
'class' => $token->getClass(),
122121
'username' => $token->getUsername(),
@@ -131,10 +130,38 @@ public function createNewToken(PersistentTokenInterface $token)
131130
'value' => \PDO::PARAM_STR,
132131
'lastUsed' => Types::DATETIME_MUTABLE,
133132
];
134-
if (method_exists($this->conn, 'executeStatement')) {
135-
$this->conn->executeStatement($sql, $paramValues, $paramTypes);
133+
if (method_exists($this->connection, 'executeStatement')) {
134+
$this->connection->executeStatement($sql, $paramValues, $paramTypes);
136135
} else {
137-
$this->conn->executeUpdate($sql, $paramValues, $paramTypes);
136+
$this->connection->executeUpdate($sql, $paramValues, $paramTypes);
137+
}
138+
}
139+
140+
/**
141+
* Adds the Table to the Schema if remember me uses this Connection.
142+
*/
143+
public function configureSchema(Schema $schema, Connection $forConnection): void
144+
{
145+
// only update the schema for this connection
146+
if ($forConnection !== $this->connection) {
147+
return;
138148
}
149+
150+
if ($schema->hasTable(self::TABLE)) {
151+
return;
152+
}
153+
154+
$this->addTableToSchema($schema);
155+
}
156+
157+
private function addTableToSchema(Schema $schema): void
158+
{
159+
$table = $schema->createTable(self::TABLE);
160+
$table->addColumn('series', Types::STRING, ['length' => 88]);
161+
$table->addColumn('value', Types::STRING, ['length' => 88]);
162+
$table->addColumn('lastUsed', Types::DATETIME_MUTABLE);
163+
$table->addColumn('class', Types::STRING, ['length' => 100]);
164+
$table->addColumn('username', Types::STRING, ['length' => 200]);
165+
$table->setPrimaryKey(['series']);
139166
}
140167
}

‎src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ public function clearRememberMeCookie(): void
9595
$this->tokenProvider->deleteTokenBySeries($series);
9696
}
9797

98+
/**
99+
* @internal
100+
*/
101+
public function getTokenProvider(): TokenProviderInterface
102+
{
103+
return $this->tokenProvider;
104+
}
105+
98106
private function generateHash(string $tokenValue): string
99107
{
100108
return hash_hmac('sha256', $tokenValue, $this->secret);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.