Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c6c300c

Browse files
committed
feature #48200 [Security] Allow custom user identifier for X509 authenticator (Spomky)
This PR was squashed before being merged into the 6.3 branch. Discussion ---------- [Security] Allow custom user identifier for X509 authenticator | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #47354 | License | MIT | Doc PR | **to be created** This PR allows defining a custom user identifier instead of the hardcoded `emailAddress`. It also adds a new option for the firewall configuration: ```yaml # config/packages/security.yaml security: # ... firewalls: main: # ... x509: provider: your_user_provider user_identifier: CN # default to emailAddress ``` **💬 Discussion**: user identifier regex changed Note that the regex is changed. The previous one was able to find an email address as expected, but now that the common name may not contain a `@` (or may contain more than one), it is required to update this part. It does not impact the previously merged PR #33759, but I prefer highlight the fact that it can now catch invalid email addresses set in `emailAddress`. Commits ------- 6479653 [Security] Allow custom user identifier for X509 authenticator
2 parents fee5714 + 6479653 commit c6c300c

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
3636
->replaceArgument(2, $firewallName)
3737
->replaceArgument(3, $config['user'])
3838
->replaceArgument(4, $config['credentials'])
39+
->replaceArgument(6, $config['user_identifier'])
3940
;
4041

4142
return $authenticatorId;
@@ -58,6 +59,7 @@ public function addConfiguration(NodeDefinition $node)
5859
->scalarNode('provider')->end()
5960
->scalarNode('user')->defaultValue('SSL_CLIENT_S_DN_Email')->end()
6061
->scalarNode('credentials')->defaultValue('SSL_CLIENT_S_DN')->end()
62+
->scalarNode('user_identifier')->defaultValue('emailAddress')->end()
6163
->end()
6264
;
6365
}

src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@
149149
abstract_arg('user key'),
150150
abstract_arg('credentials key'),
151151
service('logger')->nullOnInvalid(),
152+
abstract_arg('credentials user identifier'),
152153
])
153154
->tag('monolog.logger', ['channel' => 'security'])
154155

src/Symfony/Component/Security/Http/Authenticator/X509Authenticator.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ class X509Authenticator extends AbstractPreAuthenticatedAuthenticator
3030
{
3131
private string $userKey;
3232
private string $credentialsKey;
33+
private string $credentialUserIdentifier;
3334

34-
public function __construct(UserProviderInterface $userProvider, TokenStorageInterface $tokenStorage, string $firewallName, string $userKey = 'SSL_CLIENT_S_DN_Email', string $credentialsKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null)
35+
public function __construct(UserProviderInterface $userProvider, TokenStorageInterface $tokenStorage, string $firewallName, string $userKey = 'SSL_CLIENT_S_DN_Email', string $credentialsKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null, string $credentialUserIdentifier = 'emailAddress')
3536
{
3637
parent::__construct($userProvider, $tokenStorage, $firewallName, $logger);
3738

3839
$this->userKey = $userKey;
3940
$this->credentialsKey = $credentialsKey;
41+
$this->credentialUserIdentifier = $credentialUserIdentifier;
4042
}
4143

4244
protected function extractUsername(Request $request): string
@@ -46,13 +48,13 @@ protected function extractUsername(Request $request): string
4648
$username = $request->server->get($this->userKey);
4749
} elseif (
4850
$request->server->has($this->credentialsKey)
49-
&& preg_match('#emailAddress=([^,/@]++@[^,/]++)#', $request->server->get($this->credentialsKey), $matches)
51+
&& preg_match('#'.preg_quote($this->credentialUserIdentifier, '#').'=([^,/]++)#', $request->server->get($this->credentialsKey), $matches)
5052
) {
51-
$username = $matches[1];
53+
$username = trim($matches[1]);
5254
}
5355

5456
if (null === $username) {
55-
throw new BadCredentialsException(sprintf('SSL credentials not found: %s, %s', $this->userKey, $this->credentialsKey));
57+
throw new BadCredentialsException(sprintf('SSL credentials not found: "%s", "%s".', $this->userKey, $this->credentialsKey));
5658
}
5759

5860
return $username;

src/Symfony/Component/Security/Http/Tests/Authenticator/X509AuthenticatorTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,35 @@ public function testAuthenticationCustomCredentialsKey()
120120
$this->assertEquals('[email protected]', $passport->getUser()->getUserIdentifier());
121121
}
122122

123+
/**
124+
* @dataProvider provideServerVarsUserIdentifier
125+
*/
126+
public function testAuthenticationCustomCredentialsUserIdentifier($username, $credentials)
127+
{
128+
$authenticator = new X509Authenticator($this->userProvider, new TokenStorage(), 'main', 'SSL_CLIENT_S_DN_Email', 'SSL_CLIENT_S_DN', null, 'CN');
129+
130+
$request = $this->createRequest([
131+
'SSL_CLIENT_S_DN' => $credentials,
132+
]);
133+
$this->assertTrue($authenticator->supports($request));
134+
135+
$this->userProvider->createUser(new InMemoryUser($username, null));
136+
137+
$passport = $authenticator->authenticate($request);
138+
$this->assertEquals($username, $passport->getUser()->getUserIdentifier());
139+
}
140+
141+
public static function provideServerVarsUserIdentifier()
142+
{
143+
yield ['Sample certificate DN', 'CN=Sample certificate DN/[email protected]'];
144+
yield ['Sample certificate DN', 'CN=Sample certificate DN/[email protected]'];
145+
yield ['Sample certificate DN', 'CN=Sample certificate DN,[email protected]'];
146+
yield ['Sample certificate DN', 'CN=Sample certificate DN,[email protected]'];
147+
yield ['Sample certificate DN', '[email protected],CN=Sample certificate DN'];
148+
yield ['Firstname.Lastname', '[email protected],CN=Firstname.Lastname,OU=london,OU=company design and engineering,OU=Issuer London,OU=Roaming,OU=Interactive,OU=Users,OU=Standard,OU=Business,DC=england,DC=core,DC=company,DC=co,DC=uk'];
149+
yield ['user1', 'C=FR, O=My Organization, CN=user1, [email protected]'];
150+
}
151+
123152
private function createRequest(array $server)
124153
{
125154
return new Request([], [], [], [], [], $server);

0 commit comments

Comments
 (0)