Spring Security 4.0.0 + ActiveDirectoryLdapAuthenticationProvider + BadCredentialsException PartialResultException

我已经在stackoverflow上阅读了几乎所有关于Spring / Security / Ldap和ActiveDirectory的内容。 即使我找到了有用的提示和提示,我也无法解决我的问题。

这是:我确实使用用户服务和自定义登录页面配置了Spring Security,一切正常。 然后,我尝试切换到恰好是ActiveDirectory的最终身份validation提供程序。

这是我的security-applicationContext.xml(我提醒你这个设置在用户服务作为身份validation提供程序时工作正常,因此,文件实际上是导入的,等等):

                        <!-- This is the user-service authentication provider that is working fine      -->        

在bean myADProvider中,即使我将第一个构造函数参数更改为fsapps.company.uni或company.uni或其他任何内容,它也不会将任何内容更改为以下错误。 问题似乎是由于绑定搜索后使用错误的filter查找类似(&(userPrincipalName = {0})(objectClass = user))而不是(&(sAMAccountName = {0})(objectClass)的事实=用户))。 由于我无法弄清楚如何在使用LDAP提供程序的情况下更改此设置,因此我切换到LDAP提供程序,尝试使其无法成功运行,既不会在同一个地方遇到问题。 我还将我的Spring Framework从3.1.2升级到4.1.6.RELEASE和Spring Security从3.1.2升级到4.0.0.RELEASE阅读后出现了ActiveDirectoryLdapAuthenticationProvider的问题,希望在此期间问题得到解决有关此问题的原始讨论与版本3.x有关。

以下是我尝试使用Active Directory进行身份validation的LDAP设置配置:

                            <!--  -->  <!--     <!- -  - ->   -->  

这一次,我将bean配置部分留给AD提供程序以供参考。 这两个都不起作用。

那么,如何将用户和组搜索路径传递给AD提供程序? 或者,如何配置LDAP提供程序以使用AD并完成身份validation?

以下是我在日志中使用LDAP设置收到的消息,上面介绍了AD设置(错误的凭据主要是由于错误的搜索路径):

 2015-04-15 16:19:13,252 DEBUG (ossaProviderManager.authenticate) [http-8443-1] Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider MDC{} 2015-04-15 16:19:13,252 DEBUG (osslaAbstractLdapAuthenticationProvider.authenticate) [http-8443-1] Processing authentication request for user: ba5glag MDC{} 2015-04-15 16:19:13,252 DEBUG (osslsFilterBasedLdapUserSearch.searchForUser) [http-8443-1] Searching for user 'myuser', with user search [ searchFilter: '(&(sAMAccountName={0})(objectClass=user))', searchBase: 'dc=fsapps,dc=company,dc=uni', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ] MDC{} 2015-04-15 16:19:13,299 DEBUG (ossaDefaultAuthenticationEventPublisher.publishAuthenticationFailure) [http-8443-1] No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException MDC{} 2015-04-15 16:19:13,299 ERROR (osswaAbstractAuthenticationProcessingFilter.doFilter) [http-8443-1] An internal error occurred while trying to authenticate the user. MDC{} org.springframework.security.authentication.InternalAuthenticationServiceException: Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece(unprintable character here)]; remaining name 'dc=fsapps,dc=company,dc=uni' at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:207) ~[spring-security-ldap-4.0.0.RELEASE.jar:?] at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:82) ~[spring-security-ldap-4.0.0.RELEASE.jar:?] 

我希望我提供所有必需的信息,以便为解决此配置问题提供一些提示和指导。

更新2015-04-16~10:20

我想出了如何使用ActiveDirectoryLdapAuthenticationProvider添加搜索filter。 我还和Wireshark一起观看了我的应用服务器和AD服务器之间的交换,看看实际上做了什么。 以下是我的发现,我相信我对问题的解决方案并不遥远。 我更新了security-applicationContext.xml,因为我现在集中精力使ActiveDirectoryLdapAuthenticationProvider工作,所以我扔掉了ldap-server的东西。 所以,现在这是一个更清晰的配置:

                                      

很少有关于配置的评论。 在myADProvider bean定义中,构造函数的第一个参数fsapps.company.uni用于以username@fsapps.company.uniforms创建主体,并使用以下forms的baseObject构建搜索请求的baseObject:dc = fsapps, DC =公司,DC = UNI。

第二个构造函数的参数用于建立通信。 name =“searchFilter”的属性类型的下一个元素将调用ActiveDirectoryLdapAuthenticationProvider类的setSearchFilter()方法来设置搜索filter(这是我最初想要取得一些进展)。 因此,它现在设置为搜索(&(sAMAccountName = {0})(objectClass = user))。

通过这种设置,我可以在WireShark中看到LDAP对话并且绑定成功。 绑定响应是成功的。 接下来,搜索请求也会成功,但不会返回任何结果。 因此,我仍然在我的日志中获得以下内容:

 2015-04-16 10:30:28,201 DEBUG (ossaProviderManager.authenticate) [http-8443-2] Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider MDC{} 2015-04-16 10:30:28,201 DEBUG (osslaAbstractLdapAuthenticationProvider.authenticate) [http-8443-2] Processing authentication request for user: myusername MDC{} 2015-04-16 10:30:28,294 DEBUG (osslSpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-2] Searching for entry under DN '', base = 'dc=fsapps,dc=company,dc=uni', filter = '(&(sAMAccountName={0})(objectClass=user))' MDC{} 2015-04-16 10:30:28,294 INFO (osslSpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-2] Ignoring PartialResultException MDC{} 2015-04-16 10:30:28,310 DEBUG (osswaAbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials MDC{} 2015-04-16 10:30:28,310 DEBUG (osswaAbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Updated SecurityContextHolder to contain null Authentication MDC{} 2015-04-16 10:30:28,310 DEBUG (osswaAbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@2876b359 MDC{} 

我相信我几乎在那里,但如果有人可以提供任何帮助,我仍然可以使用一些帮助。 仔细检查后,看起来第一个构造函数的参数用于构造baseObject,而userPrincipalName是我的问题。 在我们的设置中,userPrincipalName使用的域名不是LDAPurl中的域名(即campus.company.com)。 到目前为止,我可以更改参数以匹配用于构建用户主体的域名。 现在,问题是这将改变必须匹配LDAP url架构的baseObject(即fsapps.company.uni)。

从文档中,只有一种方法可以设置搜索filter,但构造函数可以使用一个,两个或三个参数。 第三个参数是提供baseObject值。

然后我的问题通过以下配置解决,我必须使用所有可用的setter和构造函数的参数来使其工作。 myADProvider bean定义如下:

         

在我的情况下,现在可以省略searchFilter属性,因为我回退了默认值。 尽管对我的设置和问题进行了很长时间的描述。 我希望其他人可以从中受益。

以下是ActiveDirectorLdapAuthenticationProvider类文档的链接: http : //docs.spring.io/autorepo/docs/spring-security/4.0.0.RELEASE/apidocs/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider。 HTML

我发现WireShark非常有助于查看应用程序服务器和AD服务器之间发生了什么以调试此问题。

我无法使用Context.REFERRAL =“follow”来解决这个问题,实际上问题在于ActiveDirectoryLdapProvider类的方法searchForUser()的代码。 在此方法中,使用bindPrincipal调用SpringSecurityLdapTemplate.searchForSingleEntryInternal()方法,该实际上是userPrincipalName,由在第一个参数中传递给构造函数的参数和用户名组成。 因此,即使您将搜索filter设置为userPrincipalName以外的任何其他内容,也会将userPrincipalName作为参数0传递。因此,具有sAMAccountName的filter将无法与UPN一起使用并抛出exception。

应该修改或扩充searchForUser()以检测searchFilter需要用户名而不是UPN,或者提供额外的setter来使用searchFilter的模式设置参数。

但是在没有修改代码的情况下,没有办法让这个类在这种情况下正常工作。 这就是我最终做的。 我编写了自己的类,基本上是原始ActiveDirectoryLdapAUthenticationProvider的副本,对searchForUser()进行了一次简单的修改,将用户名而不是bindPrincipal传递给searchForSingleEntryInternal()。

你可以输入你想要的任何搜索filter,但强制只使用一个实际上是userPrincipalName的参数,而不是别的,这有点废话。

我遇到了类似的问题并进行了一些研究。 在我们的AD域名“my.company.com”中,我们似乎有两组用户,一组使用UPN,格式为user1@my.company.com,另一组使用user2 @ somethingelse。 COM。

当我使用org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider并尝试使用user1@my.company.com和user2@somethingelse.com对用户进行身份validation时 – 根据我传递给构造函数的内容,其中只有一个有效对于域名。

我不是AD专家,但是看看微软科技网文章: https : //technet.microsoft.com/en-us/library/cc739093(v = ws.10).aspx看起来像UPN后缀通常是一样的域名,它不是必须的,可以加上别的后缀。 引用那篇文章

UPN的第二部分(UPN后缀)标识用户帐户所在的域。 此UPN后缀可以是DNS域名,林中任何域的DNS名称,也可以是管理员创建的备用名称,仅用于登录目的。 此备用UPN后缀不需要是有效的DNS名称。

在Active Directory中,默认的UPN后缀是用户帐户在其中创建的域的DNS名称。 在大多数情况下,这是在Internet上注册为企业域的域名。 使用备用域名作为UPN后缀可以提供额外的登录安全性,并简化用于登录林中另一个域的名称。

例如,如果您的组织使用按部门和区域组织的深层域树,则域名可能会很长。 该域中用户的默认用户UPN可能是sales.westcoast.microsoft.com。 该域中用户的登录名称为user@sales.westcoast.microsoft.com。 创建UPN后缀“microsoft”将允许同一用户使用更简单的user @ microsoft登录名登录。 有关用户帐户的详细信息,请参阅用户和计算机帐户以及对象名称。

但我认为ActiveDirectoryLdapAuthenticationProvider.java似乎假设域名与UPN后缀相同。 我对ActiveDirectoryLdapAuthenticationProvider.java进行了本地修复,但没有做出这样的假设:

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

现在,具有不同UPN后缀的两个用户都是可搜索的。 如果我的假设是正确的,我可能会打开Spring安全性的错误。

在Spring Security 4.1.1 / SpringBoot 1.4.0环境中,我这样做(在Java中):

 @Configuration public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter { public void init (AuthenticationManagerBuilder aAuth) throws Exception { ActiveDirectoryLdapAuthenticationProvider myProvider = new ActiveDirectoryLdapAuthenticationProvider (ldapDomain, ldapUrl); aAuth.authenticationProvider (myProvider); aAuth.eraseCredentials (false); } } 

我没有遇到任何问题,用户可以使用sAMAccountName登录。