chap-samples.xml revision c355621bcb8725bc8482a3205306b97ebaa2e368
<?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
! legal/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 2011-2014 ForgeRock AS
!
-->
<chapter xml:id='chap-samples'
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'>
<title>More OpenIDM Samples</title>
<para>The current distribution of OpenIDM comes with a variety of samples
in <filename>openidm/samples/</filename>. Sample 1 is described in
<link xlink:href="install-guide#chap-sample"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>First OpenIDM
Sample</citetitle></link>. This chapter describes the remaining OpenIDM
samples.</para>
<section xml:id="before-you-begin-samples">
<title>Before You Begin</title>
<para>Install OpenIDM, as described in <link
xlink:href="install-guide#chap-install"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Installing
OpenIDM Services</citetitle></link>.</para>
<para>OpenIDM comes with an internal noSQL database, OrientDB, for use as
the internal repository out of the box. This makes it easy to get started
with OpenIDM. OrientDB is not yet supported for production use, however,
so use a supported JDBC database when moving to production.</para>
<section xml:id="install-samples">
<title>Installing the Samples</title>
<indexterm>
<primary>Installing</primary>
<secondary>Samples</secondary>
</indexterm>
<para>
Each sample directory in <filename>openidm/samples/</filename> contains a
number of subdirectories, such as <filename>conf/</filename> and
<filename>script/</filename>. To start OpenIDM with a sample configuration,
navigate to the <filename>/path/to/openidm</filename> directory and use the
<literal>-p</literal> option of the <command>startup</command> command to
point to the sample whose configuration you want to use. Some, but not all
samples require additional software, such as an external LDAP server or
database.
</para>
<para>
When you move from one sample to the next, bear in mind that you are
changing the OpenIDM configuration. For information on how configuration
changes work, see <link xlink:href="integrators-guide#when-configuring-notes"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Changing the
Configuration</citetitle></link> in the <citetitle>Integrator's
Guide</citetitle>.
</para>
</section>
<section xml:id="preparing-openidm">
<title>Preparing OpenIDM</title>
<para>Install an instance of OpenIDM specifically to try the samples. That
way you can experiment as much as you like, and discard the result if you
are not satisfied.</para>
<para>
If you are using the same instance of OpenIDM for multiple samples, it is
helpful to clear out the repository created for an earlier sample. To do so,
shut down OpenIDM and delete the <filename>openidm/db/openidm</filename>
directory.
</para>
<screen>$ rm -rf /path/to/openidm/db/openidm</screen>
<para>
OpenIDM should now be ready to start with a new sample. For a number of
the following samples, users are created either at the UI or with a
commons REST call. Once added, and when reconciliation is complete, such
users should be able to log into the UI.
</para>
</section>
</section>
<section xml:id="more-sample1">
<title>Sample 1 - XML File</title>
<para>Sample 1 is described in the chapter, <link
xlink:href="install-guide#chap-sample"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>First OpenIDM
Sample</citetitle></link>.</para>
</section>
<section xml:id="more-sample2">
<title>Sample 2 - LDAP One Way</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 2 - LDAP one way</secondary>
</indexterm>
<para>Sample 2 resembles the first sample, but in sample 2 OpenIDM is
connected to a local LDAP server. The sample has been tested with
<link xlink:show="new" xlink:href="http://www.forgerock.org/opendj.html">OpenDJ
</link>, but it should work with any LDAPv3 compliant server.</para>
<para>Sample 2 demonstrates how OpenIDM can pick up new or changed objects
from an external resource. The sample contains only one mapping, from the
external LDAP server resource to the OpenIDM repository. The sample therefore
does not push any changes made to OpenIDM managed user objects out to the
LDAP server.</para>
<section xml:id="external-ldap-config-2">
<title>LDAP Server Configuration</title>
<itemizedlist>
<para>Sample 2 expects the following configuration for the external LDAP
server:</para>
<listitem><para>The LDAP server runs on the local host.</para></listitem>
<listitem><para>The LDAP server listens on port 1389.</para></listitem>
<listitem><para>A user with DN <literal>cn=Directory Manager</literal>
and password <literal>password</literal> has read access to the LDAP
server.</para></listitem>
<listitem>
<para>Directory data for that server is stored under base DN
<literal>dc=example,dc=com</literal>.</para>
</listitem>
<listitem><para>User objects for that server are stored under base DN
<literal>ou=People,dc=example,dc=com</literal>.</para></listitem>
<listitem><para>User objects have the object class
<literal>inetOrgPerson</literal>.</para></listitem>
<listitem><para>User objects have the following attributes:</para>
<itemizedlist>
<listitem><para><literal>cn</literal></para></listitem>
<listitem><para><literal>description</literal></para></listitem>
<listitem><para><literal>givenName</literal></para></listitem>
<listitem><para><literal>mail</literal></para></listitem>
<listitem><para><literal>sn</literal></para></listitem>
<listitem><para><literal>telephoneNumber</literal></para></listitem>
<listitem><para><literal>uid</literal></para></listitem>
<listitem><para><literal>userPassword</literal></para></listitem>
</itemizedlist>
<para>An example user object follows.</para>
<programlisting language="ldif">
dn: uid=jdoe,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
givenName: John
uid: jdoe
cn: John Doe
telephoneNumber: 1-415-523-0772
sn: Doe
mail: jdoe@example.com
description: Created by OpenIDM
userPassword: password</programlisting>
</listitem>
</itemizedlist>
<para>Prepare the LDAP server by creating a base suffix of
<literal>dc=example,dc=com</literal>, and importing these objects from
<filename>samples/sample2/data/Example.ldif</filename>.</para>
<programlisting language="ldif">
dn: dc=com
objectClass: domain
objectClass: top
dc: com
dn: dc=example,dc=com
objectClass: domain
objectClass: top
dc: example
dn: ou=People,dc=example,dc=com
ou: people
description: people
objectclass: organizationalunit
dn: uid=jdoe,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
givenName: John
uid: jdoe
cn: John Doe
telephoneNumber: 1-415-523-0772
sn: Doe
mail: jdoe@example.com
description: Created for OpenIDM
userPassword: password
</programlisting>
<para>There is an additional user, <literal>bjensen</literal> in the
sample LDIF file. This user is essentially a "dummy" user, provided for
compliance with RFC 4519, which stipulates that every
<literal>groupOfUniqueNames</literal> object must contain at least one
<literal>uniqueMember</literal>.</para>
</section>
<section xml:id="install-sample2">
<title>Install the Sample</title>
<para>Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>,
then start OpenIDM with the configuration for sample 2.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample2</screen>
</section>
<section xml:id="run-sample2">
<title>Running the Sample</title>
<para>Run reconciliation over the REST interface.</para>
<screen width="91"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemLdapAccounts_managedUser"</screen>
<para>Successful reconciliation returns an "_id" object.</para>
<note>
<para>
If you want to run a <command>curl</command> command over regular HTTP,
remove the <literal>--cacert self-signed.crt</literal> option and change
the URL to use protocol HTTP over port 8080. For instructions on how
to set up a <filename>self-signed.crt</filename>, see the Integrator's
Guide section entitled <link xlink:show="new"
xlink:href="integrators-guide#rest-over-https"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Restrict REST Access to the HTTPS Port</citetitle></link>.
</para>
</note>
<para>With the configuration of sample 2, OpenIDM creates user objects from
LDAP in OpenIDM, assigning the new objects random unique IDs. To list user
objects by ID, run a query over the REST interface.</para>
<screen>
$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"</screen>
<para>
If you want the output to be formatted, include the
<literal>_prettyPrint=true</literal> request parameter or pipe the output to
a JSON parser such as <command>jq</command>, otherwise the resulting JSON
object appears all on one line.
</para>
<programlisting language="javascript">
{
"result": [
{
"_id": "53fbf0c5-aa37-4845-a4b3-92a21810a36d"
"_rev": "0",
},
{
"_id": "ae0aed26-2a9c-43e3-a6f0-ca707c9c6455"
"_rev": "0",
}
],
"resultCount": 2,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
}</programlisting>
<para>
You should now be able to review reconciled users in the UI. Connect to
an appropriate URI such as <literal>https://localhost:8443/openidmui</literal>,
log in as the <literal>openidm-admin</literal> user, and navigate to the
Users tab. Select the desired user for current profile information as shown.
</para>
<mediaobject>
<alt>Example of adding a new user</alt>
<imageobject>
<imagedata fileref="images/sample2-bjensen.png" format="PNG" />
</imageobject>
</mediaobject>
<para>Alternatively, you can still retrieve individual user objects by ID, as
shown here.</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/53fbf0c5-aa37-4845-a4b3-92a21810a36d"</screen>
<para>Read <filename>openidm/samples/sample2/conf/sync.json</filename> and
<filename>openidm/samples/sample2/conf/provisioner.openicf-ldap.json</filename>
to understand the layout of the user object in the repository.</para>
</section>
</section>
<section xml:id="more-sample2b">
<title>Sample 2b - LDAP Two Way</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 2b - LDAP two way</secondary>
</indexterm>
<para>Like sample 2, sample 2b also connects to an external LDAP
server.</para>
<para>Unlike sample 2, however, sample 2b has two mappings configured, one
from the LDAP server to the OpenIDM repository, and the other from the
OpenIDM repository to the LDAP server.</para>
<section xml:id="external-ldap-config-2b">
<title>External LDAP Configuration</title>
<para>Configure the LDAP server as for sample 2,
<xref linkend="external-ldap-config-2" />. The LDAP user must have write
access to create users from OpenIDM on the LDAP server.</para>
<para>
When configuring the LDAP server, be sure to import the appropriate
LDIF file, in this case,
<filename>/path/to/openidm/samples/sample2b/data/Example.ldif</filename>
</para>
</section>
<section xml:id="install-sample2b">
<title>Install the Sample</title>
<para>Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>,
then start OpenIDM with the configuration for sample 2b.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample2b</screen>
</section>
<section xml:id="run-sample2b">
<title>Running the Sample</title>
<para>Run reconciliation over the REST interface.</para>
<screen width="96"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemLdapAccounts_managedUser"</screen>
<para>Successful reconciliation returns an "_id" object.</para>
<para>With the configuration of sample 2b, OpenIDM creates user objects from
LDAP in OpenIDM, assigning the new objects random unique IDs. To list user
objects by ID, run a query over the REST interface.</para>
<screen>
$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"
</screen>
<para>The resulting JSON object should include content similar to the
following.</para>
<programlisting language="javascript">
{
"result": [
{
"_id": "53fbf0c5-aa37-4845-a4b3-92a21810a36d"
"_rev": "0",
},
{
"_id": "6490489f-bbff-4855-808a-5c1862b09339"
"_rev": "0",
}
"resultCount": 2,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
],
}</programlisting>
<para>To retrieve the user, log into the UI, on an URI such as
<literal>https://localhost:8443/openidmui</literal> as the administrative
user
</para>
<para>
Alternatively, you can make a commons REST call to get a specific user
object by ID.</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/53fbf0c5-aa37-4845-a4b3-92a21810a36d"</screen>
<para>Test the second mapping by creating a user in the OpenIDM
repository. On UNIX:</para>
<screen width="100">$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--data '{"mail":"fdoe@example.com","sn":"Doe","telephoneNumber","555-1234",
"userName":"fdoe","givenName":"Felicitas","description":"Felicitas Doe",
"displayName":"fdoe"}' \
--request POST \
"http://localhost:8443/openidm/managed/user?_action=create"</screen>
<para>On Windows:</para>
<screen width="100">$ curl ^
--cacert self-signed.crt ^
--header "X-OpenIDM-Username: openidm-admin" ^
--header "X-OpenIDM-Password: openidm-admin" ^
--header "Content-Type: application/json" ^
--request POST ^
--data "{\"mail\":\"fdoe@example.com\",\"sn\":\"Doe\",
\"telephoneNumber"\:\"555-1234\",
\"userName\":\"fdoe\", \"givenName\":\"Felicitas\",
\"description\":\"Felicitas Doe\",\"displayName\":\"fdoe\"}" ^
"http://localhost:8443/openidm/managed/user?_action=create"</screen>
<para>By default, automatic synchronization is enabled. This means that
when you update a managed object, any mappings defined in the
<filename>sync.json</filename> file are automatically executed to update
the target system. For more information, see <link
xlink:href="integrators-guide#synchronization-mappings-file"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Synchronization Mappings File</citetitle></link> in the
<citetitle>Integrator's Guide</citetitle>.</para>
<para>Test that the automatic reconciliation has been successful by
locating the new user in the LDAP directory.</para>
<screen>$ <userinput>/path/to/OpenDJ/bin/ldapsearch \
-bindDN "cn=Directory Manager" \
-bindPassword password \
-hostname localhost \
-port 1389 \
-baseDN "dc=example,dc=com" \
"uid=fdoe" </userinput>
<computeroutput>dn: uid=fdoe,ou=People,dc=example,dc=com
mail: fdoe@example.com
givenName: Felicitas
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
uid: fdoe
cn: Felicitas Doe
sn: Doe</computeroutput>
</screen>
</section>
</section>
<section xml:id="more-sample2c">
<title>Sample 2c - Synchronizing LDAP Group Membership</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 2c - Synchronizing LDAP Group Membership</secondary>
</indexterm>
<para>Like sample 2b, sample 2c also connects to an external LDAP
server. The only difference is that in sample 2c, LDAP Group Memberships
are synchronized.</para>
<section xml:id="external-ldap-config-2c">
<title>External LDAP Configuration</title>
<para>Configure the LDAP server as for sample 2,
<xref linkend="external-ldap-config-2" />. The LDAP user must have write
access to create users from OpenIDM on the LDAP server.</para>
<para>In addition, two LDAP Groups should be created, which can be found in
the LDIF file: <filename>openidm/samples/sample2c/data/Example.ldif</filename>:</para>
<programlisting language="ldif">
dn: ou=Groups,dc=example,dc=com
ou: Groups
objectClass: organizationalUnit
objectClass: top
dn: cn=openidm,ou=Groups,dc=example,dc=com
uniqueMember: uid=jdoe,ou=People,dc=example,dc=com
cn: openidm
objectClass: groupOfUniqueNames
objectClass: top
dn: cn=openidm2,ou=Groups,dc=example,dc=com
uniqueMember: uid=bjensen,ou=People,dc=example,dc=com
cn: openidm2
objectClass: groupOfUniqueNames
objectClass: top</programlisting>
<para>The users with DNs <literal>uid=jdoe,ou=People,dc=example,dc=com</literal>
and <literal>uid=bjensen,ou=People,dc=example,dc=com</literal> are also
imported with the <filename>Example.ldif</filename> file. (The user
<literal>bjensen</literal> is essentially a "dummy" user, provided for
compliance with RFC 4519, which stipulates that every
<literal>groupOfUniqueNames</literal> object must contain at least one
<literal>uniqueMember</literal>. User <literal>bjensen</literal> is not
actually used in this sample.)</para>
</section>
<section xml:id="install-sample2c">
<title>Install the Sample</title>
<para>Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>,
then start OpenIDM with the configuration for sample 2c.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample2c</screen>
</section>
<section xml:id="run-sample2c">
<title>Running the Sample</title>
<para>Run reconciliation over the REST interface.</para>
<screen width="91"><?dbfo pgwide="1"?>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemLdapAccounts_managedUser"
</userinput></screen>
<para>Successful reconciliation returns an "_id" object.</para>
<para>With the configuration of sample 2c, OpenIDM creates user objects from
LDAP in OpenIDM, assigning the new objects random unique IDs. To list user
objects by ID, run a query over the REST interface.</para>
<screen>
$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"
</screen>
<para>The resulting JSON object should appear similar to the following:</para>
<programlisting language="javascript">
{
"result": [
{
"_id": "53fbf0c5-aa37-4845-a4b3-92a21810a36d"
"_rev": "0",
}
{
"_id": "56f0fb7e-3837-464d-b9ec-9d3b6af665c3",
"_rev": "0"
}
]
"resultCount": 2,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
}</programlisting>
<para>You should now be able to retrieve John Doe's user object in the UI,
navigating to the domain for OpenIDM such as
<literal>https://localhost:8443/openidmui</literal>. Alternatively, with a
bit of trial and error, you can retrieve John Doe's user object at the
command line by his ID.</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/53fbf0c5-aa37-4845-a4b3-92a21810a36d"</screen>
<para>The user object should contain a property like: </para>
<screen>"ldapGroups":["cn=openidm,ou=Groups,dc=example,dc=com"]</screen>
<para>Now change the user on the OpenIDM side with the following REST
call (on UNIX):</para>
<screen width="96"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '[
{
"operation":"replace",
"field":"ldapGroups",
"value": ["cn=openidm2,ou=Groups,dc=example,dc=com"]
}
]' \
"https://localhost:8443/openidm/managed/user?_action=patch&amp;_queryId=for-userName&amp;uid=jdoe"
</screen>
<para>
On Windows, you might need to escape certain characters, so your REST call
would look like this:
</para>
<screen width="96"><?dbfo pgwide="1"?>$ curl ^
--cacert self-signed.crt ^
--header "X-OpenIDM-Username: openidm-admin" ^
--header "X-OpenIDM-Password: openidm-admin" ^
--header "Content-Type: application/json" ^
--request POST ^
--data "[
{
\"operation\":\"replace\",
\"field\":\"ldapGroups\",
\"value\": [\"cn=openidm2,ou=Groups,dc=example,dc=com\"]
}
]" ^
"https://localhost:8443/openidm/managed/user?_action=patch&amp;_queryId=for-userName&amp;uid=jdoe"
</screen>
<para>This will change the user's <literal>ldapGroups</literal> property
in OpenIDM from <filename>"cn=openidm,ou=Groups,dc=example,dc=com"</filename>
to <filename>"cn=openidm2,ou=Groups,dc=example,dc=com"</filename> and, as a
result, the user will be removed from the one LDAP group and added to
the other LDAP group on OpenDJ.</para>
<para>Retrieve John Doe's user object again and notice the changed
<literal>"ldapGroups"</literal> property.</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/56f0fb7e-3837-464d-b9ec-9d3b6af665c3"</screen>
<para>By default, automatic synchronization is enabled. This means that
when you update a managed object, any mappings defined in the
<filename>sync.json</filename> file are automatically executed to update
the target system. For more information, see <link
xlink:href="integrators-guide#synchronization-mappings-file"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Synchronization Mappings File</citetitle></link> in the
<citetitle>Integrator's Guide</citetitle>.</para>
</section>
</section>
<section xml:id="more-sample2d">
<title>Sample 2d - Synchronizing LDAP Groups</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 2d - Synchronizing LDAP Groups</secondary>
</indexterm>
<para>Sample 2d also connects to an external LDAP server. This sample
focuses on LDAP Group synchronization.</para>
<section xml:id="external-ldap-config-2d">
<title>External LDAP Configuration</title>
<para>Configure the LDAP server as for sample 2,
<xref linkend="external-ldap-config-2" />. The LDAP user must have write
access to create users from OpenIDM on the LDAP server.</para>
<para>In addition, two LDAP Groups should be created, which can be found in
the LDIF file: <filename>openidm/samples/sample2d/data/Example.ldif</filename>
(if they have not already been added through sample 2c):</para>
<programlisting language="ldif">
dn: ou=Groups,dc=example,dc=com
ou: Groups
objectClass: organizationalUnit
objectClass: top
dn: cn=openidm,ou=Groups,dc=example,dc=com
uniqueMember: uid=jdoe,ou=People,dc=example,dc=com
cn: openidm
objectClass: groupOfUniqueNames
objectClass: top
dn: cn=openidm2,ou=Groups,dc=example,dc=com
uniqueMember: uid=bjensen,ou=People,dc=example,dc=com
uniqueMember: uid=jdoe,ou=People,dc=example,dc=com
cn: openidm2
objectClass: groupOfUniqueNames
objectClass: top
</programlisting>
<para>The user with dn <literal>uid=jdoe,ou=People,dc=example,dc=com</literal>
is also imported with the <filename>Example.ldif</filename> file.</para>
<para>There is an additional user, <literal>bjensen</literal> in the
sample LDIF file. This user is essentially a "dummy" user, provided for
compliance with RFC 4519, which stipulates that every
<literal>groupOfUniqueNames</literal> object must contain at least one
<literal>uniqueMember</literal>. <literal>bjensen</literal> is not actually
used in this sample.</para>
</section>
<section xml:id="install-sample2d">
<title>Install the Sample</title>
<para>Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>,
then start OpenIDM with the configuration for sample 2d.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample2d</screen>
</section>
<section xml:id="run-sample2d">
<title>Running the Sample</title>
<para>Run reconciliation <emphasis>for the groups mapping</emphasis> over
the REST interface.</para>
<screen width="91"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemLdapGroups_managedGroup"</screen>
<para>Successful reconciliation returns an "_id" object.</para>
<para>With the configuration of sample 2d, OpenIDM creates group objects from
LDAP in OpenIDM. To list group objects by ID, run a query over the REST interface.</para>
<screen>
$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET
"https://localhost:8443/openidm/managed/group?_queryId=query-all-ids"
</screen>
<para>The resulting JSON object should include content similar to the
following.</para>
<programlisting language="javascript">
{
"result":[
{
"_id":"3c704429-aacd-4995-816a-fac33451c642"
"_rev": "0",
},
{
"_id":"b0982152-5099-4358-bdd1-45a39ebe0d77"
"_rev": "0",
}
]
"resultCount": 2,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
}</programlisting>
<para>To retrieve a group, get the object by ID.</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/group/b0982152-5099-4358-bdd1-45a39ebe0d77"</screen>
<para>Your group's object should be similar to the following:</para>
<programlisting language="javascript">
{
"name": [
"openidm"
],
"uniqueMember": [
"uid=jdoe,ou=People,dc=example,dc=com"
],
"description": [],
"dn": "cn=openidm,ou=Groups,dc=example,dc=com",
"_rev": "0",
"_id": "b0982152-5099-4358-bdd1-45a39ebe0d77"
}
</programlisting>
</section>
</section>
<section xml:id="more-sample3">
<title>Sample 3 - Scripted SQL</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 3 - Scripted SQL</secondary>
</indexterm>
<para>
Sample 3 shows an example configuration for the Scripted SQL connector. The
Scripted SQL connector communicates with the database through configurable
SQL scripts. Each operation, like create or delete, is represented by its own
script.
</para>
<para>
Prepare a fresh installation of OpenIDM before trying this sample.
</para>
<section xml:id="external-mysql-config-sample3">
<title>External Configuration</title>
<para>
In this example OpenIDM communicates with an external MySQL database server.
</para>
<para>
Make sure MySQL is running.
</para>
<itemizedlist>
<para>The sample expects the following configuration for MySQL:</para>
<listitem>
<para>The database is available on the local host.</para>
</listitem>
<listitem>
<para>The database listens on port 3306.</para>
</listitem>
<listitem>
<para>You can connect over the network to the database with user
<literal>root</literal> and password <literal>password</literal>.</para>
</listitem>
<listitem>
<para>MySQL serves a database called <literal>HRDB</literal> with a table
called <literal>Users</literal>.</para>
</listitem>
<listitem>
<para>
The database schema is as described in the data definition language file,
<filename>openidm/samples/sample3/data/sample_HR_DB.mysql</filename>.
Import the file into MySQL before running the sample.
</para>
<screen width="87"><?dbfo pgwide="1"?>
$ <userinput>mysql -u root -p &lt; /path/to/openidm/samples/sample3/data/sample_HR_DB.mysql
</userinput>
Enter password:
$ </screen>
</listitem>
</itemizedlist>
<para>
Once imported, you can review the contents of the sample in MySQL. The
following command accesses the MySQL prompt:
</para>
<screen>
$ mysql -u root -p
</screen>
<para>
From the <literal>mysql &gt;</literal> prompt, use the following commands
to review the users configured in the <filename>sample_HR_DB.mysql</filename>
file:
</para>
<screen>
mysql &gt; <userinput>use HRDB;</userinput>
<computeroutput>
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
</computeroutput>
mysql &gt; <userinput>select * from Users</userinput>
<computeroutput>
+----+--------+--------------+-----------+----------+---------------+------...
| id | uid | password | firstname | lastname | fullname | email...
+----+--------+------------------------------------------+-----------+-----...
| 1 | bob | e38ad2149... | Bob | Fleming | Bob Fleming | Bob. ...
| 2 | rowley | 2aa60a8ff... | Rowley | Birkin | Rowley Birkin | Rowl ...
| 3 | louis | 1119cfd37... | Louis | Balfour | Louis Balfour | Loui ...
| 4 | john | a1d7584da... | John | Smith | John Smith | John ...
| 5 | jdoe | edba955d0... | John | Doe | John Doe | John ...
+----+--------+------------------------------------------+-----------+---- ...
5 rows in set (0.01 sec)
</computeroutput>
</screen>
<para>
You can exit from the MySQL prompt with the <command>quit</command>
command.
</para>
<note>
<para>
The passwords in the output shown above are hashed to the SHA-1 standard,
as they cannot be read into OpenIDM as cleartext.
</para>
<para>
The SHA-1 Hash function is used for compatibility reasons. When configuring
a database for production, more secure algorithms should be used.
</para>
</note>
</section>
<section xml:id="install-sample3">
<title>Install the Sample</title>
<itemizedlist>
<listitem><para>Prepare OpenIDM as described in <xref
linkend="preparing-openidm"/>.</para></listitem>
<listitem>
<para>OpenIDM requires a MySQL driver, the MySQL Connector/J. Download
MySQL Connector/J, version 5.1 or later. Unpack the delivery and
copy the .jar into the <filename>openidm/bundle</filename> directory.</para>
<screen>$ cp mysql-connector-java-<replaceable>version</replaceable>-bin.jar /path/to/openidm/bundle/</screen>
</listitem>
<listitem>
<para>Start OpenIDM with the configuration for sample 3.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample3</screen>
</listitem>
</itemizedlist>
</section>
<section xml:id="run-sample3">
<title>Run the Sample</title>
<para>
The sample 3 <filename>sync.json</filename> configuration file contains a
mapping to reconcile OpenIDM and the external database. Run the
reconciliation with the following command.
</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemHrdb_managedUser"</screen>
<para>
Reconciliation creates the five users from the database in the OpenIDM
repository. Check the result with the following command.
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"</screen>
<para>
The result should resemble the following JSON object.
</para>
<programlisting language="javascript">
{
"result": [ {
"_id": "8366a23d-f6cf-46df-9746-469bf45aafcd"
"_rev": "0",
},
{
"_id": "3f90933b-9397-4897-84d0-03ed8d99f61e"
"_rev": "0",
},
{
"_id": "8fbf759d-bebc-42ed-b321-b69487b4470f"
"_rev": "0",
},
{
"_id": "9592de42-a8ef-4db3-9c6c-7d191e39b084"
"_rev": "0",
},
{
"_id": "d933441b-684b-446c-a89e-01eca6d21ef3"
"_rev": "0",
},
{
"_id": "fd962b71-752a-444b-8492-35bff57bec69"
"_rev": "0",
} ],
"resultCount": 6,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
}</programlisting>
<para>
Naturally, you can review the users from the UI, navigating to the domain
where OpenIDM is installed, with a URI similar to
<literal>https://localhost:8443/openidmui</literal>
</para>
<para>Alternatively, to view the JSON for one of the users, get the user by
the value of the <literal>_id</literal>.</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/8366a23d-f6cf-46df-9746-469bf45aafcd"</screen>
</section>
</section>
<section xml:id="more-sample4">
<title>Sample 4 - CSV to XML File</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 4 - CSV file</secondary>
</indexterm>
<para>Sample 4 works with two databases, a comma-separated value file
and an XML file. There is no need to include any external
resources.
</para>
<para>
A correlation query is used to relate the records in these
two files.
</para>
<section xml:id="install-sample4">
<title>Install the Sample</title>
<para>No external configuration is required for this sample. Prepare
OpenIDM as described in <xref linkend="preparing-openidm"/>, then start up
OpenIDM with the configuration of sample 4.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample4</screen>
</section>
<section xml:id="examine-sample4">
<title>Check and then Run the Sample</title>
<para>
The <filename>sample4/data/hr.csv</filename> file contains two example
users. The first line of the file sets the attribute names.
</para>
<para>
Review the current contents of the database in the
<filename>sample4/data/xmlConnectorData.xml</filename> file. For comparison
purposes, make a copy of the file in a temporary directory with a command
like:
</para>
<screen>
$ cp /path/to/openidm/samples/sample4/data/xmlConnectorData.xml /tmp/
</screen>
<para>
The reconciliation command run here uses the information
from the <filename>hr.csv</filename> file to update the database in the
<filename>sample4/data/xmlConnectorData.xml</filename> file.
</para>
<screen width="89"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=csv_xmlfile"</screen>
<para>Check the results of reconciliation. Review the updated contents
of the <filename>sample4/data/xmlConnectorData.xml</filename> file.</para>
<para>
If you want to experiment further, try changing the data in the
<filename>hr.csv</filename> file. Run the noted reconciliation command
again.
</para>
<para>
These users will not be visible from the OpenIDM UI, since they are mapped
directly between the XML and CSV files. The internal OpenIDM repository is
not updated in this sample.
</para>
</section>
</section>
<section xml:id="more-sample5">
<title>Sample 5 - Synchronization of Two Resources</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 5 - Synchronization of two resources</secondary>
</indexterm>
<para>Sample 5 demonstrates the flow of data from one external resource to
another. The resources are called LDAP and AD, but in the sample both
directory-like resources are simulated with XML files.</para>
<section xml:id="install-sample5">
<title>Install the Sample</title>
<para>No external configuration is required for this sample. Prepare
OpenIDM as described in <xref linkend="preparing-openidm"/>, then start
OpenIDM with the configuration of sample 5.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample5</screen>
<para>The XML files that are used are located in the
<filename>openidm/samples/sample5/data/</filename> folder. When you start
OpenIDM with the sample 5 configuration, it creates
<filename>xml_AD_Data.xml</filename>, which does not contain users in this
sample until you run reconciliation.
</para>
</section>
<section xml:id="run-sample5">
<title>Run the Sample</title>
<para>Run reconciliation between OpenIDM and the pseudo-LDAP resource.</para>
<screen width="91"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemLdapAccounts_managedUser"</screen>
<para>This command creates a user in the repository and also in the simulated
Active Directory (AD) resource, represented by the
<filename>samples/sample5/data/xml_AD_Data.xml</filename> file.</para>
</section>
</section>
<section xml:id="more-sample5b">
<title>Sample 5b - Compensated Synchronization with <literal>onSync</literal></title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 5b - Synchronization with the <literal>onSync</literal>
script hook</secondary>
</indexterm>
<para>
The automatic synchronization depicted in this sample can help manage
the risks associated with synchronizing large amounts of data. It uses
an <literal>onSync</literal> hook configured with a
<filename>compensate.js</filename> script.
</para>
<para>
Sample 5b is similar to sample 5. Like sample 5, this sample supports
automatic synchronization from managed objects to external data sources.
Like sample 5, this sample simulates two external data sources with XML files
in the <filename>/path/to/samples/sample5*/data</filename> directory. The
<filename>xml_LDAP_Data.xml</filename> file simulates an LDAP data source.
OpenIDM creates the <filename>xml_AD_Data.xml</filename> file when you start
OpenIDM with the sample.
</para>
<para>
In both samples, reconciliations are taken from the simulated
LDAP XML data source and/or the internal OpenIDM repository, and are
synchronized to the simulated Active Directory (AD) data source.
</para>
<para>
Sample 5b adds an <literal>onSync</literal> script hook to the process.
That hook is configured from the <filename>managed.json</filename> file in the
<filename>/path/to/sample5b/conf</filename> directory.
</para>
<para>
The <literal>onSync</literal> hook uses a <filename>compensate.js</filename>
script.
</para>
<para>
The following excerpt of the <filename>managed.json</filename> file shows
the <literal>onSync</literal> hook linked to the
<filename>compensate.js</filename> file, available in the
<filename>/path/to/openidm/bin/defaults/script</filename> directory.
</para>
<programlisting language="javascript">
...
},
"onSync" : {
"type" : "text/javascript",
"file" : "compensate.js"
},
</programlisting>
<para>
For a detailed analysis of how OpenIDM automatic synchronization, works with
the onSync hook, see the Integrator's Guide section on <link xlink:show="new"
xlink:role="http://docbook.org/xlink/role/olink"
xlink:href="integrators-guide#sync-types-automatic"><citetitle>More on
Automatic Sync and <literal>onSync</literal></citetitle></link>
</para>
<para>
The <literal>onSync</literal> script hook is designed to ensure that either
all entries are synchronized from managed resources to external data stores,
or no changes are made.
</para>
<section xml:id="email-sample5b">
<title>Configure Email for the Sample</title>
<para>
You can configure sample5b with a service to email summary information.
If you skip these steps, that does not change the functionality of the
sample. However, it may lead to the following message at the OpenIDM console
when running a reconciliation:
</para>
<screen>Email service not configured; report not generated.</screen>
<procedure>
<para>
To configure an email summary, take the following steps:
</para>
<step>
<para>
Copy the template <filename>external.email.json</filename> file from
the <filename>/path/to/openidm/samples/misc</filename> directory:
</para>
<screen>$ cd /path/to/openidm
$ cp samples/misc/external.email.json samples/sample5b/conf
</screen>
</step>
<step>
<para>
Edit the <filename>external.email.json</filename> file in the noted
sample5b directory for outbound email, as noted in the chapter on
<link xlink:show="new" xlink:href="integrators-guide#chap-email"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Sending Email</citetitle></link>.
</para>
</step>
<step>
<para>
Edit the <filename>reconStats.js</filename> file from the
<filename>/path/to/openidm/samples/sample5b/script</filename> directory.
Near the start of the file, configure the OpenIDM email service to send
statistics to the email addresses of your choice:
</para>
<programlisting language="javascript">
var params = {
//UPDATE THESE VALUES
_from : "openidm@example.com",
_to : "youremail@example.com",
_cc : "idmadmin2@example.com,idmadmin3@example.com",
_subject : "Recon stats for " + global.reconName,
_type : "text/html"
},
template,
</programlisting>
</step>
</procedure>
</section>
<section xml:id="install-sample5b">
<title>Install the Sample</title>
<para>No external configuration is required for this sample. Prepare
OpenIDM as described in <xref linkend="preparing-openidm"/>, then start
OpenIDM with the configuration of sample 5b.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample5b</screen>
<para>You can now find XML files that simulate an external LDAP and AD
resource in the <filename>openidm/samples/sample5b/data/</filename>
directory. The simulated AD data store file,
<filename>xml_AD_Data.xml</filename>, does not contain users
until you run reconciliation or automatic synchronization runs.
</para>
<para>
Run reconciliation, to synchronize the contents of the simulated LDAP
resource to the simulated AD resource.
</para>
<screen width="100">$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemLdapAccounts_managedUser"</screen>
<para>
You do not have to run reconciliation. With automatic synchronization, any
change in the OpenIDM managed user database propagates changes to the
simulated AD resource.
</para>
<para>
Review the contents of <filename>xml_AD_Data.xml</filename>. It should now
contain information for the same user as is shown in the startup version of
the <filename>xml_LDAP_Data.xml</filename> file.
</para>
<para>
Alternatively, you can list users in the AD repository with the following
command:
</para>
<screen width="100">$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/system/ad/account?_queryId=query-all-ids"
</userinput>
<computeroutput>{
"result" : [ {
"name" : "DDOE1",
"__UID__" : "8dad9df3-820d-41ea-a3ab-a80c241bbc98",
"_id" : "8dad9df3-820d-41ea-a3ab-a80c241bbc98"
} ],
"resultCount" : 1,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</computeroutput>
</screen>
<para>
You should be able to use the <literal>_id</literal> of the user to read
information from the simulated AD database. In this case, you can display
that information with the following command:
</para>
<screen width="110">$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/system/ad/account/8dad9df3-820d-41ea-a3ab-a80c241bbc98"
</userinput>
<computeroutput>{
"email" : [ "mail1@example.com" ],
"name" : "DDOE1",
"__UID__" : "8dad9df3-820d-41ea-a3ab-a80c241bbc98",
"firstname" : "Darth",
"lastname" : "Doe",
"_id" : "8dad9df3-820d-41ea-a3ab-a80c241bbc98"
}[</computeroutput>
</screen>
<para>
To verify, repeat the process. Set up a second user in the
<filename>xml_LDAP_Data.xml</filename> file. One example of how that file
might appear with a second user is shown here:
</para>
<programlisting language="xml" width="120">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;icf:OpenICFContainer
xmlns:icf="http://openidm.forgerock.com/xml/ns/public/resource/openicf/resource-schema-1.xsd"
xmlns:ri="http://openidm.forgerock.com/xml/ns/public/resource/instances/resource-schema-extension"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://openidm.forgerock.com/xml/ns/public/resource/instances/resource-schema-extension
samples/sample5/data/resource-schema-extension.xsd
http://openidm.forgerock.com/xml/ns/public/resource/openicf/resource-schema-1.xsd
data/resource-schema-1.xsd"&gt;
&lt;ri:__ACCOUNT__&gt;
&lt;icf:__UID__&gt;1&lt;/icf:__UID__&gt;
&lt;icf:__PASSWORD__&gt;TestPassw0rd2&lt;/icf:__PASSWORD__&gt;
&lt;ri:firstname&gt;Darth&lt;/ri:firstname&gt;
&lt;icf:__DESCRIPTION__&gt;Created By XML1&lt;/icf:__DESCRIPTION__&gt;
&lt;icf:__NAME__&gt;DDOE1&lt;/icf:__NAME__&gt;
&lt;ri:email&gt;mail1@example.com&lt;/ri:email&gt;
&lt;ri:lastname&gt;Doe&lt;/ri:lastname&gt;
&lt;/ri:__ACCOUNT__&gt;
&lt;ri:__ACCOUNT__&gt;
&lt;icf:__UID__&gt;2&lt;/icf:__UID__&gt;
&lt;icf:__PASSWORD__&gt;TestPassw0rd2&lt;/icf:__PASSWORD__&gt;
&lt;ri:firstname&gt;Garth&lt;/ri:firstname&gt;
&lt;icf:__DESCRIPTION__&gt;Created By XML1&lt;/icf:__DESCRIPTION__&gt;
&lt;icf:__NAME__&gt;GDOE1&lt;/icf:__NAME__&gt;
&lt;ri:email&gt;mail2@example.com&lt;/ri:email&gt;
&lt;ri:lastname&gt;Doe&lt;/ri:lastname&gt;
&lt;/ri:__ACCOUNT__&gt;
&lt;/icf:OpenICFContainer&gt;
</programlisting>
<para>
Rerun the reconciliation and query REST command calls shown earlier.
Substitute for the UID if it has changed. The reconciliation and query
commands would take the data from the simulated LDAP resource, and then
reconcile them to the OpenIDM managed user database. With automatic sync,
those users are then synchronized to the simulated AD resource.
</para>
</section>
<section xml:id="onsync-sample5b">
<title>Demonstrate onSync</title>
<para>
Log into the OpenIDM UI as the administrative user. On a local system,
navigate to <literal>https://localhost:8443/openidmui</literal>. The default
administrative account and password are both <literal>openidm-admin</literal>.
</para>
<para>
Make a change to the data of an existing user. With automatic sync,
that change is reflected almost immediately on the external resources.
For sample 5b, you would see the changes in both XML files in the
<filename>/path/to/openidm/sample5b/data</filename> directory. Alternatively,
you could run the REST command calls described earlier.
</para>
<para>
Automatic sync works when both external resources are
connected. The next step is to simulate a problem connecting to the LDAP
resource. One simple way to do so on the local system is to make the LDAP
data file unreadable. On a Linux system, the following command, as an
administrative user, would serve that purpose:
</para>
<screen>$ cd /path/to/openidm/samples/sample5b/data
$ sudo mv xml_LDAP_Data.xml xml_LDAP_Data.xml.bak</screen>
<para>
In the UI, now try another update to an existing user. You may see the
change reflected in only the simulated AD resource. With the change to the
filename of the simulated LDAP resource, automatic sync has nothing to write
to, and you may see the following error in the standard OpenIDM log file,
<filename>openidm0.log.0</filename>:
</para>
<screen>Data file does not exist:
/path/to/openidm/samples/sample5b/data/xml_LDAP_Data.xml</screen>
<para>
With <literal>onSync</literal>, OpenIDM invokes the
<filename>compensate.js</filename> script. If an error such as a bad
connection to a remote data store occurs, that script should revert the
most recent change.
</para>
<para>
As an administrator, you might try to make the same change a second time.
In that case, the OpenIDM UI should display an error. The user data in the
XML files should remain unchanged.
</para>
</section>
</section>
<section xml:id="more-sample6">
<title>Sample 6 - LiveSync With an AD Server</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 6 - LiveSync between two LDAP servers</secondary>
</indexterm>
<para>
Sample 6 resembles sample 5, but sample 6 includes files for two scenarios,
depending on whether you have an actual Active Directory (AD) service, or if
you need to simulate an AD database. Each scenario is associated with a
file in the <filename>/path/to/sample6/alternatives</filename> directory.
The file you select should be copied to the
<filename>/path/to/sample6/conf</filename> directory.
</para>
<variablelist>
<varlistentry>
<term>Active AD Deployment</term>
<listitem>
<para>
If you have an actual AD deployment available, copy the
<filename>provisioner.openicf-realad.json</filename> file to the
<filename>conf/</filename> subdirectory. You can then configure
synchronization between an OpenDJ Directory Server and an active AD
deployment.
</para>
<para>
As this sample demonstrates reconciliations from the AD server to
OpenDJ, information on the AD server will not be changed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Simulated AD Deployment</term>
<listitem>
<para>
If you need to simulate an AD deployment, copy the
<filename>provisioner.openicf-fakead.json</filename> file to the
<filename>conf/</filename> subdirectory. You can then configure
synchronization between an OpenDJ Directory server and a simulated
AD server.
</para>
<para>
The instructions for this sample simulates an AD server on the
same instance of OpenDJ, using a different base DN.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
The options shown in associated configuration files can be easily modified
to work with any standard LDAP server.
</para>
<section xml:id="more-sample6-realad">
<title>Sample 6 with an Active AD Deployment</title>
<para>
If you have an active instance of AD, you can set up a regular instance of
OpenDJ, as described in the <link xlink:show="new"
xlink:href="http://opendj.forgerock.org/opendj-server/doc/install-guide/">
<citetitle>OpenDJ Installation Guide</citetitle></link>.
</para>
<para>
For this purpose, populate OpenDJ with the <filename>Example.ldif</filename>
file available in the <filename>/path/to/sample6/data</filename> directory.
Any changes run in this section should write information from the AD server
to the OpenDJ server that you create.
</para>
<para>
The actions run in this sample should not change any data on the AD server.
</para>
</section>
<section>
<title>Sample 6 with a Simulated AD Deployment</title>
<para>
To minimize the risk of conflict with another LDAP server, the simulated
AD deployment uses a non-standard base DN,
<literal>dc=fakead,dc=com</literal>.
</para>
<para>
The following instructions make it possible for you to configure LiveSync
between two OpenDJ servers, configured to communicate on different ports.
One of the servers will include an LDIF file, <filename>AD.ldif</filename>,
that simulates a deployment of AD. The second server includes a different
LDIF file, <filename>Example.ldif</filename>, that supports a conventional
deployment of OpenDJ.
</para>
<para>
For this sample, two separate OpenDJ servers are not required. The
<filename>AD.ldif</filename> and <filename>Example.ldif</filename> LDIF
files are associated with two separate base DNs. Once configured, LiveSync
should work automatically with the data on both base DNs as if they were
two separate directory servers.
</para>
</section>
<section xml:id="external-resource-sample6">
<title>External Configuration</title>
<para>
Now that you know the files and port numbers to use, it is time to
configure your instance of OpenDJ. Download and start installing OpenDJ as
described in the OpenDJ Installation Guide chapter on <link xlink:show="new"
xlink:href="http://opendj.forgerock.org/opendj-server/doc/install-guide/index.html#chap-install-gui">
<citetitle>Installing OpenDJ With the Quick Setup Wizard</citetitle>.</link>
</para>
<section xml:id="prepare-livesync-sample6">
<title>Prepare OpenDJ For LiveSync</title>
<para>
This sample assumes a replicated OpenDJ server. When configured,
OpenDJ replication includes an External Change Log (ECL),
required to support LiveSync.
</para>
<para>
When enabled, LiveSync detects changes in OpenDJ by reading the ECL.
</para>
<para>
To activate the OpenDJ ECL, enable replication as described in the
<link xlink:show="new"
xlink:href="http://opendj.forgerock.org/opendj-server/doc/admin-guide/index.html#chap-replication">
<citetitle>OpenDJ Administration Guide chapter on Managing Data
Replication</citetitle></link>
</para>
<para>
Once configured, you can proceed with either an
active or simulated AD deployment.
</para>
</section>
<section xml:id="external-resource-sample6-active">
<title>External Configuration for an Active AD Deployment</title>
<para>
To configure an active AD deployment for sample 6, open the
<filename>provisioner.openicf-realad.json</filename> file in
a text editor. Update it as needed. At minimum, you should check and
if needed update the following parameters in that file, as shown in the
following table:
</para>
<table xml:id="realad-json-configuration">
<title>Key Parameters for an Active AD Configuration</title>
<tgroup cols="2">
<colspec colnum="1" colwidth="2*"/>
<colspec colnum="2" colwidth="3*"/>
<thead>
<row>
<entry>Option</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>host</entry>
<entry>The hostname/IP address of the AD server</entry>
</row>
<row>
<entry>port</entry>
<entry>The LDAP port; the default is 389.</entry>
</row>
<row>
<entry>ssl</entry>
<entry>By default, SSL is not used.</entry>
</row>
<row>
<entry>principal</entry>
<entry>The full DN of the account to bind with, such as
"CN=Administrator,CN=Users,DC=example,DC=com"</entry>
</row>
<row>
<entry>credentials</entry>
<entry>If a password is used, replace null with that password.
Once OpenIDM starts, it encrypts that password in the
<filename>provisioner.openicf-realad.conf</filename> file.</entry>
</row>
<row>
<entry>baseContexts</entry>
<entry>The DNs for account containers, such as
["CN=Users,DC=Example,DC=com"]</entry>
</row>
<row>
<entry>baseContextsToSynchronize</entry>
<entry>Set to the same value as <literal>baseContexts</literal></entry>
</row>
<row>
<entry>accountSearchFilter</entry>
<entry>Default searches for active user (not computer) accounts</entry>
</row>
<row>
<entry>accountSynchronizationFilter</entry>
<entry>Default synchronizes with active user (not computer)
accounts</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
If you do not want to filter out computer and disabled user accounts,
set the <literal>accountSearchFilter</literal> and
<literal>accountSynchronizationFilter</literal> to <literal>null</literal>.
</para>
</section>
<section xml:id="external-resource-sample6-simulated">
<title>External Configuration for a Simulated AD Deployment</title>
<para>
Not everyone has a testable instance of AD readily available. For such
administrators, you can use the <filename>AD.ldif</filename> file from
the <filename>data/</filename> subdirectory to simulate an AD deployment.
</para>
<para>
If you have not already done so, copy the
<filename>provisioner.openicf-fakead.json</filename> file to the
<filename>conf</filename> subdirectory.
</para>
<para>
While you can use a separate deployment of OpenDJ to simulate an instance
of AD, the following instructions include both databases on the same
OpenDJ server.
</para>
<para>
Open the <filename>provisioner.openicf-fakead.json</filename> file. The
default <literal>port</literal> directive cited in that file is 1389,
different from the default LDAP port of 389.
</para>
<para>
That JSON file uses a different base DN,
<literal>dc=fakead,dc=com</literal>.
</para>
<para>
In the the OpenDJ control panel, first add the
simulated AD <literal>baseDN</literal>, and then import the
<filename>/path/to/sample6/data/AD.ldif</filename> file.
</para>
<para>
When you import the <filename>AD.ldif</filename> file, do not overwrite
existing data. Otherwise, you may overwrite information from
the <filename>Example.ldif</filename> file.
</para>
</section>
</section>
<section xml:id="install-sample6">
<title>Start OpenIDM with Sample 6</title>
<para>
Now that OpenDJ and a real or simulated AD database is configured,
prepare OpenIDM as described in <xref linkend="preparing-openidm"/>.
You can then start OpenIDM with the configuration for sample 6.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample6</screen>
</section>
<section xml:id="run-sample6">
<title>Run the Sample</title>
<para>The following sections show how to run the sample with command-based
reconciliation with a REST call, and to configure scheduled reconciliation
with LiveSync.
</para>
<section xml:id="run-sample6-reconciliation">
<title>Using Reconciliation</title>
<para>
Now that OpenIDM is in operation, review the entries in the OpenDJ
data store. When you run reconciliation, any entries that share the same
<literal>uid</literal> with the AD data store will be overwritten.
</para>
<para>
If you have set up the simulated AD data store as described in
<xref linkend="external-resource-sample6-simulated" />, compare the
entries for <literal>uid=jdoe</literal> as shown in the
<filename>AD.ldif</filename> and <filename>Example.ldif</filename> files.
Note the different values of <literal>givenName</literal> for
<literal>uid=jdoe</literal>.
</para>
<para>
Run reconciliation over the REST interface. If you have followed the
instructions for the simulated AD data store, the following command
takes the information for user <literal>jdoe</literal> imported from the
<filename>AD.ldif</filename> file, with a <literal>givenName</literal> of
Johnny, and synchronizes that information to the LDAP database, overwriting
the <literal>givenName</literal> of John for that same user
<literal>jdoe</literal>.
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemAdAccounts_managedUser"</screen>
<para>The result of a successful reconciliation is an
<literal>_id</literal> object, similar to:</para>
<screen>{"_id":"9ece3807-08c3-4ec6-87fb-a6a2d0c71cee"}</screen>
<para>
OpenIDM takes the information from the AD deployment, and includes it in
the internal OpenIDM repository. That information is then automatically
synchronized to the OpenDJ server, as described in
<link xlink:show="new" xlink:href="integrators-guide#handling-sync"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Synchronization Situations and Actions</citetitle></link>.
</para>
<para>After reconciliation, list all users in the OpenDJ server data
store.</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/system/ldap/account?_queryId=query-all-ids"</screen>
<para>The result should resemble the following JSON object.</para>
<programlisting language="javascript">
{
"result": [ {
"dn" : "uid=jdoe,ou=People,dc=example,dc=com",
"_id" : "uid=jdoe,ou=People,dc=example,dc=com"
}, {
"dn" : "uid=bjensen,ou=People,dc=example,dc=com",
"_id" : "uid=bjensen,ou=People,dc=example,dc=com"
} ],
"resultCount": 2,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
}</programlisting>
<para>
You see only two entries, as the <literal>uid=jdoe</literal> entry from
<literal>dc=fakead,dc=com</literal> overwrites the original LDAP entry for
<literal>uid=jdoe</literal> in the reconciled LDAP data store.
</para>
<para>
To confirm the current status of a user, run the
<command>ldapsearch</command> command. The following example confirms the
current status of <literal>uid=jdoe</literal> in the OpenDJ datastore:
</para>
<screen>$ /ldapsearch \
--port 1389 \
--baseDN dc=example,dc=com \
"(uid=jdoe)"</screen>
<!--
<para>To read the user object, navigate to the OpenIDM UI as the
administrative user, or use the <literal>_id</literal> value.</para>
<screen width="83"><?dbfo pgwide="1"?>$ curl
\-\-cacert self-signed.crt
\-\-header "X-OpenIDM-Username: openidm-admin"
\-\-header "X-OpenIDM-Password: openidm-admin"
\-\-header "Content-Type: application/json"
\-\-request GET
"https://localhost:8443/openidm/managed/user/b6b76e9c-d534-4d0a-ac81-87153169a223"</screen>
<para>The result should resemble the following JSON object, though all
on one line.</para>
<programlisting language="javascript">
{
"displayName": "John Doe",
"givenName": "John",
"userName": "jdoe",
"familyName": "Doe",
"description": "Created for OpenIDM",
"email": "jdoe@example.com",
"_rev": "0",
"_id": "b6b76e9c-d534-4d0a-ac81-87153169a223"
}</programlisting>
-->
</section>
<section xml:id="run-sample6-live-sync">
<title>Using LiveSync</title>
<para>You can start reconciliation by using a scheduled configuration or
by using the REST interface directly. However, if you want to use LiveSync,
you need to configure a schedule. When LiveSync is active, the default
schedule in the <filename>schedule-activeSynchroniser_systemAdAccount.json
</filename> configuration file runs LiveSync every 15 seconds.
</para>
<para>
This particular action, pushes changes made in the AD
data store to the OpenIDM repository, automatically.
</para>
<para>
LiveSync is disabled by default. To activate LiveSync, change the
value of the <literal>"enabled"</literal> property
from <literal>false</literal> to <literal>true</literal>.
</para>
<programlisting language="javascript">
{
"enabled" : false,
"type" : "cron",
"schedule" : "0/15 * * * * ?",
"invokeService" : "provisioner",
"invokeContext" : {
"action" : "liveSync",
"source" : "system/ad/account"
},
"invokeLogLevel" : "debug"
}</programlisting>
<procedure xml:id="test-live-sync">
<title>Testing LiveSync</title>
<para>
Now you can test LiveSync. This procedure assumes that you have configured
OpenDJ using the parameters and commands described in this section.
</para>
<step>
<para>
Create an LDIF file.
</para>
</step>
<step>
<para>
The following is the contents of a sample
<filename>bsmith.ldif</filename> file for demonstration purposes:
<screen>dn: uid=bsmith,ou=People,dc=fakead,dc=com
objectClass: person
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: top
givenName: Barry
description: Created to see LiveSync work
uid: bsmith
cn: Barry
sn: Smith
mail: bsmith@example.com
telephoneNumber: 1-415-523-0772
userPassword: password
</screen>
</para>
</step>
<step>
<para>
Navigate to the <filename>/path/to/opendj/bin</filename> directory.
</para>
</step>
<step>
<para>
Use the <command>ldapmodify</command> command to add the
<filename>bsmith.ldif</filename> file to the directory. Be aware that
the port number may vary.
</para>
<screen>$ /ldapmodify
--port 1389
--defaultAdd
--bindDN "cn=Directory Manager"
--bindPassword password
--filename /path/to/bsmith.ldif</screen>
</step>
<step>
<para>
Now you can test synchronization. You should be able to log
into the OpenIDM UI with any AD account.
</para>
<para>
Be aware: changes made from the OpenIDM UI directly change the local
managed/user database. Changes are not reconciled to the AD database.
</para>
</step>
<step>
<para>
The following command should display the updated information in the
OpenDJ data store for all configured users:
</para>
<screen>$ /ldapsearch \
--port 1389 \
--baseDN ou=people,dc=example,dc=com \
"(uid=*)"</screen>
</step>
</procedure>
<para>
If LiveSync works, the final step in the procedure should include
information for the user newly added from the
<filename>bsmith.ldif</filename> file.
</para>
</section>
</section>
</section>
<section xml:id="more-sample7">
<title>Sample 7 - Scripting a SCIM-like Schema</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 7 - Scripting a SCIM-like Schema</secondary>
</indexterm>
<para>Sample 7 demonstrates how you can use OpenIDM to expose user data with a
SCIM-like schema. The sample uses the XML file connector to read in attributes
from external accounts and construct a JSON object for users stored in the
OpenIDM repository. For more information about SCIM schema, see
<link xlink:show="new"
xlink:href="http://www.simplecloud.info/specs/draft-scim-core-schema-01.html">
<citetitle>System for Cross-Domain Identity Management:
Core Schema 1.1</citetitle></link>.</para>
<section xml:id="install-sample7">
<title>Install the Sample</title>
<para>Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>,
then start OpenIDM with the configuration for sample 7.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample7</screen>
</section>
<section xml:id="run-sample7">
<title>Running the Sample</title>
<para>Run a reconciliation to pull the user from
<filename>samples/sample7/data/xmlConnectorData.xml</filename> into the
OpenIDM internal repository.</para>
<screen width="94"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemXmlfileAccounts_managedUser"</screen>
<para>Reconciliation creates a user object in the repository. Retrieve the
user from the repository.</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/DDOE1"</screen>
<para>The user object has the following JSON representation.</para>
<programlisting language="javascript">{
"_id" : "DDOE1",
"_rev" : "2",
"schemas" : "['urn:scim:schemas:core:1.0']",
"ims" : [ {
"type" : "aim",
"value" : "jonyOnAim"
}, {
"type" : "skype",
"value" : "skyperHiasl"
} ],
"locale" : null,
"phoneNumbers" : [ {
"type" : "work",
"value" : "1234567"
}, {
"type" : "home",
"value" : "1234568"
} ],
"emails" : [ {
"type" : "work",
"value" : "hallo@example.com",
"primary" : true
}, {
"type" : "home",
"value" : "jdoe@forgerock.com"
} ],
"externalId" : "DDOE1",
"preferredLanguage" : "en_US",
"meta" : {
"lastModified" : "Thu May 01 2014 12:57:10 GMT-0800 (GMT-08:00)",
"created" : "Thu May 01 2014 12:56:27 GMT-0800 (GMT-08:00)"
},
"userType" : "permanent",
"photos" : [ {
"type" : "photo",
"value" : "https://photos.example.com/profilephoto/72930000000Ccne/F"
}, {
"type" : "thumbnail",
"value" : "https://photos.example.com/profilephoto/72930000000Ccne/T"
} ],
"title" : "Mr.Universe",
"timezone" : "America/Denver",
"profileUrl" : "https://login.example.com/DDOE1",
"nickName" : "Jonny",
"name" : {
"familyName" : "Doe",
"middleName" : "Hias",
"formatted" : "Dr. John H Doe III",
"givenName" : "John",
"honorificSuffix" : "III",
"honorificPrefix" : "Dr."
},
"userName" : "DDOE1",
"displayName" : "John Doe",
"addresses" : [ {
"streetAddress" : "100 Universal City Plaza",
"region" : "CA",
"formatted" : "100 Universal City Plaza\nHollywood, CA 91608 USA",
"postalCode" : "91608",
"primary" : "true",
"locality" : "Hollywood",
"type" : "work",
"country" : "USA"
}, {
"streetAddress" : "222 Universal City Plaza",
"region" : "CA",
"formatted" : "222 Universal City Plaza\nHollywood, CA 91622 USA",
"postalCode" : "91622",
"primary" : "false",
"locality" : "Hollywood",
"type" : "home",
"country" : "USA"
} ],
"groups" : [ {
"value" : "usemploys",
"display" : "US Employees"
}, {
"value" : "euemploys",
"display" : "EU Employees"
} ]
}</programlisting>
<para>
The sample script file, <filename>scim.js</filename> in the
<filename>/path/to/samples/sample7/script</filename> directory,
transforms the user data from the resource into the JSON object layout
required by SCIM schema.
</para>
</section>
</section>
<section xml:id="more-sample8">
<title>Sample 8 - Logging in Scripts</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 8 - Logging in Scripts</secondary>
</indexterm>
<para>OpenIDM provides a <literal>logger</literal> object with
<literal>debug()</literal>, <literal>error()</literal>,
<literal>info()</literal>, <literal>trace()</literal>, and
<literal>warn()</literal> functions that you can use to log messages to
the OpenIDM console from your scripts.</para>
<section xml:id="install-sample8">
<title>Install the Sample</title>
<para>Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>,
then start OpenIDM with the configuration for sample 8.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample8</screen>
<para>The <filename>sync.json</filename> file in the
<filename>/path/to/samples/sample8/conf</filename> directory includes
brief examples of log messages.
</para>
</section>
<section xml:id="run-sample8">
<title>Running the Sample</title>
<para>Run reconciliation over the REST interface.</para>
<screen width="99"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemXmlfileAccounts_managedUser"</screen>
<para>Successful reconciliation returns an "_id" object.</para>
<para>Notice the log messages displayed on the OpenIDM (Felix) console.
The following example omits timestamps and so forth to show only the message
strings.</para>
<programlisting language="none">-&gt;
...Case no Source: the source object contains: = null [5235432-...
...Case emptySource: the source object contains: = {lastname=Carter, mobile...
...Case sourceDescription: the source object contains: = Created By XML1
...Case onCreate: the source object contains: = {lastname=Carter, mobile...
...Case result: the source object contains: = {SOURCE_IGNORED={count=0, ids=[]},...
</programlisting>
</section>
</section>
<section xml:id="more-sample9">
<title>Sample 9 - Asynchronous Reconciliation Using Workflows</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample 9 - asynchronous reconciliation</secondary>
</indexterm>
<para>Sample 9 demonstrates asynchronous reconciliation using workflows.
Reconciliation generates an approval request for each ABSENT user. The
configuration for this action is defined in the <filename>conf/sync.json</filename>
file, which specifies that an <literal>ABSENT</literal> condition should
launch the <literal>managedUserApproval</literal> workflow:</para>
<programlisting language="javascript">
...
{
"situation" : "ABSENT",
"action" : {
"workflowName" : "managedUserApproval",
"type" : "text/javascript",
"file" : "workflow/workflow.js"
}
},
...
</programlisting>
<para>When the request is approved by an administrator, the absent users are
created by an asynchronous reconciliation process.</para>
<para>Prepare a fresh installation of OpenIDM before trying this
sample.</para>
<section xml:id="install-sample9">
<title>Install the Sample</title>
<para>Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>,
then start OpenIDM with the configuration for sample 9.</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/sample9</screen>
</section>
<section xml:id="run-sample9">
<title>Running the Sample</title>
<orderedlist>
<listitem>
<para>Run reconciliation over the REST interface.</para>
<screen width="99"><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemXmlfileAccounts_managedUser"
</screen>
<para>Successful reconciliation returns an "_id" object.</para>
<para>The reconciliation starts an approval workflow for each ABSENT
user. These approval workflows (named <literal>managedUserApproval</literal>)
wait for the request to be approved by an administrator.</para>
</listitem>
<listitem>
<para>Query the invoked workflow task instances over REST.</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/taskinstance?_queryId=query-all-ids"
</screen>
<para>
In this case, the request returns two workflow results, each with a
process ID (<literal>_id</literal>) as well as a process definition
ID. You will use the value of the <literal>_id</literal> shortly.
</para>
<screen>{
"result" : [ {
"tenantId" : "",
"createTime" : "2014-05-01T13:48:42.980-08:00",
"executionId" : "101",
"delegationStateString" : null,
"processVariables" : { },
"_id" : "123",
"processInstanceId" : "101",
"description" : null,
"priority" : 50,
"name" : "Evaluate request",
"dueDate" : null,
"parentTaskId" : null,
"processDefinitionId" : "managedUserApproval:1:3",
"taskLocalVariables" : { },
"suspensionState" : 1,
"assignee" : "openidm-admin",
"cachedElContext" : null,
"queryVariables" : null,
"activityInstanceVariables" : { },
"deleted" : false,
"suspended" : false,
"_rev" : 1,
"revisionNext" : 2,
"category" : null,
"taskDefinitionKey" : "evaluateRequest",
"owner" : null,
"eventName" : null,
"delegationState" : null
}, {
"tenantId" : "",
"createTime" : "2014-05-01T13:48:42.980-08:00",
"executionId" : "102",
"delegationStateString" : null,
"processVariables" : { },
"_id" : "124",
"processInstanceId" : "102",
"description" : null,
"priority" : 50,
"name" : "Evaluate request",
"dueDate" : null,
"parentTaskId" : null,
"processDefinitionId" : "managedUserApproval:1:3",
"taskLocalVariables" : { },
"suspensionState" : 1,
"assignee" : "openidm-admin",
"cachedElContext" : null,
"queryVariables" : null,
"activityInstanceVariables" : { },
"deleted" : false,
"suspended" : false,
"_rev" : 1,
"revisionNext" : 2,
"category" : null,
"taskDefinitionKey" : "evaluateRequest",
"owner" : null,
"eventName" : null,
"delegationState" : null
} ],
"resultCount" : 2,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</screen>
</listitem>
<listitem>
<para>
Approve the requests over REST, by setting the
<literal>"requestApproved"</literal> parameter for the specified task
instance to <literal>"true"</literal>. Note the use of one of the
values of <literal>_id</literal> in the REST call, in this case,
<literal>124</literal>.
</para>
<para>On UNIX:</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{"requestApproved": "true"}' \
"https://localhost:8443/openidm/workflow/taskinstance/124?_action=complete"
</screen>
<para>On Windows:</para>
<screen>$ curl ^
--cacert self-signed.crt ^
--header "X-OpenIDM-Username: openidm-admin" ^
--header "X-OpenIDM-Password: openidm-admin" ^
--header "Content-Type: application/json" ^
--request POST ^
--data "{\"requestApproved\": \"true\"}" ^
"https://localhost:8443/openidm/workflow/taskinstance/124?_action=complete"
</screen>
<para>A successful call returns the following:</para>
<screen>{"Task action performed":"complete"}</screen>
</listitem>
<listitem>
<para>Once the request has been approved, an asynchronous
reconciliation operation runs, which creates the users whose accounts
were approved in the previous step.</para>
<para>List the users that were created by the asynchronous
reconciliation.</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"
</screen>
<para>One user is returned.</para>
<screen>{
"result": [ {
"_rev": "0",
"_id": "1"
} ],
"resultCount": 1,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
}</screen>
</listitem>
</orderedlist>
</section>
</section>
</chapter>