chap-samples.xml revision 8379ee46ec93e390435dc32135a00a26bb5d77b7
<?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>$ 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 a reconciliation run ID.</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. Point your
browser to <literal>https://localhost:8443/openidmui</literal>, log in as
the <literal>openidm-admin</literal> user (with password
<literal>openidm-admin</literal>), and navigate to the Users tab. Select the
user whose profile information you want to see.
</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 retrieve individual user objects by ID, as shown
here.</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/53fbf0c5-aa37-4845-a4b3-92a21810a36d"</screen>
</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>$ 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 a reconciliation run ID.</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>$ 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>$ 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"}' \
"https://localhost:8443/openidm/managed/user?_action=create"</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 "{
\"mail\":\"fdoe@example.com\",
\"sn\":\"Doe\",
\"telephoneNumber"\:\"555-1234\",
\"userName\":\"fdoe\",
\"givenName\":\"Felicitas\",
\"description\":\"Felicitas Doe\",
\"displayName\":\"fdoe\"}" ^
"https://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 that have the managed object as the
source 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>$ <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 a reconciliation run ID.</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, you can
retrieve John Doe's user object at the command line by his ID.
</para>
<screen><userinput>$ 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"</userinput></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><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 \
--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"</userinput></screen>
<para>
On Windows, you might need to escape certain characters, so your REST call
would look like this:
</para>
<screen><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 ^
--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"</userinput></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><userinput>$ 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"</userinput></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 that have the managed object as the
source 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><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=systemLdapGroups_managedGroup"</userinput></screen>
<para>Successful reconciliation returns a reconciliation run ID.</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><userinput>$ 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"</userinput></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><userinput>$ 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"</userinput></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 allows OpenIDM to communicate with the database
through configurable SQL scripts. Each operation, like create or delete, is
represented by its own script.
</para>
<para>
In this sample, you will see how OpenIDM uses a scripted connection to a
MySQL server. Do configure MySQL first, before starting OpenIDM.
</para>
<para>
After reconciliation with the existing MySQL database, you will be able to
review users in the internal repository of OpenIDM.
</para>
<para>
Sample 3 uses the following file in the <filename>conf/</filename> directory
for the Scripted SQL connector:
<filename>conf/provisioner.openicf-scriptedsql.json</filename>. It cites
customizable Groovy scripts in the
<filename>/path/to/openidm/samples/sample3/tools</filename> directory.
</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>
<note>
<para>
If you want to test this sample on an existing MySQL database, examine the
<literal>configurationProperties</literal> section of the
<filename>provisioner.openicf-scriptedsql.json</filename> file. Change
parameters such as <literal>host</literal>, <literal>database</literal>,
<literal>password</literal>, and <literal>jdbcConnectionUrl</literal> to
match your configuration.
</para>
<para>
The remainder of the Sample 3 documentation is based on the database
schema that exists in the <filename>openidm/samples/sample3/data</filename>
directory.
</para>
</note>
<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>$ <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>Set up the MySQL driver for OpenIDM. Download MySQL Connector/J,
version 5.1 or later. Unpack the download 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>Once the MySQL driver is in place, 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>$ 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 output includes the identifier <literal>_id</literal> for each user.
</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>
You can get more information about users with any of the following three
methods:
</para>
<para>
You can review the users from the UI, navigating to the domain where OpenIDM
is installed, with a URL similar to
<literal>https://localhost:8443/openidmui</literal>
</para>
<para>Alternatively, to view all fields for a single user, based on its
<literal>_id</literal>, run 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/8366a23d-f6cf-46df-9746-469bf45aafcd"</screen>
<para>
You can query specific fields with a REST call. For example, the following
command displays the unique ID and the <literal>givenName</literal> of all
managed users:
</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&amp;fields=_openidm_id,givenName"
</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>$ 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 named <literal>LDAP</literal> and
<literal>AD</literal> but in the sample, both directory-like resources are
simulated with XML files.
</para>
<para>
You can optionally configure an outbound email service, if you want to
receive emailed reconciliation summaries, as described in the following
section.
</para>
<section xml:id="email-sample5">
<title>Configure Email for the Sample</title>
<para>
If you do not configure the email service, the functionality of the sample
does not change. However, you might see the following message at the
OpenIDM console when you run a reconciliation operation:
</para>
<screen>Email service not configured; report not generated.</screen>
<procedure>
<para>
To configure an email summary, follow these 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/sample5/conf
</screen>
</step>
<step>
<para>
Edit the <filename>external.email.json</filename> file for outbound email,
as described in the chapter on
<link xlink:show="new" xlink:href="integrators-guide#chap-mail"
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/sample5/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 " + source.name + " -> " + target.name,
type : "text/html"
},
template,
</programlisting>
</step>
</procedure>
</section>
<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 simulate the resources are located in the
<filename>openidm/samples/sample5/data/</filename> folder. When you start
OpenIDM with the sample 5 configuration, OpenIDM creates the
<filename>xml_AD_Data.xml</filename> file, which does not contain users
until you run reconciliation.
</para>
</section>
<section xml:id="run-sample5">
<title>Run the Sample</title>
<para>
Run a reconciliation operation, to synchronize the contents of the simulated
LDAP resource to the OpenIDM repository.
</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=systemLdapAccounts_managedUser"</screen>
<para>
This command creates a user in the repository. It is not necessary to run a
second reconciliation operation to synchronize the AD resource. Automatic
synchronization propagates any change made to managed users in the OpenIDM
repository 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 that was present in the startup
version of the <filename>xml_LDAP_Data.xml</filename> file.
</para>
<para>
Alternatively, you can list users in the AD resource with the following
command:
</para>
<screen>$ <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 can use the <literal>_id</literal> of the user to read the user
information from the AD resource, for example:
</para>
<screen>$ <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 that the sample is working, repeat the process. Set up a second
user in the <filename>xml_LDAP_Data.xml</filename> file. An example of how
that file might appear with a second user (<literal>GDOE1</literal>) 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
/path/to/openidm/samples/sample5/data/resource-schema-extension.xsd
http://openidm.forgerock.com/xml/ns/public/resource/openicf/resource-schema-1.xsd
/path/to/openidm/samples/sample5/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 commands shown previously. The
reconciliation operation creates the new user from the simulated LDAP
resource in the OpenIDM repository. Automatic synchronization then creates
that user in the AD resource.
</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 compensated synchronization mechanism depicted in this sample can help
manage the risks associated with synchronizing data across multiple
resources.
</para>
<para>
Typically, when a managed/user object is changed, automatic synchronization
replays that change to all configured external resources. If synchronization
fails for one target resource (for example, due to a policy validation
failure on the target, or the target being unavailable), the synchronization
operation stops at that point. The effect is that a record might be changed
in the repository, and in the targets on which synchronization was successful,
but not on the failed target, or any targets that would have been
synchronized after the failure. This situation can result in disparate data
sets across resources. While a reconciliation operation would eventually
bring all targets back in sync, reconciliation can be an expensive operation
with large data sets.
</para>
<para>
The compensated synchronization mechanism ensures that either all resources
are synchronized successfully, or that the original change is rolled back.
This mechanism uses an <literal>onSync</literal> script hook configured with
a <filename>compensate.js</filename> script that can be used to "revert" the
partial change to managed/user and to the corresponding external resources.
</para>
<para>
Sample 5b is similar to sample 5 in that it simulates two external resources
with XML files (located in the
<filename>/path/to/samples/sample5b/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. Sample 5b adds the <literal>onSync</literal> script
hook to the process, configured in the
<filename>sample5b/conf/managed.json</filename> file.
</para>
<para>
The following excerpt of the <filename>managed.json</filename> file shows
the <literal>onSync</literal> hook, which calls the
<filename>compensate.js</filename> script, provided in the
<filename>/path/to/openidm/bin/defaults/script</filename> directory.
</para>
<programlisting language="javascript">
...
},
"onSync" : {
"type" : "text/javascript",
"file" : "compensate.js"
},
</programlisting>
<para>
You can use the <literal>onSync</literal> script hook to ensure that changes
made in the repository are synchronized to all external resources, or that
no changes are made. For more information about how automatic synchronization
uses the <literal>onSync</literal> script hook, see <link xlink:show="new"
xlink:role="http://docbook.org/xlink/role/olink"
xlink:href="integrators-guide#sync-types-automatic"><citetitle>How Automatic
Sync works with onSync</citetitle></link> in the <citetitle>Integrator's
Guide</citetitle>.
</para>
<para>
You can optionally configure an outbound email service for this sample, if
you want to receive emailed reconciliation summaries. The email service
configuration is identical to that of sample 5
(<xref linkend="email-sample5" />).
</para>
<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>
The XML files that simulate an external LDAP and AD resource are now located
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.
</para>
<para>
Run the sample in exactly the same way that you did for Sample 5, following
the steps in <xref linkend="run-sample5" />.
</para>
</section>
<section xml:id="onsync-sample5b">
<title>Demonstrate onSync</title>
<para>
To demonstrate integration of the samples with the OpenIDM UI, this sample
uses the UI to view and make changes to user objects in the repository.
However, you can also use the REST interface to make these changes, as shown
in the previous section.
</para>
<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 (<literal>DDOE1</literal>).
With automatic synchronization, that change is reflected almost immediately
on the external resources. For sample 5b, you should see the changes in both
XML files in the <filename>/path/to/openidm/sample5b/data</filename>
directory. Alternatively, you can query the external resources over REST, as
described previously.
</para>
<para>
The synchronization is successful, across all configured external resources,
so the updated user record can be seen in both the
<filename>xml_LDAP_Data.xml</filename> and
<filename>xml_AD_Data.xml</filename> files.
</para>
<para>
The next step is to simulate a problem connecting to the LDAP resource. One
way to do so on the local system is to rename the LDAP data file so that it
is 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 user <literal>DDOE1</literal>. With the
modified filename of the simulated LDAP resource, automatic synchronization
cannot write to this resource. An error similar to the following is
displayed in the 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>
Although the AD resource is available, automatic synchronization will not
reach this resource, because the mapping is specified
<emphasis>after</emphasis> the managed/user to LDAP mapping in the
<filename>sync.json</filename> file.
</para>
<para>
When the automatic synchronization fails for the LDAP resource, the
<literal>onSync</literal> hook invokes the
<filename>compensate.js</filename> script. This script attempts to revert
the original change by performing another update to DDOE1 in the repository
(managed/user). This change, in turn, triggers another automatic
synchronization to the AD and LDAP resources.
</para>
<para>
Because the LDAP resource is still unreadable, the synchronization to LDAP
fails again, which triggers the <literal>compensate.js</literal> script
again. This time, however, the script recognizes that the change was
originally called as a result of a compensation and aborts.
</para>
<para>
The original synchronization error from the first update is thrown from the
script and the UI should display that error. If you refresh the UI, and view
that user entry again, you will notice that the change to the entry has been
reverted.
</para>
<para>
Note that if you change the name of the AD resource file (to make it
unavailable), a change to a managed/user entry will be synchronized
successfully with the LDAP resource (because that mapping appears first in
<filename>sync.json</filename>). The synchronization will fail for the AD
resource. In this case, the change will be reverted on both the managed/user
entry, and the LDAP resource.
</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 demonstrates LiveSync from an external
resource. Sample 6 includes configuration files for two scenarios, depending
on whether you have a live Active Directory (AD) service, or whether you
need to simulate an AD service with an OpenDJ server. 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 synchronization <emphasis>from</emphasis> the
AD server <emphasis>to</emphasis> OpenDJ, data on the AD server is not
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>
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 the 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 existing, active instance of AD, set up 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>
During installation, populate OpenDJ with the data in the
<filename>Example.ldif</filename> file, available in the
<filename>/path/to/sample6/data</filename> directory.
</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>
In this sample, an AD deployment is simulated with a different baseDN
(<literal>dc=fakead,dc=com</literal>) on the same OpenDJ server instance.
You can also simulate the AD server with a separate OpenDJ instance, running
on the same host, as long as the two instances communicate on different
ports. The data for the simulated AD instance is contained in the file
<filename>AD.ldif</filename>. The data for the OpenDJ instance is contained
in the file <filename>Example.ldif</filename>.
</para>
</section>
<section xml:id="external-resource-sample6">
<title>External Configuration</title>
<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. 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.
When 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>
As previously mentioned, you can use a separate OpenDJ instance to
simulate the AD server. However, the following instructions assume that
the simulated AD server runs on the same OpenDJ instance.
</para>
<para>
Open the <filename>provisioner.openicf-fakead.json</filename> file and
note the following:
</para>
<itemizedlist>
<listitem>
<para>
OpenDJ directory server uses port 1389 by default for users who cannot
use privileged ports, so this is the port that is specified in the
provisioner file. Adjust the port if your OpenDJ server is listening on
a different port.
</para>
</listitem>
<listitem>
<para>
The simulated AD server uses the base DN
<literal>dc=fakead,dc=com</literal>.
</para>
</listitem>
</itemizedlist>
<para>
To load the data for the simulated AD instance, launch the OpenDJ control
panel, add the simulated AD baseDN (<literal>dc=fakead,dc=com</literal>),
and then import the <filename>/path/to/sample6/data/AD.ldif</filename>
file. When you import the <filename>AD.ldif</filename> file, select
"Append to Existing Data", not "Overwrite Existing Data". Otherwise, the
data in the <literal>dc=example,dc=com</literal> baseDN will be
overwritten.
</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 updated with the
contents from AD.
</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>Successful reconciliation returns a reconciliation run ID.</para>
<screen>{"_id":"9ece3807-08c3-4ec6-87fb-a6a2d0c71cee"}</screen>
<para>
The reconciliation operation synchronizes the data in the AD deployment
with OpenIDM repository (managed/user). 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><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/ldap/account?_queryId=query-all-ids"</userinput></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 read the user object in the OpenDJ server, run the
<command>ldapsearch</command> command. The following example returns the
entry for user <literal>uid=jdoe</literal>:
</para>
<screen><userinput>$ /ldapsearch \
--port 1389 \
--baseDN dc=example,dc=com \
"(uid=jdoe)"</userinput></screen>
</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, to use LiveSync, you must
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>
LiveSync 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 with a new user entry (<literal>uid=bsmith</literal>)
that will be added to the simulated AD data store.
</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: passw0rd</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.
</para>
<screen><userinput>$ /ldapmodify
--port 1389
--defaultAdd
--bindDN "cn=Directory Manager"
--bindPassword password
--filename /path/to/bsmith.ldif</userinput></screen>
</step>
<step>
<para>
Now you can test synchronization by viewing the new user in the OpenIDM
repository. The easiest way to do this, is through OpenIDM UI. You should
be able to log into the UI with any of the accounts in the AD data store.
For this example, log into the UI as user <literal>bsmith</literal>, with
password <literal>passw0rd</literal>. The fact that you can log into the
UI as this new user indicates that LiveSync has synchronized the user
from the AD data store to the managed/user repository.
</para>
</step>
<step>
<para>
Automatic synchronization pushes this change out to the OpenDJ data store.
To test this synchronization operation, search the OpenDJ baseDN for the
new user entry.
</para>
<screen><userinput>$ /ldapsearch \
--port 1389 \
--baseDN ou=people,dc=example,dc=com \
"(uid=bsmith)"</userinput></screen>
</step>
</procedure>
</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><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=systemXmlfileAccounts_managedUser"</userinput></screen>
<para>Reconciliation creates a user object in the repository. Retrieve the
user from the repository.</para>
<screen><userinput>$ 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"</userinput></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><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=systemXmlfileAccounts_managedUser"</userinput></screen>
<para>Successful reconciliation returns a reconciliation run ID.</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/triggerWorkflowFromSync.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><userinput>$ cd /path/to/openidm
$ /startup.sh -p samples/sample9</userinput></screen>
</section>
<section xml:id="run-sample9">
<title>Running the Sample</title>
<orderedlist>
<listitem>
<para>Run reconciliation over the REST interface.</para>
<screen><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=systemXmlfileAccounts_managedUser"</userinput></screen>
<para>Successful reconciliation returns a reconciliation run ID.</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><userinput>$ 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"</userinput></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><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 \
--data '{"requestApproved": "true"}' \
"https://localhost:8443/openidm/workflow/taskinstance/124?_action=complete"</userinput></screen>
<para>On Windows:</para>
<screen><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 ^
--data "{\"requestApproved\": \"true\"}" ^
"https://localhost:8443/openidm/workflow/taskinstance/124?_action=complete"</userinput></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><userinput>$ 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"</userinput></screen>
<para>One user is returned.</para>
<screen>{
"result": [ {
"_rev": "0",
"_id": "1"
} ],
"resultCount": 1,
"pagedResultsCookie": null,
"remainingPagedResults": -1,
}</screen>
</listitem>
</orderedlist>
</section>
</section>
<section xml:id="more-sample-openam">
<title>Sample OpenAM - Configuring Authentication Management for OpenIDM</title>
<indexterm>
<primary>Samples</primary>
<secondary>Sample OpenAM - Authentication Management for OpenIDM</secondary>
</indexterm>
<para>
This sample demonstrates how you can protect a deployment of OpenIDM with
ForgeRock's <link xlink:show="new"
xlink:href="http://docs.forgerock.org/en/index.html?product=openam&amp;version=11.0.0">
<citetitle>OpenAM Access Management</citetitle></link> product.
</para>
<para>
In this sample, you will use OpenIDM together with OpenAM and ForgeRock's
<link xlink:href="http://docs.forgerock.org/en/index.html?product=opendj&amp;version=2.6.0">
<citetitle>OpenDJ Directory Services</citetitle></link> product.
</para>
<para>
When configured together, you can demonstrate one use case that maximizes
Identity Relationship Management (IRM) functionality. OpenIDM can maintain
user data in OpenDJ data stores. Once protected by OpenAM, you can configure
rules for authorized access.
</para>
<para>
This sample configures OpenIDM and OpenDJ on one system, with a URL of
<literal>openidm.example.com</literal>. It configures OpenAM on a separate
second system, with a URL of <literal>openam.example.com</literal>.
</para>
<!--TODO: update if/when OpenAM 11 is updated to work with this sample, ref
AME-4386 -->
<note>
<para>
At this time, this sample assumes that you have deployed OpenAM 12.
</para>
</note>
<section xml:id="prepare-sample-openam">
<title>Prepare the Sample</title>
<para>
Before installing OpenIDM, you need to prepare your systems. To set up this
sample, you need to take the following basic steps:
</para>
<itemizedlist>
<listitem>
<para>
Install OpenDJ, using a base DN of <literal>dc=example,dc=com</literal>.
Be sure to import the <filename>Example.ldif</filename> file available in
the <literal>samples/openam/data</literal> directory.
This example assumes that you install OpenDJ on the same system as
OpenIDM, with a FQDN of <literal>openidm.example.com</literal>.
</para>
<para>
If you set up OpenDJ on a secure port with a self-signed certificate, you
should import that certificate into the OpenIDM datastore, as described in
the following section of the Integrator's Guide: <link xlink:show="new"
xlink:role="http://docbook.org/roles/xlink/role/olink"
xlink:href="integrators-guide#security-management-service"><citetitle>
Accessing the Security Management Service</citetitle></link>.
</para>
</listitem>
<listitem>
<para>
Install an OpenAM 12 server in an environment that OpenIDM can access with
RESTful calls. For installation instructions, see the <link xlink:show="new"
xlink:href="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/install-guide/index.html">
<citetitle>OpenAM Installation Guide</citetitle></link>. This example
assumes that you have deployed the associated <literal>.war</literal>
file in your selected Java EE container with the following name:
<filename>openam.war</filename>.
</para>
<para>
When installing OpenAM, configure it to use the OpenDJ data store
installed on <literal>openidm.example.com</literal>.
</para>
<para>
This sample assumes that you will configure OpenAM-based Single Sign-On
(SSO) as described in the OpenAM Administration Guide. For this sample,
you will need to configure <literal>.example.com</literal> as the sole
cookie domain as described in the following section of the noted OpenAM
Guide: <link xlink:show="new"
xlink:href="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/index.html#configure-sso-one-domain">
<citetitle>Configure SSO on One Domain</citetitle></link>.
</para>
</listitem>
<listitem>
<para>
Prepare OpenIDM as described in <xref linkend="preparing-openidm"/>.
</para>
</listitem>
<listitem>
<para>
As OpenAM works with FQDNs, you will need to either set up the noted
FQDNs <literal>(openam.example.com and openidm.example.com)</literal> in
an address database such as a DNS server or the static
<filename>hosts</filename> configuration file of both systems.
</para>
</listitem>
<listitem>
<para>
Do not start OpenIDM yet. You need to configure it further.
</para>
</listitem>
</itemizedlist>
<note>
<para>
When you configure OpenAM for this sample, you do not need to install a
Java EE agent. This sample uses the <literal>OPENAM_SESSION</literal>
module to protect OpenIDM.
</para>
</note>
</section>
<section xml:id="configure-openam-sample">
<title>Configuring OpenIDM for the OpenAM Sample</title>
<para>
Before starting OpenIDM, you will need to change two configuration files,
related to authentication and provisioning.
</para>
<section xml:id="configure-openam-sample-auth-json">
<title>Configuring the authentication.json File for OpenAM</title>
<para>
To configure OpenIDM authentication, open the
<filename>authentication.json</filename> file. For this sample, you can
find that file in the <literal>samples/openam/conf</literal> directory.
</para>
<para>
Under <literal>"authModules"</literal>, find the
<literal>"OPENAM_SESSION"</literal> authentication module. The default
version of the <filename>authentication.json</filename> file includes two
entries which you must fill in:
</para>
<programlisting language="javascript">"authModules" : [
{
"name" : "OPENAM_SESSION",
"properties" : {
"openamDeploymentUrl" : "",
"groupRoleMapping" : {
"openidm-admin" : [ ]
},</programlisting>
<para>
Based on a standard <literal>openidm-admin</literal> user and the
previously noted URL and <literal>.war</literal> file for your OpenAM
deployment, you would change the code snippet to:
</para>
<programlisting language="javascript">"authModules" : [
{
"name" : "OPENAM_SESSION",
"properties" : {
"openamDeploymentUrl" : "https://openam.example.com:8443/openam",
"groupRoleMapping" : {
"openidm-admin" : [
"cn=idmAdmins,ou=Groups,dc=example,dc=com"
]
},</programlisting>
<para>
Do remember to include <literal>/openam</literal> in the value of
<literal>"openamDeploymentUrl"</literal>. After the Java EE container used
for OpenAM starts, it unpacks a file such as <literal>openam.war</literal>
so that you can access it on the <literal>/openam</literal> endpoint.
</para>
<para>
With the <literal>"groupRoleMapping"</literal>, you can add the
Distinguished Names (DN) of groups to the list. This feature will then
assign the noted role, such as <literal>openidm-admin</literal> to any user
who is a member of one of these groups. For more information on how roles
are assigned, see the following section in the Integrator's Guide on
<link xlink:role="http://docbook.org/roles/xlink/role/olink"
xlink:href="integrators-guide#openidm-roles" xlink:show="new">
<citetitle>Roles and Authentication</citetitle></link>.
</para>
<!-- The README suggests this is needed only for self-signed certs. I think
this may be required for regular certs too, or does our truststore include
the "standard list"? -->
<para>
The <literal>"openamDeploymentUrl"</literal> shown above assumes that you
are using SSL. If you have a self-signed certificate, you will need to
import that into the OpenIDM truststore file. For more information, see
the following section of the Integrator's Guide: <link xlink:show="new"
xlink:role="http://docbook.org/roles/xlink/role/olink"
xlink:href="integrators-guide#security-management-service"><citetitle>
Accessing the Security Management Service</citetitle></link>.
</para>
</section>
<section xml:id="configure-openam-sample-prov">
<title>Configure Provisioning for the OpenAM Sample</title>
<para>
This section describes how you can customize the
<filename>provisioner.openicf-ldap.json</filename> file. The following
edits parallel those for <link xlink:show="new"
xlink:role="http://docbook.org/roles/xlink/role/olink"
xlink:href="install-guide#more-sample2c"><citetitle>Sample
2c - Synchronizing LDAP Group Membership</citetitle></link>.
</para>
<para>
Open the noted provisioner file, which you can find in the
<literal>samples/openam/conf</literal> directory. In the
initial version of this file, you should see something similar to the
following code:
</para>
<programlisting language="javascript">{
"name" : "ldap",
"configurationProperties" : {
"host" : "localhost",
"port" : 1389,
"ssl" : false,
"principal" : "cn=Directory Manager",
"credentials" : "password",
"baseContexts" : [
"dc=example,dc=com"
],
"baseContextsToSynchronize" : [
"dc=example,dc=com"
],</programlisting>
<para>
This snippet already matches the noted base context of
<literal>"dc=example,dc=com"</literal> with a principal of
<literal>"cn=Directory Manager"</literal>.
</para>
<para>
You will want to change the <literal>"localhost"</literal> entry to the
URL where OpenDJ is installed. In this case, that URL is
<literal>openidm.example.com</literal>. Depending on whether you want to
set up communications over a regular or secure LDAP port, you might
change the <literal>"port"</literal> number to 389 or 636. The following
excerpt illustrates the change to a secure connector configuration:
</para>
<programlisting language="javascript">{
"name" : "ldap",
"configurationProperties" : {
"host" : "openidm.example.com",
"port" : 636,
"ssl" : true,
"principal" : "cn=Directory Manager",
"credentials" : "password",
"baseContexts" : [
"dc=example,dc=com"
],
"baseContextsToSynchronize" : [
"dc=example,dc=com"
],</programlisting>
<para>
Just remember, if you want to set up secure communications with OpenDJ,
you should configure OpenDJ with that in mind. If you have a self-signed
certificate for OpenDJ, you will also want to import that into the
OpenIDM truststore, as discussed in the following section of the
Integrator's Guide: <link xlink:show="new"
xlink:role="http://docbook.org/roles/xlink/role/olink"
xlink:href="integrators-guide#security-management-service"><citetitle>
Accessing the Security Management Service</citetitle></link>.
</para>
</section>
</section>
<section xml:id="install-sample-openam">
<title>Install the Sample</title>
<para>
If you have not already done so, make sure OpenDJ is running on its
assigned system, in this case, <literal>openidm.example.com</literal>.
</para>
<para>
Finish preparing OpenIDM, with the procedure described in
<xref linkend="preparing-openidm"/>, then start OpenIDM with the
configuration for sample openam.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/openam</screen>
<para>
If you have not already done so, make sure OpenAM is also running on its
assigned system, in this case, <literal>openam.example.com</literal>.
</para>
</section>
<section xml:id="run-sample-openam">
<title>Running the Sample</title>
<para>
With everything configured, now run reconciliation on the
<literal>openidm.example.com</literal> system. The following command
imports users from the OpenDJ database into the OpenIDM managed/user
database:
</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=systemLdapAccounts_managedUser"</screen>
<para>
Successful reconciliation returns a reconciliation run ID.
</para>
</section>
<section xml:id="review-sample-openam">
<title>Make Sure the Sample Works as Intended</title>
<para>
You should still be able to access the OpenIDM UI
in the "normal" way. In this case, you would point a browser to
<literal>https://openidm.example.com:8443/openidmui</literal>.
</para>
<para>
The difference is how OpenIDM uses a proxy service to authenticate with
OpenAM's REST-based authentication service. This sample implements the
proxy service as a custom endpoint in the <filename>openamProxy.js</filename>
file, in the <literal>samples/openam/script</literal>
directory.
</para>
<para>
The first time you log into the OpenIDM UI, you should see a login prompt
configured with OpenAM. The default version of this prompt appears quite
similar to the OpenIDM prompt. When you login through OpenAM, successfully,
you will receive a valid SSO token.
</para>
<para>
The next time you access OpenIDM, with the SSO token stored in your browser,
you will be logged in automatically, with all the roles configured for your
user account. This works only if your session is still active in OpenAM.
For more information, see the OpenAM Administration Guide section on
<link xlink:show="new"
xlink:href="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/#session-mgmt">
<citetitle>Session Management</citetitle></link>.
</para>
<note>
<para>You can review the contents of the SSO token by pointing a browser to
the FQDN of the OpenIDM instance, with the <literal>info/login</literal>
endpoint. In this case, that URL would be
<literal>https://openidm.example.com/openidm/info/login</literal>.</para>
</note>
</section>
<section xml:id="sample-openam-going-further">
<title>Additional Options for the OpenAM Sample</title>
<para>
You can extend the OpenAM sample in one of three ways:
</para>
<itemizedlist>
<listitem>
<para><literal>Disable INTERNAL_USER by enabling LiveSync</literal></para>
<para>
To keep OpenDJ in sync with the OpenIDM managed/user database, you can
enable scheduled reconciliation and LiveSync. To do so, edit the following
files: <filename>schedule-recon.json</filename> and
<filename>schedule-livesync.json</filename>, in the
<literal>samples/openam/conf</literal> directory. Set
<literal>"enabled" : true</literal> in each of these files.
</para>
<para>
This ensures that any change to the OpenDJ user store is automatically
reflected in the OpenIDM managed/user data store. For a similar example,
see <xref linkend="more-sample6"/>.
</para>
<para>
Execute the reconciliation command described earlier in the description
for this sample.
</para>
<para>
Once scheduled reconciliation and LiveSync are configured, you can then
disable the <literal>INTERNAL_USER</literal> under
<literal>authModules</literal> in the relevant
<filename>authentication.json</filename> file. Just navigate to that
section of the file and set <literal>"enabled" : false</literal>. Once
complete, the only users with access to OpenIDM are users with a valid
SSO authentication token in their browsers.
</para>
</listitem>
<!-- possible additional options; can incorporate with more detail
<listitem>
<para>
<literal>Set up workflows to request access to applications</literal>
</para>
<para>
You can configure a workflow to allow users to request access to
additional applications. Upon approval, OpenIDM can update user accounts
with the permissions used by OpenAM to control access to that application.
For more information on workflows, see the Integrator's Guide section to
<link xlink:role="http://docbook.org/roles/xlink/role/olink"
xlink:href="integrators-guide#chap-workflow" xlink:show="new">
<citetitle>Integrating Business Processes and Workflows</citetitle>.
</link>
</para>
</listitem>
<listitem>
<para><literal>Single Sign-On Dashboard</literal></para>
<para>
You could extend workflow concepts to give users a choice of
applications, based on their SSO token. Once configured, you could set up
a "Single Sign-On" application dashboard for your users.
</para>
</listitem> also:
Integrated Services For Custom Applications
Based on the presence of a shared SSO token, any application secured by OpenAM
could reliably invoke OpenIDM REST services in an integrated and transparent
way. For example, an intranet portal could make AJAX requests to OpenIDM to
start a workflow process or execute a query. The fact that the request was
being made to OpenIDM would be hidden from the user - the SSO token that they
used to access the intranet would also be used by OpenIDM, and everything
would just work seamlessly.
-->
</itemizedlist>
</section>
</section>
</chapter>