summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles Sarrazin <charles@sarraz.in>2016-01-28 14:54:41 +0100
committerCharles Sarrazin <charles@sarraz.in>2016-02-11 18:54:23 +0100
commita07df7b1ba2f304191e4b2232072f34475bd5bcc (patch)
tree5c14602213e50803d6ae1b50b83d2e8cccebc0fa
parentb5c4b14ce46387314b6bd17f13ac151b446c6847 (diff)
downloadsymfony-security-a07df7b1ba2f304191e4b2232072f34475bd5bcc.zip
symfony-security-a07df7b1ba2f304191e4b2232072f34475bd5bcc.tar.gz
symfony-security-a07df7b1ba2f304191e4b2232072f34475bd5bcc.tar.bz2
Improved the Ldap Component
* Moved connection logic to dedicated class * Added support for Ldap result entries iterator and renamed LdapClient to Ldap * Added support for multiple adapters * Attempt anonymous bind if the connection is not bound beforehand * Finalized API * Updated the Security component to use v3.1 of the Ldap component * Updated unit tests * Added support for functional tests * Updated README file
-rw-r--r--Core/Authentication/Provider/LdapBindAuthenticationProvider.php8
-rw-r--r--Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php15
-rw-r--r--Core/Tests/User/LdapUserProviderTest.php81
-rw-r--r--Core/User/LdapUserProvider.php48
-rw-r--r--Core/composer.json2
-rw-r--r--composer.json2
6 files changed, 101 insertions, 55 deletions
diff --git a/Core/Authentication/Provider/LdapBindAuthenticationProvider.php b/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
index 7283ab9..950b603 100644
--- a/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
+++ b/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
@@ -17,7 +17,7 @@ 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\LdapInterface;
use Symfony\Component\Ldap\Exception\ConnectionException;
/**
@@ -40,11 +40,11 @@ class LdapBindAuthenticationProvider extends UserAuthenticationProvider
* @param UserProviderInterface $userProvider A UserProvider
* @param UserCheckerInterface $userChecker A UserChecker
* @param string $providerKey The provider key
- * @param LdapClientInterface $ldap An Ldap client
+ * @param LdapInterface $ldap A 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)
+ public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, $providerKey, LdapInterface $ldap, $dnString = '{username}', $hideUserNotFoundExceptions = true)
{
parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions);
@@ -74,7 +74,7 @@ class LdapBindAuthenticationProvider extends UserAuthenticationProvider
$password = $token->getCredentials();
try {
- $username = $this->ldap->escape($username, '', LDAP_ESCAPE_DN);
+ $username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_DN);
$dn = str_replace('{username}', $username, $this->dnString);
$this->ldap->bind($dn, $password);
diff --git a/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php b/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php
index 844bcef..4d2eead 100644
--- a/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php
+++ b/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php
@@ -11,10 +11,13 @@
namespace Symfony\Component\Security\Core\Tests\Authentication\Provider;
+use Symfony\Component\Ldap\LdapInterface;
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;
+use Symfony\Component\Security\Core\User\UserCheckerInterface;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* @requires extension ldap
@@ -27,14 +30,14 @@ class LdapBindAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
*/
public function testBindFailureShouldThrowAnException()
{
- $userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
- $ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
+ $userProvider = $this->getMock(UserProviderInterface::class);
+ $ldap = $this->getMock(LdapInterface::class);
$ldap
->expects($this->once())
->method('bind')
->will($this->throwException(new ConnectionException()))
;
- $userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
+ $userChecker = $this->getMock(UserCheckerInterface::class);
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
@@ -45,15 +48,15 @@ class LdapBindAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
public function testRetrieveUser()
{
- $userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
+ $userProvider = $this->getMock(UserProviderInterface::class);
$userProvider
->expects($this->once())
->method('loadUserByUsername')
->with('foo')
;
- $ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
+ $ldap = $this->getMock(LdapInterface::class);
- $userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
+ $userChecker = $this->getMock(UserCheckerInterface::class);
$provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
$reflection = new \ReflectionMethod($provider, 'retrieveUser');
diff --git a/Core/Tests/User/LdapUserProviderTest.php b/Core/Tests/User/LdapUserProviderTest.php
index 9b126e9..6876eec 100644
--- a/Core/Tests/User/LdapUserProviderTest.php
+++ b/Core/Tests/User/LdapUserProviderTest.php
@@ -11,6 +11,10 @@
namespace Symfony\Component\Security\Core\Tests\User;
+use Symfony\Component\Ldap\Adapter\CollectionInterface;
+use Symfony\Component\Ldap\Adapter\QueryInterface;
+use Symfony\Component\Ldap\Entry;
+use Symfony\Component\Ldap\LdapInterface;
use Symfony\Component\Security\Core\User\LdapUserProvider;
use Symfony\Component\Ldap\Exception\ConnectionException;
@@ -24,7 +28,7 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
*/
public function testLoadUserByUsernameFailsIfCantConnectToLdap()
{
- $ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
+ $ldap = $this->getMock(LdapInterface::class);
$ldap
->expects($this->once())
->method('bind')
@@ -40,12 +44,29 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
*/
public function testLoadUserByUsernameFailsIfNoLdapEntries()
{
- $ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
+ $result = $this->getMock(CollectionInterface::class);
+ $query = $this->getMock(QueryInterface::class);
+ $query
+ ->expects($this->once())
+ ->method('execute')
+ ->will($this->returnValue($result))
+ ;
+ $result
+ ->expects($this->once())
+ ->method('count')
+ ->will($this->returnValue(0))
+ ;
+ $ldap = $this->getMock(LdapInterface::class);
$ldap
->expects($this->once())
->method('escape')
->will($this->returnValue('foo'))
;
+ $ldap
+ ->expects($this->once())
+ ->method('query')
+ ->will($this->returnValue($query))
+ ;
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
$provider->loadUserByUsername('foo');
@@ -56,7 +77,19 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
*/
public function testLoadUserByUsernameFailsIfMoreThanOneLdapEntry()
{
- $ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
+ $result = $this->getMock(CollectionInterface::class);
+ $query = $this->getMock(QueryInterface::class);
+ $query
+ ->expects($this->once())
+ ->method('execute')
+ ->will($this->returnValue($result))
+ ;
+ $result
+ ->expects($this->once())
+ ->method('count')
+ ->will($this->returnValue(2))
+ ;
+ $ldap = $this->getMock(LdapInterface::class);
$ldap
->expects($this->once())
->method('escape')
@@ -64,12 +97,8 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
;
$ldap
->expects($this->once())
- ->method('find')
- ->will($this->returnValue(array(
- array(),
- array(),
- 'count' => 2,
- )))
+ ->method('query')
+ ->will($this->returnValue($query))
;
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
@@ -78,7 +107,29 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
public function testSuccessfulLoadUserByUsername()
{
- $ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
+ $result = $this->getMock(CollectionInterface::class);
+ $query = $this->getMock(QueryInterface::class);
+ $query
+ ->expects($this->once())
+ ->method('execute')
+ ->will($this->returnValue($result))
+ ;
+ $ldap = $this->getMock(LdapInterface::class);
+ $result
+ ->expects($this->once())
+ ->method('offsetGet')
+ ->with(0)
+ ->will($this->returnValue(new Entry('foo', array(
+ 'sAMAccountName' => 'foo',
+ 'userpassword' => 'bar',
+ )
+ )))
+ ;
+ $result
+ ->expects($this->once())
+ ->method('count')
+ ->will($this->returnValue(1))
+ ;
$ldap
->expects($this->once())
->method('escape')
@@ -86,14 +137,8 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
;
$ldap
->expects($this->once())
- ->method('find')
- ->will($this->returnValue(array(
- array(
- 'sAMAccountName' => 'foo',
- 'userpassword' => 'bar',
- ),
- 'count' => 1,
- )))
+ ->method('query')
+ ->will($this->returnValue($query))
;
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
diff --git a/Core/User/LdapUserProvider.php b/Core/User/LdapUserProvider.php
index 1593564..a37981c 100644
--- a/Core/User/LdapUserProvider.php
+++ b/Core/User/LdapUserProvider.php
@@ -11,10 +11,11 @@
namespace Symfony\Component\Security\Core\User;
+use Symfony\Component\Ldap\Entry;
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;
+use Symfony\Component\Ldap\LdapInterface;
/**
* LdapUserProvider is a simple user provider on top of ldap.
@@ -32,15 +33,15 @@ class LdapUserProvider implements UserProviderInterface
private $defaultSearch;
/**
- * @param LdapClientInterface $ldap
- * @param string $baseDn
- * @param string $searchDn
- * @param string $searchPassword
- * @param array $defaultRoles
- * @param string $uidKey
- * @param string $filter
+ * @param LdapInterface $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})')
+ public function __construct(LdapInterface $ldap, $baseDn, $searchDn = null, $searchPassword = null, array $defaultRoles = array(), $uidKey = 'sAMAccountName', $filter = '({uid_key}={username})')
{
$this->ldap = $ldap;
$this->baseDn = $baseDn;
@@ -57,33 +58,25 @@ class LdapUserProvider implements UserProviderInterface
{
try {
$this->ldap->bind($this->searchDn, $this->searchPassword);
- $username = $this->ldap->escape($username, '', LDAP_ESCAPE_FILTER);
+ $username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_FILTER);
$query = str_replace('{username}', $username, $this->defaultSearch);
- $search = $this->ldap->find($this->baseDn, $query);
+ $search = $this->ldap->query($this->baseDn, $query);
} catch (ConnectionException $e) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
}
- if (!$search) {
+ $entries = $search->execute();
+ $count = count($entries);
+
+ if (!$count) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
}
- if ($search['count'] > 1) {
+ if ($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);
+ return $this->loadUser($username, $entries[0]);
}
/**
@@ -105,4 +98,9 @@ class LdapUserProvider implements UserProviderInterface
{
return $class === 'Symfony\Component\Security\Core\User\User';
}
+
+ private function loadUser($username, Entry $entry)
+ {
+ return new User($username, $entry->getAttribute('userpassword'), $this->defaultRoles);
+ }
}
diff --git a/Core/composer.json b/Core/composer.json
index f6391e0..e2915b0 100644
--- a/Core/composer.json
+++ b/Core/composer.json
@@ -24,7 +24,7 @@
"symfony/event-dispatcher": "~2.8|~3.0",
"symfony/expression-language": "~2.8|~3.0",
"symfony/http-foundation": "~2.8|~3.0",
- "symfony/ldap": "~2.8|~3.0.0",
+ "symfony/ldap": "~3.1",
"symfony/validator": "~2.8|~3.0",
"psr/log": "~1.0"
},
diff --git a/composer.json b/composer.json
index 509bc28..7b3801f 100644
--- a/composer.json
+++ b/composer.json
@@ -37,7 +37,7 @@
"symfony/routing": "~2.8|~3.0",
"symfony/validator": "~2.8|~3.0",
"symfony/expression-language": "~2.8|~3.0",
- "symfony/ldap": "~2.8|~3.0.0",
+ "symfony/ldap": "~3.1",
"psr/log": "~1.0"
},
"suggest": {