如何同时查询samaaccountname和userprincipalname symfonyLdap

时间:2019-07-16 18:57:02

标签: symfony ldap

我有一个针对Ldap服务器进行身份验证的Symfony登录表单。我可以使用samaccountname或userprincipalname以及我的配置设置中的uid键成功查询和认证用户。我希望能够允许用户输入他们的用户名或他们的username@domain.com

我在LdapUserProviderClass的loadUserbyUsername()方法中的用户名上尝试了preg_replace(我知道这并不理想)。这需要一个用户名(例如username@domain.com)并传递用户名。我能够验证从Ldap服务器返回了正确的用户,但是我仍然返回带有“无效凭据”的登录表单。我相信会处理AuthenticationUtils类请求中发生这种情况的原因,并且请求中的用户名仍为username@domain.com,并且与来自Ldap身份验证的用户对象中的用户名(即用户名)不匹配。如果有人对如何完成允许用户名@ domain.com和用户名针对Ldap进行身份验证提出建议,我将不胜感激。

SecurityController.php

 public function login(Request $request, AuthenticationUtils $authenticationUtils): Response
{


    // get the login error if there is one
    $error = $authenticationUtils->getLastAuthenticationError();
    // last username entered by the user
    $lastUsername = $authenticationUtils->getLastUsername();

    $newLastUsername = trim(preg_replace('/@.*/', '',$lastUsername));

    return $this->render('security/login.html.twig', ['last_username' => $newLastUsername, 'error' => $error]);
}

security.yml

 providers:
        dsg_ldap:
        ldap:
            service: Symfony\Component\Ldap\Ldap
            base_dn: '%env(BASE_DSN)%'
            search_dn: '%env(SEARCH_DN)%'
            search_password: '%env(SEARCH_PWD)%'
            uid_key: '%env(UID_KEY)%'
            #filter: '({uid_key}={_username})'
            default_roles: ROLE_USER
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        anonymous: ~

        form_login_ldap:
            login_path: login
            check_path: login
            service: Symfony\Component\Ldap\Ldap
            provider: dsg_ldap
            dn_string: '%env(DN_STRING)%\{username}'

我的LdapUserProvider.php

    class LdapUserProvider extends SymfonyLdapUserProvider
{
    /** @var array maps ldap groups to roles */
    private $groupMapping = [
        '**' => '**',
        '**' => '**',
        '**' => '**',
        '**' => '**'

    ];

    /** @var string extracts group name from dn string */
      private $groupNameRegExp = '/CN=(.+?),/';

    protected function loadUser($username, Entry $entry)
    {
        $roles = ['ROLE_USER'];
        // Check if the entry has attribute with the group
        if (!$entry->hasAttribute('memberOf')) {
            return new User($username, '', $roles);
        }

        // Iterate through each group entry line
        foreach ($entry->getAttribute('memberOf') as $groupLine) {
            // Extract the group name from the line
            $groupName = $this->getGroupName($groupLine);
            // Check if the group is in the mapping
            if (array_key_exists($groupName, $this->groupMapping)) {
                // Map the group to the role(s) the user will have
                $roles[] = $this->groupMapping[$groupName];
            }
        }


        // Create and return the user object
        return new User($username, null, $roles);
    }

    /**
     * Get the group name from the DN
     * @param string $dn
     * @return string
     */
    private function getGroupName($dn)
    {
        $matches = [];
        return preg_match($this->groupNameRegExp, $dn, $matches) ? $matches[1] : '';
    }
}

Symfony \ Component \ Security \ Core \ User \ LdapUserProvider.php

 public function loadUserByUsername($username)
{

    try {
        $this->ldap->bind($this->searchDn, $this->searchPassword);
        // what i added
        $username = trim(preg_replace('/@.*/', '',$username));
        $username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_FILTER);
        $query = str_replace('{username}', $username, $this->defaultSearch);
        $search = $this->ldap->query($this->baseDn, $query);
    } catch (ConnectionException $e) {
        throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
    }

    $entries = $search->execute();
    $count = \count($entries);

    if (!$count) {
        throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
    }

    if ($count > 1) {
        throw new UsernameNotFoundException('More than one user found');
    }

    $entry = $entries[0];

    try {
        if (null !== $this->uidKey) {
            $username = $this->getAttributeValue($entry, $this->uidKey);
        }
    } catch (InvalidArgumentException $e) {
    }

    return $this->loadUser($username, $entry);
}

1 个答案:

答案 0 :(得分:0)

loadUserByUsername函数中,如果第一个查询失败,则添加另一个查询。您的$this->defaultSearch可能是一个代表LDAP过滤器的常数。

如果您在第一个if (!$count) {...}中创建相同的行,如下所示:

$query = str_replace('{username}', $username, "(userPrincipalName={username})");

然后执行该查询,您正在第二次搜索形式为 user @ domain

的userPrincipalName。