springspring-securityactive-directoryldapspring-security-ldap

Spring Security Active directory LDAP Authentication error


When i am using Spring Security Active directory LDAP Authentication , i am getting an error saying PartialResultException when user was authenticated. Also i have created a test runner file where it authenticates the user without an error but when am authenticating against the active directory i am unable to authenticate. Appreciate your valuable help.

Test Runner2.java File

package com.company.test;

import java.util.Hashtable;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;


public class Runner2 {

    private static String providerUrl = "ldap://ADHO.COMPANY.NET:389";

    private static String principle = "@company.ad";

    public static final String SEARCH_BY_SAM_ACCOUNT_NAME = "(sAMAccountName=%s)";

    public static boolean authenticateAD(String user , String password) throws Exception {

        InitialDirContext context=null;
        Hashtable<String, String> env = new Hashtable<String, String>();
        String securityPrinciple = user + principle;
        System.out.println("Security principal to search ->"+securityPrinciple);

        // Configure our directory context environment.
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, providerUrl);
        env.put(Context.SECURITY_PRINCIPAL, securityPrinciple);
        env.put(Context.SECURITY_CREDENTIALS, password);
        try {

        context = new InitialDirContext(env);       
        return true;

        }catch(AuthenticationException e) {

         throw new AuthenticationException();

        }catch(Exception e) {

            throw new Exception();
        }
        finally { 
            try {
                if (context != null) {
                    context.close();
                }
            } catch (NamingException e) {

            } 
        } 

    }

    public static void main(String[] args) throws Exception {

        String r1 = "USRXXXX;
        String r2 = "Pass#word102";
        authenticateAD(r1,r2);
    }

}

ldap.properties file

ad.domain=company.ad
ad.url=ldap://ADHO.COMPANY.NET:389/

SpringSecurityConfig.java file

package com.company.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;

import com.onezero.config.AuthenticationEntryPoint;

import java.util.Arrays;

@Configuration
@EnableWebSecurity
@PropertySource("classpath:ldap.properties")
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private Environment env;

    @Bean
    public AuthenticationEntryPoint customAuthenticationEntry() throws Exception {
      return new AuthenticationEntryPoint();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


        http.authorizeRequests()
           .antMatchers("/welcome","/atm/**","/atm2/**","/**","/survey/**","/usrauth/**").authenticated()
           .and()
           .httpBasic()
           .authenticationEntryPoint(customAuthenticationEntry())
           .and()
           .exceptionHandling()
           .and()
           .csrf().disable()
           .sessionManagement()
           .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
    }

    @Bean
    public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
    ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
    env.getProperty("ad.domain"), env.getProperty("ad.url"));

        provider.setConvertSubErrorCodesToExceptions(true);
        provider.setUseAuthenticationRequestCredentials(true);




        return provider;

    }


}

Solution

  • A PartialResultException can be thrown when the server returns a referral. That's the server's way of saying "I don't know what you're talking about, but I know who does." There is a good explanation of options in this answer. One is to set:

    env.put(Context.REFERRAL, "follow");
    

    That will tell it to send the request to wherever the server told us to go. But I don't think that's a good solution. You will end up making two network requests when only one will do. Changing your configuration to point to the right place is a better option.

    One way to figure out what it's complaining about is to inspect the resolvedName property of the PartialResultException object. That should tell you where it is sending you, and you can change your configuration to point there in the first place.

    I'm not a Java developer, so these are a lot of guesses, but I do know how AD works. Give it a try anyway.