From cf136586c780f03c81e504ec2b8018a0598a9c28 Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Thu, 03 May 2012 13:44:47 +0000
Subject: [PATCH] A bit more for the LDAP controls chapter

---
 opendj3/src/main/docbkx/dev-guide/chap-controls.xml |  273 ++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 242 insertions(+), 31 deletions(-)

diff --git a/opendj3/src/main/docbkx/dev-guide/chap-controls.xml b/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
index add663c..af21720 100644
--- a/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
+++ b/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
@@ -86,30 +86,43 @@
 supportedControl: 2.16.840.1.113730.3.4.5
 supportedControl: 2.16.840.1.113730.3.4.9</screen>
 
-  <para>The following excerpt shows the Java equivalent of the preceding
-  command.</para>
+  <para>The following excerpt shows couple of methods to check whether the
+  directory server supports a control.</para>
 
   <programlisting language="java">
-final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-  host, port);
-Connection connection = null;
+/**
+ * Controls supported by the LDAP server.
+ */
+private static Collection&lt;String> controls;
 
-try
-{
-  connection = factory.getConnection();
+/**
+ * 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();
+}
 
-  // Perform an anonymous search on the root DSE.
-  final SearchResultEntry entry = connection.searchSingleEntry(
-      "",                         // DN is "" for root DSE.
-      SearchScope.BASE_OBJECT,    // Read only the root DSE.
-      "objectclass=*",            // Every object matches this filter.
-      "supportedControl");        // Check supported controls.
-
-  final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
-  writer.writeComment("Supported controls for server " + host + ":" + port);
-  if (entry != null) writer.writeEntry(entry);
-  writer.flush();
-}</programlisting>
+/**
+ * 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 &amp;&amp; !controls.isEmpty()) {
+        return controls.contains(control);
+    }
+    return false;
+}
+</programlisting>
  </section>
  
  <section xml:id="use-assertion-request-control">
@@ -125,11 +138,11 @@
 if (isSupported(AssertionRequestControl.OID)) {
     // Modify Babs Jensen's description if her entry does not have
     // a description, yet.
-    String dn = "uid=bjensen,ou=People,dc=example,dc=com";
+    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.addControl(AssertionRequestControl.newControl(true, Filter
+            .valueOf("!(description=*)")));
     request.addModification(ModificationType.ADD, "description",
             "Created with the help of the LDAP assertion control");
 
@@ -140,26 +153,223 @@
         writer.writeEntry(connection.readEntry(dn, "description"));
         writer.close();
     } catch (final IOException e) {
-        // Ignore.
+        e.printStackTrace();
     }
 }</programlisting>
 
-  <para>OpenDJ directory server supports the LDAP assertion control.</para>
+  <para>OpenDJ directory server supports the LDAP assertion control:</para>
+
+  <programlisting language="ldif">dn: uid=bjensen,ou=People,dc=example,dc=com
+description: Created with the help of the LDAP assertion control</programlisting>
  </section>
- 
+
  <section xml:id="use-authorization-identity-control">
   <title>Authorization Identity Controls</title>
-  <para>TODO</para>
+
+  <para>The <link xlink:href="http://tools.ietf.org/html/rfc3829"
+  xlink:show="new">LDAP Authorization Identity Controls</link> let you get the
+  authorization identity established when you bind to the directory server.
+  The following excerpt shows simple use of the controls.</para>
+
+  <programlisting language="java">
+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();
+    }
+}</programlisting>
+
+  <para>OpenDJ directory server supports the LDAP Authorization Identity
+  Controls:</para>
+
+  <programlisting>Binding as uid=bjensen,ou=People,dc=example,dc=com
+Authorization ID returned: dn:uid=bjensen,ou=People,dc=example,dc=com</programlisting>
  </section>
  
  <section xml:id="use-entry-change-notification-control">
   <title>Entry Change Notification Response Controls</title>
-  <para>TODO</para>
+
+  <para>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 <link xlink:show="new"
+  xlink:href="tools.ietf.org/html/draft-ietf-ldapext-psearch">persistent
+  searches</link> for background information.</para>
+
+  <programlisting language="java">
+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();
+    }
+}
+</programlisting>
+
+  <para>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:</para>
+
+  <programlisting>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</programlisting>
  </section>
  
  <section xml:id="use-get-effective-rights-control">
-  <title>Get Effective Rights Request Control</title>
-  <para>TODO</para>
+  <title>GetEffectiveRights Request Control</title>
+
+  <para>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 <link xlink:show="new"
+  xlink:href="http://tools.ietf.org/html/draft-ietf-ldapext-acl-model">Access
+  Control Model for LDAP</link> for background.</para>
+
+  <programlisting language="java">
+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();
+    }
+}
+</programlisting>
+
+  <para>OpenDJ SDK currently implements the request control, but not the
+  response control. The results are shown as values of the
+  <literal>aclRights</literal> and more verbose <literal>aclRightsInfo</literal>
+  attributes.</para>
+
+  <programlisting language="ldif">
+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)
+</programlisting>
  </section>
  
  <section xml:id="use-manage-dsait-control-control">
@@ -194,7 +404,8 @@
  
  <section xml:id="use-persistent-search-request-control">
   <title>Persistent Search Request Control</title>
-  <para>TODO</para>
+
+  <para>See <xref linkend="use-entry-change-notification-control" />.</para>
  </section>
  
  <section xml:id="use-post-read-control">

--
Gitblit v1.10.0