dtrunk
dtrunk

Reputation: 4805

Spring Security LDAP and MD5 hashed passwords

I'm trying to access my project using LDAP. It prompts for username and password successfully, but put the correct credentials in it causes the prompt popup again (it seems the credentials are wrong, but they aren't).

Here's my 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>

Passwords are stored as {MD5}hash... And I'm using jsr 250 api.

EDIT: @TobyHobson this results in 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.

EDIT2: @TobyHobson putting password-compare around password-encoder seems to compile, but it still rejects my correct credentials.

EDIT3: Here are necessary logs:

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: I guess it has something to do with jsr 250 api and groups/roles. Here's my ldif:

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

dn: uid=demo_admin,ou=people,dc=ubuntu,dc=local
userPassword: {MD5}fe01ce2a7fbac8fafaed7c982a04e229
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: {MD5}fe01ce2a7fbac8fafaed7c982a04e229
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: {MD5}fe01ce2a7fbac8fafaed7c982a04e229
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

I used @RolesAllowed({ Role.ROLE_ADMIN, Role.ROLE_MANAGER, Role.ROLE_VIEWER }) in my controller and this is my absract role class:

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";
}

Upvotes: 2

Views: 7938

Answers (3)

Anil Kumar
Anil Kumar

Reputation: 1501

There in no need to defining hashing in spring security configuration file,the hashing technique will be handled by ldap itself. The only one thing you have to do is storing the MD5 password in ldap like this....

              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());

Upvotes: 1

Shaun the Sheep
Shaun the Sheep

Reputation: 22752

The password encoding scheme is immaterial when using bind authentication, because the password check is performed in the directory, not within Spring Security code, so Spring Security has no need to hash the password or have any knowledge of how it is stored. It will be sent as plaintext to the directory so you should use an ldaps connection if you are concerned about that.

If you were authenticating using an LDAP "compare" operation, then you would have to send an identical copy of the password field to the directory. This is error prone as it depends on the case being correct, etc. There is also no current provided support for {MD5} hashes, though there is an LdapShaPasswordEncoder which handles {SHA} and {SSHA}.

Most likely your setup is failing for some other reason, which should be clear from a closer exmination of the debug logs and your LDAP server log.

Upvotes: 0

user404345
user404345

Reputation:

You need to add a password encoder to your authentication provider to tell Spring to hash the password before binding in LDAP. e.g.

<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>

If you use a salt you would also need to include this e.g.

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

Upvotes: 1

Related Questions