2012-05-16 20 views
8
引發NullPointerException異常

我以前在XML文件中定義Spring Security的LDAP認證,它工作得很好: LdapAuthenticationProvider可疑的AbstractContextSource.getReadOnlyContext

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

} 

看起來qute你會從第一個實現所期望的,但身份驗證方法拋出以下異常:

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 ] 

有什麼想法嗎?

回答

18

您沒有完全初始化DefaultSpringSecurityContextSource(因爲您正在使用「新建」手動創建它)。

添加這種創作的下方,你應該準備就緒:

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())會將其設置爲使用匿名訪問進行只讀,因爲沒有指定user/pwd。

+0

它的工作原理!非常感謝。我已經度過了幾個令人沮喪的時間,你爲我節省了更多;)Spring Secuirty文檔或錯誤消息可以提供更實用的信息。 –

+0

兩天的工作尋找這個解決方案非常感謝 –

+0

工作在Grails 3.2.9與彈簧安全核心:3.1.2和spring-security-ldap:3.0.2。出於某種原因,application.yml設置grails.plugin.springsecurity.ldap.context.anonymousReadOnly:true被忽略。 afterPropertiesSet()修復它。 –