在Grails服务中注入LdapTemplate以返回用户详细信息会导致空指针异常

在Grails服务中注入LdapTemplate以返回用户详细信息会导致空指针异常,grails,spring-security,ldap,spring-ldap,Grails,Spring Security,Ldap,Spring Ldap,我已经和SpringSecurityLDAP斗争了一段时间了,就在我最终认为它已经被打败而屈服的时候,它又把我绊倒了 场景:我让用户使用他们的组织凭据登录,然后根据内部用户数据库进行检查。如果它们不存在,我将在本地创建它们,然后设置它们的本地权限(我不能接触LDAP服务器,只能对其进行身份验证,因此我无法在那里添加权限)。这个很好用。。。但是我想从LDAP中添加几个字段——它们的全名和电子邮件地址,这就是问题所在 我在控制器中使用LDAP搜索-使用以下代码(我已进一步注入ldapTemplate

我已经和SpringSecurityLDAP斗争了一段时间了,就在我最终认为它已经被打败而屈服的时候,它又把我绊倒了

场景:我让用户使用他们的组织凭据登录,然后根据内部用户数据库进行检查。如果它们不存在,我将在本地创建它们,然后设置它们的本地权限(我不能接触LDAP服务器,只能对其进行身份验证,因此我无法在那里添加权限)。这个很好用。。。但是我想从LDAP中添加几个字段——它们的全名和电子邮件地址,这就是问题所在

我在控制器中使用LDAP搜索-使用以下代码(我已进一步注入ldapTemplate):

这是完美的。但是,当我在一个名为post-authentication的服务中复制这段代码时,ldapTemplate总是空的。。。我尝试了一些不同的方法,但我无法让它正确填充。。。有人能解释一下原因吗?我希望从凌晨4:21开始我就在做一些愚蠢的事情,我应该在6小时前就上床睡觉了

编辑:这是所要求的服务代码,感谢您查看Burt-它目前不是很健壮,因为我在创建一个新的本地用户之前还没有工作过-还有工作要做

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

第二次编辑:我一直在尝试各种不同的事情-包括尝试使用springSecurityService.reauthenticate来获取会话期间使用的本地用户,而不是LDAP用户-这个bean也是空的。。。看起来我根本无法向我的服务中注入任何bean

我终于找到了这篇文章:这篇文章给了我一个变通的方法,我现在让它工作了。。。但我还是想知道为什么一开始它没有。。。在Grails中,我有很多东西要学——很难知道从哪里开始

提前欢呼


Steve

您如何注入authenticationSuccessHandler?您应该尝试在resources.xml中定义authenticationSuccessHandler


所以它与LDAP无关,是一个依赖注入问题?请把服务代码贴出来。我想你是对的,因为它在别的地方也能用。。。现在我想起来了,我确实尝试过将原始的搜索代码(现在控制器中的所有代码都可以正常工作)放到一个服务中,但它不起作用。。。我从来没有在凌晨4点接通过。连续20个小时编码显然是个坏主意,除非你真的在这么做——那似乎很好:)伯特,你的(修辞?)问题让我走上了正确的轨道。。。你能解释一下(在回答中,这样我就可以接受)为什么(或者很可能是为什么)出现这个问题吗?干杯,史蒂文我在参考资料中有以下内容。groovy postAuthHandlerService(postAuthHandlerService,ref('ldapTemplate'))但我得到以下信息:创建名为'postAuthHandlerService'的bean时出错:设置构造函数参数时无法解析对bean'ldapTemplate'的引用;嵌套的异常是org.springframework.beans.factory.NoSuchBeanDefinitionException:没有定义名为“ldapTemplate”的bean。您能否共享ldapTemplate bean在哪里以及如何使用ldap源填充?Grails 3中是否有类似的示例?欢迎回复。我使用的是Grails 2,在resources.groovy:authenticationSuccessHandler(com.myPackage.PostAuthHandlerService){}中有这个bean。您应该设置authenticationHandler的ldapTemplate属性。。mauthenticationSuccessHandler(com.myPackage.PostAuthHandlerService){ldapTemplate=ref(ldapTemplate)}我将尝试一下,并让您知道我的进展。。。谢谢你的提示。如果成功,我会接受答案…太棒了。。。成功了。您能告诉我这与在bean签名中添加“、ref(ldapTemplate)”有什么区别吗?resources.xml类似于application-context.xml。因此,如果要通过resources.xml加载bean,则必须手动声明所有依赖项。这意味着authenticationSuccessHandler(com.myPackage.PostAuthHandlerService){}将在不使用任何ldapTemplate的情况下实例化身份验证处理程序。
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)
}