I've used the Apache Directory API to load in user data from an Active Directory. It's similar to the example code by 'oers' found in this stackoverflow question: Apache Directory LDAP - Paged searches
Some differences I have are:
- I'm coding it with in Nashorn (Javascript running in Java)
- I'm using the PagedResultsImpl class instead of PagedResultsDecorator
- I'm saving the cookie as a string between calls by using a Base64 encoding of the byte[] cookie.
I'm using Apache Directory API with the following maven import:
<dependency> <groupId>org.apache.directory.api</groupId> <artifactId>api-all</artifactId> <version>1.0.3</version> </dependency>
Here's some of the important bits:
...
var pageCursor = ""; /** or some Base64 encoded byte[] cookie if I'm trying to start from where i left off last time. */
...
pagedSearchControl = new PagedResultsImpl();
pagedSearchControl.setSize(pageSize);
pagedSearchControl.setCookie(Base64.getEncoder().encodeToString(pageCursor.getBytes()));
...
var searchRequest = new SearchRequestImpl();
...
searchRequest.addControl(pagedSearchControl);
...
var cursor = new EntryCursorImpl(connection.search(searchRequest));
...
pagingResults = cursor.getSearchResultDone().getControl(PagedResults.OID);
if (pagingResults != null){
nextPageCursor = Base64.getEncoder().encodeToString(pagingResults.getCookie());
}
When run against Active Directory I can page all the users just fine. When I change my connection to point to an OpenLDAP directory I am able to search for users just fine, EXCEPT for when I set the page control cookie using a non-null value for pageCursor (one I got from base 64 encoding a previous call's cookie). Basically, I can't get the paged results from OpenLDAP. I get no results and there are no exceptions.
- What is needed in order to get OpenLDAP to page properly?
- Am I missing something with setting up page control in Apache Directory?
- Is paging a setting in OpenLDAP I need to turn on?
[UPDATE] I Ported my code outside of Nashorn to just Java and now I can see it is because the paging cookie appears to be only valid within the same connection for OpenLDAP, but for Active Directory it can be different connections. You can see yourself with the code below.:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Base64;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringJoiner;
import javax.naming.ConfigurationException;
//imports for json
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
//imports for LDAP
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
import org.apache.directory.api.ldap.model.message.Control;
import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
import org.apache.directory.api.ldap.model.message.SearchRequest;
import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
import org.apache.directory.api.ldap.model.message.SearchResultDone;
import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
import org.apache.directory.api.ldap.model.message.controls.PagedResults;
import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.ldap.client.api.EntryCursorImpl;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
//Nashorn
import delight.nashornsandbox.NashornSandbox;
import delight.nashornsandbox.NashornSandboxes;
public class Executor
{
public static void main( String[] args )
{
pagingTest();
}
private static void pagingTest(){
//ENTER YOUR CREDENTIALS
String server = "";
int port = 0;
String loginId = "";
String loginPassword = "";
String usersBaseDN = "";
String userObjectClass = "";
String base64cookie = null;
LdapNetworkConnection connection = new LdapNetworkConnection(server, port, true );
try{
connection.setTimeOut( 300 );
connection.bind(loginId,loginPassword);
/*First Pass*/
PagedResultsImpl pagedSearchControl = new PagedResultsImpl();
pagedSearchControl.setSize(5);
pagedSearchControl.setCookie(Base64.getDecoder().decode(""));
SearchRequestImpl searchRequest = new SearchRequestImpl();
searchRequest.setBase(new Dn(usersBaseDN));
searchRequest.setFilter("(objectClass=" + userObjectClass +")");
searchRequest.setScope(SearchScope.SUBTREE);
searchRequest.addAttributes("*");
searchRequest.addControl(pagedSearchControl);
EntryCursorImpl cursor = new EntryCursorImpl(connection.search(searchRequest));
while (cursor.next()) {
System.out.println("First Pass User: " + cursor.get().getDn());
}
PagedResults pagingResults = (PagedResults)cursor.getSearchResultDone().getControl(PagedResults.OID);
if (pagingResults != null){
byte[] cookie = pagingResults.getCookie();
if (cookie != null && cookie.length > 0) {
base64cookie = Base64.getEncoder().encodeToString(cookie);
System.out.println("First Pass Cookie: " + cookie);
}
}
cursor.close();
}catch(Exception e){
System.out.println(e);
}
finally {
//COMMENT THIS CODE BLOCK TO SEE IT WORKING (IT WILL USE THE SAME CONNECTION)
try {
connection.unBind();
connection.close();
} catch (Exception e) {
System.out.println(e);
}
connection = new LdapNetworkConnection( server, port, true );
}
try{
connection.setTimeOut( 300 );
connection.bind(loginId,loginPassword);
/*Second Pass*/
PagedResultsImpl secondPagedSearchControl = new PagedResultsImpl();
secondPagedSearchControl.setSize(5);
secondPagedSearchControl.setCookie(Base64.getDecoder().decode(base64cookie));
SearchRequestImpl secondSearchRequest = new SearchRequestImpl();
secondSearchRequest.setBase(new Dn(usersBaseDN));
secondSearchRequest.setFilter("(objectClass=" + userObjectClass +")");
secondSearchRequest.setScope(SearchScope.SUBTREE);
secondSearchRequest.addAttributes("*");
secondSearchRequest.addControl(secondPagedSearchControl);
EntryCursorImpl secondCursor = new EntryCursorImpl(connection.search(secondSearchRequest));
while (secondCursor.next()) {
System.out.println("Second Pass User: " + secondCursor.get().getDn());
}
secondCursor.close();
}catch(Exception e){
System.out.println(e);
}
finally {
try {
connection.unBind();
connection.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
So I guess my new question is:
- Is anybody aware of a workaround to allow OpenLDAP to accept pagination cookies from previous connections?