我需要针对具有自定义逻辑的LDAP服务器对用户进行身份验证。
我正在 Symfony 3.3 中实现自定义身份验证系统,并构建了一个名为 LoginFormAuthenticator 的自定义身份验证器,其扩展名为 AbstractFormLoginAuthenticator ,具体如下: http://symfony.com/doc/current/security/guard_authentication.html
我需要针对数据库中的User实体检查用户名,然后根据用户的类型,对存储在数据库中的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进行了身份验证,尽管它使调用对我进行了混淆。
我应该使用哪种服务或类来代替上面的 unknownLdapService 来查询LDAP?
答案 0 :(得分:0)
您可以使用自己的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.');
}
}
}
答案 1 :(得分:0)
我最终使用的解决方案是我首先将现有的Symfony ldap服务注入到我的方法的构造函数中。 ldap服务在 services.yml 中配置,与Symfony docs为 form_login_ldap 提供程序配置它的方式相同。
input()
然后在checkCredentials方法中,我调用了ldap bind方法:
/**
* 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;
}
这很有效,如果ldap auth失败,它会抛出相应的异常。