Java LDAP Authentication
WHAT IS LDAP?
Clients can communicate with directory services by sending requests and receiving responses using the Lightweight Directory Access Protocol (LDAP). The term "LDAP server" refers to a directory service that uses this protocol.
An information model based on X.500 is used to hold the data that an LDAP server serves. For electronic directory services, this group of computer networking standards is used.
To perform the search and user authentication, Java uses directory service access capabilities of the Java Naming and Directory Interface (JNDI). So, let’s firstly discuss JNDI.
WHAT IS JNDI?
JNDI(Java Naming and Directory Interface)’s primary goal is to give apps a mechanism to access resources and components. Applications can find and use naming and directory services using the standard API provided by JNDI. This is true both locally and remotely over a network.
This capability is supported by naming services, which offer single-point access to services, data, or objects by name in a hierarchical namespace. The server that houses the naming service configures the names assigned to each of these locally or through network-accessible resources.
Using JNDI's naming service interface, we can access directory services like LDAP. The reason for this is that a directory service is just a particular kind of naming service that makes it possible for each named entry to have a list of characteristics attached to it.
In addition to attributes, each directory item may also include one or more siblings. This enables the linking of entries in a hierarchy. The descendants of directory entries are represented by JNDI as subcontexts of their parent context.
The JNDI API’s independence from any underlying service provider implementation, such as LDAP, is one of its main advantages. As a result, we can access an LDAP directory service using JNDI without the need for procedure APIs.
Before delving into the specifics of LDAP verification on Domain Controller, let's familiarise ourselves with a few LDAP terms since most users are doing it for the first time and are not particularly familiar with terms like Dn, Ou, Bind, search, etc.
- Dn: A user can be located using their differentiated name, or Dn, on an LDAP server such as Microsoft's Active Directory.
- Ou: Organization Unit
- Bind: When performing a bind operation, LDAP clients make a request to an LDAP user along with their login and password. If the LDAP server is able to locate the passcode, it grants the user access to the LDAP server.
- Search: When performing an LDAP search, the user's Dn is received using one or more user credentials.
- Root: The top entry of an LDAP directory, similar to the root of a tree.
- BaseDn: A branch in the LDAP tree called BaseDn can be used as the starting point for LDAP searches like "power supply."
JNDI API Concepts for LDAP Authentication
Let's go over the fundamentals regarding using the JNDI API for LDAP-based authentication before talking about the example code.
- We first need to establish a JNDI InitialDirContext object before we can connect to an LDAP server. To customize it, we must do this by passing environment properties as a Hashtable into its function Object().
- We need to give this Hashtable properties for the user name and password we want to use for authentication, among other things. To accomplish this, we must set the Context. SECURITY PRINCIPAL and Context. SECURITY CREDENTIALS attribute to the user's DN and password, respectively.
- The primary JNDI service control interface, DirContext, is implemented by InitialDirContext. Our new Context may be used to carry out several LDAP server directory service tasks via this interface. These involve scanning for directory entries and assigning names and attributes to objects.
Free Star
It's important to note that the names and attributes of the objects supplied by JNDI will match those of the underlying LDAP entries. As a result, we can seek an entry by using its name and attributes as search criteria.
Once a directory entry has been obtained by JNDI, its attributes can be examined using the Attributes interface. Additionally, we may examine each of them using the Attribute interface.
What Happens If We Lack the User's DN?
Often the user's DN is not instantly accessible to use for authentication. We must first use administrator privileges to construct an InitialDirContext in order to circumvent this. Then we can use it to find the appropriate user on the directory server and obtain his DN.
The user can then be authenticated by establishing a new InitialDirContext with his credentials once we have the user's DN. Setting the user's DN and password in the environment properties is the first step in accomplishing this. The InitDirContext's function Object() { [native code] } must then get these properties when it is created.
Requirements that are required to create this Context are
- 15 minutes approx.
- an IDE or preferred text editor
- 1.8 or later JDK
- Maven 3.2+ or Gradle 4+
Additionally, you can import the code directly into your IDE:
- The suite of Spring Tools (STS)
- Microsoft IDEA
Example
Authentication of the user:
Using Java's JNDI (Java Naming and Directory Interface) APIs, the following demonstration shows how to communicate to an LDAP server. The JDK's like javax.naming.* and javax.naming.directory.* packages include the methods, classes, and occurrences of the JNDI. As a result, you typically don't need to use any extra libraries when interacting with LDAP servers.
We need to specify the url to specify the LDAP server.
String url="ldap://localhost:10389"
It provides the URL of a Lightweight Directory Access Protocol (LDAP) server that is operating on a local machine and broadcasting on port 389 by default.
The following syntax sample illustrates how to specify some environmental characteristics for the connections and authentication in a Hashtable object:
Hashtable<String, String> envi = new Hashtable<String, String>();
envi.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
envi.put(Context.PROVIDER_URL,url);
envi.put(Context.SECURITY_AUTHENTICATION, "simple");
envi.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
envi.put(Context.SECURITY_CREDENTIALS, "secret");
Five environmental attributes are listed here:
com.sun.jndi.ldap.LdapCtxFactory is the default value for INITIAL CONTEXT FACTORY, which defines the fully qualified class name of the factory class that will construct an initial context.
ldap:/localhost:10389 is an example of a PROVIDER URL that specifies the URL of the service provider to utilise.
One of the following strings, SECURITY AUTHENTICATION, determines the authentication method to use:
- Use no authentication, or "none" (anonymous).
- "Easy": Make use of shoddy authentication (password in clear text).
- sasl mech: When using SASL, utilise strong authentication (Simple Authentication and Security Layer).
In the form of an LDAP differentiated name, such as "uid=admin,ou=system," SECURITY PRINCIPAL, supplies the principal's login for the authentication process.
SECURITY CREDENTIALS: Describes the principal's credentials for authenticating
Finally, while constructing a new context in the manner described here, pass the Hashtable of environment properties:
DirContext ctxt = new InitialDirContext(envi);
ctxt.close();
If no objections arise, the connection is established and the caller's identity is verified. After that, you can carry out additional actions like browsing the directory for things.
Sample Code
The entire sample code is provided here:
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
public class Main
{
public static void main(String [] args)
{
String url = "ldap://localhost:10389";
Hashtable<String, String> envi = new Hashtable<String, String>();
envi.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
envi.put(Context.PROVIDER_URL,url);
envi.put(Context.SECURITY_AUTHENTICATION, "simple");
envi.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
try
{
DirContext ctxt = new InitialDirContext(envi);
System.out.println("connection passed");
System.out.println(ctxt.getEnvironment());
// user authentiaction failures handling
ctxt.close();
}
catch (AuthenticationNotSupportedException e)
{
System.out.println("The server does not allow authentication");
} catch (AuthenticationException e)
{
System.out.println("invalid credientials like username and password");
} catch (NamingException e)
{
System.out.println("attempt to create the context failed");
}
}
}
The code, as mentioned earlier, tries to establish a connection to a local LDAP server (in this case, we tested using the Apache DS server, which is listening on its default port number 10389), print "connected," and display the environment variables on the console.
Here is the result:
connected
{java.naming.provider.url=ldap://localhost:20389, java.naming.factory.initial
=com.sun.jndi.ldap.LdapCtxFactory,java.naming.security.principal=uid=admin,ou=system,
java.naming.security.authentication=simple, java.naming.security.credentials=secret}
If the versions of the java code have not supported, then the output will be:
Attempt to create the Context failed
Three exceptions may be thrown when trying to connect to an LDAP server:
- If the server does not support the provided authentication mechanism, an authenticationNotSupportedException will be thrown.
- If either the password or the username is invalid, a login or authentication exception will occur.
- If a naming exception occurs, use NamingException.
If the system fails to create Context, then use this.
// let us assign the login credentials like username and password with the "mysecret."
env.put(Context.SECURITY_AUTHENTICATION, "custom");
env.put(Context.SECURITY_PRINCIPAL, "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");