Implemented LDAP authentication and LDAP user provider
This commit is contained in:
parent
1c964b993f
commit
60b9f2e7ec
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* FormLoginLdapFactory creates services for form login ldap authentication.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class FormLoginLdapFactory extends FormLoginFactory
|
||||
{
|
||||
protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
|
||||
{
|
||||
$provider = 'security.authentication.provider.ldap_bind.'.$id;
|
||||
$container
|
||||
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.ldap_bind'))
|
||||
->replaceArgument(0, new Reference($userProviderId))
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
;
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
parent::addConfiguration($node);
|
||||
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->scalarNode('dn_string')->defaultValue('{username}')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'form-login-ldap';
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* HttpBasicFactory creates services for HTTP basic authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class HttpBasicLdapFactory extends HttpBasicFactory
|
||||
{
|
||||
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
|
||||
{
|
||||
$provider = 'security.authentication.provider.ldap_bind.'.$id;
|
||||
$container
|
||||
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.ldap_bind'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
;
|
||||
|
||||
// entry point
|
||||
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint);
|
||||
|
||||
// listener
|
||||
$listenerId = 'security.authentication.listener.basic.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.basic'));
|
||||
$listener->replaceArgument(2, $id);
|
||||
$listener->replaceArgument(3, new Reference($entryPointId));
|
||||
|
||||
return array($provider, $listenerId, $entryPointId);
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
parent::addConfiguration($node);
|
||||
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->scalarNode('dn_string')->defaultValue('{username}')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'http-basic-ldap';
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* LdapFactory creates services for Ldap user provider.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class LdapFactory implements UserProviderFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, $id, $config)
|
||||
{
|
||||
$container
|
||||
->setDefinition($id, new DefinitionDecorator('security.user.provider.ldap'))
|
||||
->replaceArgument(0, new Reference($config['service']))
|
||||
->replaceArgument(1, $config['base_dn'])
|
||||
->replaceArgument(2, $config['search_dn'])
|
||||
->replaceArgument(3, $config['search_password'])
|
||||
->replaceArgument(4, $config['default_roles'])
|
||||
->replaceArgument(5, $config['uid_key'])
|
||||
->replaceArgument(6, $config['filter'])
|
||||
;
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'ldap';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('service')->isRequired()->cannotBeEmpty()->end()
|
||||
->scalarNode('base_dn')->isRequired()->cannotBeEmpty()->end()
|
||||
->scalarNode('search_dn')->end()
|
||||
->scalarNode('search_password')->end()
|
||||
->arrayNode('default_roles')
|
||||
->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
||||
->requiresAtLeastOneElement()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->scalarNode('uid_key')->defaultValue('sAMAccountName')->end()
|
||||
->scalarNode('filter')->defaultValue('({uid_key}={username})')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
@ -158,10 +158,21 @@
|
||||
<argument type="service" id="security.token_storage" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
|
||||
<!-- Provisioning -->
|
||||
<service id="security.user.provider.in_memory" class="%security.user.provider.in_memory.class%" abstract="true" public="false" />
|
||||
<service id="security.user.provider.in_memory.user" class="%security.user.provider.in_memory.user.class%" abstract="true" public="false" />
|
||||
|
||||
<service id="security.user.provider.ldap" class="Symfony\Component\Security\Core\User\LdapUserProvider" abstract="true" public="false">
|
||||
<argument /> <!-- security.ldap.ldap -->
|
||||
<argument /> <!-- base dn -->
|
||||
<argument /> <!-- search dn -->
|
||||
<argument /> <!-- search password -->
|
||||
<argument /> <!-- default_roles -->
|
||||
<argument /> <!-- uid key -->
|
||||
<argument /> <!-- filter -->
|
||||
</service>
|
||||
|
||||
<service id="security.user.provider.chain" class="%security.user.provider.chain.class%" abstract="true" public="false" />
|
||||
|
||||
<service id="security.http_utils" class="%security.http_utils.class%" public="false">
|
||||
@ -169,6 +180,7 @@
|
||||
<argument type="service" id="router" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
|
||||
<!-- Validator -->
|
||||
<service id="security.validator.user_password" class="%security.validator.user_password.class%">
|
||||
<tag name="validator.constraint_validator" alias="security.validator.user_password" />
|
||||
|
@ -223,6 +223,15 @@
|
||||
<argument>%security.authentication.hide_user_not_found%</argument>
|
||||
</service>
|
||||
|
||||
<service id="security.authentication.provider.ldap_bind" class="Symfony\Component\Security\Core\Authentication\Provider\LdapBindAuthenticationProvider" public="false" abstract="true">
|
||||
<argument /> <!-- User Provider -->
|
||||
<argument type="service" id="security.user_checker" />
|
||||
<argument /> <!-- Provider-shared Key -->
|
||||
<argument /> <!-- LDAP -->
|
||||
<argument /> <!-- Base DN -->
|
||||
<argument>%security.authentication.hide_user_not_found%</argument>
|
||||
</service>
|
||||
|
||||
<service id="security.authentication.provider.simple" class="%security.authentication.provider.simple.class%" abstract="true" public="false">
|
||||
<argument /> <!-- Simple Authenticator -->
|
||||
<argument /> <!-- User Provider -->
|
||||
|
@ -15,7 +15,9 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSecurityVotersPass;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\FormLoginFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\FormLoginLdapFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\HttpBasicFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\HttpBasicLdapFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\HttpDigestFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\X509Factory;
|
||||
@ -24,6 +26,7 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimplePre
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleFormFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\GuardAuthenticationFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\LdapFactory;
|
||||
|
||||
/**
|
||||
* Bundle.
|
||||
@ -38,7 +41,9 @@ class SecurityBundle extends Bundle
|
||||
|
||||
$extension = $container->getExtension('security');
|
||||
$extension->addSecurityListenerFactory(new FormLoginFactory());
|
||||
$extension->addSecurityListenerFactory(new FormLoginLdapFactory());
|
||||
$extension->addSecurityListenerFactory(new HttpBasicFactory());
|
||||
$extension->addSecurityListenerFactory(new HttpBasicLdapFactory());
|
||||
$extension->addSecurityListenerFactory(new HttpDigestFactory());
|
||||
$extension->addSecurityListenerFactory(new RememberMeFactory());
|
||||
$extension->addSecurityListenerFactory(new X509Factory());
|
||||
@ -48,6 +53,7 @@ class SecurityBundle extends Bundle
|
||||
$extension->addSecurityListenerFactory(new GuardAuthenticationFactory());
|
||||
|
||||
$extension->addUserProviderFactory(new InMemoryFactory());
|
||||
$extension->addUserProviderFactory(new LdapFactory());
|
||||
$container->addCompilerPass(new AddSecurityVotersPass());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Security\Core\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Ldap\LdapClientInterface;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionException;
|
||||
|
||||
/**
|
||||
* LdapBindAuthenticationProvider authenticates a user against an LDAP server.
|
||||
*
|
||||
* The only way to check user credentials is to try to connect the user with its
|
||||
* credentials to the ldap.
|
||||
*
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class LdapBindAuthenticationProvider extends UserAuthenticationProvider
|
||||
{
|
||||
private $userProvider;
|
||||
private $ldap;
|
||||
private $dnString;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param UserProviderInterface $userProvider A UserProvider
|
||||
* @param UserCheckerInterface $userChecker A UserChecker
|
||||
* @param string $providerKey The provider key
|
||||
* @param LdapClientInterface $ldap An Ldap client
|
||||
* @param string $dnString A string used to create the bind DN
|
||||
* @param bool $hideUserNotFoundExceptions Whether to hide user not found exception or not
|
||||
*/
|
||||
public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, $providerKey, LdapClientInterface $ldap, $dnString = '{username}', $hideUserNotFoundExceptions = true)
|
||||
{
|
||||
parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions);
|
||||
|
||||
$this->userProvider = $userProvider;
|
||||
$this->ldap = $ldap;
|
||||
$this->dnString = $dnString;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function retrieveUser($username, UsernamePasswordToken $token)
|
||||
{
|
||||
if ('NONE_PROVIDED' === $username) {
|
||||
throw new UsernameNotFoundException('Username can not be null');
|
||||
}
|
||||
|
||||
return $this->userProvider->loadUserByUsername($username);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token)
|
||||
{
|
||||
$username = $token->getUsername();
|
||||
$password = $token->getCredentials();
|
||||
|
||||
try {
|
||||
$username = $this->ldap->escape($username, '', LdapClientInterface::LDAP_ESCAPE_DN);
|
||||
$dn = str_replace('{username}', $username, $this->dnString);
|
||||
|
||||
$this->ldap->bind($dn, $password);
|
||||
} catch (ConnectionException $e) {
|
||||
throw new BadCredentialsException('The presented password is invalid.');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Core\Tests\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\LdapBindAuthenticationProvider;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\User\User;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionException;
|
||||
|
||||
class LdapBindAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
|
||||
* @expectedExceptionMessage The presented password is invalid.
|
||||
*/
|
||||
public function testBindFailureShouldThrowAnException()
|
||||
{
|
||||
$userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
|
||||
$ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
|
||||
$ldap
|
||||
->expects($this->once())
|
||||
->method('bind')
|
||||
->will($this->throwException(new ConnectionException()))
|
||||
;
|
||||
$userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
|
||||
|
||||
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
|
||||
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
|
||||
$reflection->setAccessible(true);
|
||||
|
||||
$reflection->invoke($provider, new User('foo', null), new UsernamePasswordToken('foo', '', 'key'));
|
||||
}
|
||||
|
||||
public function testRetrieveUser()
|
||||
{
|
||||
$userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
|
||||
$userProvider
|
||||
->expects($this->once())
|
||||
->method('loadUserByUsername')
|
||||
->with('foo')
|
||||
;
|
||||
$ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
|
||||
|
||||
$userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
|
||||
|
||||
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
|
||||
$reflection = new \ReflectionMethod($provider, 'retrieveUser');
|
||||
$reflection->setAccessible(true);
|
||||
|
||||
$reflection->invoke($provider, 'foo', new UsernamePasswordToken('foo', 'bar', 'key'));
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Security\Core\Tests\User;
|
||||
|
||||
use Symfony\Component\Security\Core\User\LdapUserProvider;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionException;
|
||||
|
||||
class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\UsernameNotFoundException
|
||||
*/
|
||||
public function testLoadUserByUsernameFailsIfCantConnectToLdap()
|
||||
{
|
||||
$ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
|
||||
$ldap
|
||||
->expects($this->once())
|
||||
->method('bind')
|
||||
->will($this->throwException(new ConnectionException()))
|
||||
;
|
||||
|
||||
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
|
||||
$provider->loadUserByUsername('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\UsernameNotFoundException
|
||||
*/
|
||||
public function testLoadUserByUsernameFailsIfNoLdapEntries()
|
||||
{
|
||||
$ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
|
||||
$ldap
|
||||
->expects($this->once())
|
||||
->method('escape')
|
||||
->will($this->returnValue('foo'))
|
||||
;
|
||||
|
||||
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
|
||||
$provider->loadUserByUsername('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\UsernameNotFoundException
|
||||
*/
|
||||
public function testLoadUserByUsernameFailsIfMoreThanOneLdapEntry()
|
||||
{
|
||||
$ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
|
||||
$ldap
|
||||
->expects($this->once())
|
||||
->method('escape')
|
||||
->will($this->returnValue('foo'))
|
||||
;
|
||||
$ldap
|
||||
->expects($this->once())
|
||||
->method('find')
|
||||
->will($this->returnValue(array(
|
||||
array(),
|
||||
array(),
|
||||
'count' => 2,
|
||||
)))
|
||||
;
|
||||
|
||||
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
|
||||
$provider->loadUserByUsername('foo');
|
||||
}
|
||||
|
||||
public function testSuccessfulLoadUserByUsername()
|
||||
{
|
||||
$ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
|
||||
$ldap
|
||||
->expects($this->once())
|
||||
->method('escape')
|
||||
->will($this->returnValue('foo'))
|
||||
;
|
||||
$ldap
|
||||
->expects($this->once())
|
||||
->method('find')
|
||||
->will($this->returnValue(array(
|
||||
array(
|
||||
'sAMAccountName' => 'foo',
|
||||
'userpassword' => 'bar',
|
||||
),
|
||||
'count' => 1,
|
||||
)))
|
||||
;
|
||||
|
||||
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
|
||||
$this->assertInstanceOf(
|
||||
'Symfony\Component\Security\Core\User\User',
|
||||
$provider->loadUserByUsername('foo')
|
||||
);
|
||||
}
|
||||
}
|
109
src/Symfony/Component/Security/Core/User/LdapUserProvider.php
Normal file
109
src/Symfony/Component/Security/Core/User/LdapUserProvider.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Core\User;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Ldap\Exception\ConnectionException;
|
||||
use Symfony\Component\Ldap\LdapClientInterface;
|
||||
|
||||
/**
|
||||
* LdapUserProvider is a simple user provider on top of ldap.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class LdapUserProvider implements UserProviderInterface
|
||||
{
|
||||
private $ldap;
|
||||
private $baseDn;
|
||||
private $searchDn;
|
||||
private $searchPassword;
|
||||
private $defaultRoles;
|
||||
private $defaultSearch;
|
||||
|
||||
/**
|
||||
* @param LdapClientInterface $ldap
|
||||
* @param string $baseDn
|
||||
* @param string $searchDn
|
||||
* @param string $searchPassword
|
||||
* @param array $defaultRoles
|
||||
* @param string $uidKey
|
||||
* @param string $filter
|
||||
*/
|
||||
public function __construct(LdapClientInterface $ldap, $baseDn, $searchDn = null, $searchPassword = null, array $defaultRoles = array(), $uidKey = 'sAMAccountName', $filter = '({uid_key}={username})')
|
||||
{
|
||||
$this->ldap = $ldap;
|
||||
$this->baseDn = $baseDn;
|
||||
$this->searchDn = $searchDn;
|
||||
$this->searchPassword = $searchPassword;
|
||||
$this->defaultRoles = $defaultRoles;
|
||||
$this->defaultSearch = str_replace('{uid_key}', $uidKey, $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadUserByUsername($username)
|
||||
{
|
||||
try {
|
||||
$this->ldap->bind($this->searchDn, $this->searchPassword);
|
||||
$username = $this->ldap->escape($username, '', LdapClientInterface::LDAP_ESCAPE_FILTER);
|
||||
$query = str_replace('{username}', $username, $this->defaultSearch);
|
||||
$search = $this->ldap->find($this->baseDn, $query);
|
||||
} catch (ConnectionException $e) {
|
||||
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
|
||||
}
|
||||
|
||||
if (!$search) {
|
||||
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
|
||||
}
|
||||
|
||||
if ($search['count'] > 1) {
|
||||
throw new UsernameNotFoundException('More than one user found');
|
||||
}
|
||||
|
||||
$user = $search[0];
|
||||
|
||||
return $this->loadUser($username, $user);
|
||||
}
|
||||
|
||||
public function loadUser($username, $user)
|
||||
{
|
||||
$password = isset($user['userpassword']) ? $user['userpassword'] : null;
|
||||
|
||||
$roles = $this->defaultRoles;
|
||||
|
||||
return new User($username, $password, $roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function refreshUser(UserInterface $user)
|
||||
{
|
||||
if (!$user instanceof User) {
|
||||
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
|
||||
}
|
||||
|
||||
return new User($user->getUsername(), null, $user->getRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsClass($class)
|
||||
{
|
||||
return $class === 'Symfony\Component\Security\Core\User\User';
|
||||
}
|
||||
|
||||
}
|
@ -26,13 +26,15 @@
|
||||
"symfony/translation": "~2.0,>=2.0.5|~3.0.0",
|
||||
"symfony/validator": "~2.5,>=2.5.5|~3.0.0",
|
||||
"psr/log": "~1.0",
|
||||
"ircmaxell/password-compat": "1.0.*"
|
||||
"ircmaxell/password-compat": "1.0.*",
|
||||
"symfony/ldap": "~2.8|~3.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/event-dispatcher": "",
|
||||
"symfony/http-foundation": "",
|
||||
"symfony/validator": "For using the user password constraint",
|
||||
"symfony/expression-language": "For using the expression voter",
|
||||
"symfony/ldap": "For using LDAP integration",
|
||||
"ircmaxell/password-compat": "For using the BCrypt password encoder in PHP <5.5"
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -38,7 +38,8 @@
|
||||
"doctrine/dbal": "~2.2",
|
||||
"psr/log": "~1.0",
|
||||
"ircmaxell/password-compat": "~1.0",
|
||||
"symfony/expression-language": "~2.6|~3.0.0"
|
||||
"symfony/expression-language": "~2.6|~3.0.0",
|
||||
"symfony/ldap": "~2.8|~3.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/class-loader": "For using the ACL generateSql script",
|
||||
@ -48,7 +49,8 @@
|
||||
"symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs",
|
||||
"symfony/expression-language": "For using the expression voter",
|
||||
"ircmaxell/password-compat": "For using the BCrypt password encoder in PHP <5.5",
|
||||
"paragonie/random_compat": ""
|
||||
"paragonie/random_compat": "",
|
||||
"symfony/ldap": "For using the LDAP user and authentication providers"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\Security\\": "" }
|
||||
|
Reference in New Issue
Block a user