Symfony 3:如何检查身份验证器中的LDAP checkCredentials

时间:2017-11-01 22:22:34

标签: symfony authentication ldap symfony-3.3

我需要针对具有自定义逻辑的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?

2 个答案:

答案 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失败,它会抛出相应的异常。