问题
I have a Grails application that is successfully using the latest spring-security-core:2.0-RC4 and spring-security-ldap:2.0-RC2. Users can login perfectly using grails.plugin.springsecurity.ldap.search.base setting for LDAP login authentication.
There is a different setting for the rememberMe userDnBase (mapper) and that setting is: grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.userDnBase
The LDAP authentication grails.plugin.springsecurity.ldap.search.base is set to ou=people,dc=sitcudy,dc=edu. As mentioned above - the logins work fine because there is a property called searchSubtree that I have set to true. Unfortunately, the searchSubtree setting does not hold true and carry through consistently within the 'remember-me' portion of the code (.ldap.rememberMe)*. The remember-me portion of the code uses a map for the base DN, grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.userDnBase so I put in a string in the config.groovy file (the same as for the authentication piece) to map to the base DN of ou=people,dc=sitcudy,dc=edu.... which gets mapped to the DN for the LDAP user look up upon returning to the application for persistence cookie login.
Here's where my problem comes in, most users are segregated into different DIT's in our LDAP system. For example, some uses are in ou=staff,ou=people,dc=sitcudy,dc=edu while other users are in ou=students,ou=people,dc=sitcudy,dc=edu therefore, because of the remember me mapping, upon returning to the application, once verifying the cookie, the code tries to bind users in this format, uid=reuben_marcus,ou=people,dc=sitcudy,dc=edu which doesn't exist. What does exist is uid=reuben_marcus,ou=staff,ou=people,dc=sitcudy,dc=edu therefore the cookie is destroyed and the login (IS_AUTHENTICATED_REMEMBERED) never occurs.
If I change grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.userDnBase to ou=staff,ou=people,dc=sitcudy,dc=edu the remember me functionality works perfect for all staff members, but it doesn't work for all other people - students, faculty etc.
The main setting in question below for me in this issue is: grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.userDnBase
Since this is just a mapping and there isn't allowance for multiple userDNBases or searchSubtree search.. How is the ‘remember-me’ code supposed to find users that do not fall into this base DN setting...??
I wonder if I'm doing something wrong or if this is a feature request to have the ‘remember me’ code have options for multiple mapping userDNBases or allow it to have a searchSubtree search capability.
Relevant settings from my config.groovy:
grails.plugin.springsecurity.ldap.mapper.roleAttributes = 'sitPriRole,uid'
grails.plugin.springsecurity.ldap.context.managerDn = 'uid=SPS_bind,ou=People,dc=sitcudy,dc=edu'
grails.plugin.springsecurity.ldap.context.managerPassword = 'xxx'
grails.plugin.springsecurity.ldap.context.server = 'ldap://ds01.sitcudy.edu:389'
grails.plugin.springsecurity.ldap.authorities.groupSearchBase ='ou=Groups,dc=sitcudy,dc=edu'
grails.plugin.springsecurity.ldap.search.base = 'ou=People,dc=sitcudy,dc=edu'
grails.plugin.springsecurity.ldap.search.searchSubtree = true
grails.plugin.springsecurity.ldap.auth.hideUserNotFoundExceptions = false
grails.plugin.springsecurity.ldap.search.attributesToReturn = ['uid', 'sitPriRole', 'mail', 'displayName']
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider', 'anonymousAuthenticationProvider', 'rememberMeAuthenticationProvider']
grails.plugin.springsecurity.ldap.authorities.retrieveGroupRoles = false
grails.plugin.springsecurity.ldap.authorities.retrieveDatabaseRoles = false
grails.plugin.springsecurity.password.algorithm = 'SHA-256'
grails.plugin.springsecurity.rememberMe.persistent = true
grails.plugin.springsecurity.rememberMe.persistentToken.domainClassName = 'od.PersistentLogin'
// role-specific LDAP config
// grails.plugin.springsecurity.ldap.useRememberMe = true
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.attributesToRetrieve = null
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.groupMemberAttributeName = 'uniquemember'
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.groupRoleAttributeName = 'cn'
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.groupSearchBase = 'ou=Groups,dc=sitcudy,dc=edu'
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.passwordAttributeName = 'userPassword'
grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.userDnBase = 'ou=People,dc=sitcudy,dc=edu'
grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.usernameAttribute = 'uid'
回答1:
This problem was mentioned here: Grails - Spring security plugin ldap: remember me not working
I found a workaround for this by registering custom TokenBasedRememberMeServices bean in resources.groovy
.
I didn't use persistent logins functionality available in grails-spring-security-ldap
plugin, because I found it incompatible with my Active Directory tree layout. Most probably, this could be customized by extending LdapUserDetailsManager
but in my situation I found it unnecessary to store token in database.
I used regular spring security remember me cookie option but without storing user password in the cookie. I extended the following methods from TokenBasedRememberMeServices
makeTokenSignature
- make token signature without password fieldprocessAutoLoginCookie
- if cookie exists, then retrieve username from cookie token and fetch ldap user details (I had to write my own methodretrieveUserFromLdap()
explained later)onLoginSuccess
- this gets triggered when user logs in with remember-me option checked. Here, I'm removing password and saving token signature to cookie.
To fetch user details and roles from LDAP it might depend on specific implementation but my method looks like this:
static protected UserDetails retrieveUserFromLdap(String username) {
def ldapUserSearch = Holders.applicationContext.getBean('ldapUserSearch')
def userContextMapper = Holders.applicationContext.getBean('ldapUserDetailsMapper')
def authoritiesPopulator = Holders.applicationContext.getBean('ldapAuthoritiesPopulator')
def userContext = ldapUserSearch.searchForUser(username)
def userAuthorities = authoritiesPopulator.getGrantedAuthorities(userContext,username)
userContextMapper.mapUserFromContext(userContext,username,userAuthorities)
}
来源:https://stackoverflow.com/questions/26784260/ldap-rememberme-usernamemapper-userdnbase-multiple-instances-of-searchsubtre