好的,经过大约一天半的研究,我弄清楚了。
我最初的方法是扩展Spring的
ActiveDirectoryLdapAuthenticationProvider类,并覆盖其
loadUserAuthorities()方法,以便自定义身份验证用户权限的构建方式。由于不明显的原因,
ActiveDirectoryLdapAuthenticationProvider该类被指定为
final,因此我当然不能扩展它。
值得庆幸的是,开源提供了黑客手段(而该类的超类 不是
final),因此我只是复制了它的全部内容,删除了
final名称,并相应地调整了包和类的引用。我没有编辑此类中的任何代码,只是添加了一个高度可见的注释,该注释说不要对其进行编辑。然后
OverrideActiveDirectoryLdapAuthenticationProvider,我在中扩展了该类,我也在
ldap.xml文件中引用了该类,并在其中添加了重写方法
loadUserAuthorities。通过在未加密会话上(在隔离的虚拟服务器上)的简单LDAP绑定,所有这些工作都很好。
实际的网络环境要求所有LDAP查询均以TLS握手开始,但是,要查询的服务器不是PDC,其名称为“ sub.domain.tld”,但已根据“
domain.tld”对用户进行了正确的身份验证。” 此外,用户名必须以“ NT_DOMAIN
”开头才能进行绑定。所有这些都需要自定义工作,但不幸的是,我在任何地方都没有或几乎没有帮助。
因此,这是荒谬的简单更改,所有这些更改都包含以下进一步的覆盖
OverrideActiveDirectoryLdapAuthenticationProvider:
@Overrideprotected 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字符串格式化的方式,并向哈希表添加了键/值。
我不必从
domain传递给我的类的参数中删除子域,因为它是由
ldap.xml; 传递的;我只是改变了参数 存在 于
<constructor-arg value="domain.tld"/>
然后我更改了
searchForUser()方法
OverrideActiveDirectoryLdapAuthenticationProvider:
@Overrideprotected 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(出于我的目的):
@OverrideString 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而是插入了传递的字符串。
希望有人能对您有所帮助。



