LDAP AD Spring 当域与 userPrincipalName 结尾不匹配时安全验证失败
LDAP AD Spring Security authentication fails when domain does not match userPrincipalName ending
我正在使用 ActiveDirectoryLdapAuthenticationProvider
对 AD 服务器进行身份验证。它适用于大多数环境,但当域名与个人用户 userPrincipalName
的结尾不相同时会出现问题。
我设置了以下属性:
xxx.api.auth.ad.domain:foo.bar.com
xxx.api.auth.ad.url:ldaps://yyy.foo.bar.com:636
并且用户 userPrincipalName
设置为 john.doe@bar.com
。注意与域名的区别
然后在我的 LoginService
我有这个:
private AuthResultDto loginAD(LoginDto login) {
String adDomain = env.getProperty("xxx.api.auth.ad.domain");
String adUrl = env.getProperty("xxx.api.auth.ad.url");
ActiveDirectoryLdapAuthenticationProvider provider =
new ActiveDirectoryLdapAuthenticationProvider(adDomain, adUrl);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(new InetOrgPersonContextMapper());
Authentication auth = provider
.authenticate(new UsernamePasswordAuthenticationToken(login.getEmail(), login.getPassword()));
if (!auth.isAuthenticated())
throw new CustomMessageException("Invalid Login");
...
}
在这种情况下,身份验证失败并显示消息 Active Directory authentication failed: Supplied password was invalid
。
spring-ldap-core:2.3.2.RELEASE
spring-security-ldap:5.0.3.RELEASE
问题似乎是 ActiveDirectoryLdapAuthenticationProvider
中的 createBindPrincipal()
检查 username
是否以 domain
结尾,如果不是,则 appends it。这导致用户名变为 john.doe@bar.com@foo.bar.com
不幸的是,ActiveDirectoryLdapAuthenticationProvider
是最终的,因此无法覆盖它。我们采用的解决方案是不传递 domain
,而是传递 rootDN
(通过从 ActiveDirectoryLdapAuthenticationProvider
复制代码构建)
private AuthResultDto loginAD(LoginDto login) {
String adDomain = env.getProperty("xxx.api.auth.ad.domain");
String adUrl = env.getProperty("xxx.api.auth.ad.url");
ActiveDirectoryLdapAuthenticationProvider provider =
new ActiveDirectoryLdapAuthenticationProvider(null, adUrl, rootDnFromDomain(adDomain));
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(new InetOrgPersonContextMapper());
Authentication auth = provider
.authenticate(new UsernamePasswordAuthenticationToken(login.getEmail(), login.getPassword()));
if (!auth.isAuthenticated())
throw new CustomMessageException("Invalid Login");
...
}
// copied from ActiveDirectoryLdapAuthenticationProvider
private String rootDnFromDomain(String domain) {
String[] tokens = StringUtils.tokenizeToStringArray(domain, ".");
StringBuilder root = new StringBuilder();
for (String token : tokens) {
if (root.length() > 0) {
root.append(',');
}
root.append("dc=").append(token);
}
return root.toString();
}
我正在使用 ActiveDirectoryLdapAuthenticationProvider
对 AD 服务器进行身份验证。它适用于大多数环境,但当域名与个人用户 userPrincipalName
的结尾不相同时会出现问题。
我设置了以下属性:
xxx.api.auth.ad.domain:foo.bar.com
xxx.api.auth.ad.url:ldaps://yyy.foo.bar.com:636
并且用户 userPrincipalName
设置为 john.doe@bar.com
。注意与域名的区别
然后在我的 LoginService
我有这个:
private AuthResultDto loginAD(LoginDto login) {
String adDomain = env.getProperty("xxx.api.auth.ad.domain");
String adUrl = env.getProperty("xxx.api.auth.ad.url");
ActiveDirectoryLdapAuthenticationProvider provider =
new ActiveDirectoryLdapAuthenticationProvider(adDomain, adUrl);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(new InetOrgPersonContextMapper());
Authentication auth = provider
.authenticate(new UsernamePasswordAuthenticationToken(login.getEmail(), login.getPassword()));
if (!auth.isAuthenticated())
throw new CustomMessageException("Invalid Login");
...
}
在这种情况下,身份验证失败并显示消息 Active Directory authentication failed: Supplied password was invalid
。
spring-ldap-core:2.3.2.RELEASE
spring-security-ldap:5.0.3.RELEASE
问题似乎是 ActiveDirectoryLdapAuthenticationProvider
中的 createBindPrincipal()
检查 username
是否以 domain
结尾,如果不是,则 appends it。这导致用户名变为 john.doe@bar.com@foo.bar.com
不幸的是,ActiveDirectoryLdapAuthenticationProvider
是最终的,因此无法覆盖它。我们采用的解决方案是不传递 domain
,而是传递 rootDN
(通过从 ActiveDirectoryLdapAuthenticationProvider
复制代码构建)
private AuthResultDto loginAD(LoginDto login) {
String adDomain = env.getProperty("xxx.api.auth.ad.domain");
String adUrl = env.getProperty("xxx.api.auth.ad.url");
ActiveDirectoryLdapAuthenticationProvider provider =
new ActiveDirectoryLdapAuthenticationProvider(null, adUrl, rootDnFromDomain(adDomain));
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(new InetOrgPersonContextMapper());
Authentication auth = provider
.authenticate(new UsernamePasswordAuthenticationToken(login.getEmail(), login.getPassword()));
if (!auth.isAuthenticated())
throw new CustomMessageException("Invalid Login");
...
}
// copied from ActiveDirectoryLdapAuthenticationProvider
private String rootDnFromDomain(String domain) {
String[] tokens = StringUtils.tokenizeToStringArray(domain, ".");
StringBuilder root = new StringBuilder();
for (String token : tokens) {
if (root.length() > 0) {
root.append(',');
}
root.append("dc=").append(token);
}
return root.toString();
}