2

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?
8
  • Can you show the actual (whole) code that runs properly against AD ? Commented Aug 30, 2019 at 13:33
  • Unfortunately, it's pretty coupled with the rest of my project which I can't share. I'll see if I can write a smaller test. Commented Aug 30, 2019 at 17:28
  • hmm... ported the code to Java... and it worked with both directories. i've pasted the code in the post. Commented Aug 30, 2019 at 18:09
  • Now I've reproduced my error in Java. the OpenLDAP cookie is only good within the same connection. When I reset the connection the cookie no longer works. I wonder if there is a way to make OpenLDAP accept page cookies from old connections? Commented Aug 30, 2019 at 20:38
  • No there isn't. The operation doesn't make sense. Otherwise the server would have to retain the state of every pagination search that had ever been performed in case somebody came back ten years later with an old search state cookie. Use the same connection. Commented Aug 30, 2019 at 23:26

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.