【问题标题】:LdapAuthenticationProvider throws NullPointerException at AbstractContextSource.getReadOnlyContextLdapAuthenticationProvider 在 AbstractContextSource.getReadOnlyContext 抛出 NullPointerException
【发布时间】:2012-05-23 21:04:49
【问题描述】:

我使用了在 xml 文件中定义的 Spring Security LDAP 身份验证,它运行良好:

<security:authentication-manager>
    <security:ldap-authentication-provider 
        user-search-filter="(uid={0})"
        user-search-base="dc=company,dc=com">
    </security:ldap-authentication-provider>
</security:authentication-manager>

<security:ldap-server url="ldap://mail.company.com" />

我需要在身份验证器提供程序中插入一些逻辑(登录到数据库以命名一个),因此我实现了 DaoAuthenticationProvider 以使用 LDAP:

xml配置:

<security:authentication-manager>
    <security:authentication-provider ref="appAuthenticationProvider" />
</security:authentication-manager>

类实现:

@Service("appAuthenticationProvider")
public class AppAuthenticationProvider extends DaoAuthenticationProvider  {

    private LdapAuthenticationProvider ldapProvider;

    public AppAuthenticationProvider(){
        DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://mail.company.com");
        BindAuthenticator authenticator = new BindAuthenticator(contextSource);
        authenticator.setUserSearch(new FilterBasedLdapUserSearch("dc=company,dc=com", "(uid={0})", contextSource));
        ldapProvider = new LdapAuthenticationProvider(authenticator);
    }

    public Authentication authenticate(Authentication authRequest) throws AuthenticationException {
        return ldapProvider.authenticate(authRequest);
    }

}

它看起来很符合您对第一个实现的期望,但身份验证方法会引发以下异常:

java.lang.NullPointerException
org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:125)
org.springframework.ldap.core.LdapTemplate.executeReadOnly(LdapTemplate.java:792)
org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleEntry(SpringSecurityLdapTemplate.java:196)
org.springframework.security.ldap.search.FilterBasedLdapUserSearch.searchForUser(FilterBasedLdapUserSearch.java:116)
org.springframework.security.ldap.authentication.BindAuthenticator.authenticate(BindAuthenticator.java:90)
org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:178)
org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:61)
myapp.security.AppAuthenticationProvider.authenticate(AppAuthenticationProvider.java:69)

第一种情况下的日志如下所示:

[myapp] 2012-05-16 11:38:44,339 INFO  org.springframework.security.ldap.DefaultSpringSecurityContextSource -  URL 'ldap://mail.company.com', root DN is ''
[myapp] 2012-05-16 11:38:44,364 INFO  org.springframework.security.ldap.DefaultSpringSecurityContextSource -  URL 'ldap://mail.company.com', root DN is ''
[myapp] 2012-05-16 11:38:44,365 DEBUG org.springframework.ldap.core.support.AbstractContextSource - AuthenticationSource not set - using default implementation
[myapp] 2012-05-16 11:38:44,365 INFO  org.springframework.ldap.core.support.AbstractContextSource - Property 'userDn' not set - anonymous context will be used for read-write operations
[myapp] 2012-05-16 11:38:44,365 DEBUG org.springframework.ldap.core.support.AbstractContextSource - Using LDAP pooling.
[myapp] 2012-05-16 11:38:44,365 DEBUG org.springframework.ldap.core.support.AbstractContextSource - Trying provider Urls: ldap://mail.company.com
[myapp] 2012-05-16 11:38:44,369 INFO  org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator - groupSearchBase is empty. Searches will be performed from the context source base
[myapp] 2012-05-16 11:39:33,956 DEBUG org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
[myapp] 2012-05-16 11:39:33,957 DEBUG org.springframework.security.ldap.authentication.LdapAuthenticationProvider - Processing authentication request for user: JohnDoe
[myapp] 2012-05-16 11:39:33,960 DEBUG org.springframework.security.ldap.search.FilterBasedLdapUserSearch - Searching for user 'JohnDoe', with user search [ searchFilter: '(uid={0})', searchBase: 'dc=company,dc=com', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]
[myapp] 2012-05-16 11:39:34,812 DEBUG org.springframework.ldap.core.support.AbstractContextSource - Got Ldap context on server 'ldap://mail.company.com'
[myapp] 2012-05-16 11:39:35,025 DEBUG org.springframework.security.ldap.SpringSecurityLdapTemplate - Searching for entry under DN '', base = 'dc=company,dc=com', filter = '(uid={0})'
[myapp] 2012-05-16 11:39:35,060 DEBUG org.springframework.security.ldap.SpringSecurityLdapTemplate - Found DN: cn=JohnDoe,cn=users,dc=company,dc=com
[myapp] 2012-05-16 11:39:35,082 DEBUG org.springframework.security.ldap.authentication.BindAuthenticator - Attempting to bind as cn=JohnDoe,cn=users,dc=company,dc=com

第二种情况:

[myapp] 2012-05-16 11:34:13,563 INFO  org.springframework.security.ldap.DefaultSpringSecurityContextSource -  URL 'ldap://mail.company.com', root DN is ''
[myapp] 2012-05-16 11:34:28,363 INFO  org.springframework.security.ldap.DefaultSpringSecurityContextSource -  URL 'ldap://mail.company.com', root DN is ''
[myapp] 2012-05-16 11:34:37,194 DEBUG org.springframework.security.authentication.ProviderManager - Authentication attempt using myapp.security.AppAuthenticationProvider
[myapp] 2012-05-16 11:34:37,197 DEBUG org.springframework.security.ldap.authentication.LdapAuthenticationProvider - Processing authentication request for user: JohnDoe
[myapp] 2012-05-16 11:34:37,197 DEBUG org.springframework.security.ldap.search.FilterBasedLdapUserSearch - Searching for user 'JohnDoe', with user search [ searchFilter: '(uid={0})', searchBase: 'dc=company,dc=com', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]

有什么想法吗?

【问题讨论】:

    标签: spring security spring-security ldap


    【解决方案1】:

    您没有完全初始化DefaultSpringSecurityContextSource(因为您是使用“new”手动创建的)。

    在创建下面添加这个,你应该已经准备好了:

    contextSource.afterPropertiesSet();
    

    在这种特殊情况下,这一行是关键:

    [myapp] 2012-05-16 11:38:44,365 INFO  org.springframework.ldap.core.support.AbstractContextSource - Property 'userDn' not set - anonymous context will be used for read-write operations
    

    当您尝试使用手动创建(但未正确初始化)的上下文源时,它会按照默认行为进行,即使用非匿名访问进行只读操作。由于您没有指定任何管理员 dn 或密码,因此它会因 NPE 而失败。

    正确初始化实例(通过调用afterPropertiesSet())会将其设置为使用匿名访问进行只读,因为没有指定用户/密码。

    【讨论】:

    • 有效!非常感谢。我已经度过了令人沮丧的几个小时,您又为我节省了几个小时;)Spring Secuirty 文档或错误消息可以提供更多实用信息。
    • 在 Grails 3.2.9 中使用 spring-security-core:3.1.2 和 spring-security-ldap:3.0.2。由于某种原因,application.yml 设置 grails.plugin.springsecurity.ldap.context.anonymousReadOnly: true 被忽略了。 afterPropertiesSet() 修复了它。
    • 非常感谢。这是一个糟糕的 API 设计,NPE 消息具有误导性,并且 afterPropertiesSet 方法不直观。
    • 我访问了这个答案两次。我完全同意,这是一个不直观的糟糕 API 设计。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    • 2013-09-07
    • 2013-06-18
    • 2016-07-07
    • 2014-10-02
    • 2012-05-21
    • 2014-08-15
    相关资源
    最近更新 更多