Saturday, 29 May 2021

Java: ldapsdk: Working with LDAP connection pool

LDAPConnectionPool class is used to define a ldap connection pool.

 

Signature

public LDAPConnectionPool(@NotNull final ServerSet serverSet,
        @Nullable final BindRequest bindRequest,
        final int initialConnections, final int maxConnections,
        final int initialConnectThreads,
        @Nullable final PostConnectProcessor postConnectProcessor,
        final boolean throwOnConnectFailure)

Below table summarizes all the arguments of LDAPConnectionPool constructor.

 

Argument

Description

serverSet

The server set to use to create the connections.  It is acceptable for the server set to create the connections across multiple servers.

bindRequest

The bind request to use to authenticate the connections that are established.  It may be if no authentication should be performed on the connections.  Note that if the server set is configured to perform authentication, this bind request should be the same bind request used by the server set.  This is important because even

though the server set may be used to perform the initial authentication on a newly established connection, this connection pool may still need to re-authenticate the connection..

initialConnections

The number of connections to initially establish when the pool is created.  It must be greater than or equal to zero.

maxConnections

The maximum number of connections that should be maintained in the pool.  It must be greater than or equal to the initial number of connections, and must not be zero. See the "Pool Connection Management" section of the class-level documentation for an explanation of how the pool treats the maximum number of connections.

initialConnectThreads

The number of concurrent threads to use to

establish the initial set of connections. A value greater than one indicates that the attempt to establish connections should be parallelized.

postConnectProcessor

A processor that should be used to perform

any post-connect processing for connections

in this pool.  It may be null if no special processing is needed.  Note that if the server set is configured with a non-null post-connect processor, then the post-connect processor provided to the pool must be null.

throwOnConnectFailure

If an exception should be thrown if a problem is encountered while attempting to create the specified initial number of connections.  If true, then the attempt to create the pool will fail. if any connection cannot be established.  If

false, then the pool will be created but may have fewer than the initial number of connections (or possibly no connections).

 

Follow below step-by-step procedure to get LDAPConnectionPool.

 

Step 1: Define LDAPConnectionOptions object. 

LDAPConnectionOptions ldapConnectionOptions = new LDAPConnectionOptions();
ldapConnectionOptions.setResponseTimeoutMillis(10000);
ldapConnectionOptions.setUseSynchronousMode(true);
ldapConnectionOptions.setAllowConcurrentSocketFactoryUse(true);
ldapConnectionOptions.setConnectTimeoutMillis(10000);
ldapConnectionOptions.setAbandonOnTimeout(true);
ldapConnectionOptions.setBindWithDNRequiresPassword(false);

 

Step 2: Get an instance of SSLSocketFactory.

TrustAllTrustManager allTrustManager = new TrustAllTrustManager();
SSLUtil sslUtil = new SSLUtil(allTrustManager);
SSLSocketFactory sslSocketFactory = sslUtil.createSSLSocketFactory();

 

Step 3: Define RoundRobinServerSet.

RoundRobinServerSet roundRobinSet = new RoundRobinServerSet(serverNames, ports, sslSocketFactory, ldapConnectionOptions);

 

Step 4: Define SimpleBindRequest.

SimpleBindRequest bindRequest = new SimpleBindRequest(userName, password);

 

Step 5: Get an instance of LDAPConnectionPool.

LDAPConnectionPool ldapConnectionPool = new LDAPConnectionPool(roundRobinSet, bindRequest, 10, 50, serverNames.length * 2, null, true);

That’s it you are done.

 

Find the below working application.

 

LDAPUtil.java

package com.sample.app.util;

import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.spi.NamingManager;
import javax.net.ssl.SSLSocketFactory;

import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.RoundRobinServerSet;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;

public class LDAPUtil {

	private static final String LDAP_SERVICE_PREFIX = "dns:///_ldap";
	private static final String[] SRV_ID = { "SRV" };
	private static final String SRV_PROPERTY = "SRV";

	/**
	 * Example:
	 * LDAPUtil.getAllServersBehindThisObject("dns:///_ldap._tcp.ca.sample.com", 4);
	 * This logic will change based on the srvRecords format received from DNS
	 * 
	 * @param ldapDNSURL
	 * @param limitServers
	 * @return
	 * @throws NamingException
	 */
	public static List<String> getAllServersBehindThisObject(String ldapDNSURL, int limitServers)
			throws NamingException {

		if (ldapDNSURL == null || ldapDNSURL.isEmpty()) {
			throw new IllegalArgumentException("ldapDNSURL must not be empty");
		}

		if (!ldapDNSURL.startsWith(LDAP_SERVICE_PREFIX)) {
			throw new IllegalArgumentException("ldapDNSURL must start with " + LDAP_SERVICE_PREFIX);
		}

		List<String> serversBehindThisDNS = new ArrayList<>();

		DirContext context = (DirContext) NamingManager.getURLContext("dns", new Hashtable<String, Object>());
		Attributes attributes = context.getAttributes(ldapDNSURL, SRV_ID);
		Attribute srvRecords = attributes.get(SRV_PROPERTY);

		for (int i = 0; i < srvRecords.size(); i++) {
			if (i > limitServers - 1) {
				break;
			}

			String srvRecord = srvRecords.get(i).toString();
			String serverName = extractServerNameFromSRVRecord(srvRecord);

			if (serverName == null) {
				continue;
			}

			serversBehindThisDNS.add(serverName);

		}

		return serversBehindThisDNS;
	}

	public static LDAPConnection getLDAPConnection(final String host, final int port, final String userName,
			final String password) throws LDAPException, GeneralSecurityException {

		LDAPConnectionOptions ldapConnectionOptions = getDefaultLDAPConnectionOptions();
		SSLSocketFactory sslSocketFactory = getDefaultSSLSocketFactory();

		LDAPConnection ldapConnection = new LDAPConnection(sslSocketFactory, ldapConnectionOptions, host, port,
				userName, password);

		if (ldapConnection == null) {
			throw new IllegalArgumentException("Invalid username or password");
		}

		return ldapConnection;

	}

	public static LDAPConnectionPool getLdapConnectionPool(final String[] serverNames, final int[] ports,
			final String userName, final String password) throws GeneralSecurityException, LDAPException {
		LDAPConnectionOptions ldapConnectionOptions = getDefaultLDAPConnectionOptions();
		SSLSocketFactory sslSocketFactory = getDefaultSSLSocketFactory();

		RoundRobinServerSet roundRobinSet = new RoundRobinServerSet(serverNames, ports, sslSocketFactory,
				ldapConnectionOptions);
		SimpleBindRequest bindRequest = new SimpleBindRequest(userName, password);

		return new LDAPConnectionPool(roundRobinSet, bindRequest, 10, 50, serverNames.length * 2, null, true);
	}

	public static Map<String, List<String>> executeQuery(LDAPConnectionPool ldapConnectionPool,
			SearchRequest searchRequest) throws LDAPSearchException {
		SearchResult searchResults = ldapConnectionPool.search(searchRequest);
		List<SearchResultEntry> searchResultEntries = searchResults.getSearchEntries();

		Map<String, List<String>> result = new HashMap<>();

		for (SearchResultEntry searchResultEntry : searchResultEntries) {
			Collection<com.unboundid.ldap.sdk.Attribute> attributes = searchResultEntry.getAttributes();

			for (com.unboundid.ldap.sdk.Attribute attribute : attributes) {
				String[] valuesArray = attribute.getValues();
				String attrName = attribute.getName().toLowerCase();

				List<String> valuesList = Arrays.asList(valuesArray);
				result.put(attrName, valuesList);
			}
		}
		return result;
	}

	public static SSLSocketFactory getDefaultSSLSocketFactory() throws GeneralSecurityException {
		TrustAllTrustManager allTrustManager = new TrustAllTrustManager();
		SSLUtil sslUtil = new SSLUtil(allTrustManager);

		return sslUtil.createSSLSocketFactory();

	}

	public static LDAPConnectionOptions getDefaultLDAPConnectionOptions() {
		LDAPConnectionOptions ldapConnectionOptions = new LDAPConnectionOptions();
		ldapConnectionOptions.setResponseTimeoutMillis(10000);
		ldapConnectionOptions.setUseSynchronousMode(true);
		ldapConnectionOptions.setAllowConcurrentSocketFactoryUse(true);
		ldapConnectionOptions.setConnectTimeoutMillis(10000);
		ldapConnectionOptions.setAbandonOnTimeout(true);
		ldapConnectionOptions.setBindWithDNRequiresPassword(false);
		return ldapConnectionOptions;
	}

	private static String extractServerNameFromSRVRecord(String srvRecord) {
		String[] splits = srvRecord.split(" ");

		if (splits.length != 4) {
			return null;
		}

		String server = splits[3];

		int lastCharIndex = server.lastIndexOf(".");
		if (lastCharIndex == server.length() - 1) {
			server = server.substring(0, server.length() - 1);
		}
		return server;

	}

}

 

HelloWorld.java

package com.sample.app;

import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.naming.NamingException;

import com.sample.app.util.LDAPUtil;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;

public class HelloWorld {

	private static final String USER_NAME = "";
	private static final String PASSWORD = "";
	private static final String DOMAIN_NAME = "hr.sample.com";
	private static final String DOMAIN_NAME_WITH_LDAP_TCP = "_ldap._tcp." + DOMAIN_NAME;
	private static final String DOMAIN_NAME_WITH_LDAP_TCP_DNS = "dns:///" + DOMAIN_NAME_WITH_LDAP_TCP;

	// Attributes related to search
	private static final String BASE_DN = "DC=hr,DC=sample,DC=com";
	private static final String FILTER = "(userPrincipalName=krishna@hr.sample.com)";
	private static final String[] ATTRIBUTES_TO_SEARCH = { "displayname", "mail", "memberof" };

	public static void main(String args[]) throws GeneralSecurityException, LDAPException, NamingException {

		List<String> serversBehindThisDomain = LDAPUtil.getAllServersBehindThisObject(DOMAIN_NAME_WITH_LDAP_TCP_DNS, 4);

		int noOfServers = serversBehindThisDomain.size();
		String[] arr = new String[noOfServers];
		String[] serversToConnect = serversBehindThisDomain.toArray(arr);

		int[] ports = new int[noOfServers];
		for (int i = 0; i < noOfServers; i++) {
			ports[i] = 636;
		}

		LDAPConnectionPool ldapConnectionPool = LDAPUtil.getLdapConnectionPool(serversToConnect, ports, USER_NAME,
				PASSWORD);

		SearchRequest searchRequest = new SearchRequest(BASE_DN, SearchScope.SUB, FILTER);
		searchRequest.setAttributes(ATTRIBUTES_TO_SEARCH);

		Map<String, List<String>> result = LDAPUtil.executeQuery(ldapConnectionPool, searchRequest);

		System.out.println(result);

	}

}

 


  

Previous                                                    Next                                                    Home

No comments:

Post a Comment