8000 Add a normalization step for the user-identifier in firewalls · symfony/symfony@4f87434 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4f87434

Browse files
committed
Add a normalization step for the user-identifier in firewalls
1 parent ae5843f commit 4f87434

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class UserBadge implements BadgeInterface
3434
private $userLoader;
3535
private UserInterface $user;
3636

37+
private ?\Closure $identifierNormalizer = null;
38+
3739
/**
3840
* Initializes the user badge.
3941
*
@@ -51,6 +53,7 @@ public function __construct(
5153
private string $userIdentifier,
5254
?callable $userLoader = null,
5355
private ?array $attributes = null,
56+
?\Closure $identifierNormalizer = null,
5457
) {
5558
if ('' === $userIdentifier) {
5659
trigger_deprecation('symfony/security-http', '7.2', 'Using an empty string as user identifier is deprecated and will throw an exception in Symfony 8.0.');
@@ -60,12 +63,20 @@ public function __construct(
6063
if (\strlen($userIdentifier) > self::MAX_USERNAME_LENGTH) {
6164
throw new BadCredentialsException('Username too long.');
6265
}
66+
if ($identifierNormalizer) {
67+
$this->identifierNormalizer = static fn () => $identifierNormalizer($userIdentifier);
68+
}
6369

6470
$this->userLoader = $userLoader;
6571
}
6672

6773
public function getUserIdentifier(): string
6874
{
75+
if (isset($this->identifierNormalizer)) {
76+
$this->userIdentifier = ($this->identifierNormalizer)();
77+
$this->identifierNormalizer = null;
78+
}
79+
6980
return $this->userIdentifier;
7081
}
7182

@@ -88,15 +99,15 @@ public function getUser(): UserInterface
8899
}
89100

90101
if (null === $this->getAttributes()) {
91-
$user = ($this->userLoader)($this->userIdentifier);
102+
$user = ($this->userLoader)($this->getUserIdentifier());
92103
} else {
93-
$user = ($this->userLoader)($this->userIdentifier, $this->getAttributes());
104+
$user = ($this->userLoader)($this->getUserIdentifier(), $this->getAttributes());
94105
}
95106

96107
// No user has been found via the $this->userLoader callback
97108
if (null === $user) {
98109
$exception = new UserNotFoundException();
99-
$exception->setUserIdentifier($this->userIdentifier);
110+
$exception->setUserIdentifier($this->getUserIdentifier());
100111

101112
throw $exception;
102113
}

src/Symfony/Component/Security/Http/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.3
5+
---
6+
7+
* Add argument `$identifierNormalizer` to `UserBadge::__construct()` to allow normalizing the identifier
8+
49
7.2
510
---
611

src/Symfony/Component/Security/Http/Tests/Authenticator/Passport/Badge/UserBadgeTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait;
1616
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
1717
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
18+
use Symfony\Component\String\Slugger\AsciiSlugger;
19+
use Symfony\Component\String\UnicodeString;
20+
21+
use function Symfony\Component\String\u;
1822

1923
class UserBadgeTest extends TestCase
2024
{
@@ -36,4 +40,29 @@ public function testEmptyUserIdentifier()
3640
// $this->expectException(BadCredentialsException::class)
3741
new UserBadge('', fn () => null);
3842
}
43+
44+
/**
45+
* @dataProvider provideUserIdentifierNormalizationData
46+
*/
47+
public function testUserIdentifierNormalization(string $identifier, string $expectedNormalizedIdentifier, callable $normalizer)
48+
{
49+
$badge = new UserBadge($identifier, fn () => null, identifierNormalizer: $normalizer);
50+
51+
static::assertSame($expectedNormalizedIdentifier, $badge->getUserIdentifier());
52+
}
53+
54+
public static function provideUserIdentifierNormalizationData(): iterable
55+
{
56+
$lowerAndNFKC = fn (string $identifier) => u($identifier)->normalize(UnicodeString::NFKC)->lower()->toString();
57+
$upperAndAscii = fn (string $identifier) => u($identifier)->ascii()->upper()->toString();
58+
$slugger = new AsciiSlugger('en');
59+
$asciiWithPrefix = fn (string $identifier) => u($slugger->slug($identifier))->ascii()->lower()->prepend('USERID--')->toString();
60+
61+
yield 'Simple lower conversion' => ['SmiTh', 'smith', $lowerAndNFKC];
62+
yield 'Normalize fi to fi. Other unicode characters are preserved (р, с, ѕ and а)' => ['рrinсeѕѕ.fionа', 'рrinсeѕѕ.fionа', $lowerAndNFKC];
63+
yield 'Greek characters' => ['ΝιΚόΛΑος', 'νικόλαος', $lowerAndNFKC];
64+
yield 'Greek to ASCII' => ['ΝιΚόΛΑος', 'NIKOLAOS', $upperAndAscii];
65+
yield 'Katakana to ASCII' => ['たなかそういち', 'TANAKASOUICHI', $upperAndAscii];
66+
yield 'Username with prefix' => ['John Doe 1', 'USERID--john-doe-1', $asciiWithPrefix];
67+
}
3968
}

0 commit comments

Comments
 (0)
0