Chapter 5. Configuring OpenIDM

Table of Contents
5.1. OpenIDM Configuration Objects
5.2. Changing the Default Configuration
5.3. Configuring an OpenIDM System for Production
5.4. Configuring OpenIDM Over REST
5.5. Using Property Value Substitution in the Configuration
5.6. Adding Custom Endpoints

OpenIDM configuration is split between .properties and container configuration files, and also dynamic configuration objects. The majority of OpenIDM configuration files are stored under openidm/conf/, as described in the appendix listing the File Layout.

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.

5.1. OpenIDM Configuration Objects

OpenIDM exposes internal configuration objects in JSON format. Configuration elements can be either single instance or multiple instance for an OpenIDM installation.

Single Instance Configuration Objects

Single instance configuration objects correspond to services that have at most one instance per installation.

JSON file views of these configuration objects are named object-name.json.

  • The audit configuration specifies how audit events are logged.

  • The authentication configuration controls REST access.

  • The endpoint configuration controls any custom REST endpoints.

  • The managed configuration defines managed objects and their schemas.

  • The policy configuration defines the policy validation service.

  • The process access configuration defines access to any configured workflows.

  • The repo.repo-type configuration such as repo.orientdb or repo.jdbc configures the internal repository.

  • The router configuration specifies filters to apply for specific operations.

  • The sync configuration defines the mappings that OpenIDM uses when synchronizing and reconciling managed objects.

  • The ui configuration defines the configurable aspects of the default user interface.

  • The workflow configuration defines the configuration of the workflow engine.

Multiple Instance Configuration Objects

Multiple instance configuration objects correspond to services that can have many instances per installation. Configuration objects are named objectname/instancename, for example, provisioner.openicf/xml.

JSON file views of these configuration objects are named objectname-instancename.json, for example, provisioner.openicf-xml.json.

  • Multiple schedule configurations can run reconciliations and other tasks on different schedules.

  • Multiple provisioner.openicf configurations correspond to the resources connected to OpenIDM.

5.2. Changing the Default Configuration

When you change OpenIDM's configuration objects, take the following points into account.

  • 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.

    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.

  • 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.

  • Avoid editing configuration objects directly in the internal repository. Rather edit the configuration over the REST API, or in the configuration JSON files to ensure consistent behavior and that operations are logged.

  • OpenIDM stores its configuration in the internal database by default. If you remove an OpenIDM instance and do not specifically drop the repository, the configuration remains in effect for a new OpenIDM instance that uses that repository. For testing or evaluation purposes, you can disable this persistent configuration in the conf/system.properties file by uncommenting the following line:

    # openidm.config.repo.enabled=false
                 

    Disabling persistent configuration means that OpenIDM will store its configuration in memory only. You should not disable persistent configuration in a production environment.

5.3. Configuring an OpenIDM System for Production

Out of the box, OpenIDM is configured to make it easy to install and evaluate. Specific configuration changes are required before you deploy OpenIDM in a production environment.

5.3.1. Configuring a Production Repository

By default, OpenIDM uses OrientDB for its internal repository so that you do not have to install a database in order to evaluate OpenIDM. Before you use OpenIDM in production, you must replace OrientDB with a supported repository.

For more information, see Installing a Repository for Production in the Installation Guide.

5.3.2. Disabling Automatic Configuration Updates

By default, OpenIDM polls the JSON files in the conf directory periodically for any changes to the configuration. In a production system, it is recommended that you disable automatic polling for updates to prevent untested configuration changes from disrupting your identity service.

To disable automatic polling for configuration changes, edit the conf/system.properties file by uncommenting the following line:

# openidm.fileinstall.enabled=false

Before you disable automatic polling, you must have started the OpenIDM instance at least once to ensure that the configuration has been loaded into the database.

Note that scripts are loaded each time 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. You do not need to restart OpenIDM for script modifications to take effect.

5.3.3. Disabling the File-Based Configuration View

To control configuration changes to the OpenIDM system, you disable the file-based configuration view and have OpenIDM read its configuration only from the repository. To disable the file-based configuration view, edit the conf/system.properties file to uncomment the following line: # openidm.fileinstall.enabled=false.

5.4. Configuring OpenIDM Over REST

OpenIDM exposes configuration objects under the /openidm/config context.

You can list the configuration on the local host by performing a GET http://localhost:8080/openidm/config. The following example shows the default configuration for an OpenIDM instance started with Sample 1.

$ curl --request GET 
 --header "X-OpenIDM-Username: openidm-admin"
 --header "X-OpenIDM-Password: openidm-admin"
 http://localhost:8080/openidm/config

{
    "configurations": [
        {
            "_id": "endpoint/getprocessesforuser",
            "pid": "endpoint.788f364e-d870-4f46-982a-793525fff6f0",
            "factoryPid": "endpoint"
        },
        {
            "_id": "provisioner.openicf/xml",
            "pid": "provisioner.openicf.90b18af9-fe27-45a2-a4ae-1056c04a4d31",
            "factoryPid": "provisioner.openicf"
        },
        {
            "_id": "ui/configuration",
            "pid": "ui.36bb2bf4-8e19-43d2-9df2-a0553ffac590",
            "factoryPid": "ui"
        },
        {
            "_id": "managed",
            "pid": "managed",
            "factoryPid": null
        },
        {
            "_id": "sync",
            "pid": "sync",
            "factoryPid": null
        },
        {
            "_id": "router",
            "pid": "router",
            "factoryPid": null
        },
        {
            "_id": "process/access",
            "pid": "process.44743c97-a01b-4562-85ad-8a2c9b89155a",
            "factoryPid": "process"
        },
        {
            "_id": "endpoint/siteIdentification",
            "pid": "endpoint.ef05a7f3-a420-4fbb-998c-02d283cae4d1",
            "factoryPid": "endpoint"
        },
        {
            "_id": "endpoint/securityQA",
            "pid": "endpoint.e2d87637-c918-4056-99a1-20f25c897066",
            "factoryPid": "endpoint"
        },
        {
            "_id": "scheduler",
            "pid": "scheduler",
            "factoryPid": null
        },
        {
            "_id": "ui/countries",
            "pid": "ui.acde0f4c-808f-45fb-9627-d7d2ca702e7c",
            "factoryPid": "ui"
        },
        {
            "_id": "org.apache.felix.fileinstall/openidm",
            "pid": "org.apache.felix.fileinstall.2dedea63-4592-4074-a709-ffa70f1e841d",
            "factoryPid": "org.apache.felix.fileinstall"
        },
        {
            "_id": "schedule/reconcile_systemXmlAccounts_managedUser",
            "pid": "schedule.f53b235a-862e-4e18-a3cf-10ae3cbabc1e",
            "factoryPid": "schedule"
        },
        {
            "_id": "workflow",
            "pid": "workflow",
            "factoryPid": null
        },
        {
            "_id": "endpoint/getavailableuserstoassign",
            "pid": "endpoint.d19da94f-bae3-4101-922c-fe47ea8616d2",
            "factoryPid": "endpoint"
        },
        {
            "_id": "repo.orientdb",
            "pid": "repo.orientdb",
            "factoryPid": null
        },
        {
            "_id": "audit",
            "pid": "audit",
            "factoryPid": null
        },
        {
            "_id": "endpoint/gettasksview",
            "pid": "endpoint.edcc1ff8-a7ba-4c46-8258-bf5216e85192",
            "factoryPid": "endpoint"
        },
        {
            "_id": "ui/secquestions",
            "pid": "ui.649e2c65-0cc7-4a0d-a6b1-95f4c5168bdc",
            "factoryPid": "ui"
        },
        {
            "_id": "org.apache.felix.fileinstall/activiti",
            "pid": "org.apache.felix.fileinstall.a0ba2f7d-bdb9-43b5-b84e-0e8feee6be72",
            "factoryPid": "org.apache.felix.fileinstall"
        },
        {
            "_id": "policy",
            "pid": "policy",
            "factoryPid": null
        },
        {
            "_id": "endpoint/usernotifications",
            "pid": "endpoint.e96d5319-6260-41db-af76-bd4e692b792d",
            "factoryPid": "endpoint"
        },
        {
            "_id": "org.apache.felix.fileinstall/ui",
            "pid": "org.apache.felix.fileinstall.89f8c6dd-f54e-46a4-bfda-1e76ac044c33",
            "factoryPid": "org.apache.felix.fileinstall"
        },
        {
            "_id": "authentication",
            "pid": "authentication",
            "factoryPid": null
        }
    ]
}

Single instance configuration objects are located under openidm/config/object-name. The following example shows the default audit configuration.

$ 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"
        }
    ]
}

Multiple instance configuration objects are found under openidm/config/object-name/instance-name. The following example shows the configuration for the XML connector provisioner.

$ 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": "",
        "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": "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": {}
}

You can change the configuration over REST by using an HTTP PUT request to modify the required configuration object. The following example modifies the router.json file to remove all filters, effectively bypassing any policy validation.

$ 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"
  

See the REST API Reference appendix for additional details and examples using REST access to update and patch objects.

5.5. Using Property Value Substitution in the Configuration

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.

Property substitution enables you to achieve the following:

  • Define a configuration that is specific to a single OpenIDM instance, for example, setting the location of the keystore on a particular host.

  • Define a configuration whose parameters vary between different environments, for example, the URLs and passwords for test, development, and production environments.

  • Disable certain capabilities on specific nodes. For example, you might want to disable the workflow engine on specific instances.

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.

Property references are contained within the construct &{ }. When such references are found, OpenIDM replaces them with the appropriate property value, defined in the boot.properties file.

Example 5.1. 

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.

The environments are defined by adding the following lines to the conf/boot.properties file:

   PROD.location=production
   DEV.location=development
   

The database URL is then specified as follows in the repo.orientdb.json file:

    {
    "dbUrl" : "local:./db/&{&{environment}.location}-openidm",
    "user" : "admin",
    "poolMinSize" : 5,
    "poolMaxSize" : 20,
    ...
    }
   

The effective database URL is determined by setting the OPENIDM_OPTS environment variable when you start OpenIDM. To use the production environment, start OpenIDM as follows:

   $ export OPENIDM_OPTS="-Xmx1024m -Denvironment=PROD"
   $ ./startup.sh
   

To use the development environment, start OpenIDM as follows:

   $ export OPENIDM_OPTS="-Xmx1024m -Denvironment=DEV"
   $ ./startup.sh
   

5.5.1. Using Property Value Substitution With System Properties

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.

Example 5.2. 

The following example modifies the audit.json file so that the log file is written to the user's directory. The user.home property is a default Java System property.

{
    "logTo" : [
        {
            "logType" : "csv",
            "location" : "&{user.home}/audit",
            "recordDelimiter" : ";"
        }
    ]
}
   

You can define nested properties (that is a property definition within another property definition) and you can combine system properties and boot properties.

Example 5.3. 

The following example uses the user.country property, a default Java System property. The example defines specific LDAP ports, depending on the country (identified by the country code) in the boot.properties file. The value of the LDAP port (set in the provisioner.openicf-ldap.json file) depends on the value of the user.country System property.

The port numbers are defined in the boot.properties file as follows:

   openidm.NO.ldap.port=2389
   openidm.EN.ldap.port=3389
   openidm.US.ldap.port=1389

The following extract from the provisioner.openicf-ldap.json file shows how the value of the LDAP port is eventually determined, based on the System property:

   "configurationProperties" :
   {
      "credentials" : "Passw0rd",
      "port" : "&{openidm.&{user.country}.ldap.port}",
      "principal" : "cn=Directory Manager",
      "baseContexts" :
         [
            "dc=example,dc=com"
         ],
      "host" : "localhost"
   }
   

5.5.2. Limitations of Property Value Substitution

Note the following limitations when you use property value substitution:

  • You cannot reference complex objects or properties with syntaxes other than String. Property values are resolved from the boot.properties file or from the System properties and the value of these properties is always in String format.

    Property substitution of boolean values is currently only supported in stringified format, that is, resulting in "true" or "false".

  • Substitution of encrypted property values is currently not supported.

5.6. Adding Custom Endpoints

You can customize OpenIDM to meet the specific requirements of your deployment by adding your own RESTful endpoints. Endpoints are configured in files named conf/endpoint-name.json, where name generally describes the purpose of the endpoint.

A sample custom endpoint configuration is provided at openidm/samples/customendpoint. The sample includes two files:

conf/endpoint-echo.json, which provides the configuration for the endpoint.
script/echo.js, which is launched when the endpoint is accessed.

The structure of an endpoint configuration file is as follows:

{ 
  "context" : "endpoint/echo", 
  "type" : "text/javascript", 
  "file" : "script/echo.js" 
}    
    
"context"

The URL context under which the endpoint is registered. Currently this must be under endpoint/. An endpoint registered under the context endpoint/echo is addressable over REST at http://localhost:8080/openidm/endpoint/echo and with the internal resource API, for example openidm.read("endpoint/echo").

"type"

The type of implementation. Currently only "text/javascript" is supported.

"source" or "file

The actual script, inline, or a pointer to the file that contains the script. The sample script, (samples/customendpoint/script/echo.js) simply returns the HTTP request when a request is made on that endpoint.

The endpoint script has a request variable available in its scope. The request structure carries all the information about the request, and includes the following properties:

id

The local ID, without the endpoint/ prefix, for example, echo.

method

The requested operation, that is, create, read, update, delete, patch, query or action.

params

The parameters that are passed in. For example, for an HTTP GET with ?param=x, the request contains "params":{"param":"x"}.

parent

Provides the context for the invocation, including headers and security.

Note that the interface for this context is still evolving and may change in a future release.

A script implementation should check and reject requests for methods that it does not support. For example, the following implementation supports only the read method:

if (request.method == "read") {
    ...
} else {
    throw "Unsupported operation: " + request.method;
}
    

The final statement in the script is the return value. Unlike for functions, at this global scope there is no return keyword. In the following example, the value of the last statement (x) is returned.

var x = "Sample return"
functioncall();
x
    

The following example uses the sample provided in openidm/samples/customendpoint and shows the complete request structure, which is returned by the query.

$ curl
 --header "X-OpenIDM-Username: openidm-admin"
 --header "X-OpenIDM-Password: openidm-admin"
 --request GET
 "http://localhost:8080/openidm/endpoint/echo?param=x"
{
  "type": "resource",
  "uuid": "21c5ddc6-a66e-464e-9fa4-9b777505799e",
  "params": {
    "param": "x"
  },
  "method": "query",
  "parent": {
    "path": "/openidm/endpoint/echo",
    "headers": {
      "Accept": "*/*",
      "User-Agent": "curl/7.21.4 ... OpenSSL/0.9.8r zlib/1.2.5",
      "Authorization": "Basic b3BlbmlkbS1hZG1pbjpvcGVuaWRtLWFkbWlu",
      "Host": "localhost:8080"
    },
    "query": {
      "param": "x"
    },
    "method": "GET",
    "parent": {
      "uuid": "bec97cbf-8618-42f8-a841-9f5f112538e9",
      "parent": null,
      "type": "root"
    },
    "type": "http",
    "uuid": "7fb3e0d9-5f56-4b15-b710-28f2147cf4b4",
    "security": {
      "openidm-roles": [
        "openidm-admin",
        "openidm-authorized"
      ],
      "username": "openidm-admin",
      "userid": {
        "component": "internal/user",
        "id": "openidm-admin"
      }
    }
  },
  "id": "echo"
} 
    

You must protect access to any custom endpoints by configuring the appropriate authorization for those contexts. For more information, see the Authorization section.