LdapTemplate: javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name ‘…’

BACKGROUND

Let’s assume we have the following LDAP configuration…

@Configuration
class LdapConfig {
    @Bean
    AuthenticationSource getAuthenticationSource(AppConfigService appConfigService) {
        return new AuthenticationSource() { ... }
    }

    @Bean
    ContextSource contextSource(AuthenticationSource authenticationSource) {
        return new LdapContextSource(
                authenticationSource: authenticationSource,
                url: 'ldap://server:389',
                base: 'dc=domain'
        )
    }

    @Bean
    LdapTemplate getLdapTemplate(ContextSource contextSource) {
        return new LdapTemplate(contextSource: contextSource)
    }
}

When running any LDAP query, the following exception is thrown:-

Caused by: javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name '/'
	at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2846)
	at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2820)
	at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:129)
	at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:198)
	at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:171)
	at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:365)

SOLUTION

There are 3 solutions to this problem.

Query against Gobal Catalog

To prevent the referral issues when dealing with Active Directory, we may query against the Global Catalog by using port 3268.

@Bean
ContextSource contextSource(AuthenticationSource authenticationSource) {
    return new LdapContextSource(
            authenticationSource: authenticationSource,
            url: 'ldap://server:3268',
            base: 'dc=domain'
    )
}

The possible downside to this approach is the Global Catalog may not have the pertinent data we need, such as employeeID, etc.

Configure Referral to Follow

We can configure LdapTemplate to automatically follow any referrals.

@Bean
ContextSource contextSource(AuthenticationSource authenticationSource) {
    return new LdapContextSource(
            authenticationSource: authenticationSource,
            url: 'ldap://server:389',
            base: 'dc=domain',
            referral: 'follow'
    )
}

The downside to this approach is it makes the query much slower. Based on my testing, it is at least 5 to 10 seconds slower.

Ignore Exception

Sometimes, it pays to read the JavaDoc. Based on the LdapTemplate’s documentation, it says…

Note for Active Directory (AD) users: AD servers are apparently unable to handle referrals automatically, which causes a PartialResultException to be thrown whenever a referral is encountered in a search. To avoid this, set the ignorePartialResultException property to true. There is currently no way of manually handling these referrals in the form of ReferralException, i.e. either you get the exception (and your results are lost) or all referrals are ignored (if the server is unable to handle them properly. Neither is there any simple way to get notified that a PartialResultException has been ignored (other than in the log).

Bada Bing, Bada Boom…

@Bean
LdapTemplate getLdapTemplate(ContextSource contextSource) {
    return new LdapTemplate(
            contextSource: contextSource,
            ignorePartialResultException: true
    )
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s