【问题标题】:Symfony LDAP auth bind with username and passwordSymfony LDAP 身份验证与用户名和密码绑定
【发布时间】:2017-03-10 13:12:32
【问题描述】:

我正在尝试使 LDAP 身份验证适用于 Symfony 防火墙,但遇到了问题。主要问题似乎源于 Symfony LdapUserProvider - 在尝试 ldap_bind() 时,它不需要用户提供的用户名和密码。

所以,我有这个作为我的防火墙配置:

$app->register(new SilexProvider\SecurityServiceProvider(), [
    'security.firewalls' => [
        'secured' => [
            'pattern' => '^.*$',
            'http' => true,
            'users' => new \Symfony\Component\Security\Core\User\LdapUserProvider(
                \Symfony\Component\Ldap\Ldap::create('ext_ldap', [
                    'connection_string' => 'ldap://MY_LDAP_DOMAIN',
                ]),
                'dc=MY_DC_1,dc=MY_DC_2',
                'uid={username},cn=users,cn=accounts,dc=MY_DC_1,dc=MY_DC_2'
            ),
        ],
    ],
]);

但是当调用ldap_bind 方法时,我的{username} 部分不会被用户提供的用户名替换。因此,传递给 ldap_binddn 字符串实际上是 uid={username},cn=users,cn=accounts,dc=MY_DC_1,dc=MY_DC_2 - 用户名不会被替换。

如果我查看代码,尽管这是意料之中的,因为 LdapUserProvider->loadUserByUsername() 在进行任何字符串替换之前会调用 bind。另一个问题是它直到很久以后才知道用户提供的密码,所以bind 再次调用没有用户提供的密码。

我该如何设置它以适当地替换我的dn 和密码?如果我使用这两条基本线(其中$data 是一个有效用户的数组):

$ldap = ldap_connect('MY_LDAP_DOMAIN');
$bind = ldap_bind($ldap, 'uid=' . $data['username'] . ',cn=users,cn=accounts,dc=MY_DC_1,dc=MY_DC_2', $data['password']);

然后完美结合。我怎样才能将这两行翻译成 Symfony 防火墙可以理解的情况?

【问题讨论】:

    标签: php symfony silex


    【解决方案1】:

    现有代码中有 2 个主要问题:

    1. Symfony 的 LdapUserProvider 组件默认使用 Active Directory (Windows) 架构:sAMAccountName={username} 而不是 Open LDAP 的 uid={username}
    2. 您正在使用内置的http 安全防火墙,默认情况下使用DaoAuthenticationProvider 身份验证提供程序。如果是 LDAP 身份验证,您需要改用LdapBindAuthenticationProvider

    第一个问题可以通过将用户标识符密钥传递给LdapUserProvider来解决:

    $app['ldap.users'] = function () use ($app) {
        return new LdapUserProvider(
            // your LDAP adapter
            $app['ldap'],
            // base DN
            'dc=example,dc=com',
            // you don't need search DN
            null,
            // you don't need search password
            null,
            // list of default roles, can be empty array
            ['ROLE_USER'],
            // user identifier key for LDAP
            // this identitfer must be set explicitly
            'uid'
        );
    };
    

    注意第三个和第四个参数可以是null,因为它们永远不会被使用:LdapBindAuthenticationProvider会被首先调用,所以LDAP连接已经被绑定了。

    第二期需要一点编码。 Symfony 具有内置的http_basic_ldap 身份验证提供程序,非常适合您的要求。不幸的是,Silex 没有,所以你需要自己做。使用 Silex 文档作为参考:Defining a custom Authentication Provider

    这是我为 Silex 实现的form_login_ldap 示例。 注册所有与 LDAP 相关的服务:

    $app // register other services
        ->register(new LdapServiceProvider())
        ->register(new LdapUsersServiceProvider())
        ->register(new LdapSecurityServiceProvider())
        ->register(new \Silex\Provider\SecurityServiceProvider(), [
            'security.firewalls' => [
                'login' => [
                    'pattern' => '^/login$',
                ],
                'secured' => [
                    'pattern' => '^.*$',
                    'form_login_ldap' => [
                        'login_path' => 'login',
                        'check_path' => 'login_check',
                        'default_target_path' => 'backoffice',
                    ],
                    'users' => $this['ldap.users'],
                ],
            ],
        ])
    ;
    

    LDAP 适配器的服务提供者

    use Pimple\Container;
    use Pimple\ServiceProviderInterface;
    use Symfony\Component\Ldap\Ldap;
    
    class LdapServiceProvider implements ServiceProviderInterface
    {
        public function register(Container $app)
        {
            $app['ldap'] = function () {
                return Ldap::create('ext_ldap', [
                    'connection_string' => 'ldap.example.com',
                ]);
            };
        }
    }
    

    LDAP 用户的服务提供者

    use Pimple\Container;
    use Pimple\ServiceProviderInterface;
    use Symfony\Component\Security\Core\User\LdapUserProvider;
    
    class LdapUsersServiceProvider implements ServiceProviderInterface
    {
        public function register(Container $app)
        {
            $app['ldap.users'] = function () use ($app) {
                return new LdapUserProvider(
                    $app['ldap'],
                    'dc=example,dc=com',
                    null,
                    null,
                    ['ROLE_USER'],
                    'uid'
                );
            };
        }
    }
    

    LDAP 表单的安全认证监听器工厂的服务提供者(你最感兴趣的部分)

    use Pimple\Container;
    use Pimple\ServiceProviderInterface;
    use Symfony\Component\Security\Core\Authentication\Provider\LdapBindAuthenticationProvider;
    
    class LdapSecurityServiceProvider implements ServiceProviderInterface
    {
        public function register(Container $app)
        {
            $app['security.authentication_listener.factory.form_login_ldap'] = $app->protect(function ($name, $options) use ($app) {
                // define the authentication provider object
                $app['security.authentication_provider.'.$name.'.form_login_ldap'] = function () use ($app, $name) {
                    return new LdapBindAuthenticationProvider(
                        $app['security.user_provider.'.$name],
                        $app['security.user_checker'],
                        $name,
                        $app['ldap'],
                        'uid={username},dc=example,dc=com',
                        $app['security.hide_user_not_found']
                    );
                };
    
                // define the authentication listener object
                $app['security.authentication_listener.'.$name.'.form_login_ldap'] = $app['security.authentication_listener.form._proto']($name, $options);
    
                // define the entry point object
                $app[$entryPoint = 'security.entry_point.'.$name.'.form_login_ldap'] = $app['security.entry_point.form._proto']($name, array());
    
                return array(
                    // the authentication provider id
                    'security.authentication_provider.'.$name.'.form_login_ldap',
                    // the authentication listener id
                    'security.authentication_listener.'.$name.'.form_login_ldap',
                    // the entry point id
                    $entryPoint,
                    // the position of the listener in the stack
                    'form'
                );
            });
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-07-31
      • 2018-07-13
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      • 2011-10-23
      • 2016-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多