title: 6.7 - Control navPrev: 6.6-csn.html navPrevText: 6.6 - Csn navUp: 6-ldap-data-structures.html navUpText: 6 - LDAP data structures navNext: 6.8-cursor.html navNextText: 6.8 - Cursor

6.7 - Control (...)

A LDAP Control is an extension to an operation. It tells the server to do something aside the standard operation, or it let the server send back some information to the client. A Control contains three different parts :

  • An identifier, the control OID
  • A flag telling the server what to do if it does not know about the control or if it results in an error (either return an error or ignore the control)
  • A value which is generally BER encoded

There are many controls available, some being standardized, other being server specific.

One or more control can be added to any operation.

Note that either the client or the server might not know about the controls being used, and if the criticality flag is set to FALSE, the server will ignore the control in this case.

Managed controls

Here is the list of controls the LDAP API currently know about. The following short names are used to name the LDAP Servers that support each control.

  • AP : ApacheDS
  • OL : OpenLDAP
  • AD : Active Directory
  • OS : OpenDS
  • OJ : OpenDJ
  • UI : UnboundID
  • ID : IMB DS
  • All : all the servers

The C/S column indicate if the control is sent to the server (S), or back to the client (C) or can be used both ways (C/S).

NameOIDDescriptionC/SRFCLDAP Servers
AdDirSync1.2.840.113556.1.4.841Microsoft LDAP Control for Directory SynchronizationC/SDIRSync draftAD
AdPolicyHints1.2.840.113556.1.4.223Enforces the password history length constraint during password setSLDAP_SERVER_POLICY_HINTS_OIDAD
AdShowDeleted1.2.840.113556.1.4.417DirSync search returns deleted entriesCLDAP_SERVER_SHOW_DELETED_OIDAD
Cascade1.3.6.1.4.1.18060.0.0.1Used to ask the server to delete an entry and all its descendantsSNoneAP
ChangeNotifications1.2.840.113556.1.4.528Registers the client to be notified when changes are made to an object in Active Directory.SLDAP_SERVER_NOTIFICATION_OIDAD
EntryChange2.16.840.1.113730.3.4.7Provides a simple mechanism by which an LDAP client can receive notification of changes that occur in an LDAP serverCPersistent Search: A Simple LDAP Change Notification MechanismAP
ManageDSAIT2.16.840.1.113730.3.4.2Allows access to management objects as standard objectsSRFC 3296AP/OL
PagedResults1.2.840.113556.1.4.319A request/response control used to implement a simple paging of search resultsC/SRFC 2696All
PasswordPolicy1.3.6.1.4.1.42.2.27.8.5.1The password policy controlC/SPasswordPolicy draftAP/OL
PermissiveModify1.2.840.113556.1.4.1413Allows an LDAP modify to work under less restrictive conditionsSLDAP_SERVER_PERMISSIVE_MODIFY_OIDAD
PersistentSearch2.16.840.1.113730.3.4.3Provides a simple mechanism by which an LDAP client can receive notification of changes that occur in an LDAP serverSPersistent SearchAP/OL
ProxiedAuthz2.16.840.1.113730.3.4.18Defines the Proxy Authorization requestSRFC 4370AP/OL
SortRequest1.2.840.113556.1.4.473Server Side Sort request controlSRFC 2891AP/OL
SortResponse1.2.840.113556.1.4.474Server Side Sort request controlCRFC 2891AP/OL
Subentries1.3.6.1.4.1.4203.1.10.1Controls the visibility of entries and subentriesSRFC 3672AP/OL
SyncDoneValue1.3.6.1.4.1.4203.1.9.1.3Control sent when replication has been completed. It contains a cookie.CRFC 4533AP/OL
SyncRequestValue1.3.6.1.4.1.4203.1.9.1.1Controls the syncrepl processSRFC 4533AP/OL
SyncStateValue1.3.6.1.4.1.4203.1.9.1.2Gives the syncrepl stateCRFC 4533AP/OL
VirtualListViewRequest2.16.840.1.113730.3.4.9Sent to the server to request a subset of resultsSScrolling View Browsing of Search ResultsAP
VirtualListViewResponse2.16.840.1.113730.3.4.10Sent back to the client to give the search current statusCScrolling View Browsing of Search ResultsAP

How to use controls

It's quite simple. You just have to instanciate the control you want to use, set its value, and add it to the request you will send to the server. Here is an example with the ManageDsaIT control :

:::Java
AddRequest addRequest = new AddRequestImpl();       // Create the request
ManageDsaIT manageDSAIT = new ManageDsaITImpl();    // Instanciate the control
manageDSAIT.setCritical( true );                    // Set a value
addRequest.addControl( manageDSAIT );               // Add the control to the request
...

and that's it !

Note that you have to create an instance of teh operation you want to send to the server, if yu want to add a control to it.

On the client side, you may want to check if there is a control and read it if so. This is a bit more complex, because you need to know which kind of control you are expecting. We will see with a more complex control, the Paged Search control (which allows the user to get a specific number of enries at each call). Here, we will fetch 4 entries in one go, until all the entries have been read, and as we have 10 entries to read, we will send 3 SearchRequest, teh first two will return 4 entries and the last one only 2.

:::Java
try ( LdapConnection connection = new LdapNetworkConnection( "MyServer", 389 ) )
{
    connection.bind( "cn=user,ou=system", "secret" );

    // Create the control, and tell it we want 4 entries for every call
    PagedResults pagedControl = new PagedResultsImpl();
    pagedControl.setSize( 4 );

    // Read all the elements
    List<Entry> results = new ArrayList<>();

    // Create the SearchRequest
    SearchRequest searchRequest = new SearchRequestImpl();
    searchRequest.setBase( new Dn( "dc=users,ou=system" ) );
    searchRequest.setFilter( "(cn=*)" );
    searchRequest.setScope( SearchScope.SUBTREE );

    while ( true )
    {
        // Add the PagedSearch control to the SearchRequest
        searchRequest.addControl( pagedControl );
            
        // Do the search now
        try ( SearchCursor cursor = connection.search( searchRequest ) )
        {
            // Loop on all the entries we got back (Should be 4, or less)
            while ( cursor.next() )
            {
                Entry result = cursor.getEntry();
                results.add( result );
            }

            // Check if we have reached the size limit
            if ( cursor.getSearchResultDone().getLdapResult().getResultCode() == ResultCodeEnum.SIZE_LIMIT_EXCEEDED )
            {
                break;
            }
    
            // Now check the returned controls
            Map<String, Control> controls =  cursor.getSearchResultDone().getControls();

            // We should get a PagedResult response
            PagedResults responseControl = ( PagedResults ) controls.get( PagedResults.OID );

            if ( responseControl != null )
            {
                // check if this is over, ie the cookie is empty
                byte[] cookie = responseControl.getCookie();
            
                if ( Strings.isEmpty( cookie ) )
                {
                    // Ok, we are done
                    break;
                }

                // Prepare the next iteration, sending a bad cookie
                pagedControl.setCookie( cookie );
            }
            else
            {
                break;
            }
        }
    }

    // At this point, we should have read 10 entries
}

This sounds like a bit complex, but actually, this control is complex. What we are interested in is the way we get the control returned by the server. In this case, the control we are interested in is attached to the SearchResultDone response, which is the last result we have when reading the cursor. As we may have more than one control, the response conains a Map of controls, ot of which we should be able to retreive the PagedSearch control from its OID. This is what does this piece of code :

:::Java
            ...
            // We should get a PagedResult response
            PagedResults responseControl = ( PagedResults ) controls.get( PagedResults.OID );
            ...

If it's not null, we can proceed with the control.

Side note : in this piece of code, we don't close the connection nor the cursor, because they are Closeable : They will be close when we exit the try scope. This is a feature added in Java 7, called try with resources

Managed Controls detail

AdDirSync

A control used to initiate a synchronization with an Active Directory server, and get back the results. Check Microsoft LDAP Control for Directory Synchronization for a better understanding on how to use this control.

  • OID : 1.2.840.113556.1.4.841
  • Criticality : TRUE
  • ASN.1 description :

Sent to the server :

realReplControlValue ::= SEQUENCE {
    flags                 integer
    maxBytes              integer
    cookie                OCTET STRING
}

This control is only valid when send with a SearchRequest.

Received from the server :

realReplControlValue ::= SEQUENCE {
    flag                  integer
    maxReturnLength       integer
    cookie                OCTET STRING
}

The cookie read from this control has to be injected in the control sent to the server for the next search.

AdPolicyHints

  • OID : 1.2.840.113556.1.4.223

AdShowDeleted

  • OID : 1.2.840.113556.1.4.417

Cascade

  • OID : 1.3.6.1.4.1.18060.0.0.1

ChangeNotifications

  • OID : 1.2.840.113556.1.4.528

EntryChange

  • OID : 2.16.840.1.113730.3.4.7

ManageDSAIT

  • OID : 2.16.840.1.113730.3.4.2

This is oe of the simplest control : it has no value, and he criticality flag may be absent.

It‘s used to get access to special objects, like referrals or subentries as normal objects. Let’s see what that means for referrals.

A Referral is a special object which once returned to the client, will automatically will redirect the client to another part of teh DIT (or to another LDAP server). So to speak, the end user does not see the referral, but the reffered entry. The question is : how do we set a referral, or how do we modify it ? We use the ManageDsaIT control.

Let say we have such an entry, which is actually a referal :

dn: uid=entryRef,ou=users,dc=acme,dc=com
objectClass: extensibleObject
objectClass: referral
objectClass: top
uid: entryref"
ref: ldap://localhost:10389/uid=entry,ou=users,dc=acme,dc=com
ref: ldap://trust:10389/uid=entry,ou=users,dc=trust,dc=com

A client searchingg for uid=entryRef,ou=users,dc=acme,dc=com will be redirected to uid=entry,ou=users,dc=acme,dc=com on the local server or on uid=entry,ou=users,dc=trust,dc=com on the trust server (it's up to the client to decide which entry to fetch).

If we want to modify this referral, we need to add the ManageDsaIT control :

:::Java
try ( LdapConnection connection = new LdapNetworkConnection( "MyServer", 389 ) )
{
    connection.bind( "cn=user,ou=system", "secret" );

    // modify the referral 
    ModifyRequest modifyRequest = new ModifyRequestImpl();
    modifyRequest.setName( new Dn( "uid=entryRef,ou=users,dc=acme,dc=com" ) );
    modifyRequest.add( "ref", "ldap://subsidiary:10389/uid=entry,ou=users,dc=subsidiary,dc=com" );

    // Add the control
    modifyRequest.addControl( new ManageDsaITImpl() );

    // And apply the modification
    connection.modify( modifyRequest );
}

Now, if we fetch the entry (still using the control), it will looks like :

dn: uid=entryRef,ou=users,dc=acme,dc=com
objectClass: extensibleObject
objectClass: referral
objectClass: top
uid: entryref"
ref: ldap://localhost:10389/uid=entry,ou=users,dc=acme,dc=com
ref: ldap://trust:10389/uid=entry,ou=users,dc=trust,dc=com
ref: ldap://subsidiary:10389/uid=entry,ou=users,dc=subsidiary,dc=com

As you can see, a third ref value has been added.

PagedResults

  • OID : 1.2.840.113556.1.4.319

PasswordPolicy

  • OID : 1.3.6.1.4.1.42.2.27.8.5.1

PermissiveModify

  • OID : 1.2.840.113556.1.4.1413

PersistentSearch

  • OID : 2.16.840.1.113730.3.4.3

ProxiedAuthz

  • OID : 2.16.840.1.113730.3.4.18

SortRequest

  • OID : 1.2.840.113556.1.4.473

SortResponse

  • OID : 1.2.840.113556.1.4.474

Subentries

  • OID : 1.3.6.1.4.1.4203.1.10.1

SyncDoneValue

  • OID : 1.3.6.1.4.1.4203.1.9.1.3

SyncRequestValue

  • OID : 1.3.6.1.4.1.4203.1.9.1.1

SyncStateValue

  • OID : 1.3.6.1.4.1.4203.1.9.1.2

VirtualListViewRequest

  • OID : 2.16.840.1.113730.3.4.9

VirtualListViewResponse

  • OID : 2.16.840.1.113730.3.4.10