make LdapBindAuthenticationProvider capable of searching for the DN

This commit is contained in:
Lukas Kahwe Smith 2017-01-25 12:53:34 +01:00
parent b9b6ebd643
commit a30191f30a
No known key found for this signature in database
GPG Key ID: D859E62434DF44F7
3 changed files with 103 additions and 2 deletions

View File

@ -27,7 +27,7 @@ class FormLoginLdapFactory extends FormLoginFactory
protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
{
$provider = 'security.authentication.provider.ldap_bind.'.$id;
$container
$definition = $container
->setDefinition($provider, new ChildDefinition('security.authentication.provider.ldap_bind'))
->replaceArgument(0, new Reference($userProviderId))
->replaceArgument(1, new Reference('security.user_checker.'.$id))
@ -36,6 +36,10 @@ class FormLoginLdapFactory extends FormLoginFactory
->replaceArgument(4, $config['dn_string'])
;
if (!empty($config['query_string'])) {
$definition->addMethodCall('setQueryString', array($config['query_string']));
}
return $provider;
}
@ -47,6 +51,7 @@ class FormLoginLdapFactory extends FormLoginFactory
->children()
->scalarNode('service')->defaultValue('ldap')->end()
->scalarNode('dn_string')->defaultValue('{username}')->end()
->scalarNode('query_string')->end()
->end()
;
}

View File

@ -33,6 +33,7 @@ class LdapBindAuthenticationProvider extends UserAuthenticationProvider
private $userProvider;
private $ldap;
private $dnString;
private $queryString;
/**
* Constructor.
@ -53,6 +54,16 @@ class LdapBindAuthenticationProvider extends UserAuthenticationProvider
$this->dnString = $dnString;
}
/**
* Set a query string to use in order to find a DN for the username.
*
* @param string $queryString
*/
public function setQueryString($queryString)
{
$this->queryString = $queryString;
}
/**
* {@inheritdoc}
*/
@ -79,7 +90,20 @@ class LdapBindAuthenticationProvider extends UserAuthenticationProvider
try {
$username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_DN);
$dn = str_replace('{username}', $username, $this->dnString);
if ($this->queryString) {
$query = str_replace('{username}', $username, $this->queryString);
$query = $this->ldap->query($this->dnString, $query);
$result = $query->execute();
if (1 !== $result->count()) {
throw new BadCredentialsException('The presented username is invalid.');
}
$dn = $result[0]->getDn();
} else {
$dn = str_replace('{username}', $username, $this->dnString);
}
$this->ldap->bind($dn, $password);
} catch (ConnectionException $e) {

View File

@ -12,6 +12,9 @@
namespace Symfony\Component\Security\Core\Tests\Authentication\Provider;
use Symfony\Component\Ldap\LdapInterface;
use Symfony\Component\Ldap\Entry;
use Symfony\Component\Ldap\Adapter\QueryInterface;
use Symfony\Component\Ldap\Adapter\CollectionInterface;
use Symfony\Component\Security\Core\Authentication\Provider\LdapBindAuthenticationProvider;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\User\User;
@ -81,4 +84,73 @@ class LdapBindAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
$reflection->invoke($provider, 'foo', new UsernamePasswordToken('foo', 'bar', 'key'));
}
public function testQueryForDn()
{
$userProvider = $this->getMockBuilder(UserProviderInterface::class)->getMock();
$collection = new \ArrayIterator(array(new Entry('')));
$query = $this->getMockBuilder(QueryInterface::class)->getMock();
$query
->expects($this->once())
->method('execute')
->will($this->returnValue($collection))
;
$ldap = $this->getMockBuilder(LdapInterface::class)->getMock();
$ldap
->expects($this->once())
->method('escape')
->with('foo', '')
->will($this->returnValue('foo'))
;
$ldap
->expects($this->once())
->method('query')
->with('{username}', 'foobar')
->will($this->returnValue($query))
;
$userChecker = $this->getMockBuilder(UserCheckerInterface::class)->getMock();
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
$provider->setQueryString('{username}bar');
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
$reflection->setAccessible(true);
$reflection->invoke($provider, new User('foo', null), new UsernamePasswordToken('foo', 'bar', 'key'));
}
/**
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
* @expectedExceptionMessage The presented username is invalid.
*/
public function testEmptyQueryResultShouldThrowAnException()
{
$userProvider = $this->getMockBuilder(UserProviderInterface::class)->getMock();
$collection = $this->getMockBuilder(CollectionInterface::class)->getMock();
$query = $this->getMockBuilder(QueryInterface::class)->getMock();
$query
->expects($this->once())
->method('execute')
->will($this->returnValue($collection))
;
$ldap = $this->getMockBuilder(LdapInterface::class)->getMock();
$ldap
->expects($this->once())
->method('query')
->will($this->returnValue($query))
;
$userChecker = $this->getMockBuilder(UserCheckerInterface::class)->getMock();
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
$provider->setQueryString('{username}bar');
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
$reflection->setAccessible(true);
$reflection->invoke($provider, new User('foo', null), new UsernamePasswordToken('foo', 'bar', 'key'));
}
}