当前位置: 首页 > 面试题库 >

如何通过TLS上的LDAP对Active Directory进行身份验证?

宗增
2023-03-14
问题内容

我有一个有效的概念验证应用程序,可以通过测试服务器上的LDAP通过Active
Directory进行成功的身份验证,但是生产应用程序必须通过TLS进行身份验证-域控制器会关闭所有未通过TLS发起的连接。

我已经在Eclipse中安装了LDAP浏览器,并且确实可以在 其中 使用TLS进行绑定,但是我一生都无法弄清楚如何让我的应用程序使用TLS。

ldap.xml

<bean id="ldapAuthenticationProvider"
        class="my.project.package.OverrideActiveDirectoryLdapAuthenticationProvider">

    <!-- this works to authenticate by binding as the user in question -->
    <constructor-arg value="test.server"/>
    <constructor-arg value="ldap://192.168.0.2:389"/>

    <!-- this doesn't work, because the server requires a TLS connection -->
    <!-- <constructor-arg value="production.server"/> -->
    <!-- <constructor-arg value="ldaps://192.168.0.3:389"/> -->

    <property name="convertSubErrorCodesToExceptions" value="true"/>
</bean>

OverrideActiveDirectoryLdapAuthenticationProvider是重写类,它扩展了Spring
ActiveDirectoryLdapAuthenticationProvider类的副本,该类由于某种原因而指定了final。我优先考虑的原因与自定义在用户对象上填充权限的方式有关(我们将使用相关组的组成员身份来建立用户的权限,或者从AD用户对象的字段中读取内容)。在其中,我仅覆盖loadUserAuthorities()方法,但我怀疑我可能还需要覆盖bindAsUser()方法或可能覆盖doAuthentication()方法。

XML和一个重写类是我的应用程序管理身份验证的唯一两个地方,而不是让Spring进行工作。我已经阅读了几个启用TLS的地方,我需要扩展DefaultTlsDirContextAuthenticationStrategy该类,但是在哪里连接它呢?有名称空间解决方案吗?我是否需要完全做其他事情(即放弃使用Spring的ActiveDirectoryLdapAuthenticationProvider使用,而是使用LdapAuthenticationProvider)?

任何帮助表示赞赏。


问题答案:

好的,经过大约一天半的研究,我弄清楚了。

我最初的方法是扩展Spring的ActiveDirectoryLdapAuthenticationProvider类,并覆盖其loadUserAuthorities()方法,以便自定义身份验证用户权限的构建方式。由于不明显的原因,ActiveDirectoryLdapAuthenticationProvider该类被指定为final,因此我当然不能扩展它。

值得庆幸的是,开源提供了黑客手段(而该类的超类 不是
final),因此我只是复制了它的全部内容,删除了final名称,并相应地调整了包和类的引用。我没有编辑此类中的任何代码,只是添加了一个高度可见的注释,该注释说不要对其进行编辑。然后OverrideActiveDirectoryLdapAuthenticationProvider,我在中扩展了该类,我也在ldap.xml文件中引用了该类,并在其中添加了重写方法loadUserAuthorities。通过在未加密会话上(在隔离的虚拟服务器上)的简单LDAP绑定,所有这些工作都很好。

实际的网络环境要求所有LDAP查询均以TLS握手开始,但是,要查询的服务器不是PDC,其名称为“ sub.domain.tld”,但已根据“
domain.tld”对用户进行了正确的身份验证。” 此外,用户名必须以“ NT_DOMAIN
\”开头才能进行绑定。所有这些都需要自定义工作,但不幸的是,我在任何地方都没有或几乎没有帮助。

因此,这是荒谬的简单更改,所有这些更改都包含以下进一步的覆盖OverrideActiveDirectoryLdapAuthenticationProvider

@Override
protected DirContext bindAsUser(String username, String password) {
    final String bindUrl = url; //super reference
    Hashtable<String,String> env = new Hashtable<String,String>();
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    //String bindPrincipal = createBindPrincipal(username);
    String bindPrincipal = "NT_DOMAIN\\" + username; //the bindPrincipal() method builds the principal name incorrectly
    env.put(Context.SECURITY_PRINCIPAL, bindPrincipal);
    env.put(Context.PROVIDER_URL, bindUrl);
    env.put(Context.SECURITY_CREDENTIALS, password);
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxtFactory");
    //and finally, this simple addition
    env.put(Context.SECURITY_PROTOCOL, "tls");

    //. . . try/catch portion left alone
}

也就是说,我对该方法所做的全部工作就是更改了bindPrincipal字符串html" target="_blank">格式化的方式,并向哈希表添加了键/值。

我不必从domain传递给我的类的参数中删除子域,因为它是由ldap.xml; 传递的;我只是改变了参数 存在<constructor- arg value="domain.tld"/>

然后我更改了searchForUser()方法OverrideActiveDirectoryLdapAuthenticationProvider

@Override
protected DirContextOperations searchForUser(DirContext ctx, String username) throws NamingException {
    SearchControls searchCtls = new SearchControls();
    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

    //this doesn't work, and I'm not sure exactly what the value of the parameter {0} is
    //String searchFilter = "(&(objectClass=user)(userPrincipalName={0}))";
    String searchFilter = "(&(objectClass=user)(userPrincipalName=" + username + "@domain.tld))";

    final String bindPrincipal = createBindPrincipal(username);
    String searchRoot = rootDn != null ? rootDn : searchRootFromPrincipal(bindPrincipal);

    return SpringSecurityLdapTemplate.searchForSingleEntryInternal(ctx, searchCtls, searchRoot, searchFilter, new Object[]{bindPrincipal});

最后的更改是createBindPrincipal()方法,以正确构建String(出于我的目的):

@Override
String createBindPrincipal(String username) {
    if (domain == null || username.toLowerCase().endsWith(domain)) {
        return username;
    }
    return "NT_DOMAIN\\" + username;
}

有了以上更改-我仍然需要从所有测试和总公司中清除这些更改-我得以针对自己在网络上的Active
Directory进行绑定和身份验证,捕获所需的任何用户对象字段,确定组成员身份等

哦,显然TLS不需要’ldaps://’,所以我ldap.xml只需使用ldap://192.168.0.3:389

tl; dr

要启用TLS,请复制Spring的ActiveDirectoryLdapAuthenticationProvider类,删除该final名称,在自定义类中对其进行扩展,然后bindAsUser()通过添加env.put(Context.SECURITY_PROTOCOL, "tls");到环境哈希表进行覆盖。而已。

要更严格地控​​制绑定用户名,域和LDAP查询字符串,请适当地覆盖适用的方法。在我的情况下,我不能仅确定的值{0}是什么,因此我将其完全删除,username而是插入了传递的字符串。

希望有人能对您有所帮助。



 类似资料:
  • 我有一个工作的概念验证应用程序,它可以通过测试服务器上的LDAP成功地对Active Directory进行身份验证,但是生产应用程序必须通过TLS进行身份验证--域控制器关闭任何不通过TLS发起的连接。 ldap.xml: 是一个重写类,它扩展了Spring的类的副本,该类出于某种原因被指定为。我要重写的原因与自定义在用户对象上填充权限/权限的方式有关(我们要么使用相关组的组成员身份来构建用户的

  • 在我配置了下面的配置之后,它不会连接到Active Directory。我无法使用Active Directory的帐户登录。会有什么问题? 我有一个Ubuntu服务器18.04,带有ApacheGuacamoleV1。0.0. 安装。我想使用LDAP身份验证来验证用户。我已经下载了鳄梨酱-auth-ldap-1.0.0。jar和jldap-4.3。jar扩展。 10.10.10.21,10.10

  • 我正在尝试用.NET中的LDAP制作一个简单的身份验证系统。我检查了.NET中的一些名称空间,并简单地制作了标准代码片段,如下所示。 我有一个管理员用户名和密码和,用于对客户端应用程序进行身份验证。我有第二个用户名和密码和,需要在LDAP中检查才能登录。 是管理帐户,只是LDAP中的用户。那么如何检查的密码呢?

  • 目前用户名总是匿名的。设置调用方主体的正确方法是什么?我在拦截器里做这个吗?还是在豆子本身?我的目标是基本上能够调用一个方法loginUserWithEJBOnJboss(String user,String pass),该方法使用在jboss中配置的登录方法并正确设置主体。 我在这里不知所措,谷歌什么也没找到。也许我只是在寻找错误的单词。

  • 问题内容: 我正在寻找一种通过PHP(通过Active Directory作为提供者)通过LDAP验证用户身份的方法。理想情况下,它应该能够在IIS 7上运行(adLDAP在Apache上运行)。有谁做过类似的事情,并且成功了? 编辑:我更喜欢一个带有代码的库/类,这些代码已经准备好去做……如果有人已经发明了轮子,那就太愚蠢了。 问题答案: 当您只需要两行代码时,导入整个库似乎效率很低。

  • 我无法使用真正的active directory进行身份验证,让我更好地解释一下,我尝试使用spring提出的示例进行身份验证。io无问题—内部服务启动时没有任何问题。参考https://spring.io/guides/gs/authenticating-ldap/ 我试图通过插入active directory的配置来修改下面的代码,但没有成功。你能不能给我一个真实的例子,让我看看在不使用内部