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进行抽取。