Symfony 3:如何在 Authenticator checkCredentials 中检查 LDAP
Symfony 3: How to check LDAP inside Authenticator checkCredentials
我需要使用自定义逻辑根据 LDAP 服务器对用户进行身份验证。
我正在 Symfony 3.3 中实现自定义身份验证系统,并构建了一个名为 LoginFormAuthenticator 的自定义身份验证器,它扩展了 AbstractFormLoginAuthenticator,根据:
http://symfony.com/doc/current/security/guard_authentication.html
我需要根据数据库中的用户实体检查用户名,然后根据用户类型,根据存储在数据库中的 bcrypt 密码或外部 LDAP 服务器进行身份验证。
在 checkCredentials 方法中,我可以通过以下方式成功验证存储在数据库中的密码:
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator {
...
public function checkCredentials($credentials, UserInterface $user)
{
...
// check password if the user is database user
if ($user->getApp() == 'DB') {
if ($this->passwordEncoder->isPasswordValid($user, $password)) {
return true;
}
}
// check LDAP server if LDAP user
if ($this->getApp() == 'LDAP') {
if ($this->unknownLdapService->check($user, $password)
{
return true;
}
...
我不清楚使用本机 symfony 功能检查 LDAP 服务器的用户名和密码的正确方法。
如果我将我的配置更改为使用 form_login_ldap(而不是我的新身份验证器),它实际上会成功地针对 LDAP 进行身份验证,尽管它在哪里进行调用对我来说是模糊的。
我应该使用什么服务或 class 来查询 LDAP 来代替上面的 unknownLdapService?
您可以使用自己的 LDAP 服务:您只需调用 ldap_bind。 (它可以让你做更多的 ldap 检查或模拟它)
您也可以使用 Symfony 提供程序:vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
namespace Symfony\Component\Security\Core\Authentication\Provider;
class LdapBindAuthenticationProvider extends UserAuthenticationProvider
{
private $userProvider;
private $ldap;
private $dnString;
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();
if ('' === $password) {
throw new BadCredentialsException('The presented password must not be empty.');
}
try {
$username = $this->ldap->escape($username, '', 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.');
}
}
}
我在这里最终使用的解决方案是,我首先将现有的 Symfony ldap 服务注入到我的方法的构造函数中。 ldap 服务在 services.yml 中的配置方式与 Symfony 文档为 form_login_ldap 提供商配置的方式相同。
/**
* LoginFormAuthenticator constructor.
* @param FormFactoryInterface $formFactory
* @param EntityManager $em
* @param RouterInterface $router
* @param SecureUserPasswordEncoder $passwordEncoder
* @param Ldap $ldap
*/
public function __construct(..., Ldap $ldap, ... )
{
...
$this->ldap = $ldap;
}
然后在我的 checkCredentials 方法中,我调用了 ldap 绑定方法:
public function checkCredentials($credentials, $userInterface $user)
...
$password = $credentials['_password'];
$login_format = 'DOMAIN\%s'; // this is the expected format in my case
$login_username = sprintf($login_format, $user);
...
try {
// try to bind with the username and provided password
$this->ldap->bind($login_username, $password);
} catch (\Symfony\Component\Ldap\Exception\ConnectionException $e) {
//return false;
throw new CustomUserMessageAuthenticationException('The submitted LDAP password is invalid.');
};
return true;
};
这有效,如果 ldap 身份验证失败,它会抛出相应的异常。
我需要使用自定义逻辑根据 LDAP 服务器对用户进行身份验证。
我正在 Symfony 3.3 中实现自定义身份验证系统,并构建了一个名为 LoginFormAuthenticator 的自定义身份验证器,它扩展了 AbstractFormLoginAuthenticator,根据: http://symfony.com/doc/current/security/guard_authentication.html
我需要根据数据库中的用户实体检查用户名,然后根据用户类型,根据存储在数据库中的 bcrypt 密码或外部 LDAP 服务器进行身份验证。
在 checkCredentials 方法中,我可以通过以下方式成功验证存储在数据库中的密码:
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator {
...
public function checkCredentials($credentials, UserInterface $user)
{
...
// check password if the user is database user
if ($user->getApp() == 'DB') {
if ($this->passwordEncoder->isPasswordValid($user, $password)) {
return true;
}
}
// check LDAP server if LDAP user
if ($this->getApp() == 'LDAP') {
if ($this->unknownLdapService->check($user, $password)
{
return true;
}
...
我不清楚使用本机 symfony 功能检查 LDAP 服务器的用户名和密码的正确方法。
如果我将我的配置更改为使用 form_login_ldap(而不是我的新身份验证器),它实际上会成功地针对 LDAP 进行身份验证,尽管它在哪里进行调用对我来说是模糊的。
我应该使用什么服务或 class 来查询 LDAP 来代替上面的 unknownLdapService?
您可以使用自己的 LDAP 服务:您只需调用 ldap_bind。 (它可以让你做更多的 ldap 检查或模拟它)
您也可以使用 Symfony 提供程序:vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
namespace Symfony\Component\Security\Core\Authentication\Provider;
class LdapBindAuthenticationProvider extends UserAuthenticationProvider
{
private $userProvider;
private $ldap;
private $dnString;
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();
if ('' === $password) {
throw new BadCredentialsException('The presented password must not be empty.');
}
try {
$username = $this->ldap->escape($username, '', 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.');
}
}
}
我在这里最终使用的解决方案是,我首先将现有的 Symfony ldap 服务注入到我的方法的构造函数中。 ldap 服务在 services.yml 中的配置方式与 Symfony 文档为 form_login_ldap 提供商配置的方式相同。
/**
* LoginFormAuthenticator constructor.
* @param FormFactoryInterface $formFactory
* @param EntityManager $em
* @param RouterInterface $router
* @param SecureUserPasswordEncoder $passwordEncoder
* @param Ldap $ldap
*/
public function __construct(..., Ldap $ldap, ... )
{
...
$this->ldap = $ldap;
}
然后在我的 checkCredentials 方法中,我调用了 ldap 绑定方法:
public function checkCredentials($credentials, $userInterface $user)
...
$password = $credentials['_password'];
$login_format = 'DOMAIN\%s'; // this is the expected format in my case
$login_username = sprintf($login_format, $user);
...
try {
// try to bind with the username and provided password
$this->ldap->bind($login_username, $password);
} catch (\Symfony\Component\Ldap\Exception\ConnectionException $e) {
//return false;
throw new CustomUserMessageAuthenticationException('The submitted LDAP password is invalid.');
};
return true;
};
这有效,如果 ldap 身份验证失败,它会抛出相应的异常。