Here is a sample Java code to authenticate against Windows Active Directory server.

  • The code finds all available active directory servers in your network.
  • It uses one of the available active directory server for authentication.
  • If an active directory server is down then it starts using next available server if any.
  • This class is thread-safe, you can create one instance and re-use them multiple times.
  • I tested this code from Linux and Windows box.

You can find the below source code in GitHub as well.
ActiveDirectoryAuthentication.java

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.security.auth.login.AccountException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;

public class ActiveDirectoryAuthentication {

	private static final String CONTEXT_FACTORY_CLASS = "com.sun.jndi.ldap.LdapCtxFactory";

	private String ldapServerUrls[];

	private int lastLdapUrlIndex;

	private final String domainName;

	public ActiveDirectoryAuthentication(String domainName) {
		this.domainName = domainName.toUpperCase();

		try {
			ldapServerUrls = nsLookup(domainName);
		} catch (Exception e) {
			e.printStackTrace();
		}
		lastLdapUrlIndex = 0;
	}

	public boolean authenticate(String username, String password) throws LoginException {
		if (ldapServerUrls == null || ldapServerUrls.length == 0) {
			throw new AccountException("Unable to find ldap servers");
		}
		if (username == null || password == null || username.trim().length() == 0 || password.trim().length() == 0) {
			throw new FailedLoginException("Username or password is empty");
		}
		int retryCount = 0;
		int currentLdapUrlIndex = lastLdapUrlIndex;
		do {
			retryCount++;
			try {
				Hashtable<Object, Object> env = new Hashtable<Object, Object>();
				env.put(Context.INITIAL_CONTEXT_FACTORY, CONTEXT_FACTORY_CLASS);
				env.put(Context.PROVIDER_URL, ldapServerUrls[currentLdapUrlIndex]);
				env.put(Context.SECURITY_PRINCIPAL, username + "@" + domainName);
				env.put(Context.SECURITY_CREDENTIALS, password);
				DirContext ctx = new InitialDirContext(env);
				ctx.close();
				lastLdapUrlIndex = currentLdapUrlIndex;
				return true;
			} catch (CommunicationException exp) {
				exp.printStackTrace(); // TODO you can replace with log4j or slf4j API
				// if the exception of type communication we can assume the AD is not reachable hence retry can be attempted with next available AD
				if (retryCount < ldapServerUrls.length) {
					currentLdapUrlIndex++;
					if (currentLdapUrlIndex == ldapServerUrls.length) {
						currentLdapUrlIndex = 0;
					}
					continue;
				}
				return false;
			} catch (Throwable throwable) {
				throwable.printStackTrace();
				return false;
			}
		} while (true);
	}

	private static String[] nsLookup(String argDomain) throws Exception {
		try {
			Hashtable<Object, Object> env = new Hashtable<Object, Object>();
			env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
			env.put("java.naming.provider.url", "dns:");
			DirContext ctx = new InitialDirContext(env);
			Attributes attributes = ctx.getAttributes(String.format("_ldap._tcp.%s", argDomain), new String[] { "srv" });
			// try thrice to get the KDC servers before throwing error
			for (int i = 0; i < 3; i++) {
				Attribute a = attributes.get("srv");
				if (a != null) {
					List<String> domainServers = new ArrayList<String>();
					NamingEnumeration<?> enumeration = a.getAll();
					while (enumeration.hasMoreElements()) {
						String srvAttr = (String) enumeration.next();
						// the value are in space separated 0) priority 1)
						// weight 2) port 3) server
						String values[] = srvAttr.toString().split(" ");
						domainServers.add(String.format("ldap://%s:%s", values[3], values[2]));
					}
					String domainServersArray[] = new String[domainServers.size()];
					domainServers.toArray(domainServersArray);
					return domainServersArray;
				}
			}
			throw new Exception("Unable to find srv attribute for the domain " + argDomain);
		} catch (NamingException exp) {
			throw new Exception("Error while performing nslookup. Root Cause: " + exp.getMessage(), exp);
		}
	}
}

Here is sample code to test this class.

	public static void main(String[] args) {
		ActiveDirectoryAuthentication authentication = new ActiveDirectoryAuthentication("YOUR.DOMAIN.COM");
		try {
			boolean authResult = authentication.authenticate("Username", "password");
			System.out.print("Auth: " + authResult);
		} catch (LoginException e) {
			e.printStackTrace();
		}
	}

19 responses to “Java: Sample Active Directory authentication code”

  1. mohanmca

    Thanks quite useful.

    But it is not thread safe. You use instance level variable inside method.

    1) Remove currentLdapUrlIndex from class level
    2) move int currentLdapUrlIndex = 0; into authenticate method
    3) Decorate other variable as final

  2. Thanks as always. Made the ldap index variable as thread-safe.

  3. jhlee

    Thank you for your blog.

  4. Anonymous

    After having such a hard time trying to make Spring LDAP to run, I found your page. Exactly what I need and to the point.

  5. Dharmendra

    I got a requirement to implement the single sign on web application. I have downloaded your code and after ran on server I got a error. The below is log error message.

    Oracle Corporation
    Java config name: null
    Native config name: C:\Windows\krb5.ini
    Loaded from native config
    >>> KdcAccessibility: reset
    default etypes for default_tkt_enctypes: 23 3 1 16.
    >>> KrbAsReq creating message
    >>> KrbKdcReq send: kdc=localhost UDP:88, timeout=30000, number of retries =3, #bytes=147
    >>> KDCCommunication: kdc=localhost UDP:88, timeout=30000,Attempt =1, #bytes=147
    SocketTimeOutException with attempt: 1
    >>> KDCCommunication: kdc=localhost UDP:88, timeout=30000,Attempt =2, #bytes=147

    It’s repeatedly throwing the error SocketTimeOutException . Could you please let me do I need to configure any thing.

    Appreciate for your support !!!

    Dharmendra

  6. Anonymous

    Thanks…. Its working fine

  7. Thank you for this blog….
    That is very helpful to me …

  8. Anonymous

    Thank you very much!!!

  9. Ravi Akella

    Thanks a lot venkat.. great piece of code.. serves my needs perfectly..

  10. Anonymous

    Thanks for the code. It’s working. nice work….

  11. Anonymous

    Thanks nice work!

  12. Anonymous

    Awesome!!!

  13. Javier

    Thanks a lot!!

  14. Anonymous

    Excelent !! well done bien jugado

  15. Sudhir Maduri

    Excellent!! Thanks a lot

  16. Bala

    how to get user details AD in java

  17. jagadeesan

    Hi Venkat,
    can you please help me to find how can I authenticate a user in Swings based desktop application using Windows credentials.

    I tried for JCIF,but, it is not working,

  18. helpsoft

    thank you so much, it’s working well

  19. […] Java: Sample Active Directory authentication code | Venkat … […]

Leave a comment

I’m Venkat

A passionate software engineer with over 20 years of experience in the tech industry. Welcome to my digital playground where I share my journey through the ever-evolving world of software development and cloud technologies!