Symfony 4.通过LDAP授权。如何自定义AuthenticationProvider?

时间:2019-10-06 22:34:26

标签: php symfony authentication ldap

首先,对不起我的英语和英语google-translate:)

俄语:https://ru.stackoverflow.com/questions/1031596/symfony-4-Авторизация-через-ldap-Как-подключить-кастомный-authenticationprovid

我的问题是,我的LDAP服务器在搜索后仅对从Entry接收的dn进行授权。也就是说,它通过用户名进行搜索:

$query: (samAccountName=AIvanov)

但仅对dn属性授权:

$dn: CN=Ivanov Alxey,OU=Staff,OU=Users,OU=Company,DC=company,DC=local

如果有一种方法可以使用配置指定从自定义UserProvider传输到本地LdapBindAuthenticationProvider数据的方法,则您不需要使用令牌中的用户名,而要使用此自定义用户的对象中的用户名:

$user->getUsername()

谁将返回这个该死的名字和姓氏,我将不胜感激。 因为否则只能创建我来到这里的CustomLdapBindAuthenticationProvider。

使用了手册:https://symfony.com/doc/current/security/custom_authentication_provider.html

我停止了一个事实,就是我不知道我的工厂和防火墙之间有什么关系,并且在呼叫我的这个工厂时出错。

因此,按照本手册,我创建了一个自定义身份验证提供程序。我尝试从本机Ldap继承...但是它的ldap属性是私有的,因此我只是将整个Ldap复制到自己并重命名为CustomLdapBindAuthenticationProvider。在那里更改了这一行,因此大惊小怪。然后,我通过从本地FormLoginLdapFactory继承它来创建自己的工厂

class CustomFormLoginLdapFactory extends FormLoginLdapFactory {
    protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId) {
    $provider = 'security.authentication.provider.ldap_bind.'.$id;
    $definition = $container
        //->setDefinition($provider, new ChildDefinition('security.authentication.provider.ldap_bind'))
        ->setDefinition($provider, new ChildDefinition(CustomLdapBindAuthenticationProvider::class))
        ->replaceArgument(0, new Reference($userProviderId))
        ->replaceArgument(1, new Reference('security.user_checker.'.$id))
        ->replaceArgument(2, $id)
        ->replaceArgument(3, new Reference($config['service']))
        ->replaceArgument(4, $config['dn_string']);
    if (!empty($config['query_string'])) {
        $definition->addMethodCall('setQueryString', [$config['query_string']]);
    }

    return $provider;
}

我按照手册中的指示提供了服务

App\Security\Authentication\Provider\CustomLdapBindAuthenticationProvider:
    arguments:
        $userProvider: '@Symfony\Component\Security\Core\User\UserProviderInterface'
        $ldap: '@Symfony\Component\Ldap\Ldap'
        $dnString: '{username}'

,因此也尝试了(我在第一个参数中传递了ChainUserProvider对象)

App\Security\Authentication\Provider\CustomLdapBindAuthenticationProvider:
    arguments:
        $userProvider: '@Symfony\Component\Security\Core\User\ChainUserProvider'
        $ldap: '@Symfony\Component\Ldap\Ldap'
        $dnString: '{username}'

最后,我在内核(src / Kernel.php)中插入了一个新方法,我也从手册中获取了它:

public function build(ContainerBuilder $container)
{
    $extension = $container->getExtension('security');
    $extension->addSecurityListenerFactory(new CustomFormLoginLdapFactory());
}

但是在防火墙块中写的内容对我来说并不明显,培训手册中没有任何说明。 结果,原始的form_login_ldap无法正常工作。尝试用类似的东西替换form_login_ldap失败,例如custom_form_login_ldap失败,交响乐说配置的这一部分只能有原始名称。

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        anonymous: true
        provider: chain_provider
        #http_basic: ~
        form_login_ldap:
            login_path: /login
            check_path: /login
            csrf_token_generator: security.csrf.token_manager
            service: 'Symfony\Component\Ldap\Ldap'
            dn_string: 'cn={username},OU=Staff,OU=Users,OU=Company,DC=company,DC=local'

当我使用此配置运行时:

Service "security.authentication.provider.ldap_bind.main": The argument "0" doesn't exist. (1/1) OutOfBoundsException

Service "security.authentication.provider.ldap_bind.main": The argument "0" doesn't exist. in Definition.php line 275 at Definition->replaceArgument(0, object(Reference))in ResolveChildDefinitionsPass.php line 163 at ResolveChildDefinitionsPass->doResolveDefinition(object(ChildDefinition))in ResolveChildDefinitionsPass.php line 62 at ResolveChildDefinitionsPass->resolveDefinition(object(ChildDefinition))in ResolveChildDefinitionsPass.php line 43 at ResolveChildDefinitionsPass->processValue(object(ChildDefinition), true)in AbstractRecursivePass.php line 82

那么,如何将工厂链接到防火墙部分?

1 个答案:

答案 0 :(得分:0)

使用电报和用户artem解决了该问题。因此,首先,如何将工厂连接到防火墙部分:一切都很明显,很快就发现了,疏忽引起了这个问题。 可能有人可以搜索以使问题不再得到答案

工厂方法

public function getKey()
{
    return 'form-login-ldap';
}

设置防火墙中该部分的密钥:form_login_ldap只有短划线变成下划线。

最重要的是,如何建立CustomLdapBindAuthenticationProvider的连接。我在其中获取FormLoginLdapFactory复本代码的原始工厂使用数字作为键。它显然对她有用,因为在交响乐的供应商配置的深处,LdapBindAuthenticationProvider服务的描述使用这些数字来表示参数:

->replaceArgument(0, new Reference($userProviderId))
->replaceArgument(1, new Reference('security.user_checker.'.$id))
->replaceArgument(2, $id)
->replaceArgument(3, new Reference($config['service']))
->replaceArgument(4, $config['dn_string'])

当我确实连接了CustomLdapBindAuthenticationProvider时,我在服务配置中指定了

App\Security\Authentication\Provider\CustomLdapBindAuthenticationProvider:
    arguments:
        $userProvider: '@Symfony\Component\Security\Core\User\UserProviderInterface'
        $userChecker: '@Symfony\Component\Security\Core\User\UserCheckerInterface'
        $providerKey: ''
        $ldap: '@Symfony\Component\Ldap\Ldap'
        $dnString: '{username}'
        $userRepository: '@App\Repository\UserRepository'

,因此还必须在工厂写信:

->setDefinition($provider, new ChildDefinition(CustomLdapBindAuthenticationProvider::class))
->replaceArgument('$userProvider', new Reference($userProviderId))
->replaceArgument('$userChecker', new Reference('security.user_checker.'.$id))
->replaceArgument('$providerKey', $id)
->replaceArgument('$ldap', new Reference($config['service']))
->replaceArgument('$dnString', $config['dn_string'])

它奏效了。

相关问题