Symfony2:同时使用LDAP(Active Directory)和数据库进行用户身份验证

9
我正在使用Symfony框架v 2.4.2更新一个现有的网站,该网站执行双重身份验证以登录用户:
  1. 首先,它通过PHP的ldap_bind()函数检查用户名和密码是否属于有效的Active Directory用户;
  2. 如果是,则只检查用户名是否在DB表中存在(DB中没有存储密码);
  3. 如果在DB表中找到了用户名,则从DB加载用户配置文件,并对用户进行身份验证。
如何在Symfony2中复制此身份验证过程? 到目前为止,我在FOSUserBundle和FR3DLdapBundle方面遇到了困难:我设法使用链接提供者(ldapdb),但似乎LDAP凭据被完全忽略:即使ldap_bind()失败(这是第1点和第2点的确切相反), 用户也可以使用存储在DB中的凭据登录。
另外,在使用FOSUserBundle时,好像必须将密码存储在DB中。
注意第2点:用户必须可以自由更改他们在网站外部(即Active Directory)的LDAP密码,然后使用新的凭据登录 -而无需更新网站的用户数据库。
欢迎任何解决方案,我对FOSUserBundle和FR3DLdapBundle都不是很满意。
2个回答

4
我是这样处理的:
  1. 基于FOSUserBundle用户模型创建自定义用户实体;
  2. 创建自定义用户提供程序(请参阅Javad对此问题的答案),将其注册为服务,并将其添加到我的providers部分中,在app/config/security.yml中;
  3. 从v2.4开始,Symfony(幸运的是)提供了一个简化的身份验证系统,不强制你经历所有自定义身份验证提供程序的繁琐操作(在我看来,这真是令人痛苦):它称为Authenticator,并在这里进行了说明。我实现了自己的Authenticator类,并使用自定义UserProvider类执行了双重检查。

你们的解决方案中是否包含任何选项,如果用户已通过身份验证但在数据库中不存在,则在数据库中为其创建一个个人资料?也许你们不需要这个功能,但我很好奇。 - Javad
不,绝对不行:用户必须同时存在于LDAP和数据库中。 - Paolo Stefan
你能否展示一些代码吗?我有几乎相同的目标要实现。作为额外的奖励功能,我尝试通过Kerberos或NTLM进行SSO :-) - Rufinus
@Rufinus 这是一个私人项目,所以我不能随意提供代码参考...你对哪个部分感兴趣? - Paolo Stefan

3

您需要为LDAP定义一个CustomUserProvider,该提供程序将在AD中查找用户,并在security.yml中设置此提供程序(自定义用户提供程序)。

providers:
    ldap_provider:
        id: myprovider.security.user.provider   # as you know when you create a custom web service provider you need to define it as a service and use the ID of the service here #

你还需要在防火墙中启用服务。
下一步是为LDAP创建自定义认证提供程序,该提供程序通过LDAP验证用户名和密码,并从数据库返回用户对象(自定义认证提供程序
根据这个过程,首先它会尝试在LDAP中查找用户,如果存在,则继续通过LDAP进行身份验证,如果用户经过身份验证,则将从数据库返回用户对象。
以下是自定义用户提供程序的示例。
public function loadUserByUsername($username)
{
   $ldap_obj = new adLDAP('exampl.ldapdircetory.com', 'prot', 'Base_DN', 'ldap_admin_user', 'ldap_admin_pass'));
   $filter = "( &(objectclass=person)( |(uid=".$username.")(cn=".$username.")(mail=".$username.") ) )";
   $info = $ldap_obj->search_user($filter);
   if ($info['count'] != 0) {
      // create temp User instance of UserInterface base on the returned info
      $user = new User();
      ...
      return $user
   }
   else {
      throw new UsernameNotFoundException('No match username was found.');
   }

我假设您已经有了adLDAP类来通过LDAP验证用户。

非常感谢,我已经按照您的指示实现了自定义用户提供程序,并与FOSUserBundle一起使用。您能否在第二部分(从数据库返回用户对象)上更具体一些?我有一个用户实体,现在该如何对其进行身份验证并从数据库加载其角色? - Paolo Stefan
抱歉回复晚了,我生病了;但好消息是你自己找到了解决方案;很高兴看到这一点 :) - Javad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接