From c2d6efe56f08399d12f76ea3a31bd5cb885b6caa Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Fri, 01 Mar 2013 17:09:07 +0000
Subject: [PATCH] CR-1327 Fix for OPENDJ-772: Document how to set up the REST to LDAP Servlet
---
opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-rest2ldap.xml | 513 +++++++++++++++++++++++
opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-whats-new.xml | 8
opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-standards.xml | 27 +
opendj-sdk/opendj3/src/main/docbkx/admin-guide/index.xml | 2
opendj-sdk/opendj3/src/main/docbkx/install-guide/chap-install-cli.xml | 82 +++
opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-rest-operations.xml | 612 +++++++++++++++++++++++++++
opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-listeners.xml | 58 ++
opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-before-you-install.xml | 4
8 files changed, 1,303 insertions(+), 3 deletions(-)
diff --git a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-rest2ldap.xml b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-rest2ldap.xml
new file mode 100644
index 0000000..280c699
--- /dev/null
+++ b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-rest2ldap.xml
@@ -0,0 +1,513 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ! CCPL HEADER START
+ !
+ ! This work is licensed under the Creative Commons
+ ! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
+ ! To view a copy of this license, visit
+ ! http://creativecommons.org/licenses/by-nc-nd/3.0/
+ ! or send a letter to Creative Commons, 444 Castro Street,
+ ! Suite 900, Mountain View, California, 94041, USA.
+ !
+ ! You can also obtain a copy of the license at
+ ! trunk/opendj3/legal-notices/CC-BY-NC-ND.txt.
+ ! See the License for the specific language governing permissions
+ ! and limitations under the License.
+ !
+ ! If applicable, add the following below this CCPL HEADER, with the fields
+ ! enclosed by brackets "[]" replaced with your own identifying information:
+ ! Portions Copyright [yyyy] [name of copyright owner]
+ !
+ ! CCPL HEADER END
+ !
+ ! Copyright 2013 ForgeRock AS
+ !
+-->
+<appendix xml:id='appendix-rest2ldap'
+ xmlns='http://docbook.org/ns/docbook' version='5.0' xml:lang='en'
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+ xsi:schemaLocation='http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd'
+ xmlns:xlink='http://www.w3.org/1999/xlink'
+ xmlns:xinclude='http://www.w3.org/2001/XInclude'>
+ <title>REST LDAP Gateway Configuration</title>
+ <indexterm><primary>REST LDAP gateway</primary></indexterm>
+ <!-- This belongs in an OpenDJ reference. Ultimately this doc should
+ be generated, too, rather than written by hand. CREST-71? -->
+
+ <para>The OpenDJ REST LDAP gateway runs as a Servlet independent from your
+ directory service. You configure the gateway to access your directory service
+ by editing <filename>opendj-rest2ldap-servlet.json</filename> where you deploy
+ the gateway web application.</para>
+
+ <variablelist>
+ <para>The JSON format configuration can hold the following configuration
+ objects.</para>
+
+ <varlistentry>
+ <term>"primaryLDAPServers" (required)</term>
+ <listitem>
+ <para>The gateway accesses this array of LDAP servers before failing over
+ to the secondary LDAP servers. These might be LDAP servers in the same
+ data center for example.</para>
+
+ <programlisting language="javascript">{
+ "primaryLDAPServers": [
+ {
+ "hostname": "local1.example.com",
+ "port": 1389
+ },
+ {
+ "hostname": "local2.example.com",
+ "port": 1389
+ }
+ ]
+}</programlisting>
+
+ <para>By default, the gateway connects to the directory server listening
+ on port 1389 on the local host.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <!-- TODO: change when we get more authentication options. -->
+ <term>"authentication" (required)</term>
+ <listitem>
+ <para>The gateway authenticates by simple bind using the credentials
+ specified.</para>
+
+ <programlisting language="javascript">{
+ "authentication": {
+ "bindDN": "cn=Directory Manager",
+ "password": "password"
+ }
+}</programlisting>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"mappings"</term>
+ <listitem>
+ <para>For each gateway collection URI such as <literal>/users</literal> and
+ <literal>/groups</literal>, you configure a mapping between the JSON
+ resource returned by the gateway, and the LDAP entry returned by the
+ directory service.</para>
+
+ <variablelist>
+ <para>Each mapping has a number of configuration elements.</para>
+
+ <varlistentry>
+ <term>"baseDN" (required)</term>
+ <listitem>
+ <para>The base DN where LDAP entries are found for this mapping.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"attributes" (required)</term>
+ <listitem>
+ <para>How the JSON resource fields map to attributes on LDAP
+ entries, each taking the form "<replaceable>field-name</replaceable>":
+ <replaceable>mapping-object</replaceable>. A number of
+ <replaceable>mapping-object</replaceable>s are supported.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>"constant"</term>
+ <listitem>
+ <para>Maps a single JSON attribute to a fixed value.</para>
+
+ <para>This can be useful as in the default case where each JSON
+ resource "schemas" takes the SCIM URN, and so the value is not related
+ to the underlying LDAP entries.</para>
+
+ <programlisting language="javascript">{
+ "schemas": {
+ "constant": [
+ "urn:scim:schemas:core:1.0"
+ ]
+ }
+}</programlisting>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"simple"</term>
+ <listitem>
+ <para>Maps a JSON field to an LDAP attribute.</para>
+
+ <para>Simple mappings are used where the correspondence between JSON
+ fields and LDAP attributes is one-to-one.</para>
+
+ <programlisting language="javascript">{
+ "userName": {
+ "simple": {
+ "ldapAttribute": "mail",
+ "isSingleValued": true,
+ "writability": "readOnly"
+ }
+ }
+}</programlisting>
+
+ <itemizedlist>
+ <para>Simple mappings can take a number of fields.</para>
+
+ <listitem>
+ <para>(Required) "ldapAttribute": the name of LDAP attribute.</para>
+ </listitem>
+
+ <listitem>
+ <para>(Optional) "defaultValue": the JSON value if no LDAP attribute
+ is available on the entry.</para>
+ </listitem>
+
+ <listitem>
+ <para>(Optional) "isBinary": true means the LDAP attribute is
+ binary and the JSON field gets the base64-encoded value.</para>
+ </listitem>
+
+ <listitem>
+ <para>(Optional) "isRequired": true means the LDAP attribute is
+ mandatory and must be provided to create the resource.</para>
+ </listitem>
+
+ <listitem>
+ <para>(Optional) "isSingleValued": true means represent a possibly
+ multi-valued LDAP attribute as a single value, rather than an array
+ of values.</para>
+ </listitem>
+
+ <listitem>
+ <para>(Optional) "writability": indicates whether the LDAP attribute
+ supports updates. This field can take the following values.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>"createOnly": This attribute can be set only when the
+ entry is created. Attempts to update this attribute thereafter
+ result in errors.</para>
+ </listitem>
+ <listitem>
+ <para>"createOnlyDiscardWrites": This attribute can be set only
+ when the entry is created. Attempts to update this attribute
+ thereafter do not result in errors. Instead the update value
+ is discarded.</para>
+ </listitem>
+ <listitem>
+ <para>"readOnly": This attribute cannot be updated. Attempts to
+ update this attribute result in errors.</para>
+ </listitem>
+ <listitem>
+ <para>"readOnlyDiscardWrites": This attribute cannot be updated.
+ Attempts to update this attribute do not result in errors. Instead
+ the update value is discarded.</para>
+ </listitem>
+ <listitem>
+ <para>"readWrite": This attribute can be set at creation and
+ updated thereafter.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"object"</term>
+ <listitem>
+ <para>Maps a JSON object to LDAP attributes.</para>
+
+ <para>This mapping lets you create JSON objects whose fields themselves
+ have mappings to LDAP attributes.</para>
+ </listitem>
+ </varlistentry>
+
+ <!-- More to come?
+ <varlistentry>
+ <term></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ -->
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"namingStrategy" (required)</term>
+ <listitem>
+ <para>The approach used to map LDAP entry names to JSON resources. One
+ of the following.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>RDN and resource ID are both derived from a single user attribute
+ in the LDAP entry, as in the following example, where the
+ <literal>uid</literal> attribute is the RDN and its value is the
+ JSON resource ID.</para>
+
+ <programlisting language="javascript">{
+ "namingStrategy": {
+ "strategy": "clientDNNaming",
+ "dnAttribute": "uid"
+ }
+}</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>RDN and resource ID are derived from separate user attributes in
+ the LDAP entry, as in the following example where the RDN attribute is
+ <literal>uid</literal> but the JSON resource ID is the value of the
+ <literal>mail</literal> attribute.</para>
+
+ <programlisting language="javascript">{
+ "namingStrategy": {
+ "strategy": "clientNaming",
+ "dnAttribute": "uid",
+ "idAttribute": "mail"
+ }
+}</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>RDN is derived from a user attribute and the resource ID from an
+ operational attribute in the LDAP entry, as in the following example,
+ where the RDN attribute is <literal>uid</literal> but the JSON resource
+ ID is the value of the <literal>entryUUID</literal> operational
+ attribute.</para>
+
+ <programlisting language="javascript">{
+ "namingStrategy": {
+ "strategy": "serverNaming",
+ "dnAttribute": "uid",
+ "idAttribute": "entryUUID"
+ }
+}</programlisting>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"additionalLDAPAttributes" (optional, but necessary)</term>
+ <listitem>
+ <para>LDAP attributes to include during LDAP add operations as an
+ array of type-value lists, such as the following example.</para>
+
+ <programlisting language="javascript">{
+ "additionalLDAPAttributes": [
+ {
+ "type": "objectClass",
+ "values": [
+ "top",
+ "person",
+ "organizationalPerson",
+ "inetOrgPerson"
+ ]
+ }
+ ]
+}</programlisting>
+
+ <para>This configuration element is useful to set LDAP object classes
+ for example, which are not present in JSON resources.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"etagAttribute" (optional)</term>
+ <listitem>
+ <para>The LDAP attribute to use for multi-version concurrency control
+ (MVCC).</para>
+
+ <para>Default: "etag"</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"readOnUpdatePolicy" (optional)</term>
+ <listitem>
+ <para>The policy used to read an entry before it is deleted, or to
+ read an entry after it is added or modified. One of the following.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>"controls": use RFC 4527 read-entry controls to reflect the
+ state of the resource at the time the update was performed.</para>
+ <para>The directory service must support RFC 4527.</para>
+ <para>This is the default if no policy is specified.</para>
+ </listitem>
+
+ <listitem>
+ <para>"disabled": do not read the entry or return the resource on
+ update.</para>
+ </listitem>
+
+ <listitem>
+ <para>"search": perform an LDAP search to retrieve the entry before
+ deletion or after it is added or modified.</para>
+ <para>The JSON resource returned might differ from the LDAP entry that
+ was updated.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>The default mapping exposes a SCIM view of sample data.</para>
+
+ <programlisting language="javascript">{
+ "/users": {
+ "baseDN": "ou=people,dc=example,dc=com",
+ "readOnUpdatePolicy": "controls",
+ "additionalLDAPAttributes": [
+ {
+ "type": "objectClass",
+ "values": [
+ "top",
+ "person",
+ "organizationalPerson",
+ "inetOrgPerson"
+ ]
+ }
+ ],
+ "namingStrategy": {
+ "strategy": "clientDNNaming",
+ "dnAttribute": "uid"
+ },
+ "etagAttribute": "etag",
+ "attributes": {
+ "schemas": {
+ "constant": [
+ "urn:scim:schemas:core:1.0"
+ ]
+ },
+ "id": {
+ "simple": {
+ "ldapAttribute": "uid",
+ "isSingleValued": true,
+ "isRequired": true,
+ "writability": "createOnly"
+ }
+ },
+ "rev": {
+ "simple": {
+ "ldapAttribute": "etag",
+ "isSingleValued": true,
+ "writability": "readOnly"
+ }
+ },
+ "userName": {
+ "simple": {
+ "ldapAttribute": "mail",
+ "isSingleValued": true,
+ "writability": "readOnly"
+ }
+ },
+ "displayName": {
+ "simple": {
+ "ldapAttribute": "cn",
+ "isSingleValued": true,
+ "isRequired": true
+ }
+ },
+ "name": {
+ "object": {
+ "givenName": {
+ "simple": {
+ "ldapAttribute": "givenName",
+ "isSingleValued": true
+ }
+ },
+ "familyName": {
+ "simple": {
+ "ldapAttribute": "sn",
+ "isSingleValued": true,
+ "isRequired": true
+ }
+ }
+ }
+ },
+ "contactInformation": {
+ "object": {
+ "telephoneNumber": {
+ "simple": {
+ "ldapAttribute": "telephoneNumber",
+ "isSingleValued": true
+ }
+ },
+ "emailAddress": {
+ "simple": {
+ "ldapAttribute": "mail",
+ "isSingleValued": true
+ }
+ }
+ }
+ }
+ }
+ }
+}</programlisting>
+ </listitem>
+ </varlistentry>
+
+ <!--
+ <varlistentry>
+ <term>"useSSL" (optional)</term>
+ <listitem>
+ <para>If the gateway connects with StartTLS or SSL to the directory
+ service, then you must specify how it uses SSL.</para>
+ <para>TODO: Not yet implemented.</para>
+ </listitem>
+ </varlistentry>
+ -->
+
+ <varlistentry>
+ <term>"secondaryLDAPServers" (optional)</term>
+ <listitem>
+ <para>The gateway accesses this array of LDAP servers if primary LDAP
+ servers cannot be contacted. These might be LDAP servers in the same
+ data center for example.</para>
+
+ <programlisting language="javascript">{
+ "secondaryLDAPServers": [
+ {
+ "hostname": "remote1.example.com",
+ "port": 1389
+ },
+ {
+ "hostname": "remote2.example.com",
+ "port": 1389
+ }
+ ]
+}</programlisting>
+
+ <para>No secondary LDAP servers are configured by default.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"connectionPoolSize" (optional)</term>
+ <listitem>
+ <para>The gateway creates connection pools to the primary and secondary
+ LDAP servers that maintain up to <literal>connectionPoolSize</literal>
+ connections to the servers.</para>
+
+ <para>Default: 10</para>
+
+ <programlisting language="javascript">"connectionPoolSize": 10</programlisting>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>"heartBeatIntervalSeconds" (optional)</term>
+ <listitem>
+ <para>The gateway tests its connections every
+ <literal>heartBeatIntervalSeconds</literal> seconds to detect whether the
+ connection is still alive.</para>
+
+ <para>Default: 30 (seconds)</para>
+
+ <programlisting language="javascript">"heartBeatIntervalSeconds": 30</programlisting>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+</appendix>
diff --git a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-standards.xml b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-standards.xml
index 259864f..337fe4c 100644
--- a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-standards.xml
+++ b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/appendix-standards.xml
@@ -20,7 +20,7 @@
!
! CCPL HEADER END
!
- ! Copyright 2011-2012 ForgeRock AS
+ ! Copyright 2011-2013 ForgeRock AS
!
-->
<appendix xml:id='appendix-standards'
@@ -984,5 +984,30 @@
XML documents.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><link xlink:show="new" xlink:href='http://www.json.org'
+ >JavaScript Object Notation</link></term>
+ <listitem>
+ <indexterm>
+ <primary>Supported standards</primary>
+ <secondary>JSON</secondary>
+ </indexterm>
+ <para>A data-interchange format that aims to be both "easy for humans to
+ read and write," and also "easy for machines to parse and generate."</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><link xlink:show="new"
+ xlink:href='http://www.simplecloud.info/specs/draft-scim-core-schema-00.html'
+ >Simple Cloud Identity Management: Core Schema 1.0</link></term>
+ <listitem>
+ <indexterm>
+ <primary>Supported standards</primary>
+ <secondary>SCIM Core Schema 1.0</secondary>
+ </indexterm>
+ <para>Platform neutral schema and extension model for representing users
+ and groups in JSON and XML formats. OpenDJ supports the JSON formats.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</appendix>
diff --git a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-listeners.xml b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-listeners.xml
index bb9881d..98dae99 100644
--- a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-listeners.xml
+++ b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-listeners.xml
@@ -816,6 +816,64 @@
--trustAll</screen>
</section>
+ <section xml:id="setup-rest2ldap">
+ <title>RESTful Client Access</title>
+ <indexterm><primary>JSON</primary></indexterm>
+ <indexterm><primary>REST</primary></indexterm>
+
+ <orderedlist>
+ <para>OpenDJ offers two ways to give RESTful client applications HTTP access
+ to directory data as JSON resources.</para>
+
+ <listitem>
+ <para>Configure an additional listener on the directory server to respond
+ to REST requests.</para>
+
+ <para>With this approach, you do not need to install additional
+ software.</para>
+ </listitem>
+
+ <listitem>
+ <para>Configure the external REST LDAP gateway Servlet to access your
+ directory service.</para>
+
+ <para>With this approach, you must install the gateway separately.</para>
+ </listitem>
+ </orderedlist>
+
+ <procedure xml:id="setup-rest2ldap-connection-handler">
+ <title>To Set Up REST Access to OpenDJ Directory Server</title>
+
+ <para>Follow these steps to configure a listener for REST access directly
+ to an OpenDJ server.</para>
+
+ <step>
+ <para>TODO, https://bugster.forgerock.org/jira/browse/OPENDJ-688</para>
+ </step>
+ </procedure>
+
+ <procedure xml:id="setup-rest2ldap-gateway">
+ <title>To Set Up OpenDJ REST LDAP Gateway</title>
+
+ <para>Follow these steps to set up OpenDJ REST LDAP gateway Servlet to access
+ your directory service.</para>
+
+ <step>
+ <para>Download and install the gateway as described in <link
+ xlink:href="install-guide#install-rest2ldap-servlet"
+ xlink:role="http://docbook.org/xlink/role/olink"><citetitle>To Install
+ OpenDJ REST LDAP Gateway</citetitle></link>.</para>
+ </step>
+
+ <step>
+ <para>Adjust the configuration for your directory service as described in
+ <link xlink:href="admin-guide#appendix-rest2ldap"
+ xlink:role="http://docbook.org/xlink/role/olink"><citetitle>REST LDAP
+ Gateway Configuration</citetitle></link>.</para>
+ </step>
+ </procedure>
+ </section>
+
<section xml:id="setup-dsml">
<title>DSML Client Access</title>
<indexterm><primary>DSML</primary></indexterm>
diff --git a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-rest-operations.xml b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-rest-operations.xml
new file mode 100644
index 0000000..ce30083
--- /dev/null
+++ b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/chap-rest-operations.xml
@@ -0,0 +1,612 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ! CCPL HEADER START
+ !
+ ! This work is licensed under the Creative Commons
+ ! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
+ ! To view a copy of this license, visit
+ ! http://creativecommons.org/licenses/by-nc-nd/3.0/
+ ! or send a letter to Creative Commons, 444 Castro Street,
+ ! Suite 900, Mountain View, California, 94041, USA.
+ !
+ ! You can also obtain a copy of the license at
+ ! trunk/opendj3/legal-notices/CC-BY-NC-ND.txt.
+ ! See the License for the specific language governing permissions
+ ! and limitations under the License.
+ !
+ ! If applicable, add the following below this CCPL HEADER, with the fields
+ ! enclosed by brackets "[]" replaced with your own identifying information:
+ ! Portions Copyright [yyyy] [name of copyright owner]
+ !
+ ! CCPL HEADER END
+ !
+ ! Copyright 2013 ForgeRock AS
+ !
+-->
+<chapter xml:id='chap-rest-operations'
+ xmlns='http://docbook.org/ns/docbook' version='5.0' xml:lang='en'
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+ xsi:schemaLocation='http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd'
+ xmlns:xlink='http://www.w3.org/1999/xlink'
+ xmlns:xinclude='http://www.w3.org/2001/XInclude'>
+ <title>Performing RESTful Operations</title>
+ <indexterm><primary>JSON</primary></indexterm>
+ <indexterm><primary>REST</primary></indexterm>
+
+ <para>OpenDJ lets you access directory data as JSON resources over HTTP. To
+ configure this capability, see <link xlink:href="admin-guide#setup-rest2ldap"
+ xlink:role="http://docbook.org/xlink/role/olink"><citetitle>REST Client
+ Access</citetitle></link> for instructions.</para>
+
+ <para>This chapter demonstrates basic RESTful client operations using the
+ default configuration and sample directory data imported into OpenDJ from
+ <link xlink:show="new" xlink:href="http://opendj.forgerock.org/Example.ldif"
+ >Example.ldif</link>.</para>
+
+ <section xml:id="understand-rest">
+ <title>Understanding the OpenDJ REST API</title>
+
+ <para>The OpenDJ REST API is built on a common ForgeRock HTTP-based REST API
+ for interacting with JSON Resources. APIs built on this common layer all let
+ you perform the following operations.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>Create</term>
+ <listitem>
+ <para>Add a resource that does not yet exist</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Read</term>
+ <listitem>
+ <para>Retrieve a single resource</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Update</term>
+ <listitem>
+ <para>Replace an existing resource</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Delete</term>
+ <listitem>
+ <para>Remove an existing resource</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Patch</term>
+ <listitem>
+ <para>Modify part of an existing resource</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Action</term>
+ <listitem>
+ <para>Perform a predefined action</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Query</term>
+ <listitem>
+ <para>List a set of resources</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>The present implementation in OpenDJ maps JSON resources onto LDAP
+ entries, meaning REST clients can in principle do just about anything an
+ LDAP client can do with directory data.</para>
+
+ <variablelist>
+ <para>In addition to query string parameters that depend on the operation,
+ the examples in this chapter make use of the following parameters that
+ apply to the JSON resource returned for all operations.</para>
+ <varlistentry>
+ <term><literal>_fields=<replaceable>field</replaceable>[,...]</literal></term>
+ <listitem>
+ <para>Retain only the specified fields in the JSON resource returned.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>_prettyPrint=true|false</literal></term>
+ <listitem>
+ <para>Make the JSON resource returned easy for humans to read.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+
+ <section xml:id="authenticate-rest">
+ <title>Authenticating Over REST</title>
+
+ <para>TODO, https://bugster.forgerock.org/jira/browse/OPENDJ-694</para>
+ </section>
+
+ <section xml:id="create-rest">
+ <title>Creating Resources</title>
+
+ <para>There are two ways to create resources.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>To create a resource using an ID that you specify, perform an HTTP PUT
+ request with headers <literal>Content-Type: application/json</literal> and
+ <literal>If-None-Match: *</literal>, and the JSON content of your
+ resource.</para>
+
+ <para>The following example creates a new user entry with ID
+ <literal>newuser</literal>.</para>
+
+ <screen>$ curl
+ --request PUT
+ --header "Content-Type: application/json"
+ --header "If-None-Match: *"
+ --data '{
+ "id": "newuser",
+ "contactInformation": {
+ "telephoneNumber": "+1 408 555 1212",
+ "emailAddress": "newuser@example.com"
+ },
+ "name": {
+ "familyName": "New",
+ "givenName": "User"
+ },
+ "displayName": "New User"
+ }'
+ http://opendj.example.com:8080/rest2ldap/users/newuser?_prettyPrint=true
+{
+ "id" : "newuser",
+ "rev" : "0000000049522179",
+ "schemas" : [ "urn:scim:schemas:core:1.0" ],
+ "contactInformation" : {
+ "telephoneNumber" : "+1 408 555 1212",
+ "emailAddress" : "newuser@example.com"
+ },
+ "name" : {
+ "familyName" : "New",
+ "givenName" : "User"
+ },
+ "userName" : "newuser@example.com",
+ "displayName" : "New User"
+}</screen>
+ </listitem>
+
+ <listitem>
+ <para>To create a resource letting the server choose the ID, perform an HTTP
+ POST with <literal>_action=create</literal> as described in
+ <xref linkend="action-rest" />.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section xml:id="read-rest">
+ <title>Reading a Resource</title>
+
+ <para>To read a resource, perform an HTTP GET.</para>
+
+ <screen>$ curl http://opendj.example.com:8080/rest2ldap/users/bjensen?_prettyPrint=true
+{
+ "id" : "bjensen",
+ "rev" : "000000002f43b789",
+ "schemas" : [ "urn:scim:schemas:core:1.0" ],
+ "contactInformation" : {
+ "telephoneNumber" : "+1 408 555 1862",
+ "emailAddress" : "bjensen@example.com"
+ },
+ "name" : {
+ "familyName" : "Jensen",
+ "givenName" : "Barbara"
+ },
+ "userName" : "bjensen@example.com",
+ "displayName" : "Barbara Jensen"
+}</screen>
+ </section>
+
+ <section xml:id="update-rest">
+ <title>Updating Resources</title>
+
+ <para>TODO, https://bugster.forgerock.org/jira/browse/OPENDJ-693</para>
+ </section>
+
+ <section xml:id="delete-rest">
+ <title>Deleting Resources</title>
+
+ <para>TODO, https://bugster.forgerock.org/jira/browse/OPENDJ-692</para>
+ </section>
+
+ <section xml:id="patch-rest">
+ <title>Patching Resources</title>
+
+ <para>TODO, https://bugster.forgerock.org/jira/browse/CREST-3</para>
+ </section>
+
+ <section xml:id="action-rest">
+ <title>Using Actions</title>
+
+ <para>OpenDJ implements an action that lets the server choose the resource ID
+ on creation. To use this action, perform an HTTP POST with header
+ <literal>Content-Type: application/json</literal>,
+ <literal>_action=create</literal> in the query string, and the JSON content of
+ your resource.</para>
+
+ <para>The following example creates a new user entry. Lines are folded for
+ readability.</para>
+
+ <para>TODO, fix pending https://bugster.forgerock.org/jira/browse/OPENDJ-775</para>
+ <screen>$ curl
+ --request POST
+ --header "Content-Type: application/json"
+ --data '{
+ "id": "newuser",
+ "contactInformation": {
+ "telephoneNumber": "+1 408 555 1212",
+ "emailAddress": "newuser@example.com"
+ },
+ "name": {
+ "familyName": "New",
+ "givenName": "User"
+ },
+ "displayName": "New User"
+}'
+ http://opendj.example.com:8080/rest2ldap/users?_action=create&_prettyPrint=true
+{
+ "id": "newuser",
+ "rev": "0000000049522179",
+ "schemas": [
+ "urn:scim:schemas:core:1.0"
+ ],
+ "contactInformation": {
+ "telephoneNumber": "+1 408 555 1212",
+ "emailAddress": "newuser@example.com"
+ },
+ "name": {
+ "familyName": "New",
+ "givenName": "User"
+ },
+ "userName": "newuser@example.com",
+ "displayName": "New User"
+}</screen>
+
+ <para>TODO, https://bugster.forgerock.org/jira/browse/OPENDJ-695</para>
+ </section>
+
+ <section xml:id="query-rest">
+ <title>Querying Resource Collections</title>
+
+ <para>To query resource collections, perform an HTTP GET with a
+ <literal>_filter=<replaceable>filter</replaceable></literal> parameter in
+ your query string.</para>
+
+ <variablelist>
+ <para>For query operations, your <replaceable>filter</replaceable>
+ expressions are constructed from the following building blocks.
+ Make sure you URL encode the filter expressions, which are shown here
+ without URL encoding to make them easier to read.</para>
+
+ <para>In these expressions the simplest
+ <replaceable>json-pointer</replaceable> is a field of the JSON resource,
+ such as <literal>userName</literal> or <literal>id</literal>. A
+ <replaceable>json-pointer</replaceable> can however point to nested
+ elements as described in the <link xlink:show="new"
+ xlink:href="http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer">JSON
+ Pointer</link> Internet-Draft.</para>
+
+ <varlistentry>
+ <term>Comparison expressions</term>
+ <listitem>
+ <para>You can build filters using the following comparison expressions.</para>
+
+ <para>Request URLs are folded in the following examples to make them
+ easier to read.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> eq <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches when the pointer equals the value, as in the following
+ example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?
+ _filter=userName+eq+"bjensen@example.com"
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "id" : "bjensen",
+ "rev" : "000000002f43b789",
+ "schemas" : [ "urn:scim:schemas:core:1.0" ],
+ "contactInformation" : {
+ "telephoneNumber" : "+1 408 555 1862",
+ "emailAddress" : "bjensen@example.com"
+ },
+ "name" : {
+ "familyName" : "Jensen",
+ "givenName" : "Barbara"
+ },
+ "userName" : "bjensen@example.com",
+ "displayName" : "Barbara Jensen"
+ } ],
+ "resultCount" : 1,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> co <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches when the pointer contains the value, as in the following
+ example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?
+ _filter=userName+co+"jensen"
+ &_fields=userName
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "userName" : "ajensen@example.com"
+ }, {
+ "userName" : "bjensen@example.com"
+ }, {
+ "userName" : "gjensen@example.com"
+ }, {
+ "userName" : "jjensen@example.com"
+ }, {
+ "userName" : "kjensen@example.com"
+ }, {
+ "userName" : "rjensen@example.com"
+ }, {
+ "userName" : "tjensen@example.com"
+ } ],
+ "resultCount" : 7,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> sw <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches when the pointer starts with the value, as in the
+ following example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?
+ _filter=userName+sw+"ab"
+ &_fields=userName
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "userName" : "abarnes@example.com"
+ }, {
+ "userName" : "abergin@example.com"
+ } ],
+ "resultCount" : 2,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> lt <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches when the pointer is less than the value, as in the
+ following example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?
+ _filter=userName+lt+"ac"
+ &_fields=userName
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "userName" : "abarnes@example.com"
+ }, {
+ "userName" : "abergin@example.com"
+ } ],
+ "resultCount" : 2,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> le <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches when the pointer is less than or equal to the value, as
+ in the following example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?
+ _filter=userName+le+"ad"
+ &_fields=userName
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "userName" : "abarnes@example.com"
+ }, {
+ "userName" : "abergin@example.com"
+ }, {
+ "userName" : "achassin@example.com"
+ } ],
+ "resultCount" : 3,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> gt <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches when the pointer is greater than the value, as in the
+ following example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?
+ _filter=userName+gt+"tt"
+ &_fields=userName
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "userName" : "ttully@example.com"
+ }, {
+ "userName" : "tward@example.com"
+ }, {
+ "userName" : "wlutz@example.com"
+ } ],
+ "resultCount" : 3,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> ge <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches when the pointer is greater than or equal to the value,
+ as in the following example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?
+ _filter=userName+ge+"tw"
+ &_fields=userName
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "userName" : "tward@example.com"
+ }, {
+ "userName" : "wlutz@example.com"
+ } ],
+ "resultCount" : 2,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <!--
+ <varlistentry>
+ <term><literal><replaceable>json-pointer</replaceable> <replaceable>string</replaceable> <replaceable>json-value</replaceable></literal></term>
+ <listitem>
+ <para>Matches an extended comparison.</para>
+ <screen>TODO</screen>
+ </listitem>
+ </varlistentry>
+ -->
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Presence expression</term>
+ <listitem>
+ <para><literal><replaceable>json-pointer</replaceable> pr</literal> matches
+ any resource on which the <replaceable>json-pointer</replaceable> is
+ present, as in the following example.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users?_filter=userName%20pr
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "id" : "abarnes",
+ "rev" : "000000002609a565",
+ "schemas" : [ "urn:scim:schemas:core:1.0" ],
+ "contactInformation" : {
+... many entries omitted ...
+ "userName" : "fdupont@example.fr",
+ "displayName" : "Frederique Dupont"
+ } ],
+ "resultCount" : 151,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Literal expressions</term>
+ <listitem>
+ <para><literal>true</literal> matches any resource in the collection.</para>
+ <para><literal>false</literal> matches no resource in the collection.</para>
+
+ <para>In other words you can list all resources in a collection as in the
+ following example.</para>
+
+ <screen>$ curl http://opendj.example.com:8080/rest2ldap/users?_filter=true
+... much output omitted ...</screen>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Complex expressions</term>
+ <listitem>
+ <para>You can combine expressions using boolean operators
+ <literal>and</literal>, <literal>or</literal>, and <literal>!</literal>
+ (not), using parentheses,
+ <literal>(<replaceable>expression</replaceable>)</literal>, to group
+ expressions. The following example queries resources with last name
+ Jensen and first name starting with <literal>Bar</literal>. Notice that the
+ filters use the JSON pointers <literal>name/familyName</literal> and
+ <literal>name/givenName</literal> to identify the fields that are nested
+ inside the <literal>name</literal> object.</para>
+
+ <screen>$ curl 'http://opendj.example.com:8080/rest2ldap/users
+ ?_filter=(name/familyName+eq+"jensen"+and+name/givenName+sw+"Bar")
+ &_fields=name
+ &_prettyPrint=true'
+{
+ "result" : [ {
+ "name" : {
+ "familyName" : "Jensen",
+ "givenName" : "Barbara"
+ }
+ } ],
+ "resultCount" : 1,
+ "pagedResultsCookie" : null,
+ "remainingPagedResults" : -1
+}</screen>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>You can have the server sort JSON resources before it returns them by
+ using the <literal>_sortKeys[+-]=<replaceable>field</replaceable>[,...]</literal>
+ query string. TODO, pending implementation https://bugster.forgerock.org/jira/browse/OPENDJ-702</para>
+
+ <variablelist>
+ <para>You can page through search results using the following query string
+ parameters.</para>
+
+ <para>TODO, pending implementation https://bugster.forgerock.org/jira/browse/OPENDJ-701</para>
+
+ <varlistentry>
+ <term><literal>__pagedResultsCookie=<replaceable>string</replaceable></literal></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>__pagedResultsOffset=<replaceable>string</replaceable></literal></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>__pagedResultsCookie=<replaceable>string</replaceable></literal></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+</chapter>
diff --git a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/index.xml b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/index.xml
index fed89e1..da38cec 100644
--- a/opendj-sdk/opendj3/src/main/docbkx/admin-guide/index.xml
+++ b/opendj-sdk/opendj3/src/main/docbkx/admin-guide/index.xml
@@ -65,6 +65,7 @@
<xinclude:include href='chap-listeners.xml' />
<xinclude:include href='chap-privileges-acis.xml' />
<xinclude:include href='chap-ldap-operations.xml' />
+ <xinclude:include href='chap-rest-operations.xml' />
<xinclude:include href='chap-indexing.xml' />
<xinclude:include href='chap-replication.xml' />
<xinclude:include href='chap-backup-restore.xml' />
@@ -134,6 +135,7 @@
<xinclude:include href="../shared/glossary.xml" />
+ <xinclude:include href="appendix-rest2ldap.xml" />
<xinclude:include href='appendix-file-layout.xml' />
<xinclude:include href='appendix-ports-used.xml' />
<xinclude:include href='appendix-standards.xml' />
diff --git a/opendj-sdk/opendj3/src/main/docbkx/install-guide/chap-install-cli.xml b/opendj-sdk/opendj3/src/main/docbkx/install-guide/chap-install-cli.xml
index 0983653..d1e8e5a 100644
--- a/opendj-sdk/opendj3/src/main/docbkx/install-guide/chap-install-cli.xml
+++ b/opendj-sdk/opendj3/src/main/docbkx/install-guide/chap-install-cli.xml
@@ -465,6 +465,88 @@
</step>
</procedure>
+ <procedure xml:id="install-rest2ldap-servlet">
+ <title>To Install OpenDJ REST LDAP Gateway</title>
+ <indexterm><primary>REST LDAP gateway</primary></indexterm>
+
+ <para>The OpenDJ REST LDAP gateway functions as a web application in a web
+ application container, running independently of OpenDJ. <!-- Alternatively,
+ you can add an HTTP listener directly to OpenDJ. See <link
+ xlink:href="admin-guide#setup-rest2ldap"
+ xlink:role="http://docbook.org/xlink/role/olink"><citetitle>REST Client
+ Access</citetitle></link> for instructions.--> You configure the gateway
+ to access your directory service by editing
+ <filename>opendj-rest2ldap-servlet.json</filename> where you deploy the
+ gateway web application.</para>
+
+ <step>
+ <para>Deploy
+ <filename>opendj-rest2ldap-servlet-<?eval ${docTargetVersion}?>-servlet.war</filename>
+ according to the instructions for your application server.</para>
+ </step>
+
+ <step>
+ <para>Edit <filename>opendj-rest2ldap-servlet.json</filename> where you
+ deployed the gateway web application.</para>
+
+ <para>The default JSON resource for the configuration includes both
+ connection and authentication information, and also
+ <literal>mappings</literal>. The <literal>mappings</literal> describe how
+ the gateway translates between JSON and LDAP representations of your
+ data. The default <literal>mappings</literal> are built to work with
+ generated example data and also the sample content in <link xlink:show="new"
+ xlink:href="http://opendj.forgerock.org/Example.ldif"
+ >Example.ldif</link>.</para>
+
+ <para>At minimum, make sure that the host name and port numbers for
+ <literal>primaryLDAPServers</literal> are properly configured, that
+ <literal>authentication</literal> reflects the correct simple bind
+ credentials, and that the <literal>mappings</literal> for the endpoints
+ correctly match your directory data.</para>
+
+ <para>For details on the configuration, see <link
+ xlink:href="admin-guide#appendix-rest2ldap"
+ xlink:role="http://docbook.org/xlink/role/olink"><citetitle>REST LDAP
+ Gateway Configuration</citetitle></link>.</para>
+ </step>
+
+ <step>
+ <para>Restart the REST LDAP gateway or the application server to make
+ sure the changes are taken into account.</para>
+ </step>
+
+ <step>
+ <para>Make sure that your directory server is running, and then check that
+ the gateway is connecting correctly.</para>
+
+ <para>The following command reads Babs Jensen's entry through the gateway
+ to the backend holding data from <filename>Example.ldif</filename>.</para>
+
+ <screen>$ curl
+ http://opendj.example.com:8080/rest2ldap/users/bjensen?_prettyPrint=true
+{
+ "id" : "bjensen",
+ "rev" : "000000002f43b789",
+ "schemas" : [ "urn:scim:schemas:core:1.0" ],
+ "contactInformation" : {
+ "telephoneNumber" : "+1 408 555 1862",
+ "emailAddress" : "bjensen@example.com"
+ },
+ "name" : {
+ "familyName" : "Jensen",
+ "givenName" : "Barbara"
+ },
+ "userName" : "bjensen@example.com",
+ "displayName" : "Barbara Jensen"
+}</screen>
+
+ <para>If you generated example data, Babs Jensen's entry is not included.
+ Try a URL such as
+ <literal>http://opendj.example.com:8080/rest2ldap/users/user.0</literal>
+ instead.</para>
+ </step>
+ </procedure>
+
<procedure xml:id="install-dsml-gateway">
<title>To Install OpenDJ DSML gateway</title>
<indexterm><primary>DSML gateway</primary></indexterm>
diff --git a/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-before-you-install.xml b/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-before-you-install.xml
index 95af958..aaaf08d 100644
--- a/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-before-you-install.xml
+++ b/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-before-you-install.xml
@@ -133,8 +133,8 @@
<para>OpenDJ directory server runs as a standalone Java service, and
does not depend on an application server.</para>
- <para>OpenDJ <?eval ${docTargetVersion}?> DSML gateway has been validated
- on Apache Tomcat 6.</para>
+ <para>OpenDJ <?eval ${docTargetVersion}?> DSML and REST LDAP gateway Servlets
+ have been validated on Apache Tomcat 6.</para>
</section>
<section xml:id="prerequisites-fqdn">
diff --git a/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-whats-new.xml b/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-whats-new.xml
index ee7b2af..bfbf726 100644
--- a/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-whats-new.xml
+++ b/opendj-sdk/opendj3/src/main/docbkx/release-notes/chap-whats-new.xml
@@ -68,6 +68,14 @@
<para>TODO: Bring this list up to date post OpenDJ 2.5.0-Xpress1.</para>
</listitem>
<listitem>
+ <para>OpenDJ now provides RESTful access to directory data (<link
+ xlink:show="new"
+ xlink:href="https://bugster.forgerock.org/jira/browse/OPENDJ-687"
+ >OPENDJ-687</link>, <link xlink:show="new"
+ xlink:href="https://bugster.forgerock.org/jira/browse/OPENDJ-688"
+ >OPENDJ-688</link>).</para>
+ </listitem>
+ <listitem>
<para>OpenDJ now sets <literal>isMemberOf</literal> on groups as well as
user entries (<link xlink:show="new"
xlink:href="https://bugster.forgerock.org/jira/browse/OPENDJ-513"
--
Gitblit v1.10.0