Spring Security LDAP 和 MD5 哈希密码

Posted

技术标签:

【中文标题】Spring Security LDAP 和 MD5 哈希密码【英文标题】:Spring Security LDAP and MD5 hashed passwords 【发布时间】:2012-03-28 17:34:31 【问题描述】:

我正在尝试使用 LDAP 访问我的项目。 它成功提示输入用户名和密码,但在其中输入正确的凭据会导致再次弹出提示(似乎凭据错误,但事实并非如此)。

这是我的 security-context.xml:

<?xml version="1.0" encoding="utf-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/security
                                 http://www.springframework.org/schema/security/spring-security.xsd">

  <ldap-server url="ldap://$ldap.host:$ldap.port/$ldap.root" manager-dn="$ldap.manager.dn" manager-password="$ldap.manager.password" />

  <authentication-manager>
    <ldap-authentication-provider group-search-base="$ldap.group.search.base" user-search-filter="(uid=0)" user-search-base="$ldap.user.search.base" />
  </authentication-manager>

  <http use-expressions="true">
    <intercept-url pattern="/**" />
    <http-basic />
  </http>

</beans:beans>

密码存储为MD5哈希... 我正在使用 jsr 250 api。

编辑: @TobyHobson 这导致org.xml.sax.SAXParseException; lineNumber: 14; columnNumber: 38; cvc-complex-type.2.4.a: Invalid content was found starting with element 'password-encoder'. One of '"http://www.springframework.org/schema/security":password-compare' is expected.

编辑2: @TobyHobson 将 password-compare 放在 password-encoder 周围似乎可以编译,但它仍然拒绝我的正确凭据。

编辑3: 以下是必要的日志:

DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'sessionFactory'
DEBUG: org.springframework.security.web.FilterChainProxy - /licenses/index.html at position 1 of 8 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@397af435. A new one will be created.
DEBUG: org.springframework.security.web.FilterChainProxy - /licenses/index.html at position 2 of 8 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Basic Authentication Authorization header found for user 'demo_admin'
DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
DEBUG: org.springframework.security.ldap.authentication.LdapAuthenticationProvider - Processing authentication request for user: demo_admin
DEBUG: org.springframework.security.ldap.search.FilterBasedLdapUserSearch - Searching for user 'demo_admin', with user search [ searchFilter: '(uid=0)', searchBase: 'ou=people', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]
DEBUG: org.springframework.security.ldap.SpringSecurityLdapTemplate - Searching for entry under DN 'dc=ubuntu,dc=local', base = 'ou=people', filter = '(uid=0)'
DEBUG: org.springframework.security.ldap.SpringSecurityLdapTemplate - Found DN: uid=demo_admin,ou=people
DEBUG: org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator - Performing LDAP compare of password attribute 'userPassword' for user 'uid=demo_admin,ou=people'
DEBUG: org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

EDIT4:我想这与 jsr 250 api 和组/角色有关。 这是我的 ldif:

dn: ou=people,dc=ubuntu,dc=local
objectClass: organizationalUnit
ou: people

dn: uid=demo_admin,ou=people,dc=ubuntu,dc=local
userPassword: MD5fe01ce2a7fbac8fafaed7c982a04e229
objectClass: posixAccount
objectClass: account
homeDirectory: null
uid: demo_admin
uidNumber: 1001
gidNumber: 1000
cn: Demo Admin

dn: uid=demo_manager,ou=people,dc=ubuntu,dc=local
userPassword: MD5fe01ce2a7fbac8fafaed7c982a04e229
objectClass: posixAccount
objectClass: account
homeDirectory: null
uid: demo_manager
uidNumber: 2001
gidNumber: 2000
cn: Demo Manager

dn: uid=demo_viewer,ou=people,dc=ubuntu,dc=local
userPassword: MD5fe01ce2a7fbac8fafaed7c982a04e229
objectClass: posixAccount
objectClass: account
homeDirectory: null
uid: demo_viewer
uidNumber: 3001
gidNumber: 3000
cn: Demo Viewer

dn: ou=groups,dc=ubuntu,dc=local
objectClass: organizationalUnit
ou: groups

dn: cn=Admins,ou=groups,dc=ubuntu,dc=local
objectClass: posixGroup
cn: Admins
gidNumber: 1000

dn: cn=Managers,ou=groups,dc=ubuntu,dc=local
objectClass: posixGroup
cn: Managers
gidNumber: 2000

dn: cn=Viewers,ou=groups,dc=ubuntu,dc=local
objectClass: posixGroup
cn: Viewers
gidNumber: 3000

我在控制器中使用了@RolesAllowed( Role.ROLE_ADMIN, Role.ROLE_MANAGER, Role.ROLE_VIEWER ),这是我的抽象角色类:

public abstract class Role

  public static final String ROLE_ADMIN = "Admins";
  public static final String ROLE_MANAGER = "Managers";
  public static final String ROLE_VIEWER = "Viewers";

【问题讨论】:

您写道“密码存储为 MD5hash”。您的意思是在您的配置文件中,编码的密码在绑定请求中传输到目录服务器? 密码存储为 md5 哈希值。如果凭据正确,它应该将编码的密码传输到服务器以获得好的回复。我不想在服务器端做一些质量检查之类的事情——这只是为了登录...... 【参考方案1】:

您需要向您的身份验证提供程序添加一个password encoder,以告诉 Spring 在绑定到 LDAP 之前对密码进行哈希处理。例如

<authentication-manager>
  <ldap-authentication-provider group-search-base="$ldap.group.search.base" user-search-filter="(uid=0)" user-search-base="$ldap.user.search.base">
    <password-encoder hash="md5"/>
  </ldap-authentication-provider>
</authentication-manager>

如果你使用盐,你还需要包括这个,例如

<password-encoder hash="md5">
  <salt-source user-property="username"/>
</password-encoder>

【讨论】:

注意:如果目录服务器被用于检查密码质量和密码历史,传输一个预编码的、不可逆的密码将使服务器无法执行上述检查。 这是不正确的。标准 Spring Security MD5 密码编码器与 LDAP 哈希或绑定身份验证不兼容。【参考方案2】:

密码编码方案在使用绑定认证时无关紧要,因为密码检查是在目录中进行的,而不是在 Spring Security 代码中,所以 Spring Security 不需要对密码进行哈希处理,也不需要知道密码是如何存储的。它将以明文形式发送到目录,因此如果您担心的话,应该使用 ldaps 连接。

如果您使用 LDAP“比较”操作进行身份验证,则必须将密码字段的相同副本发送到目录。这很容易出错,因为它取决于大小写是否正确等。目前还没有提供对 MD5 哈希的支持,尽管有一个处理 SHA 和 SSHA 的LdapShaPasswordEncoder

您的设置很可能由于某些其他原因而失败,仔细检查调试日志和您的 LDAP 服务器日志应该会清楚这一点。

【讨论】:

在 slapd.conf 中将 loglevel 设为 296,我在 slapd.log 中只能看到 &lt;= bdb_equality_candidates: (uid) not indexed 如果您在 slapd 中有完整的登录,那么您应该看到所有内容,包括使用 DN、密码等解组绑定请求。也请检查 Spring Security 调试日志。开始时可能找不到用户。【参考方案3】:

spring 安全配置文件中不需要定义散列,散列技术将由 ldap 自己处理。 您唯一需要做的就是像这样将 MD5 密码存储在 ldap 中......

              Attributes attrs = new BasicAttributes();
      BasicAttribute ocattr = new BasicAttribute("objectclass");
      ocattr.add("top");
      ocattr.add("person");
      ocattr.add("inetorgperson");
      ocattr.add("organizationalperson");
      attrs.put(ocattr);
      attrs.put("sn",user.getName());
      attrs.put("userPassword","MD5"+user.getPassword());

【讨论】:

以上是关于Spring Security LDAP 和 MD5 哈希密码的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security和LDAP身份验证

基于Spring LDAP和Spring Security的用户认证和权限控制Web实现

使用 Spring Security 的 ldap 身份验证

Spring Security LDAP 和记住我

如何使用带有 LDAP 的 Spring Security 获取用户信息

Spring 3,Spring Security,LDAP,如何向 LDAP 添加角色?