OpenLDap Spring集成:Bad Credentials
我有OSX上运行的openldap(虽然将转移到生产时运行IPA的centos)。OpenLDap Spring集成:Bad Credentials
简单的弹簧引导应用程序除了单个家庭控制器,弹簧安全和ldap启动器外没有任何东西。 POM依赖关系如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
除了依赖上面我有一个配置类,如下所示:
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and().formLogin();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userDnPatterns("uid={0},ou=users")
.groupSearchBase("ou=groups")
.contextSource(contextSource())
.passwordCompare()
.passwordEncoder(new LdapShaPasswordEncoder())
.passwordAttribute("userPassword");
}
@Bean
public DefaultSpringSecurityContextSource contextSource() {
return new DefaultSpringSecurityContextSource(Arrays.asList("ldap://localhost:389/"), "dc=m,dc=com");
}
}
我的LDAP目录是非常简单的,它具有如下:
# m.com
dn: dc=m,dc=com
objectClass: dcObject
objectClass: organization
o: M
dc: m
# users, m.com
dn: ou=users,dc=m,dc=com
objectClass: organizationalUnit
ou: users
# taylorj, users, m.com
dn: uid=taylorj,ou=users,dc=m,dc=com
objectClass: top
objectClass: account
objectClass: posixAccount
cn: Jonathan Taylor
uid: taylorj
uidNumber: 1
gidNumber: 1
homeDirectory: /home/taylorj
userPassword:: e1NTSEF9UVNVNDBOdlh1bkJqNkhGeVUwekVVYXlNb2RidTErekg=
当我运行Spring应用程序时,它连接到LDAP,我可以看到在LDAP服务器上进入的请求,我可以看到它搜索确定并返回一个结果,然后对使用进行CMP rPassword属性,但是,LDAP则返回错误代码5(LDAP_COMPARE_FALSE)和春天,我看到以下异常:
2017-09-13 15:52:13.315 DEBUG 92002 --- [nio-8132-exec-3] o.s.s.l.a.LdapAuthenticationProvider : Processing authentication request for user: taylorj
2017-09-13 15:52:13.317 DEBUG 92002 --- [nio-8132-exec-3] o.a.c.loader.WebappClassLoaderBase : findResources(jndi.properties)
2017-09-13 15:52:13.330 DEBUG 92002 --- [nio-8132-exec-3] o.s.l.c.support.AbstractContextSource : Got Ldap context on server 'ldap://localhost:389/dc=m,dc=com'
2017-09-13 15:52:13.339 DEBUG 92002 --- [nio-8132-exec-3] .s.s.l.a.PasswordComparisonAuthenticator : Performing LDAP compare of password attribute 'userPassword' for user 'uid=taylorj,ou=users'
2017-09-13 15:52:13.340 DEBUG 92002 --- [nio-8132-exec-3] o.s.l.c.support.AbstractContextSource : Got Ldap context on server 'ldap://localhost:389/dc=m,dc=com'
2017-09-13 15:52:13.342 DEBUG 92002 --- [nio-8132-exec-3] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-09-13 15:52:13.342 DEBUG 92002 --- [nio-8132-exec-3] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
org.springframework.security.authentication.BadCredentialsException: Bad credentials
at org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator.authenticate(PasswordComparisonAuthenticator.java:114) ~[spring-security-ldap-4.2.3.RELEASE.jar:4.2.3.RELEASE]
我真的不知道我在做什么错,因为它似乎是某种内部的弹簧事件正在导致密码比较失败。
任何想法?
UPDATE
我恢复到春天提供LDIF,而且工作得很好。沮丧,我然后运行以下来更改由用户提供的弹簧LDIF的密码
ldappasswd -x -D“cn = admin,dc = m,dc = com”-W -S“uid = ben, OU =人,DC = M,DC = COM”
运行此命令后,我登录不再起作用
看着Spring提供的LDIF:
dn: uid=ben,ou=people,dc=m,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
好像被设置密码作为SHA,而当我运行ldappasswd时,它最终成为盐渍SHA {SSHA}。据我从文档中可以看到,尽管如此,Spring实现应该同时处理SHA和SSHA。
虽然还不确定发生了什么。
事实证明,spring-security有一个bug。
org.springframework.security.ldap.authentication。 PasswordComparisonAuthenticator
setPasswordEncoder方法的初始行:
public void setPasswordEncoder(Object passwordEncoder) {
if (passwordEncoder instanceof PasswordEncoder) {
this.usePasswordAttrCompare = false;
setPasswordEncoder((PasswordEncoder) passwordEncoder);
return;
}
在此它设置usePasswordAttrCompare
到假如果密码编码器类型的的PasswordEncoder。与此问题是,当此标志设置为错误它回落到获取LDAP进行密码比较。由于密码存储为SSHA,因此Spring无法提前知道SHA Salt,因此只发送SHA1版本的密码,这显然不匹配。
在authenticate()的
else if (isLdapPasswordCompare(user, ldapTemplate, password)) {
return user;
}
由于LdapShaPasswordEncoder的实现方式中,编码功能只需明文口令,而isPasswordValid用于比较需要两个明文口令和哈希密码,因此可以通过提取盐来计算SSHA变体。
我作如下修改(我会回去做正确的某些点)setPasswordEncoder
功能:
if (passwordEncoder instanceof PasswordEncoder) {
if(passwordEncoder instanceof org.springframework.security.authentication.encoding.LdapShaPasswordEncoder) {
this.usePasswordAttrCompare = true;
} else {
this.usePasswordAttrCompare = false;
}
setPasswordEncoder((PasswordEncoder) passwordEncoder);
return;
}
在我们有一个LdapShaPasswordEncoder我们会一直回落到isPasswordValid方法的情况下,其处理明文,SHA和SSHA密码。
重建弹簧安全并重新对我的代码对新的罐子工作正常。现在想出一个更好的方法来做到这一点,并将其提交给Spring进行抽取。