Symfony LDAP使用用户名和密码进行身份验证

时间:2017-03-10 13:12:33

标签: php symfony silex

我正在尝试让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'
            ),
        ],
    ],
]);

但是,在调用{username}方法时,我的ldap_bind部分不会被用户提供的用户名替换。因此,传递给dn的{​​{1}}字符串实际上是ldap_bind - 用户名不会被替换。

如果我仔细查看代码,那么uid={username},cn=users,cn=accounts,dc=MY_DC_1,dc=MY_DC_2会在执行任何字符串替换之前调用LdapUserProvider->loadUserByUsername()。另一个问题是它在很久之后才知道用户提供的密码,因此再次bind调用没有用户提供的密码。

如何设置它以便它会适当地替换我的bind和密码?如果我使用这两条基本行(其中dn是有效用户的数组):

$data

然后它完美结合。如何将这两行转换为Symfony防火墙理解的情况?

1 个答案:

答案 0 :(得分:3)

现有代码中存在 2 主要问题:

  1. Symfony的LdapUserProvider组件默认使用Active Directory(Windows)架构:sAMAccountName={username}而不是Open LDAP' uid={username}
  2. 您正在使用内置http安全防火墙,默认情况下使用DaoAuthenticationProvider身份验证提供程序。如果是LDAP身份验证,则需要使用LdapBindAuthenticationProvider代替。
  3. 第一个问题可以通过将用户标识符密钥传递给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'
        );
    };
    

    注意第3和第4个参数可以是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'
                );
            });
        }
    }