LdapAuthenticationProvider throws NullPointerException at AbstractContextSource.getReadOnlyContext

Bad Pitt picture Bad Pitt · May 16, 2012 · Viewed 11.8k times · Source

I used Spring Security LDAP authentication defined in xml file and it worked fine:

<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" />

I needed to insert some logic into authenticator provider (logging into database to name one) so I implemented DaoAuthenticationProvider to use LDAP:

xml configuration:

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

class implementation:

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

}

It looks qute what you'd expect from the first implementation but authenticate method throws following exception:

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)

Logs in first case looks like this:

[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

In the second case:

[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 ]

Got any idea?

Answer

pap picture pap · May 16, 2012

You are not fully initializing the DefaultSpringSecurityContextSource (since you are creating it manually using "new").

Add this below the creation, and you should be all set:

contextSource.afterPropertiesSet();

In this particular case, this line is the key:

[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

When you try to use your manually created (but not properly initialized) context source it's going by the default behavior, which to use non-anonymous access for read-only operations. Since you aren't specifying any manager dn or password, it fails with a NPE.

Properly initializing the instance (by calling afterPropertiesSet()) will set it up to use anonymous access for read-only since no user/pwd is specified.