Search code examples
grailsspring-securityldapopenldapslapd

Grails OpenLDAP login failed: Sorry, we were not able to find a user with that username and password


I am trying to add a Ldap login to my grails app. after adding the spring-secutiry-core and spring-security-ldap (2.0.1) plugin, i added configuration in config.groovy:

grails.plugin.springsecurity.providerNames = ['ldapAuthProvider','anonymousAuthenticationProvider','rememberMeAuthenticationProvider']
grails.plugin.springsecurity.ldap.context.managerDn = 'uid=admin,dc=sw01,dc=com'
grails.plugin.springsecurity.ldap.context.managerPassword = 'Admin123'
grails.plugin.springsecurity.ldap.context.server = 'ldap://localhost:389'
grails.plugin.springsecurity.ldap.context.anonymousReadOnly = true
grails.plugin.springsecurity.ldap.authorities.groupSearchBase = 'ou=Groups,dc=sw01,dc=com'
grails.plugin.springsecurity.ldap.authorities.retrieveGroupRoles = false
grails.plugin.springsecurity.ldap.authorities.retrieveDatabaseRoles = false
grails.plugin.springsecurity.ldap.authorities.groupSearchFilter = 'member={0}'
grails.plugin.springsecurity.ldap.useRememberMe = false
grails.plugin.springsecurity.ldap.search.base = 'dc=sw01,dc=com'
grails.plugin.springsecurity.ldap.search.attributesToReturn = ['uid', 'mail', 'cn', 'sn', 'givenName', 'jpegPhoto' , 'telephoneNumber']
grails.plugin.springsecurity.ldap.search.filter = '(uid={0})'
grails.plugin.springsecurity.ldap.authenticator.attributesToReturn = ['uid', 'mail', 'cn', 'sn', 'givenName', 'jpegPhoto' , 'telephoneNumber']
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'uid'

I added my userDetails class, details contextMapper class as following the official guide.

When loading up the Grails app and trying to log in, the error message as in the title is shown.

While looking at the background slapd log, I am quite sure (not familiar with slapd log format, though) the user's DN search had been successful... :

5ac1d79a => send_search_entry: conn 1017 dn="uid=sito,ou=Users,dc=sw01,dc=com"
ber_flush2: 3768 bytes to sd 15
ldap_write: want=3768, written=3768
  0000:  30 82 0e b4 02 01 01 64  82 0e ad 04 20 75 69 64   0......d.... uid  
  0010:  3d 73 69 74 6f 2c 6f 75  3d 55 73 65 72 73 2c 64   =sito,ou=Users,d  
  0020:  63 3d 73 77 30 31 2c 64  63 3d 63 6f 6d 30 82 0e   c=sw01,dc=com0..  
  0030:  87 30 5e 04 0b 6f 62 6a  65 63 74 43 6c 61 73 73   .0^..objectClass  
  0040:  31 4f 04 10 65 78 74 65  6e 73 69 62 6c 65 4f 62   1O..extensibleOb  
  0050:  6a 65 63 74 04 09 75 69  64 4f 62 6a 65 63 74 04   ject..uidObject.  
  0060:  06 70 65 72 73 6f 6e 04  14 6f 72 67 61 6e 69 7a   .person..organiz  
  0070:  61 74 69 6f 6e 61 6c 50  65 72 73 6f 6e 04 0d 69   ationalPerson..i  
  0080:  6e 65 74 4f 72 67 50 65  72 73 6f 6e 04 03 74 6f   netOrgPerson..to  
  0090:  70 30 16 04 02 63 6e 31  10 04 0e 41 6c 66 6f 6e   p0...cn1...Alfon  
  00a0:  73 6f 20 52 69 76 65 72  6f 30 16 04 09 67 69 76   so Rivero0...giv

...

ber_get_next
ldap_read: want=8 error=Resource temporarily unavailable
5ac1d79a conn=1018 op=0 do_bind
ber_scanf fmt ({imt) ber:
ber_scanf fmt (m}) ber:
5ac1d79a >>> dnPrettyNormal: <uid=sito,ou=Users,dc=sw01,dc=com>
5ac1d79a <<< dnPrettyNormal: <uid=sito,ou=Users,dc=sw01,dc=com>, <uid=sito,ou=users,dc=sw01,dc=com>
5ac1d79a do_bind: version=3 dn="uid=sito,ou=Users,dc=sw01,dc=com" method=128
5ac1d79a mdb_dn2entry("uid=sito,ou=users,dc=sw01,dc=com")
5ac1d79a => mdb_dn2id("uid=sito,ou=users,dc=sw01,dc=com")
5ac1d79a <= mdb_dn2id: got id=0xd
5ac1d79a => mdb_entry_decode:
5ac1d79a <= mdb_entry_decode
5ac1d79a send_ldap_result: conn=1018 op=0 p=3
5ac1d79a send_ldap_response: msgid=1 tag=97 err=49
ber_flush2: 14 bytes to sd 16
ldap_write: want=14, written=14
  0000:  30 0c 02 01 01 61 07 0a  01 31 04 00 04 00         0....a...1....    
5ac1d79a connection_get(16): got connid=1018
5ac1d79a connection_read(16): checking for input on id=1018
ber_get_next
ldap_read: want=8, got=0

5ac1d79a ber_get_next on fd 16 failed errno=0 (Undefined error: 0)
5ac1d79a connection_close: conn=1018 sd=16

But yet the page still show no matching username and password. I had try both with and without the following config line, same error:

grails.plugin.springsecurity.password.algorithm = 'SHA-256'

Did I had some config wrong, or miss out anything in the implementation? Please help, any info is much appreciated!

[Update 20180403]

So I did a bit more digging. I modified the auto generated LoginController.groovy authfail() action and printout the exception stacktrace:

| Error org.springframework.security.authentication.BadCredentialsException: Bad credentials
| Error     at org.springframework.security.ldap.authentication.BindAuthenticator.authenticate(BindAuthenticator.java:95)
| Error     at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:178)
| Error     at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:80)
| Error     at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
| Error     at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:92)
| Error     at grails.plugin.springsecurity.web.authentication.GrailsUsernamePasswordAuthenticationFilter.attemptAuthentication(GrailsUsernamePasswordAuthenticationFilter.java:59)
| Error     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
| Error     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)

It's happening at org.springframework.security.ldap.authentication.BindAuthenticator with a BadCredentialsException exception...

But I do have the users imported from a sample ldif (also verified with JXplorer browser):

dn: uid=mcurie,ou=Users,dc=sw01,dc=com
objectClass: uidObject
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
cn: Marie Curie
facsimileTelephoneNumber: +1 904 982 6883
givenName: Marie
mail: [email protected]
ou: Users
roomNumber: 667
sn: Curie
telephoneNumber: +1 904 982 6882
uid: mcurie
userPassword:: c2VjcmV0

The only thing is, I do not have a 'userName' field to user, so I am using the 'uid' to login, also specified in config.groovy:

grails.plugin.springsecurity.userLookup.usernamePropertyName = 'uid'

Is the above correct, or I am still missing something else?

Any info/help much appreciated!

[UPDATE 20180406]

So I go back to the most basic, just test out from the ldap commands search and bind a user:

$ ldapsearch -D 'cn=admin,dc=sw01,dc=com' -W -x -b 'uid=wpauli,ou=Users,dc=sw01,dc=com'
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <uid=wpauli,ou=Users,dc=sw01,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# wpauli, Users, sw01.com
dn: uid=wpauli,ou=Users,dc=sw01,dc=com
objectClass: uidObject
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
cn: Wolfgang Pauli
facsimileTelephoneNumber: +1 904 982 6883
givenName: Wolfgang
mail: [email protected]
ou: Users
roomNumber: 667
sn: Pauli
telephoneNumber: +1 904 982 6882
uid: wpauli
userPassword:: c2VjcmV0

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

And then (not sure I need single quotes around DN, so I tried both, both failed):

$ ldapwhoami -vvv -h localhost -p 389 -D 'uid=wpauli,ou=Users,dc=sw01,dc=com' -x -w c2VjcmV0
ldap_initialize( ldap://localhost:389 )
ldap_bind: Invalid credentials (49)

$ ldapwhoami -vvv -h localhost -p 389 -D uid=wpauli,ou=Users,dc=sw01,dc=com -x -w c2VjcmV0
ldap_initialize( ldap://localhost:389 )
ldap_bind: Invalid credentials (49)

Why did it failed to bind? The password used was matching the one returned by the Ldapsearch result above?

Help anyone?


Solution

  • Ah I got it sorted. Looked back closely at the sample LDIF file I used, the line populating the userPassword has double-colon '::', that means the password is base64-encoded...

    telephoneNumber: +1 904 982 6882
    uid: sito
    userPassword:: c2VjcmV0
    

    I ran the value 'c2VjcmV0' through a base64 decoder, it's 'secret'. duh...

    So now changing the ldapwhoami test with the proper password

    From:

    $ ldapwhoami -vvv -h localhost -p 389 -D uid=wpauli,ou=Users,dc=sw01,dc=com -x -w c2VjcmV0
    

    To:

    $ ldapwhoami -vvv -h localhost -p 389 -D uid=wpauli,ou=Users,dc=sw01,dc=com -x -w secret 
    

    had successfully authenticated it.

    And going back to my sample Grails App login with the proper password also can now login with no problem.