Working With Controls This chapter demonstrates how to use LDAP controls.
About LDAP Controls Controls provide a mechanism whereby the semantics and arguments of existing LDAP operations may be extended. One or more controls may be attached to a single LDAP message. A control only affects the semantics of the message it is attached to. Controls sent by clients are termed request controls, and those sent by servers are termed response controls.
Determining Supported Controls For OpenDJ, the controls supported are listed in the Administration Guide appendix, LDAP Controls. You can access the list of OIDs for supported LDAP controls by reading the supportedControl attribute of the root DSE. $ ldapsearch --baseDN "" --searchScope base --port 1389 "(objectclass=*)" supportedControl dn: supportedControl: 1.2.826.0.1.3344810.2.3 supportedControl: 1.2.840.113556.1.4.1413 supportedControl: 1.2.840.113556.1.4.319 supportedControl: 1.2.840.113556.1.4.473 supportedControl: 1.2.840.113556.1.4.805 supportedControl: 1.3.6.1.1.12 supportedControl: 1.3.6.1.1.13.1 supportedControl: 1.3.6.1.1.13.2 supportedControl: 1.3.6.1.4.1.26027.1.5.2 supportedControl: 1.3.6.1.4.1.42.2.27.8.5.1 supportedControl: 1.3.6.1.4.1.42.2.27.9.5.2 supportedControl: 1.3.6.1.4.1.42.2.27.9.5.8 supportedControl: 1.3.6.1.4.1.4203.1.10.1 supportedControl: 1.3.6.1.4.1.4203.1.10.2 supportedControl: 1.3.6.1.4.1.7628.5.101.1 supportedControl: 2.16.840.1.113730.3.4.12 supportedControl: 2.16.840.1.113730.3.4.16 supportedControl: 2.16.840.1.113730.3.4.17 supportedControl: 2.16.840.1.113730.3.4.18 supportedControl: 2.16.840.1.113730.3.4.19 supportedControl: 2.16.840.1.113730.3.4.2 supportedControl: 2.16.840.1.113730.3.4.3 supportedControl: 2.16.840.1.113730.3.4.4 supportedControl: 2.16.840.1.113730.3.4.5 supportedControl: 2.16.840.1.113730.3.4.9 The following excerpt shows couple of methods to check whether the directory server supports a control. /** * Controls supported by the LDAP server. */ private static Collection<String> controls; /** * Populate the list of supported LDAP control OIDs. * * @param connection * Active connection to the LDAP server. * @throws ErrorResultException * Failed to get list of controls. */ static void checkSupportedControls(Connection connection) throws ErrorResultException { controls = RootDSE.readRootDSE(connection).getSupportedControls(); } /** * Check whether a control is supported. Call {@code checkSupportedControls} * first. * * @param control * Check support for this control, provided by OID. * @return True if the control is supported. */ static boolean isSupported(final String control) { if (controls != null && !controls.isEmpty()) { return controls.contains(control); } return false; }
Assertion Request Control The LDAP assertion control lets you specify a condition that must be true in order for the operation you request to be processed normally. The following excerpt shows, for example, how you might check that no description exists on the entry before adding your description. if (isSupported(AssertionRequestControl.OID)) { // Modify Babs Jensen's description if her entry does not have // a description, yet. final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; ModifyRequest request = Requests.newModifyRequest(dn); request.addControl(AssertionRequestControl.newControl(true, Filter .valueOf("!(description=*)"))); request.addModification(ModificationType.ADD, "description", "Created with the help of the LDAP assertion control"); connection.modify(request); LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(connection.readEntry(dn, "description")); writer.close(); } catch (final IOException e) { e.printStackTrace(); } } OpenDJ directory server supports the LDAP assertion control: dn: uid=bjensen,ou=People,dc=example,dc=com description: Created with the help of the LDAP assertion control
Authorization Identity Controls The LDAP Authorization Identity Controls let you get the authorization identity established when you bind to the directory server. The following excerpt shows simple use of the controls. if (isSupported(AuthorizationIdentityRequestControl.OID)) { final String name = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] password = "hifalutin".toCharArray(); System.out.println("Binding as " + name); BindRequest request = Requests.newSimpleBindRequest(name, password); request.addControl(AuthorizationIdentityRequestControl.newControl(true)); final BindResult result = connection.bind(request); try { final AuthorizationIdentityResponseControl control = result.getControl(AuthorizationIdentityResponseControl.DECODER, new DecodeOptions()); System.out.println("Authorization ID returned: " + control.getAuthorizationID()); } catch (final DecodeException e) { e.printStackTrace(); } } OpenDJ directory server supports the LDAP Authorization Identity Controls: Binding as uid=bjensen,ou=People,dc=example,dc=com Authorization ID returned: dn:uid=bjensen,ou=People,dc=example,dc=com
Entry Change Notification Response Controls When performing a persistent search, your application can retrieve information using this response control about why the directory server returned the entry. See the Internet-Draft on persistent searches for background information. if (isSupported(PersistentSearchRequestControl.OID)) { SearchRequest request = Requests.newSearchRequest( "dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(objectclass=inetOrgPerson)", "cn"); request.addControl(PersistentSearchRequestControl.newControl( true, true, true, // isCritical, changesOnly, returnECs PersistentSearchChangeType.ADD, PersistentSearchChangeType.DELETE, PersistentSearchChangeType.MODIFY, PersistentSearchChangeType.MODIFY_DN)); final ConnectionEntryReader reader = connection.search(request); try { while (reader.hasNext()) { if (!reader.isReference()) { final SearchResultEntry entry = reader.readEntry(); System.out.println("Entry changed: " + entry.getName().toString()); EntryChangeNotificationResponseControl control = entry.getControl( EntryChangeNotificationResponseControl.DECODER, new DecodeOptions()); PersistentSearchChangeType type = control.getChangeType(); System.out.println("Change type: " + type.toString()); if (type.equals(PersistentSearchChangeType.MODIFY_DN)) { System.out.println("Previous DN: " + control.getPreviousName().toString()); } System.out.println("Change number: " + control.getChangeNumber()); System.out.println(); // Add a blank line. } } } catch (final DecodeException e) { e.printStackTrace(); } catch (final ErrorResultIOException e) { e.printStackTrace(); } catch (final SearchResultReferenceIOException e) { e.printStackTrace(); } } OpenDJ directory server supports persistent searches and the entry change notification response control. When another application renames Anne-Louise Barnes's entry, the sample code picks up information from the entry change notification response control: Entry changed: uid=bdobbs,ou=People,dc=example,dc=com Change type: modifyDN Previous DN: uid=abarnes,ou=People,dc=example,dc=com Change number: -1
GetEffectiveRights Request Control Your application can attach the GetEffectiveRights request control to a search in order to determine what access a user has to perform operations on entries found. See the Internet-Draft on the Access Control Model for LDAP for background. if (isSupported(GetEffectiveRightsRequestControl.OID)) { final String authDN = "uid=kvaughan,ou=People,dc=example,dc=com"; SearchRequest request = Requests.newSearchRequest( "dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(uid=bjensen)", "cn", "aclRights", "aclRightsInfo"); request.addControl( GetEffectiveRightsRequestControl.newControl(true, authDN, "cn")); final ConnectionEntryReader reader = connection.search(request); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { while (reader.hasNext()) { if (!reader.isReference()) { final SearchResultEntry entry = reader.readEntry(); writer.writeEntry(entry); } } writer.close(); } catch (final ErrorResultIOException e) { e.printStackTrace(); } catch (final SearchResultReferenceIOException e) { e.printStackTrace(); } catch (final IOException e) { e.printStackTrace(); } } OpenDJ SDK currently implements the request control, but not the response control. The results are shown as values of the aclRights and more verbose aclRightsInfo attributes. dn: uid=bjensen,ou=People,dc=example,dc=com aclRightsInfo;logs;attributeLevel;selfwrite_delete;cn: acl_summary(main) : access allowed(write) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com , distinguishedName) to (uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: allow all Admin group) aclRightsInfo;logs;entryLevel;read: acl_summary(main): access allowed(read ) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, objectClass) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied) ( reason : evaluated allow , deciding_aci: Anonymous read-search access) aclRightsInfo;logs;attributeLevel;proxy;cn: acl_summary(main) : access not allowed(proxy) on entry/attr(uid=bjensen,ou=People,dc=example, dc=com, cn) to (uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) (reason: no acis matched the subject ) aclRights;attributeLevel;cn: search:1,read:1,compare:1,write:1,selfwrite_add:1, selfwrite_delete:1,proxy:0 aclRightsInfo;logs;attributeLevel;write;cn: acl_summary(main): access allowed (write) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, cn) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: allow all Admin group) aclRights;entryLevel: add:1,delete:1,read:1,write:1,proxy:0 aclRightsInfo;logs;attributeLevel;search;cn: acl_summary(main): access allowed( search) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, cn) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: Anonymous read-search access) aclRightsInfo;logs;entryLevel;write: acl_summary(main): access allowed(write ) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, NULL) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: allow all Admin group) aclRightsInfo;logs;attributeLevel;selfwrite_add;cn: acl_summary(main ): access allowed(write) on entry/attr(uid=bjensen,ou=People,dc=example, dc=com, distinguishedName) to (uid=kvaughan,ou=People,dc=example,dc=com) ( not proxied) ( reason: evaluated allow , deciding_aci: allow all Admin group) aclRightsInfo;logs;entryLevel;add: acl_summary(main): access allowed(add ) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, NULL) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: allow all Admin group) aclRightsInfo;logs;attributeLevel;read;cn: acl_summary(main): access allowed( read) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, cn) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: Anonymous read-search access) cn: Barbara Jensen cn: Babs Jensen aclRightsInfo;logs;entryLevel;proxy: acl_summary(main): access not allowed( proxy) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, NULL) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: no acis matched the subject ) aclRightsInfo;logs;attributeLevel;compare;cn: acl_summary(main): access allowed (compare) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, cn) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: Anonymous read-search access) aclRightsInfo;logs;entryLevel;delete: acl_summary(main): access allowed( delete) on entry/attr(uid=bjensen,ou=People,dc=example,dc=com, NULL) to ( uid=kvaughan,ou=People,dc=example,dc=com) (not proxied ) ( reason: evaluated allow , deciding_aci: allow all Admin group)
Manage DSAIT Request Control TODO
Matched Values Request Control TODO
Password Expired Response Control TODO
Password Expiring Response Control TODO
Password Policy Controls TODO
Permissive Modify Request Control TODO
Persistent Search Request Control See .
Post-Read Controls TODO
Pre-Read Controls TODO
Proxied Authorization Request Controls TODO
Server-Side Sort Controls TODO
Simple Paged Results Control TODO
Sub-entries Request Control TODO
Subtree Delete Request Control TODO
Virtual List View Controls TODO
Custom Controls TODO