Skip to content

Commit 3c9ff1f

Browse files
committed
feature #31560 [Ldap][Security] LdapBindAuthenticationProvider does not bind before search query (Simperfit)
This PR was merged into the 4.4 branch. Discussion ---------- [Ldap][Security] LdapBindAuthenticationProvider does not bind before search query | Q | A | ------------- | --- | Branch? | master | Bug fix? | yesish | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | yes <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #24210 <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> <!-- Replace this notice by a short README for your feature/bugfix. This will help people understand your PR and can be used as a start for the documentation. Additionally (see https://symfony.com/roadmap): - Bug fixes must be submitted against the lowest maintained branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the master branch. --> This is tagged as a bug but since we need to add new params to the differents login providers and a deprecation I think we need to consider it as a new feature, maybe this could go in 3.4 too but without the deprecation. This allow using a searchDn and a sarchPassword when passing a queryString in order to do the query authenticated. Commits ------- cb2d97f [Ldap][Security] LdapBindAuthenticationProvider does not bind before search query
2 parents 950db8e + cb2d97f commit 3c9ff1f

File tree

7 files changed

+88
-3
lines changed

7 files changed

+88
-3
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

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

4+
4.4.0
5+
6+
* Deprecated the usage of "query_string" without a "search_dn" and a "search_password" config key in Ldap factories.
7+
48
4.3.0
59
-----
610

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,14 @@ protected function createAuthProvider(ContainerBuilder $container, $id, $config,
3434
->replaceArgument(2, $id)
3535
->replaceArgument(3, new Reference($config['service']))
3636
->replaceArgument(4, $config['dn_string'])
37+
->replaceArgument(5, $config['search_dn'])
38+
->replaceArgument(6, $config['search_password'])
3739
;
3840

3941
if (!empty($config['query_string'])) {
42+
if ('' === $config['search_dn'] || '' === $config['search_password']) {
43+
@trigger_error('Using the "query_string" config without using a "search_dn" and a "search_password" is deprecated since Symfony 4.4 and will throw in Symfony 5.0.', E_USER_DEPRECATED);
44+
}
4045
$definition->addMethodCall('setQueryString', [$config['query_string']]);
4146
}
4247

@@ -52,6 +57,8 @@ public function addConfiguration(NodeDefinition $node)
5257
->scalarNode('service')->defaultValue('ldap')->end()
5358
->scalarNode('dn_string')->defaultValue('{username}')->end()
5459
->scalarNode('query_string')->end()
60+
->scalarNode('search_dn')->defaultValue('')->end()
61+
->scalarNode('search_password')->defaultValue('')->end()
5562
->end()
5663
;
5764
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider,
3535
->replaceArgument(2, $id)
3636
->replaceArgument(3, new Reference($config['service']))
3737
->replaceArgument(4, $config['dn_string'])
38+
->replaceArgument(5, $config['search_dn'])
39+
->replaceArgument(6, $config['search_password'])
3840
;
3941

4042
// entry point
4143
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint);
4244

4345
if (!empty($config['query_string'])) {
46+
if ('' === $config['search_dn'] || '' === $config['search_password']) {
47+
@trigger_error('Using the "query_string" config without using a "search_dn" and a "search_password" is deprecated since Symfony 4.4 and will throw in Symfony 5.0.', E_USER_DEPRECATED);
48+
}
4449
$definition->addMethodCall('setQueryString', [$config['query_string']]);
4550
}
4651

@@ -62,6 +67,8 @@ public function addConfiguration(NodeDefinition $node)
6267
->scalarNode('service')->defaultValue('ldap')->end()
6368
->scalarNode('dn_string')->defaultValue('{username}')->end()
6469
->scalarNode('query_string')->end()
70+
->scalarNode('search_dn')->defaultValue('')->end()
71+
->scalarNode('search_password')->defaultValue('')->end()
6572
->end()
6673
;
6774
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ protected function createAuthProvider(ContainerBuilder $container, $id, $config,
3636
->replaceArgument(2, $id)
3737
->replaceArgument(3, new Reference($config['service']))
3838
->replaceArgument(4, $config['dn_string'])
39+
->replaceArgument(5, $config['search_dn'])
40+
->replaceArgument(6, $config['search_password'])
3941
;
4042

4143
if (!empty($config['query_string'])) {
44+
if ('' === $config['search_dn'] || '' === $config['search_password']) {
45+
@trigger_error('Using the "query_string" config without using a "search_dn" and a "search_password" is deprecated since Symfony 4.4 and will throw in Symfony 5.0.', E_USER_DEPRECATED);
46+
}
4247
$definition->addMethodCall('setQueryString', [$config['query_string']]);
4348
}
4449

@@ -54,6 +59,8 @@ public function addConfiguration(NodeDefinition $node)
5459
->scalarNode('service')->defaultValue('ldap')->end()
5560
->scalarNode('dn_string')->defaultValue('{username}')->end()
5661
->scalarNode('query_string')->end()
62+
->scalarNode('search_dn')->defaultValue('')->end()
63+
->scalarNode('search_password')->defaultValue('')->end()
5764
->end()
5865
;
5966
}

src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@
195195
<argument /> <!-- UserChecker -->
196196
<argument /> <!-- Provider-shared Key -->
197197
<argument /> <!-- LDAP -->
198+
<argument /> <!-- search dn -->
199+
<argument /> <!-- search password -->
198200
<argument /> <!-- Base DN -->
199201
<argument>%security.authentication.hide_user_not_found%</argument>
200202
</service>

src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,18 @@ class LdapBindAuthenticationProvider extends UserAuthenticationProvider
3434
private $ldap;
3535
private $dnString;
3636
private $queryString;
37+
private $searchDn;
38+
private $searchPassword;
3739

38-
public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, string $providerKey, LdapInterface $ldap, string $dnString = '{username}', bool $hideUserNotFoundExceptions = true)
40+
public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, string $providerKey, LdapInterface $ldap, string $dnString = '{username}', bool $hideUserNotFoundExceptions = true, string $searchDn = '', string $searchPassword = '')
3941
{
4042
parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions);
4143

4244
$this->userProvider = $userProvider;
4345
$this->ldap = $ldap;
4446
$this->dnString = $dnString;
47+
$this->searchDn = $searchDn;
48+
$this->searchPassword = $searchPassword;
4549
}
4650

4751
/**
@@ -82,6 +86,11 @@ protected function checkAuthentication(UserInterface $user, UsernamePasswordToke
8286
$username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_DN);
8387

8488
if ($this->queryString) {
89+
if ('' !== $this->searchDn && '' !== $this->searchPassword) {
90+
$this->ldap->bind($this->searchDn, $this->searchPassword);
91+
} else {
92+
@trigger_error('Using the "query_string" config without using a "search_dn" and a "search_password" is deprecated since Symfony 4.4 and will throw in Symfony 5.0.', E_USER_DEPRECATED);
93+
}
8594
$query = str_replace('{username}', $username, $this->queryString);
8695
$result = $this->ldap->query($this->dnString, $query)->execute();
8796
if (1 !== $result->count()) {

src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ public function testQueryForDn()
123123
->with('foo', '')
124124
->willReturn('foo')
125125
;
126+
$ldap
127+
->expects($this->at(1))
128+
->method('bind')
129+
->with('elsa', 'test1234A$');
126130
$ldap
127131
->expects($this->once())
128132
->method('query')
@@ -131,7 +135,48 @@ public function testQueryForDn()
131135
;
132136
$userChecker = $this->getMockBuilder(UserCheckerInterface::class)->getMock();
133137

134-
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
138+
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap, '{username}', true, 'elsa', 'test1234A$');
139+
$provider->setQueryString('{username}bar');
140+
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
141+
$reflection->setAccessible(true);
142+
143+
$reflection->invoke($provider, new User('foo', null), new UsernamePasswordToken('foo', 'bar', 'key'));
144+
}
145+
146+
public function testQueryWithUserForDn()
147+
{
148+
$userProvider = $this->getMockBuilder(UserProviderInterface::class)->getMock();
149+
150+
$collection = new \ArrayIterator([new Entry('')]);
151+
152+
$query = $this->getMockBuilder(QueryInterface::class)->getMock();
153+
$query
154+
->expects($this->once())
155+
->method('execute')
156+
->will($this->returnValue($collection))
157+
;
158+
159+
$ldap = $this->getMockBuilder(LdapInterface::class)->getMock();
160+
$ldap
161+
->expects($this->once())
162+
->method('escape')
163+
->with('foo', '')
164+
->will($this->returnValue('foo'))
165+
;
166+
$ldap
167+
->expects($this->at(1))
168+
->method('bind')
169+
->with('elsa', 'test1234A$');
170+
$ldap
171+
->expects($this->once())
172+
->method('query')
173+
->with('{username}', 'foobar')
174+
->will($this->returnValue($query))
175+
;
176+
177+
$userChecker = $this->getMockBuilder(UserCheckerInterface::class)->getMock();
178+
179+
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap, '{username}', true, 'elsa', 'test1234A$');
135180
$provider->setQueryString('{username}bar');
136181
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
137182
$reflection->setAccessible(true);
@@ -157,14 +202,18 @@ public function testEmptyQueryResultShouldThrowAnException()
157202
;
158203

159204
$ldap = $this->getMockBuilder(LdapInterface::class)->getMock();
205+
$ldap
206+
->expects($this->at(1))
207+
->method('bind')
208+
->with('elsa', 'test1234A$');
160209
$ldap
161210
->expects($this->once())
162211
->method('query')
163212
->willReturn($query)
164213
;
165214
$userChecker = $this->getMockBuilder(UserCheckerInterface::class)->getMock();
166215

167-
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
216+
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap, '{username}', true, 'elsa', 'test1234A$');
168217
$provider->setQueryString('{username}bar');
169218
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
170219
$reflection->setAccessible(true);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy