问题
I've been struggling with Spring Security LDAP for a while now, and just when I finally thought I had it beaten into submission, its tripped me up again.
The scenario: I'm having users log in using their organisation credentials, which I then check against the internal user database. If they don't exist, I create them locally and then set their local authorities (I can't touch the LDAP server, only authenticate against it - so I can't add the authorities there). This works fine... but I then want to add a couple of fields from LDAP - their full name and email address, and this is where it goes wrong.
I have LDAP searches working in a controller - using the following code (I've injected ldapTemplate further up):
def fullName = ldapTemplate.search("", "(uid=" + uid + "*)", new AttributesMapper() {
@Override
public Object mapFromAttributes(Attributes attrs) throws NamingException {
return attrs.get("cn").get()
}
})
and this works perfectly. But when I replicate this code in a service that is called post-authentication the ldapTemplate is always null... I've tried a few different things, but I can't get it to populate properly... can anyone shed some light on why? I'm hoping its something stupid I'm doing since its 4:21am and I should have been in bed about 6 hours ago...
EDIT: Here is the service code as requested, thanks for taking a look Burt - its currently not very robust as I haven't got it working past simply creating a new local user - there is work to do on it yet.
package com.myPackage
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import org.springframework.ldap.core.AttributesMapper
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.apache.commons.lang.RandomStringUtils
class PostAuthHandlerService implements AuthenticationSuccessHandler {
def springSecurityService
def ldapTemplate
private AuthenticationSuccessHandler target = new SavedRequestAwareAuthenticationSuccessHandler();
private List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication auth) {
def username = auth.principal.getAt("username")
User.withTransaction { status ->
// Check to see if this user exists in the local db
def user = User.findByUsername(username)
if (!user) { // User doesn't exist yet, so create and make a user...
def userRole = Role.findByAuthority('ROLE_USER') ?:
new Role(authority: 'ROLE_AM').save(failOnError: true)
user = new User(
username: username,
password: auth.getCredentials() ?: placeholderPassword(),
displayName: getLdapDetails("username", "cn") ?: "",
email: getLdapDetails("username", "mail") ?: "",
enabled: true).save(failOnError: true)
UserRole.create user, userRole
}
else {
println("--- You exist already! Updating details")
user.displayName = getLdapDetails("username", "cn") ?: ""
}
target.onAuthenticationSuccess(request, response, auth)
}
}
def getLdapDetails(username, attr) {
return ldapTemplate.search("", "(uid=$username*)", new AttributesMapper() {
@Override
public Object mapFromAttributes(Attributes attrs) throws NamingException {
return attrs.get(attr).get()
}
})
}
def placeholderPassword () {
// This is here because we also allow local logins for some users.
// If the password is not available, then create a big ugly one...
return org.apache.commons.lang.RandomStringUtils.randomAlphanumeric(128)
}
public void proceed(HttpServletRequest request,
HttpServletResponse response, Authentication auth) {
target.onAuthenticationSuccess(request, response, auth)
}
}
2nd Edit: I've been trying various different things - including trying to use springSecurityService.reauthenticate to get the local user to be used during the session rather than the LDAP one - and this bean is null as well... it seems like I can't inject any beans into my service at all.
I eventually found this post: http://burtbeckwith.com/blog/?p=993 which gave me a workaround and I now have it working... but I'd still like to know why it didn't in the first place... I have so much to learn in Grails - and its hard to know where to start.
Cheers in advance
Steve
回答1:
How are you injecting authenticationSuccessHandler ? You should try defining authenticationSuccessHandler in resources.xml
Grails 1.3.5 and Spring Security Core
来源:https://stackoverflow.com/questions/9141915/injecting-ldaptemplate-to-return-user-details-inside-a-grails-service-causes-nul