chap-configuration.xml revision cc1ea11bc48ff93fc5ce56a8255269bf11ec493d
<?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-2012 ForgeRock AS
!
-->
<chapter xml:id="chap-configuration"
xmlns="http://docbook.org/ns/docbook"
version="5.0" xml:lang="en"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xinclude="http://www.w3.org/2001/XInclude">
<title>Configuration Options</title>
<para>OpenIDM configuration is split between <filename>.properties</filename> and container
configuration files, and also dynamic configuration objects. The majority
of OpenIDM configuration files are stored under
<filename>openidm/conf/</filename>, as described in the appendix listing the
<link xlink:href="integrators-guide#appendix-file-layout"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>File
Layout</citetitle></link>.</para>
<para>OpenIDM stores configuration objects in its internal repository.
You can manage the configuration by using either the REST access to the
configuration objects, or by using the JSON file based views.</para>
<section xml:id="configuration-objects">
<title>About Configuration Objects</title>
<indexterm>
<primary>Objects</primary>
<secondary>Configuration objects</secondary>
</indexterm>
<indexterm>
<primary>Configuration</primary>
<secondary>Objects</secondary>
</indexterm>
<para>OpenIDM exposes internal configuration objects in JSON. Configuration
elements can be either single instance or multiple instance for
an OpenIDM installation.</para>
<itemizedlist xml:id="single-instance-configuration-objects">
<title>Single Instance Configuration Objects</title>
<para>Single instance configuration objects correspond to services that have
at most one instance per installation.</para>
<para>JSON file views of these configuration objects are named
<filename><replaceable>object-name</replaceable>.json</filename>.</para>
<listitem>
<para>The <literal>audit</literal> configuration specifies how audit
events are logged.</para>
</listitem>
<listitem>
<para>The <literal>authentication</literal> configuration controls
REST access.</para>
</listitem>
<listitem>
<para>The <literal>managed</literal> configuration defines managed
objects and their schemas.</para>
</listitem>
<listitem>
<para>The <literal>repo.<replaceable>repo-type</replaceable></literal>
configuration such as <literal>repo.orientdb</literal> or
<literal>repo.jdbc</literal> configures the internal repository.</para>
</listitem>
<listitem>
<para>The <literal>router</literal> configuration specifies filters to
apply for specific operations.</para>
</listitem>
<listitem>
<para>The <literal>sync</literal> configuration defines all the mappings
OpenIDM uses when synchronizing and reconciling managed objects.</para>
</listitem>
</itemizedlist>
<itemizedlist xml:id="multiple-instance-configuration-objects">
<title>Multiple Instance Configuration Objects</title>
<para>Multiple instance configuration objects correspond to services that
can have many instances per installation.</para>
<para><emphasis>Configuration objects</emphasis> are named
<literal><replaceable>objectname</replaceable>/<replaceable
>instancename</replaceable></literal>. For example, <filename>provisioner.openicf/xml</filename>.</para>
<para><emphasis>JSON file</emphasis> views of these configuration objects
are named <filename><replaceable>objectname</replaceable>-<replaceable
>instancename</replaceable>.json</filename>. For example,
<filename>provisioner.openicf-xml.json.</filename></para>
<listitem>
<para>Multiple <literal>schedule</literal> configurations can run
reconciliations and other tasks on different schedules.</para>
</listitem>
<listitem>
<para>Multiple <literal>provisioner.openicf</literal> configurations
correspond to the resources connected to OpenIDM.</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="when-configuring-notes">
<title>Changing the Configuration</title>
<itemizedlist>
<para>When you change OpenIDM's configuration objects, take the following
points into account.</para>
<listitem>
<para>OpenIDM's authoritative configuration source is the internal
repository. JSON files provide a view of the configuration objects, but
do not represent the authoritative source.</para>
<para>OpenIDM updates JSON files after making configuration changes,
whether those changes are made through REST access to configuration
objects, or through edits to the JSON files.</para>
</listitem>
<listitem>
<para>OpenIDM recognizes changes to JSON files when it is running. OpenIDM
must be running when you delete configuration objects, even if you do so by
editing the JSON files.</para>
</listitem>
<listitem>
<para>OpenIDM polls the JSON files in the <literal>conf</literal> directory
periodically for any changes to the configuration. To disable this
automatic polling for changes, edit the <filename>conf/system.properties</filename>
file by uncommenting the following line:</para>
<programlisting>
# openidm.fileinstall.enabled=false
</programlisting>
<para>Scripts are loaded when the configuration calls the script.
Modifications to scripts are therefore not applied dynamically. If you
modify a script, you must either modify the configuration that calls the
script, or restart the component that uses the modified script. It is not
necessary to restart OpenIDM for script modifications to take effect.</para>
</listitem>
<listitem>
<para>OpenIDM stores its configuration in the internal database by default.
This means that even if you remove an OpenIDM instance, the configuration
remains in the repository. You can disable this <emphasis>persistent
configuration</emphasis> in the <filename>conf/system.properties</filename>
file by uncommenting the following line:</para>
<programlisting>
# openidm.config.repo.enabled=false
</programlisting>
<para>Disabling persistent configuration means that OpenIDM will store its
configuration in memory only. You should not disable persistent
configuration in a production environment.</para>
</listitem>
<listitem>
<para>Avoid directly editing configuration objects in the internal
repository. Use either REST access or JSON files to ensure consistent
behavior and that operations are logged.</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="configuring-over-rest">
<title>Configuring OpenIDM Over REST</title>
<indexterm>
<primary>REST API</primary>
</indexterm>
<indexterm>
<primary>Configuration</primary>
<secondary>REST API</secondary>
</indexterm>
<para>OpenIDM exposes configuration objects under the
<literal>/openidm/config</literal> context.</para>
<indexterm>
<primary>REST API</primary>
<secondary>Listing configuration objects</secondary>
</indexterm>
<para>You can list the configuration on the local host by performing a GET
<literal>http://localhost:8080/openidm/config</literal>.</para>
<screen>$ curl --request GET
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
http://localhost:8080/openidm/config
{
"configurations": [
{
"_id": "managed",
"pid": "managed",
"factoryPid": null
},
{
"_id": "repo.orientdb",
"pid": "repo.orientdb",
"factoryPid": null
},
{
"_id": "scheduler/reconcile_systemXmlAccounts_managedUser",
"pid": "scheduler.adc5cd2f-7086-4e30-9d80-b36077861868",
"factoryPid": "scheduler"
},
{
"_id": "org.apache.felix.fileinstall/openidm",
"pid":
"org.apache.felix.fileinstall.abb696a2-95c6-4432-ae74-ba60a319d1bb",
"factoryPid": "org.apache.felix.fileinstall"
},
{
"_id": "sync",
"pid": "sync",
"factoryPid": null
},
{
"_id": "audit",
"pid": "audit",
"factoryPid": null
},
{
"_id": "provisioner.openicf/xml",
"pid": "provisioner.openicf.10e2dd6d-442d-466c-a077-643bb53e2006",
"factoryPid": "provisioner.openicf"
},
{
"_id": "router",
"pid": "router",
"factoryPid": null
},
{
"_id": "authentication",
"pid": "authentication",
"factoryPid": null
}
]
}</screen>
<para>Single instance configuration objects are located under
<literal>openidm/config/<replaceable>object-name</replaceable></literal>.
The following example shows the default <literal>audit</literal>
configuration.</para>
<screen>$ curl
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
http://localhost:8080/openidm/config/audit
{
"eventTypes": {
"activity": {
"filter": {
"actions": [
"create",
"update",
"delete",
"patch",
"action"
]
}
},
"recon": {}
},
"logTo": [
{
"logType": "csv",
"location": "audit",
"recordDelimiter": ";"
},
{
"logType": "repository"
}
]
}</screen>
<para>Multiple instance configuration objects are found under
<literal>openidm/config/<replaceable>object-name</replaceable>/<replaceable
>instance-name</replaceable></literal>.
The following example shows the configuration for the XML connector
provisioner.</para>
<screen>$ curl
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
http://localhost:8080/openidm/config/provisioner.openicf/xml
{
"name": "xmlfile",
"connectorRef": {
"bundleName":
"org.forgerock.openicf.connectors.file.openicf-xml-connector",
"bundleVersion": "<?eval ${openicfBundleVersion}?>",
"connectorName": "com.forgerock.openicf.xml.XMLConnector"
},
"producerBufferSize": 100,
"connectorPoolingSupported": true,
"poolConfigOption": {
"maxObjects": 10,
"maxIdle": 10,
"maxWait": 150000,
"minEvictableIdleTimeMillis": 120000,
"minIdle": 1
},
"operationTimeout": {
"CREATE": -1,
"TEST": -1,
"AUTHENTICATE": -1,
"SEARCH": -1,
"VALIDATE": -1,
"GET": -1,
"UPDATE": -1,
"DELETE": -1,
"SCRIPT_ON_CONNECTOR": -1,
"SCRIPT_ON_RESOURCE": -1,
"SYNC": -1,
"SCHEMA": -1
},
"configurationProperties": {
"xsdIcfFilePath": "samples/sample1/data/resource-schema-1.xsd",
"xsdFilePath": "samples/sample1/data/resource-schema-extension.xsd",
"xmlFilePath": "samples/sample1/data/xmlConnectorData.xml"
},
"objectTypes": {
"account": {
"$schema": "http://json-schema.org/draft-03/schema",
"id": "__ACCOUNT__",
"type": "object",
"nativeType": "__ACCOUNT__",
"properties": {
"description": {
"type": "string",
"nativeName": "__DESCRIPTION__",
"nativeType": "string"
},
"firstname": {
"type": "string",
"nativeName": "firstname",
"nativeType": "string"
},
"email": {
"type": "array",
"items": {
"type": "string",
"nativeType": "string"
},
"nativeName": "email",
"nativeType": "string"
},
"__UID__": {
"type": "string",
"nativeName": "__UID__"
},
"password": {
"type": "string",
"required": false,
"nativeName": "__PASSWORD__",
"nativeType": "JAVA_TYPE_GUARDEDSTRING",
"flags": [
"NOT_READABLE",
"NOT_RETURNED_BY_DEFAULT"
]
},
"name": {
"type": "string",
"required": true,
"nativeName": "__NAME__",
"nativeType": "string"
},
"lastname": {
"type": "string",
"required": true,
"nativeName": "lastname",
"nativeType": "string"
}
}
}
},
"operationOptions": {}
}</screen>
<para>You can change the configuration over REST by using an HTTP PUT request
to modify the required configuration object. The following example modifies
the <filename>router.json</filename> file to remove all filters, effectively
bypassing any policy validation.</para>
<programlisting language="javascript">$ curl
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
--request PUT
--data '{
"filters" : [
{
"onRequest" : {
"type" : "text/javascript",
"file" : "bin/defaults/script/router-authz.js"
}
}
]
}'
"http://localhost:8080/openidm/config/router"
</programlisting>
<para>See the <link xlink:href="integrators-guide#appendix-rest"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>REST API
Reference</citetitle></link> appendix for additional details and
examples using REST access to update and patch objects.</para>
</section>
<section xml:id="using-property-substitution">
<title>Using Property Value Substitution in the Configuration</title>
<para>In an environment where you have more than one OpenIDM instance, you
might require a configuration that is similar, but not identical, across the
different OpenIDM hosts. OpenIDM supports variable replacement in its
configuration which means that you can modify the effective configuration
according to the requirements of a specific environment or OpenIDM instance.</para>
<itemizedlist><para>Property substitution enables you to achieve the following:</para>
<listitem><para>Define a configuration that is specific to a single OpenIDM
instance, for example, setting the location of the keystore on a particular
host.</para></listitem>
<listitem><para>Define a configuration whose parameters vary between different
environments, for example, the URLs and passwords for test, development,
and production environments.</para></listitem>
</itemizedlist>
<para>When OpenIDM starts up, it combines the system configuration, which
might contain specific environment variables, with the defined OpenIDM
configuration properties. This combination makes up the effective configuration
for that OpenIDM instance. By varying the environment properties, you can
change specific configuration items that vary between OpenIDM instances or
environments.</para>
<para>Property references are contained within the construct
<literal>&amp;{ }</literal>. When such references are found, OpenIDM replaces
them with the appropriate property value, defined in the
<filename>boot.properties</filename> file.</para>
<example>
<para>The following example defines two separate OpenIDM environments -
a development environment and a production environment. You can specify the
environment at startup time and, depending on the environment, the database
URL is set accordingly.</para>
<para>The environments are defined by adding the following lines to the
<filename>conf/boot.properties</filename> file:</para>
<programlisting language="javascript">
PROD.location=production
DEV.location=development
</programlisting>
<para>The database URL is then specified as follows in the
<filename>repo.orientdb.json</filename> file:</para>
<programlisting language="javascript">
{
"dbUrl" : "local:/db/&amp;{&amp;{environment}.location}-openidm",
"user" : "admin",
"poolMinSize" : 5,
"poolMaxSize" : 20,
...
}
</programlisting>
<para>The effective database URL is determined by setting the
<literal>OPENIDM_OPTS</literal> environment variable when you start OpenIDM.
To use the production environment, start OpenIDM as follows:</para>
<screen>
$ export OPENIDM_OPTS="-Xmx1024m -Denvironment=PROD"
$ /startup.sh
</screen>
<para>To use the development environment, start OpenIDM as follows:</para>
<screen>
$ export OPENIDM_OPTS="-Xmx1024m -Denvironment=DEV"
$ /startup.sh
</screen>
</example>
</section>
<section>
<title>Using Property Value Substitution With System Properties</title>
<para>You can use property value substitution in conjunction with the system
properties, to modify the configuration according to the system on which
the OpenIDM instance runs.</para>
<example>
<para>The following example modifies the <literal>audit.json</literal> file so
that the log file is written to the user's directory. The
<literal>user.home</literal> property is a default Java System property.</para>
<programlisting language="javascript">{
"logTo" : [
{
"logType" : "csv",
"location" : "&amp;{user.home}/audit",
"recordDelimiter" : ";"
}
]
}
</programlisting>
</example>
<para>You can define <emphasis>nested</emphasis> properties (that is a property
definition within another property definition) and you can combine system
properties and boot properties.</para>
<example>
<para>The following example uses the <literal>user.country</literal> property,
a default Java System property. The example defines specific LDAP ports,
depending on the country (identified by the country code) in the
<literal>boot.properties</literal> file. The value of the LDAP port (set in
the <literal>provisioner.openicf-ldap.json</literal> file) depends on the
value of the <literal>user.country</literal> System property.</para>
<para>The port numbers are defined in the <literal>boot.properties</literal>
file as follows:</para>
<programlisting language="javascript">
openidm.NO.ldap.port=2389
openidm.EN.ldap.port=3389
openidm.US.ldap.port=1389</programlisting>
<para>The following extract from the
<literal>provisioner.openicf-ldap.json</literal> file shows how the value of
the LDAP port is eventually determined, based on the System property:</para>
<programlisting language="javascript">
"configurationProperties" :
{
"credentials" : "Passw0rd",
"port" : "&amp;{openidm.&amp;{user.country}.ldap.port}",
"principal" : "cn=Directory Manager",
"baseContexts" :
[
"dc=example,dc=com"
],
"host" : "localhost"
}
</programlisting>
</example>
</section>
<section>
<title>Limitations of Property Value Substitution</title>
<itemizedlist>
<para>Note the following limitations when you use property value substitution:
</para>
<listitem><para>You cannot reference complex objects or properties with syntaxes
other than String. Property values are resolved from the
<literal>boot.properties</literal> file or from the System properties and the
value of these properties is always in String format.</para></listitem>
<listitem><para>Substitution of encrypted property values is currently not
supported.</para></listitem>
<!-- TO DO
For now, encypted property substitution is not supported. Check and
replace with this chunk when it is
<listitem><para>Encryption is performed before the property value substitution.
This can be problematic for properties whose values should be encrypted after
substitution, for example, passwords.</para>
<para>To use encrypted values with property substitution break the encrypted
object down into separate string properties, as shown in the following
example.</para>
<para>The following extract of the <literal>repo.jdbc.json</literal> file shows
the expected encrypted object:</para>
<programlisting language="javascript">"credentials" : {
"$crypto" : {
"value" : {
"iv" : "6Lk0/4WL8VsobGNCSh7bNQ==",
"data" : "R0L0E0h8opPFANzb2iYrlg==",
"cipher" : "AES/CBC/PKCS5Padding",
"key" : "openidm-sym-default"
},
"type" : "x-simple-encryption"
}
}
</programlisting>
<para>To use property substitution for the <literal>iv</literal> and
<literal>data</literal> properties, define two string properties in the
<literal>boot.properties</literal> file:</para>
<programlisting language="javascript">
ldap.credentials.iv=6Lk0/4WL8VsobGNCSh7bNQ==
ldap.credentials.data=R0L0E0h8opPFANzb2iYrlg==
</programlisting>
<para>You can then change the configuration in <literal>repo.jdbc.json</literal>
as follows:</para>
<programlisting language="javascript">"credentials" : {
"$crypto" : {
"value" : {
"iv" : "&amp;{ldap.credentials.iv}",
"data" : "&amp;{ldap.credentials.data}",
"cipher" : "AES/CBC/PKCS5Padding",
"key" : "openidm-sym-default"
},
"type" : "x-simple-encryption"
}
}
</programlisting></listitem>
-->
</itemizedlist>
</section>
<!-- Add this section when you have been able to test the example
</section>
<section xml:id="optimizing-the-openidm-object-model">
<title>Optimizing the OpenIDM Object Model</title>
<para>You can improve performance in specific deployment scenarios by
customizing the way in which OpenIDM objects are mapped to the relational
database. This section assumes that you are using MySQL as an internal
repository (for more information, see
<link xlink:href="install-guide#chap-repository"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Installing a Repository For Production</citetitle></link>).</para>
<itemizedlist>
<para>There are two ways in which OpenIDM objects can be mapped to the
relational database tables:</para>
<listitem><para><emphasis>Using a generic mapping</emphasis>, which allows
arbitrary objects to be stored without specific setup or administration.</para>
<para>The generic mapping facilitates rapid development, and makes system
evolution and maintenance simpler by providing a more stable database structure.
However, the generic mapping incurs a performance cost because it does not
take full advantage of the benefits of a relational database. The object model
is not normalized in the traditional sense and there is less flexibility in
indexing.</para></listitem>
<listitem><para><emphasis>Using an explicit mapping</emphasis>, which allows you
to optimize storage and queries by explicitly mapping a specific object type to
the database.</para>
<para>The explicit mapping provides a traditional object-relational mapping
and can therefore take greater advantage of relational database capabilities.
However, an explicit mapping implies that, as an administrator, you must
ensure that the mapping and objects remain synchronized at all times, and
must manage any migration or upgrade procedures carefully when objects are
added or changed. There are currently some limitations to an explicit table
mapping, and it has not been extensively tested for managed objects.</para>
</listitem>
</itemizedlist>
<para>Out of the box, OpenIDM uses an explicit mapping for a few specific tables
whose structure will remain stable, tables for which easy external queries are
required, or tables for which performance is particularly important. Tables for
managed objects (such as "managed/user") use a generic mapping by default.</para>
<para>The generic mapping provided out of the box indexes every property to
make it searchable, as shown in the following <literal>repo.jdbc.json</literal>
extract:</para>
<programlisting language="javascript">"credentials" : {
"genericMapping" : {
"managed/*" : {
"mainTable" : "managedobjects",
"propertiesTable" : "managedobjectproperties",
"searchableDefault" : true
}
},
</programlisting>
<para>In certain deployments, such a configuration might not
meet your performance requirements. You can optimize the performance of the
generic mapping by restricting the properties that are indexed (searchable).
To do this, change the <literal>searchableDefault</literal> property to
<literal>false</literal> and explicitly specify the properties that can be
searched by using the <literal>searchable</literal> setting.</para>
<para>Alternatively, leave the <literal>searchableDefault</literal> property
set to <literal>true</literal> and specify which properties should
<emphasis>not</emphasis> be indexed by setting the
<literal>searchableDefault</literal> property to <literal>false</literal> for
those properties.</para>
<para>The following example creates a separate generic table for managed/user
objects and indexes only two properties, <literal>_id</literal> and
<literal>username</literal>:</para>
<programlisting language="javascript">
"genericMapping" : {
"managed/user" : {
"mainTable" : "manageduserobjects",
"propertiesTable" : "manageduserobjectproperties",
"searchableDefault" : false,
"properties" : {
"/_id" : {
"searchable" : true
},
"/username" : {
"searchable" : true
}
}
}
},
</programlisting>
<para>Another way to optimize performance is to change the mapping
configuration to use a different mapping table type. For example, you can
change the configuration for a managed object such as "managed/user" to an
explicit table mapping, in which you specifically define the columns and
indexes. For example:</para>
<programlisting language="javascript">
"explicitMapping" : {
"managed/user" : {
...
</programlisting>
<orderedlist>
<para>In general, you should assess the following performance improvement
strategies, in order:</para>
<listitem><para>Optimize the generic mapping by explicitly defining which
properties should be searchable.</para></listitem>
<listitem><para>Place different managed object types in different generic
tables (by default, all managed object types are mapped to the
<literal>managedobjects</literal> and <literal>managedobjectproperties</literal>
tables).</para></listitem>
<listitem><para>Finally, consider explicit mappings where appropriate.</para></listitem>
</orderedlist>
</section>
-->
</chapter>