Guide to configuring and integrating ForgeRock® Identity Management software into identity management solutions. This software offers flexible services for automating management of the identity life cycle.

Preface

ForgeRock Identity Platform™ serves as the basis for our simple and comprehensive Identity and Access Management solution. We help our customers deepen their relationships with their customers, and improve the productivity and connectivity of their employees and partners. For more information about ForgeRock and about the platform, see https://www.forgerock.com.

1. About This Guide

In this guide you will learn how to integrate ForgeRock Identity Management (IDM) software as part of a complete identity management solution.

This guide is written for systems integrators building solutions based on ForgeRock Identity Management services. This guide describes the product functionality, and shows you how to set up and configure IDM software as part of your overall identity management solution.

2. Accessing Documentation Online

ForgeRock publishes comprehensive documentation online:

  • The ForgeRock Knowledge Base offers a large and increasing number of up-to-date, practical articles that help you deploy and manage ForgeRock software.

    While many articles are visible to community members, ForgeRock customers have access to much more, including advanced information for customers using ForgeRock software in a mission-critical capacity.

  • ForgeRock product documentation, such as this document, aims to be technically accurate and complete with respect to the software documented. It is visible to everyone and covers all product features and examples of how to use them.

3. Using the ForgeRock.org Site

The ForgeRock.org site has links to source code for ForgeRock open source software, as well as links to the ForgeRock forums and technical blogs.

If you are a ForgeRock customer, raise a support ticket instead of using the forums. ForgeRock support professionals will get in touch to help you.

Chapter 1. Architectural Overview

This chapter introduces the IDM architecture, and describes component modules and services.

In this chapter you will learn:

  • How IDM uses the OSGi framework as a basis for its modular architecture

  • How the infrastructure modules provide the features required for IDM's core services

  • What those core services are and how they fit in to the overall architecture

  • How IDM provides access to the resources it manages

1.1. Modular Framework

IDM implements infrastructure modules that run in an OSGi framework. It exposes core services through RESTful APIs to client applications.

The following figure provides an overview of the architecture. Specific components are described in more detail in subsequent sections of this chapter.

Modular Architecture
IDM architecture

The IDM framework is based on OSGi:

OSGi

OSGi is a module system and service platform for the Java programming language that implements a complete and dynamic component model. For more information, see What is OSGi? IDM runs in Apache Felix, an implementation of the OSGi Framework and Service Platform.

Servlet

The Servlet layer provides RESTful HTTP access to the managed objects and services. IDM embeds the Jetty Servlet Container, which can be configured for either HTTP or HTTPS access.

1.2. Infrastructure Modules

The infrastructure modules provide the underlying features needed for core services:

BPMN 2.0 Workflow Engine

The embedded workflow and business process engine is based on Activiti and the Business Process Model and Notation (BPMN) 2.0 standard.

For more information, see "Integrating Business Processes and Workflows".

Task Scanner

The task-scanning mechanism performs a batch scan for a specified property, on a scheduled interval. The task scanner executes a task when the value of that property matches a specified value.

For more information, see "Scanning Data to Trigger Tasks".

Scheduler

The scheduler supports Quartz cron triggers and simple triggers. Use the scheduler to trigger regular reconciliations, liveSync, and scripts, to collect and run reports, to trigger workflows, and to perform custom logging.

For more information, see "Scheduling Tasks and Events".

Script Engine

The script engine is a pluggable module that provides the triggers and plugin points for IDM. JavaScript and Groovy are supported.

Policy Service

An extensible policy service applies validation requirements to objects and properties, when they are created or updated.

For more information, see "Using Policies to Validate Data".

Audit Logging

Auditing logs all relevant system activity to the configured log stores. This includes the data from reconciliation as a basis for reporting, as well as detailed activity logs to capture operations on the internal (managed) and external (system) objects.

For more information, see "Setting Up Audit Logging".

Repository

The repository provides a common abstraction for a pluggable persistence layer. IDM supports reconciliation and synchronization with several major external data stores in production, including relational databases, LDAP servers, and even flat CSV and XML files.

The repository API uses a JSON-based object model with RESTful principles consistent with the other IDM services. To facilitate testing, IDM includes an embedded instance of ForgeRock Directory Services (DS). In production, you must use a supported repository, as described in "Selecting a Repository" in the Installation Guide.

1.3. Core Services

The core services are the heart of the resource-oriented unified object model and architecture:

Object Model

Artifacts handled by IDM are Java object representations of the JavaScript object model as defined by JSON. The object model supports interoperability and potential integration with many applications, services, and programming languages.

IDM can serialize and deserialize these structures to and from JSON as required. IDM also exposes a set of triggers and functions that you can define, in either JavaScript or Groovy, which can natively read and modify these JSON-based object model structures.

Managed Objects

A managed object is an object that represents the identity-related data managed by IDM. Managed objects are configurable, JSON-based data structures that IDM stores in its pluggable repository. The default managed object configuration includes users and roles, but you can define any kind of managed object, for example, groups or devices.

You can access managed objects over the REST interface with a query similar to the following:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/..."
System Objects

System objects are pluggable representations of objects on external systems. For example, a user entry that is stored in an external LDAP directory is represented as a system object in IDM.

System objects follow the same RESTful resource-based design principles as managed objects. They can be accessed over the REST interface with a query similar to the following:

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

There is a default implementation for the ICF framework, that allows any connector object to be represented as a system object.

Mappings

Mappings define policies between source and target objects and their attributes during synchronization and reconciliation. Mappings can also define triggers for validation, customization, filtering, and transformation of source and target objects.

For more information, see "Synchronizing Data Between Resources".

Synchronization and Reconciliation

Reconciliation enables on-demand and scheduled resource comparisons between the managed object repository and the source or target systems. Comparisons can result in different actions, depending on the mappings defined between the systems.

Synchronization enables creating, updating, and deleting resources from a source to a target system, either on demand or according to a schedule.

For more information, see "Synchronizing Data Between Resources".

1.4. Secure Commons REST Commands

Representational State Transfer (REST) is a software architecture style for exposing resources, using the technologies and protocols of the World Wide Web. For more information on the ForgeRock REST API, see "REST API Reference".

REST interfaces are commonly tested with a curl command. Many of these commands are used in this document. They work with the standard ports associated with Java EE communications, 8080 and 8443.

To run curl over the secure port, 8443, you must include either the --insecure option, or follow the instructions shown in "Restricting REST Access to the HTTPS Port". You can use those instructions with the self-signed certificate generated when IDM starts, or with a *.crt file provided by a certificate authority.

1.5. Access Layer

The access layer provides the user interfaces and public APIs for accessing and managing the repository and its functions:

RESTful Interfaces

IDM provides REST APIs for CRUD operations, for invoking synchronization and reconciliation, and to access several other services.

For more information, see "REST API Reference".

User Interfaces

User interfaces provide access to most of the functionality available over the REST API.

Chapter 2. Starting, Stopping, and Running the Server

This chapter covers the scripts provided for starting and stopping IDM, and describes how to verify the health of a system, that is, that all requirements are met for a successful system startup.

2.1. To Start and Stop the Server

By default, you start and stop IDM in interactive mode.

To start the server interactively, open a terminal or command window, change to the openidm directory, and run the startup script:

  • startup.sh (UNIX)

  • startup.bat (Windows)

The startup script starts the server, and opens an OSGi console with a -> prompt where you can issue console commands.

The default hostname and ports for IDM are set in the resolver/boot.properties file found in the openidm/ directory. IDM is initially configured to run on http on port 8080, https on port 8443, with a hostname of localhost. For more information about changing ports and hostnames, see "Host and Port Information".

To stop the server interactively in the OSGi console, run the shutdown command:

-> shutdown

You can also start IDM as a background process on UNIX and Linux systems. Follow these steps, preferable before you start IDM for the first time:

  1. If you have already started the server, shut it down and remove the Felix cache files under openidm/felix-cache/:

    -> shutdown
    ...
    $ rm -rf felix-cache/*
  2. Start the server in the background. The nohup survives a logout and the 2>&1& redirects standard output and standard error to the noted console.out file:

    $ nohup ./startup.sh > logs/console.out 2>&1&
    [1] 2343
    

To stop the server running as a background process, use the shutdown.sh script:

$ ./shutdown.sh
./shutdown.sh
Stopping OpenIDM (2343)

Note

Although installations on OS X systems are not supported in production, you might want to run IDM on OS X in a demo or test environment. To run IDM in the background on an OS X system, take the following additional steps:

  • Remove the org.apache.felix.shell.tui-*.jar bundle from the openidm/bundle directory.

  • Disable ConsoleHandler logging, as described in "Disable Logs".

2.2. Specifying the Startup Configuration

By default, IDM starts with the configuration, script, and binary files in the openidm/conf, openidm/script, and openidm/bin directories. You can launch IDM with a different set of configuration, script, and binary files for test purposes, to manage different projects, or to run one of the included samples.

The startup.sh script specifies the following elements of a running instance:

-p | --project-location {/path/to/project/directory}

The project location specifies the directory that contains the configuration and script files that IDM will use.

All configuration objects and any artifacts that are not in the bundled defaults (such as custom scripts) must be included in the project location. These objects include all files otherwise included in the openidm/conf and openidm/script directories.

For example, the following command starts the server with the configuration of the sync-with-csv sample (located in /path/to/openidm/samples/sync-with-csv):

$ ./startup.sh -p /path/to/openidm/samples/sync-with-csv

If you do not provide an absolute path, the project location path is relative to the system property, user.dir. IDM sets idm.instance.dir to that relative directory path. Alternatively, if you start the server without the -p option, IDM sets idm.instance.dir to /path/to/openidm.

Note

In this documentation, "your project" refers to the value of idm.instance.dir.

-w |--working-location {/path/to/working/directory}

The working location specifies the directory in which the embedded DS instance is installed, and the directory to which IDM writes its database cache, audit logs, and felix cache. The working location includes everything that is in the default db/, audit/, and felix-cache/ subdirectories.

The following command specifies that IDM writes its database cache and audit data to /Users/admin/openidm/storage:

$ ./startup.sh -w /Users/admin/openidm/storage

If you do not provide an absolute path, the path is relative to the system property, user.dir. IDM sets idm.data.dir to that relative directory path. If you do not specify a working location, IDM sets idm.data.dir to /path/to/openidm. This means the default working location data is located in the openidm/db, openidm/felix-cache and openidm/audit directories.

Note that this property does not affect the location of the IDM system logs. To change the location of these logs, edit the conf/logging.properties file.

You can also change the location of the Felix cache, by editing the conf/config.properties file, or by starting the server with the -s option, described later in this section.

-c | --config {/path/to/config/file}

A customizable startup configuration file (named launcher.json) lets you specify how the OSGi Framework is started.

Unless you are working with a highly customized deployment, you should not modify the default framework configuration. This option is therefore described in more detail in "Advanced Configuration".

-P {property=value}

Any properties passed to the startup script with the -P option are used when the server loads the launcher.json startup configuration file.

Options specified here have the lowest order of precedence when the configuration is loaded. If the same property is defined in any other configuration source, the value specified here is ignored.

-s | --storage {/path/to/storage/directory}

Specifies the OSGi storage location of the cached configuration files.

You can use this option to redirect output if you are installing on a read-only filesystem volume. For more information, see "Installing on a Read-Only Volume" in the Installation Guide. This option is also useful when you are testing different configurations. Sometimes when you start the server with two different sample configurations, one after the other, the cached configurations are merged and cause problems. Specifying a storage location creates a separate felix-cache directory in that location, and the cached configuration files remain completely separate.

Additionally, IDM sets the system property idm.install.dir to the location IDM is installed in. For example, if IDM was installed in /Users/admin/openidm/, that is what idm.install.dir will be set to.

For information about changing the startup configuration by substituting property values, see "Using Property Value Substitution".

2.3. Monitoring Server Health

Because IDM is highly modular and configurable, it is often difficult to assess whether a system has started up successfully, or whether the system is ready and stable after dynamic configuration changes have been made.

The health check service allows you to monitor the status of internal resources.

To monitor the status of external resources such as LDAP servers and external databases, use the commands described in "Checking the Status of External Systems Over REST".

2.3.1. Basic Health Checks

The health check service reports on the state of the server and outputs this state to the OSGi console and to the log files. The server can be in one of the following states:

  • STARTING - the server is starting up

  • ACTIVE_READY - all of the specified requirements have been met to consider the server ready

  • ACTIVE_NOT_READY - one or more of the specified requirements have not been met and the server is not considered ready

  • STOPPING - the server is shutting down

To verify the current server state, use the following REST call:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/info/ping"
{
  "_id": "",
  "_rev": "",
  "shortDesc": "OpenIDM ready",
  "state": "ACTIVE_READY"
}

2.3.2. Obtaining Session Information

To obtain information about the current IDM session, beyond basic health checks, use the following REST call:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"http://localhost:8080/openidm/info/login"
{
  "_id": "login",
  "authenticationId": "openidm-admin",
  "authorization": {
    "component": "internal/user",
    "authLogin": false,
    "roles": [
      "internal/role/openidm-admin",
      "internal/role/openidm-authorized"
    ],
    "ipAddress": "0:0:0:0:0:0:0:1",
    "id": "openidm-admin",
    "moduleId": "INTERNAL_USER"
  }
}

Note

You can also increment the loginCount with a related endpoint described in "Authenticating Internal and Managed Users".

2.3.3. Monitoring Tuning and Health Parameters

The openidm/health endpoint provides more detailed monitoring information on the following areas:

  • Operating System on the openidm/health/os endpoint

  • Memory on the openidm/health/memory endpoint

  • Reconciliation, on the openidm/health/recon endpoint.

For information on controlling access to these endpoints, see "Understanding the Access Configuration Script (access.js)".

2.3.3.1. Operating System Health Check

With the following REST call, you can get basic information about the host operating system:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/health/os"
{
    "_id" : "",
    "_rev" : "",
    "availableProcessors" : 1,
    "systemLoadAverage" : 0.06,
    "operatingSystemArchitecture" : "amd64",
    "operatingSystemName" : "Linux",
    "operatingSystemVersion" : "2.6.32-504.30.3.el6.x86_64"
}

From the output, you can see that this particular system has one 64-bit CPU, with a load average of 6 percent, on a Linux system with the noted kernel operatingSystemVersion number.

2.3.3.2. Memory Health Check

With the following REST call, you can get basic information about overall JVM memory use:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/health/memory"
{
    "_id" : "",
    "_rev" : "",
    "objectPendingFinalization" : 0,
    "heapMemoryUsage" : {
        "init" : 1073741824,
        "used" : 88538392,
        "committed" : 1037959168,
        "max" : 1037959168
    },
    "nonHeapMemoryUsage" : {
        "init" : 24313856,
        "used" : 69255024,
        "committed" : 69664768,
        "max" : 224395264
    }
}

The output includes information on JVM Heap and Non-Heap memory, in bytes. Briefly:

  • JVM Heap memory is used to store Java objects.

  • JVM Non-Heap Memory is used by Java to store loaded classes and related meta-data.

2.3.3.3. Reconciliation Health Check

With the following REST call, you can get basic information about the system demands related to reconciliation:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/health/recon"
{
    "_id" : "",
    "_rev" : "",
    "activeThreads" : 1,
    "corePoolSize" : 10,
    "largestPoolSize" : 1,
    "maximumPoolSize" : 10,
    "currentPoolSize" : 1
}

From the output, you can review the number of active threads used by the reconciliation, as well as the available thread pool.

2.3.4. Verifying the State of Health Check Service Modules

The configurable health check service verifies the status of the modules and services required for an operational system. During system startup, IDM checks that these modules and services are available and reports on any requirements that have not been met. If dynamic configuration changes are made, IDM rechecks that the required modules and services are functioning, to allow ongoing monitoring of system operation.

Examples of Required Modules

IDM checks all required modules. Examples of those modules are shown here:

     "org.forgerock.openicf.framework.connector-framework"
     "org.forgerock.openicf.framework.connector-framework-internal"
     "org.forgerock.openicf.framework.connector-framework-osgi"
     "org.forgerock.openidm.audit"
     "org.forgerock.openidm.core"
     "org.forgerock.openidm.enhanced-config"
     "org.forgerock.openidm.external-email"
     ...
     "org.forgerock.openidm.system"
     "org.forgerock.openidm.ui"
     "org.forgerock.openidm.util"
     "org.forgerock.commons.org.forgerock.json.resource"
     "org.forgerock.commons.org.forgerock.util"
     "org.forgerock.openidm.security-jetty"
     "org.forgerock.openidm.jetty-fragment"
     "org.forgerock.openidm.quartz-fragment"
     "org.ops4j.pax.web.pax-web-extender-whiteboard"
     "org.forgerock.openidm.scheduler"
     "org.ops4j.pax.web.pax-web-jetty-bundle"
     "org.forgerock.openidm.repo-jdbc"
     "org.forgerock.openidm.repo-ds"
     "org.forgerock.openidm.config"
     "org.forgerock.openidm.crypto"

Examples of Required Services

IDM checks all required services. Examples of those services are shown here:

     "org.forgerock.openidm.config"
     "org.forgerock.openidm.provisioner"
     "org.forgerock.openidm.provisioner.openicf.connectorinfoprovider"
     "org.forgerock.openidm.external.rest"
     "org.forgerock.openidm.audit"
     "org.forgerock.openidm.policy"
     "org.forgerock.openidm.managed"
     "org.forgerock.openidm.script"
     "org.forgerock.openidm.crypto"
     "org.forgerock.openidm.recon"
     "org.forgerock.openidm.info"
     "org.forgerock.openidm.router"
     "org.forgerock.openidm.scheduler"
     "org.forgerock.openidm.scope"
     "org.forgerock.openidm.taskscanner"

You can replace the list of required modules and services, or add to it, by adding the following lines to your resolver/boot.properties file. Bundles and services are specified as a list of symbolic names, separated by commas:

  • openidm.healthservice.reqbundles - overrides the default required bundles.

  • openidm.healthservice.reqservices - overrides the default required services.

  • openidm.healthservice.additionalreqbundles - specifies required bundles (in addition to the default list).

  • openidm.healthservice.additionalreqservices - specifies required services (in addition to the default list).

By default, the server is given 15 seconds to start up all the required bundles and services before system readiness is assessed. Note that this is not the total start time, but the time required to complete the service startup after the framework has started. You can change this default by setting the value of the servicestartmax property (in milliseconds) in your resolver/boot.properties file. This example sets the startup time to five seconds:

openidm.healthservice.servicestartmax=5000

2.4. Displaying Information About Installed Modules

On a running instance, you can list the installed modules and their states by typing the following command in the OSGi console. (The output will vary by configuration):

-> scr list 
  
 BundleId Component Name Default State
    Component Id State      PIDs (Factory PID)
 [   5]   org.forgerock.openidm.config.enhanced.starter  enabled
    [   1] [active      ] org.forgerock.openidm.config.enhanced.starter
 [   5]   org.forgerock.openidm.config.manage  enabled
    [   0] [active      ] org.forgerock.openidm.config.manage
 [  10]   org.forgerock.openidm.datasource.jdbc  enabled
 [  10]   org.forgerock.openidm.repo.jdbc  enabled
 [  11]   org.forgerock.openidm.repo.ds  enabled
    [  35] [active      ] org.forgerock.openidm.repo.ds
 [  16]   org.forgerock.openidm.cluster  enabled
    [  18] [active      ] org.forgerock.openidm.cluster
 [  17]   org.forgerock.openidm.http.context  enabled
    [   2] [active      ] org.forgerock.openidm.http.context
 [ 123]   org.forgerock.openidm.api-servlet  enabled
    [   5] [active      ] org.forgerock.openidm.api-servlet
 [ 123]   org.forgerock.openidm.error-servlet  enabled
    [   3] [active      ] org.forgerock.openidm.error-servlet
 [ 123]   org.forgerock.openidm.router.servlet  enabled
    [   4] [active      ] org.forgerock.openidm.router.servlet
 [ 124]   org.forgerock.openidm.audit  enabled
    [  24] [active      ] org.forgerock.openidm.audit
 [ 124]   org.forgerock.openidm.audit.filter  enabled
    [   6] [active      ] org.forgerock.openidm.audit.filter
->

To display additional information about a particular module or service, run the following command, substituting the Component Id from the preceding list:

-> scr info Id

The following example displays additional information about the router service:

-> scr info 4
*** Bundle: org.forgerock.openidm.api-servlet (123)
Component Description:
  Name: org.forgerock.openidm.router.servlet
  Implementation Class: org.forgerock.openidm.servlet.internal.ServletConnectionFactory
  Default State: enabled
  Activation: immediate
  Configuration Policy: ignore
  Activate Method: activate
  Deactivate Method: deactivate
  Modified Method: -
  Configuration Pid: [org.forgerock.openidm.router.servlet]
  Services:
    org.forgerock.json.resource.ConnectionFactory
    org.forgerock.openidm.router.RouterFilterRegistration
  Service Scope: singleton
  Reference: requestHandler
    Interface Name: org.forgerock.json.resource.RequestHandler
    Target Filter: (org.forgerock.openidm.router=*)
    Cardinality: 1..1
    Policy: static
    Policy option: reluctant
    Reference Scope: bundle
...
->

2.5. Querying Enabled Features

"Displaying Information About Installed Modules" showed how to list installed modules and their states on a running IDM instance. An alternative method of assessing the state of a server configuration is to query the enabled features over REST.

The feature availability service determines the set of possible features from the active bundles, and provides the following information:

  • The name and _id of the feature

  • Whether the feature is enabled

  • If the feature is enabled, the REST endpoint on which that feature can be accessed

You can query the available features on the info/features endpoint, for example:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/info/features?_queryFilter=true"
{
  "result": [
    {
      "_id": "retrieveUsername",
      "name": "retrieveUsername",
      "enabled": false,
      "endpoints": []
    },
    {
      "_id": "identityProviders",
      "name": "identityProviders",
      "enabled": true,
      "endpoints": [
        "identityProviders"
      ]
    },
    {
      "_id": "workflow",
      "name": "workflow",
      "enabled": true,
      "endpoints": [
        "workflow*"
      ]
    },
    {
      "_id": "passwordReset",
      "name": "passwordReset",
      "enabled": false,
      "endpoints": []
    },
    {
      "_id": "registration",
      "name": "registration",
      "enabled": true,
      "endpoints": [
        "selfservice/registration"
      ]
    },
    {
      "_id": "email",
      "name": "email",
      "enabled": false,
      "endpoints": []
    }
  ],
  ...
}

2.6. Starting in Debug Mode

To debug custom libraries, you can start the server with the option to use the Java Platform Debugger Architecture (JPDA):

  • Start IDM with the jpda option:

    $ cd /path/to/openidm
    $ ./startup.sh jpda
    Executing ./startup.sh...
    Using OPENIDM_HOME:   /path/to/openidm
    Using OPENIDM_OPTS:   -Xmx1024m -Xms1024m -Djava.compiler=NONE -Xnoagent -Xdebug
     -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n
    Using LOGGING_CONFIG:
       -Djava.util.logging.config.file=/path/to/openidm/conf/logging.properties
    Listening for transport dt_socket at address: 5005
    Using boot properties at /path/to/openidm/resolver/boot.properties
    -> OpenIDM version "6.5.2.0" (revision: xxxx)
    OpenIDM ready

    The relevant JPDA options are outlined in the startup script (startup.sh).

  • In your IDE, attach a Java debugger to the JVM via socket, on port 5005.

Caution

This interface is internal and subject to change. If you depend on this interface, contact ForgeRock support.

2.7. Troubleshooting a Server Instance

For information about troubleshooting various issues in IDM, including collecting useful troubleshooting information such as logs, heap dumps and stack traces, see the corresponding Knowledge Base article.

Chapter 3. Command-Line Interface

This chapter describes the basic command-line interface (CLI). The CLI includes a number of utilities for managing an IDM instance.

All of the utilities are subcommands of the cli.sh (UNIX) or cli.bat (Windows) scripts. To use the utilities, you can either run them as subcommands, or launch the cli script first, and then run the utility. For example, to run the encrypt utility on a UNIX system:

$ cd /path/to/openidm 
$ ./cli.sh 
Using boot properties at /path/to/openidm/resolver/boot.properties
openidm# encrypt ....

or

$ cd /path/to/openidm
$ ./cli.sh encrypt ... 

By default, the command-line utilities run with the properties defined in your resolver/boot.properties file.

If you run the cli.sh command by itself, it opens an IDM-specific shell prompt:

openidm#

The startup and shutdown scripts are not discussed in this chapter. For information about these scripts, see "Starting, Stopping, and Running the Server".

The following sections describe the subcommands and their use. Examples assume that you are running the commands on a UNIX system. For Windows systems, use cli.bat instead of cli.sh.

For a list of subcommands available from the openidm# prompt, run the cli.sh help command. The help and exit options shown below are self-explanatory. The other subcommands are explained in the subsections that follow:

local:secureHash   Hash the input string.
local:keytool      Export or import a SecretKeyEntry. The Java Keytool does
                   not allow for exporting or importing SecretKeyEntries.
local:encrypt      Encrypt the input string.
local:validate     Validates all json configuration files in the configuration
                   (default: /conf) folder.
basic:help   Displays available commands.
basic:exit   Exit from the console.
remote:configureconnector   Generate connector configuration.
remote:configexport         Exports all configurations.
remote:update               Update the system with the provided update file.
remote:configimport         Imports the configuration set from local file/directory.

The following options are common to the configexport, configimport, and configureconnector subcommands:

-u or --user USER[:PASSWORD]

Allows you to specify the server user and password. Specifying a username is mandatory. If you do not specify a username, the following error is output to the OSGi console: Remote operation failed: Unauthorized. If you do not specify a password, you are prompted for one. This option is used by all three subcommands.

--url URL

The URL of the REST service. The default URL is http://localhost:8080/openidm/. This can be used to import configuration files from a remote running IDM instance. This option is used by all three subcommands.

-P or --port PORT

The port number associated with the REST service. If specified, this option overrides any port number specified with the --url option. The default port is 8080. This option is used by all three subcommands.

3.1. Using the configexport Subcommand

The configexport subcommand exports all configuration objects to a specified location, enabling you to reuse a system configuration in another environment. For example, you can test a configuration in a development environment, then export it and import it into a production environment. This subcommand also lets you inspect the active configuration of an IDM instance.

OpenIDM must be running when you execute this command.

Usage is as follows:

$ ./cli.sh configexport --user username:password export-location

For example:

$ ./cli.sh configexport --user openidm-admin:openidm-admin /tmp/conf

On Windows systems, the export-location must be provided in quotation marks, for example:

C:\openidm\cli.bat configexport --user openidm-admin:openidm-admin "C:\temp\openidm"

Configuration objects are exported as .json files to the specified directory. The command creates the directory if needed. Configuration files that are present in this directory are renamed as backup files, with a timestamp, for example, audit.json.2014-02-19T12-00-28.bkp, and are not overwritten. The following configuration objects are exported:

  • The internal repository table configuration (repo.ds.json or repo.jdbc.json) and the datasource connection configuration, for JDBC repositories (datasource.jdbc-default.json)

  • The script configuration (script.json)

  • The log configuration (audit.json)

  • The authentication configuration (authentication.json)

  • The cluster configuration (cluster.json)

  • The configuration of a connected SMTP email server (external.email.json)

  • Custom configuration information (info-name.json)

  • The managed object configuration (managed.json)

  • The connector configuration (provisioner.openicf-*.json)

  • The router service configuration (router.json)

  • The scheduler service configuration (scheduler.json)

  • Any configured schedules (schedule-*.json)

  • Standard security questions (selfservice.kba.json)

  • The synchronization mapping configuration (sync.json)

  • If workflows are defined, the configuration of the workflow engine (workflow.json) and the workflow access configuration (process-access.json)

  • Any configuration files related to the user interface (ui-*.json)

  • The configuration of any custom endpoints (endpoint-*.json)

  • The configuration of servlet filters (servletfilter-*.json)

  • The policy configuration (policy.json)

3.2. Using the configimport Subcommand

The configimport subcommand imports configuration objects from the specified directory, enabling you to reuse a system configuration from another environment. For example, you can test a configuration in a development environment, then export it and import it into a production environment.

The command updates the existing configuration from the import-location over the REST interface. By default, if configuration objects are present in the import-location and not in the existing configuration, these objects are added. If configuration objects are present in the existing location but not in the import-location, these objects are left untouched in the existing configuration.

The subcommand takes the following options:

-r, --replaceall, --replaceAll

Replaces the entire list of configuration files with the files in the specified import location.

Note that this option wipes out the existing configuration and replaces it with the configuration in the import-location. Objects in the existing configuration that are not present in the import-location are deleted.

--retries (integer)

This option specifies the number of times the command should attempt to update the configuration if the server is not ready.

Default value : 10

--retryDelay (integer)

This option specifies the delay (in milliseconds) between configuration update retries if the server is not ready.

Default value : 500

Usage is as follows:

$ ./cli.sh configimport --user username:password [--replaceAll] [--retries integer] [--retryDelay integer] import-location

For example:

$ ./cli.sh configimport --user openidm-admin:openidm-admin --retries 5 --retryDelay 250 --replaceAll /tmp/conf

On Windows systems, the import-location must be provided in quotation marks, for example:

C:\openidm\cli.bat configimport --user openidm-admin:openidm-admin --replaceAll "C:\temp\openidm"

Configuration objects are imported as .json files from the specified directory to the conf directory. The configuration objects that are imported are the same as those for the export command, described in the previous section.

3.3. Using the configureconnector Subcommand

The configureconnector subcommand generates a configuration for an ICF connector.

Usage is as follows:

$ ./cli.sh configureconnector --user username:password --name connector-name

Select the type of connector that you want to configure. The following example configures a new CSV connector:

$ ./cli.sh configureconnector --user openidm-admin:openidm-admin --name myCsvConnector
 Executing ./cli.sh...
Starting shell in /path/to/openidm
Mar 22, 2018 09:50:01 AM org.forgerock.openidm.core.FilePropertyAccessor loadProps
0. Workday Connector version 1.5.20.8
1. SSH Connector version 1.5.20.8
2. ServiceNow Connector version 1.5.20.8
3. Scripted SQL Connector version 1.5.20.8
4. Scripted REST Connector version 1.5.20.8
5. Scim Connector version 1.5.20.8
6. Salesforce Connector version 1.5.20.8
7. MongoDB Connector version 1.5.20.8
8. Marketo Connector version 1.5.20.8
9. LDAP Connector version 1.5.20.8
10. Kerberos Connector version 1.5.20.8
11. Scripted Poolable Groovy Connector version 1.5.20.8
12. Scripted Groovy Connector version 1.5.20.8
13. GoogleApps Connector version 1.5.20.8
14. Database Table Connector version 1.5.20.8
15. CSV File Connector version 1.5.20.8
16. Adobe Marketing Cloud Connector version 1.5.20.8
17. Exit
Select [0..17]: 15
Edit the configuration file and run the command again. The configuration was saved to
/path/to/openidm/temp/provisioner.openicf-myCsvConnector.json

The basic configuration is saved in a file named /openidm/temp/provisioner.openicf-connector-name.json. Edit at least the configurationProperties parameter in this file to complete the connector configuration. For example, for a CSV connector:

"configurationProperties" : {
    "headerPassword" : "password",
    "csvFile" : "&{idm.instance.dir}/data/csvConnectorData.csv",
    "newlineString" : "\n",
    "headerUid" : "uid",
    "quoteCharacter" : "\"",
    "fieldDelimiter" : ",",
    "syncFileRetentionCount" : 3
},

For more information about the connector configuration properties, see "Configuring Connectors".

When you have modified the file, run the configureconnector command again so that IDM can pick up the new connector configuration:

$ ./cli.sh configureconnector --user openidm-admin:openidm-admin --name myCsvConnector
Executing ./cli.sh...
Starting shell in /path/to/openidm
Using boot properties at /path/to/openidm/resolver/boot.properties
Configuration was found and read from: /path/to/openidm/temp/provisioner.openicf-myCsvConnector.json

You can now copy the new provisioner.openicf-myCsvConnector.json file to your project's conf/ subdirectory.

You can also configure connectors over the REST interface, or through the Admin UI. For more information, see "Configuring Connectors".

3.4. Using the encrypt Subcommand

The encrypt subcommand encrypts an input string, or JSON object, provided at the command line. This subcommand can be used to encrypt passwords, or other sensitive data, to be stored in the repository. The encrypted value is output to standard output and provides details of the cryptography key that is used to encrypt the data.

Usage is as follows:

$ ./cli.sh encrypt [-j] string

If you do not enter the string as part of the command, the command prompts for the string to be encrypted. If you enter the string as part of the command, any special characters, for example quotation marks, must be escaped.

The -j option indicates that the string to be encrypted is a JSON object, and validates the object. If the object is malformed JSON and you use the -j option, the command throws an error. It is easier to input JSON objects in interactive mode. If you input the JSON object on the command-line, the object must be surrounded by quotes and any special characters, including curly braces, must be escaped. The rules for escaping these characters are fairly complex. For more information, see the OSGi specification. For example:

$ ./cli.sh encrypt -j '\{\"password\":\"myPassw0rd\"\}'

The following example encrypts a normal string value:

$ ./cli.sh encrypt mypassword
Executing ./cli.sh...x
Starting shell in /path/to/openidm
-----BEGIN ENCRYPTED VALUE-----
{
  "$crypto" : {
    "type" : "x-simple-encryption",
    "value" : {
      "cipher" : "AES/CBC/PKCS5Padding",
      "stableId" : "openidm-sym-default",
      "salt" : "vdz6bUztiT6QsExNrZQAEA==",
      "data" : "RgMLRbX0guxF80nwrtaZkkoFFGqSQdNWF7Ve0zS+N1I=",
      "keySize" : 16,
      "purpose" : "idm.config.encryption",
      "iv" : "R9w1TcWfbd9FPmOjfvMhZQ==",
      "mac" : "9pXtSKAt9+dO3Mu0NlrJsQ=="
    }
  }
}
------END ENCRYPTED VALUE------

The following example prompts for a JSON object to be encrypted:

$ ./cli.sh encrypt -j
Using boot properties at /path/to/openidm/resolver/boot.properties
Enter the Json value

> Press ctrl-D to finish input
Start data input:
{"password":"myPassw0rd"}
^D        
-----BEGIN ENCRYPTED VALUE-----
{
  "$crypto" : {
    "type" : "x-simple-encryption",
    "value" : {
      "cipher" : "AES/CBC/PKCS5Padding",
      "stableId" : "openidm-sym-default",
      "salt" : "vdz6bUztiT6QsExNrZQAEA==",
      "data" : "RgMLRbX0guxF80nwrtaZkkoFFGqSQdNWF7Ve0zS+N1I=",
      "keySize" : 16,
      "purpose" : "idm.config.encryption",
      "iv" : "R9w1TcWfbd9FPmOjfvMhZQ==",
      "mac" : "9pXtSKAt9+dO3Mu0NlrJsQ=="
    }
  }
}
------END ENCRYPTED VALUE------

3.5. Using the secureHash Subcommand

The secureHash subcommand hashes an input string, or JSON object, using the specified hash algorithm. This subcommand can be used to hash password values, or other sensitive data, to be stored in the repository. The hashed value is output to standard output and provides details of the algorithm that was used to hash the data.

Usage is as follows:

$ ./cli.sh secureHash --algorithm [-j] string

The -a or --algorithm option specifies the hash algorithm to use. For a list of supported hash algorithms, see "Encoding Attribute Values by Using Salted Hash Algorithms".

If you do not enter the string as part of the command, the command prompts for the string to be hashed. If you enter the string as part of the command, any special characters, for example quotation marks, must be escaped.

The -j option indicates that the string to be hashed is a JSON object, and validates the object. If the object is malformed JSON and you use the -j option, the command throws an error. It is easier to input JSON objects in interactive mode. If you input the JSON object on the command-line, the object must be surrounded by quotes and any special characters, including curly braces, must be escaped. The rules for escaping these characters are fairly complex. For more information, see the OSGi specification. For example:

$ ./cli.sh secureHash --algorithm SHA-384 '\{\"password\":\"myPassw0rd\"\}'

The following example hashes a password value (mypassword) using the SHA-384 algorithm:

$ ./cli.sh secureHash --algorithm SHA-384 mypassword
Executing ./cli.sh...
Starting shell in /path/to/openidm
Nov 14, 2017 1:19:49 PM org.forgerock.openidm.core.FilePropertyAccessor loadProps
INFO: Using properties at /path/to/openidm/resolver/boot.properties
-----BEGIN HASHED VALUE-----
{
  "$crypto" : {
    "value" : {
      "algorithm" : "SHA-384",
      "data" : "1bgOyADyXRFt4lNA80NOM0MeqWyBmAITFnB4742QdSTaLZkCw0kITPOCUhnSaeM8vKMG/W3jRN7slpcrc9jjqg=="
    },
    "type" : "salted-hash"
  }
}
------END HASHED VALUE------

The following example prompts for a JSON object to be hashed:

$ ./cli.sh secureHash --algorithm SHA-384 -j
Executing ./cli.sh...
Executing ./cli.sh...
Starting shell in /path/to/openidm
Nov 14, 2017 1:24:26 PM org.forgerock.openidm.core.FilePropertyAccessor loadProps
INFO: Using properties at /path/to/openidm/resolver/boot.properties
Enter the Json value

> Press ctrl-D to finish input
Start data input:
{"password":"myPassw0rd"}
^D
-----BEGIN HASHED VALUE-----
{
  "$crypto" : {
    "value" : {
      "algorithm" : "SHA-384",
      "data" : "7Caabx7d+vOZ7d3VMwdQObQJdTQ3uGOItsX5AwR4ViygUfARR/XuxRIBQt1LRq58ZOQXFwuw+3rvzK7Kld8pSg=="
    },
    "type" : "salted-hash"
  }
}
------END HASHED VALUE------

3.6. Using the keytool Subcommand

The keytool subcommand exports or imports secret key values.

The Java keytool command lets you export and import public keys and certificates, but not secret or symmetric keys. The IDM keytool subcommand provides this functionality.

Usage is as follows:

$ ./cli.sh keytool [--export, --import] alias

For example, to export the default IDM symmetric key, run the following command:

$ ./cli.sh keytool --export openidm-sym-default
   Executing ./cli.sh...
Starting shell in /home/idm/openidm
Use KeyStore from: /openidm/security/keystore.jceks
Please enter the password: 
[OK] Secret key entry with algorithm AES
AES:606d80ae316be58e94439f91ad8ce1c0  

The default keystore password is changeit. For security reasons, you must change this password in a production environment. For information about changing the keystore password, see "To Change the Default Keystore Password".

To import a new secret key named my-new-key, run the following command:

$ ./cli.sh keytool --import my-new-key   
Using boot properties at /openidm/resolver/boot.properties
Use KeyStore from: /openidm/security/keystore.jceks
Please enter the password: 
Enter the key: 
AES:606d80ae316be58e94439f91ad8ce1c0 

If a secret key with that name already exists, IDM returns the following error:

"KeyStore contains a key with this alias"

3.7. Using the validate Subcommand

The validate subcommand validates all .json configuration files in your project's conf/ directory.

Usage is as follows:

$ ./cli.sh validate
Executing ./cli.sh
Starting shell in /path/to/openidm
Using boot properties at /path/to/openidm/resolver/boot.properties
...................................................................
[Validating] Load JSON configuration files from:
[Validating] 	/path/to/openidm/conf
[Validating] audit.json .................................. SUCCESS
[Validating] authentication.json ......................... SUCCESS
    ...
[Validating] sync.json ................................... SUCCESS
[Validating] ui-configuration.json ....................... SUCCESS
[Validating] ui-countries.json ........................... SUCCESS
[Validating] workflow.json ............................... SUCCESS
  

3.8. Using the update Subcommand

The update subcommand supports updates for patches and migrations. For an example of this process, see "Updating Servers" in the Installation Guide.

Chapter 4. Using the Browser-Based UI

IDM provides a customizable, browser-based user interface. The functionality is subdivided into Administrative and Self-Service User Interfaces.

If you are configuring or administering IDM, navigate to the Administrative User Interface (Admin UI). If IDM is installed on the local system, you can get to the Admin UI at the following URL: https://localhost:8443/admin. In the Admin UI, you can configure connectors, customize managed objects, set up attribute mappings, manage accounts, and more.

The End User UI provides role-based access to tasks based on BPMN2 workflows, and allows users to manage certain aspects of their own accounts, including configurable self-service registration. When IDM starts, you can access the End User UI at https://localhost:8443/. For more information, see "Configuring User Self-Service".

All users, including openidm-admin, can change their password through the End User UI.

Warning

The default password for the administrative user, openidm-admin, is openidm-admin. To protect your deployment in production, change the default administrative password, as described in "To Change the Default Administrator Password".

4.1. Configuring the Server from the Admin UI

The Admin UI provides a graphical interface for most aspects of the IDM configuration.

Use the Quick Start cards and the Configure and Manage drop-down menus to configure the server.

In the following sections, you will examine the default Admin UI dashboard, and learn how to set up custom Admin UI dashboards.

Caution

If your browser uses an AdBlock extension, it might inadvertently block some UI functionality, particularly if your configuration includes strings such as ad. For example, a connection to an Active Directory server might be configured at the endpoint system/ad. To avoid problems related to blocked UI functionality, either remove the AdBlock extension, or set up a suitable white list to ensure that none of the targeted endpoints are blocked.

4.1.1. Default Admin UI Dashboards

The Admin UI includes multiple default dashboards. You can create additional dashboards, or add and remove widgets from the existing dashboards. For more information, see "Managing Dashboards".

When you log into the Admin UI the Quick Start dashboard loads by default.

Quick Start Dashboard
Administrative User Interface: Main Screen

The Admin UI includes a fixed top menu bar. As you navigate around the Admin UI, you should see the same menu bar throughout.

To display all configured dashboards, select Dashboards > Manage Dashboards. In addition to the Quick Start dashboard, three dashboards are provided by default: System Monitoring, Resource Report and Business Report. The default dashboards cover the following functionality:

Quick Start Dashboard
  • Quick Start cards support one-click access to common administrative tasks. For more information, see "Quick Start Cards".

System Monitoring Dashboard
  • Audit Events include information on audit data, segregated by date. For more information on these events, see "Setting Up Audit Logging".

  • System Health includes data on current CPU and memory usage.

  • Last Reconciliation includes data from the most recent reconciliation between data stores.

Resource Report
  • The Resources Report includes widgets that show the number of active users, configured roles, and active connectors.

  • The Resources widget shows all configured connectors, mappings, and managed object types.

Business Report

The Business Report includes widgets related to login and registration activity.

4.1.1.1. Quick Start Cards

The Quick Start cards allow quick access to the following configuration options:

4.1.2. Managing Dashboards

You can set up additional dashboards for customized views of the Admin UI, and you can embed external dashboards such as Kibana or Grafana, or other monitoring boards.

To create a new dashboard, select Dashboards > New Dashboard. Enter a dashboard name and select whether this dashboard should be the default board that is displayed when you load the Admin UI.

  • For a customized view of the Admin UI, select Widgets as the Dashboard Type, then select Create Dashboard and add the widgets that you want exposed in that view.

    You can also customize the view by starting with an existing dashboard. In the upper-right corner of the UI, next to the Add Widget button, click the vertical ellipses () then select Rename or Duplicate.

  • To embed an external dashboard, select Embedded URL as the Dashboard Type, then enter the URL of the dashboard that you want to embed and select Create Dashboard.

To add a widget to a dashboard, click Add Widget and select the widget type. Widgets are grouped in logical categories, so scroll down to the category that fits the widget you want to add.

  • To modify the position of a widget in a dashboard, click and drag the move icon for the widget ().

If you add a new Quick Start widget, select the vertical ellipsis () icon in the upper right corner of the widget, and click Settings.

  • You can configure an Admin UI sub-widget to embed in the Quick Start widget.

  • If you are linking to a specific page in the Admin UI, the destination URL can be the part of the address after the main page for the Admin UI, such as https://localhost:8443/<someURI>

    For example, to create a quick start link to the Audit configuration tab, at https://localhost:8443/admin/#settings/audit/, enter #settings/audit in the destination URL text box.

IDM writes the changes you make to the ui-dashboard.json file for your project.

For example, if you add two widgets (Last Reconciliation and System Health) to a new dashboard named Test, you'll see the following excerpt in your ui-dashboard.json file:

{
    "name" : "test",
    "isDefault" : false,
    "widgets" : [
        {
            "type" : "lastRecon",
            "size" : "large",
            "barchart" : "false"
        },
        {
            "type" : "systemHealthFull",
            "size" : "large"
        }
    ],
    "embeddedDashboard" : false
}

For more information on each property, see the following table:

Admin UI Widget Properties in ui-dashboard.json
PropertyOptionsDescription
nameUser entryDashboard name
isDefaulttrue or falseDefault dashboard; can set one default
widgetsDifferent options for typeCode blocks that define a widget
typelifeCycleMemoryHeap, lifeCycleMemoryNonHeap, systemHealthFull, cpuUsage, lastRecon, resourceList, quickStart, frame, userRelationship Widget name
sizex-small, small, medium, or largeWidth of widget, based on a 12-column grid system, where x-small=4, small=6, medium=8, and large=12; for more information, see Bootstrap CSS
heightHeight, in units such as cm, mm, px, and inHeight; applies only to Embed Web Page widget
frameUrlURLWeb page to embed; applies only to Embed Web Page widget
titleUser entryLabel shown in the UI; applies only to Embed Web Page widget
barcharttrue or falseReconciliation bar chart; applies only to Last Reconciliation widget

When complete, you can select the name of the new dashboard under the Dashboards menu or from the Manage Dashboards panel.

You can modify the options for each dashboard and widget. Select the vertical ellipsis in the upper right corner of the object, and make desired choices from the pop-up menu.

The following tables display an alphabetical list of the available widgets, by category:

Admin UI Reporting Widgets
NameDescription
Audit EventsGraphical display of audit events; also see "Viewing Audit Events in the Admin UI".
Count Widget A reporting widget that provides an instant display of the number of specific objects, for example active managed users, enabled social providers, and so on. For more information, see "Reporting, Monitoring, and Notifications".
Dropwizard Table With Graph Does not appear in the list of widgets unless metrics are active, per "Metrics and Monitoring".
Graph WidgetProvides a graphical view of a specific managed resource, for example managed users, based on some metric.
Last ReconciliationShows statistics from the most recent reconciliation, shown in System Monitoring dashboard; also see "Obtaining the Details of a Reconciliation"
New Registrations The number of users that have self-registered that week. To display data using this widget, user self-registration must be enabled (see "User Self-Registration").
Password Resets The number of password resets that week. To display data using this widget, password reset must be enabled (see "User Password Reset").
ResourcesConnectors, mappings, managed objects; shown in Administration dashboard
Sign-Ins The number of managed users that have signed in to the service that week.

Social Widgets
NameDescription
Daily Social LoginsGraphical display of logins via social identity providers; for related information see "Configuring Social Identity Providers"
Social Registration (year)Graphical display of registrations over the past year; for related information, see "Configuring Social Identity Providers"

System Status Widgets
NameDescription
Cluster Node StatusLists the instances in a cluster, with their status. For more information, see "Managing Nodes Through the Admin UI".
CPU UsageAlso part of System Health widget
Memory Usage (JVM Heap)Graphs available JVM Heap memory (ref "Memory Health Check"
Memory Usage (JVM NonHeap)Graphs available JVM Non-Heap memory (ref "Memory Health Check"
System Health Shown in System Monitoring dashboard; includes CPU Usage, Memory Usage (JVM Heap), and Memory Usage (JVM NonHeap)

Utility Widgets
NameDescription
Embed Web Page Supports embedding of external content; for more information, see Embed Web Page Widget Requirements
Identity RelationshipsGraphical display of relationships between identities; also see "Viewing Relationships in Graph Form"
Managed Objects Relationship DiagramGraphical diagram with connections between managed object properties; also see "Viewing the Relationship Configuration in the UI"
Quick StartLinks to common tasks; shown in Administration dashboard

Embed Web Page Widget Requirements

To use the Embed Web Page applet, you'll need a web site that supports appropriate x-frame-options. For example, Google has a Maps Embed API for that purpose.

4.2. Managing Accounts

Only administrative users (with the role openidm-admin) can add, modify, and delete accounts from the Admin UI. Regular users can modify certain aspects of their own accounts from the End User UI.

4.2.1. Account Configuration

In the Admin UI, you can manage most details associated with an account. Create a user if needed, and then select Manage > User > Username. In the screen that appears, you can configure the following elements of a user account:

Details

The Details tab includes basic identifying data for each user, based on attributes configured in your project's managed.json file.

Password

As an administrator, you can create new passwords for users in the managed user repository.

Provisioning Roles

Used to specify how objects are provisioned to an external system. For more information, see "Working With Managed Roles".

Authorization Roles

Used to specify the authorization rights of a managed user within IDM. For more information, see "Working With Managed Roles".

Direct Reports

Users who are listed as managers of others have graphical entries linked to those users under the Direct Reports tab.

Linked Systems

Used to display account information reconciled from external systems.

4.2.2. Procedures for Managing Accounts

With the following procedures, you can use the Admin UI to add, update, and delete accounts for managed objects such as users. To make these changes using REST, see "Working with Managed Users".

The managed object does not have to be a user. It can be a role, a group, or even a physical item such as an IoT device. The basic process for adding, modifying, deactivating, and deleting other objects is the same as it is with accounts. However, the details may vary; for example, many IoT devices do not have telephone numbers.

To Add a User Account
  1. Log in to the Admin UI at https://localhost:8443/admin.

  2. Click Manage > User.

  3. Click New User.

  4. Complete the fields on the New User page.

    By default, the New User page displays only the password and the fields that are configured as required in the schema, as shown in this excerpt from managed.json

    "required" : [
        "userName",
        "givenName",
        "sn",
        "mail"
    ]

    To display additional properties on the New User page, add the desired property to this list of required attributes.

    The fields on this page are subject to policy validation, as described in "Using Policies to Validate Data". So, for example, the email address must be a valid email address, and the password must comply with the configured password policy.

In a similar way, you can create accounts for other managed objects.

You can review new managed object settings in the managed.json file of your project-dir/conf directory.

In the following procedures, you learn how:

To Update a User Account
  1. Log in to the Admin UI at https://localhost:8443/admin as an administrative user.

  2. Click Manage > User.

  3. Click the Username of the user that you want to update.

  4. On the profile page for the user, modify the fields you want to change and click Update.

    The user account is updated in the repository.

To Delete a User Account
  1. Log in to the Admin UI at https://localhost:8443/admin as an administrative user.

  2. Click Manage > User.

  3. Select the checkbox next to the desired Username.

  4. Click the Delete Selected button.

  5. Click OK to confirm the deletion.

    The user is deleted from the internal repository.

To View an Account in External Resources

The Admin UI displays the details of the account in the repository (managed/user). When a mapping has been configured between the repository and one or more external resources, you can view details of that account in any external system to which it is linked. As this view is read-only, you cannot update a user record in a linked system from within the Self-Service UI.

By default, implicit synchronization is enabled for mappings from the managed/user repository to any external resource. This means that when you update a managed object, any mappings defined in the sync.json file that have the managed object as the source are automatically executed to update the target system. You can see these changes in the Linked Systems section of a user's profile.

To view a user's linked accounts:

  1. Log in to the Admin UI at https://localhost:8443/admin.

  2. Click Manage User > Username > Linked Systems.

  3. The Linked Systems panel indicates the external mapped resource or resources.

  4. Select the resource in which you want to view the account, from the Linked Resource list.

    The user record in the linked resource is displayed.

4.3. Customizing the Admin UI

You can customize the Admin UI for your specific deployment. When you install IDM, you will find the default Admin UI configuration files in the following directory: openidm/ui/admin/default.

In most cases, we recommend that you copy this directory to openidm/ui/admin/extension with commands such as:

$ cd /path/to/openidm/ui/admin
$ cp -r default/. extension

You can then set up custom files in the extension/ subdirectory.

The Admin UI templates in the openidm/ui/admin/default/templates directory might help you get started.

If you want to customize workflows in the UI, see "Managing User Access to Workflows".

4.3.1. Customizing the Admin UI, by Functionality

You may want to customize parts of the Admin UI. You've set up an openidm/ui/admin/extension directory as described in "Customizing the Admin UI". In that directory, you can find a series of subdirectories. The following table is intended to help you search for the right file(s) to customize:

File Functionality by Admin UI Directory
SubdirectoryDescription
configTop-level configuration directory of JavaScript files. Customizable subdirectories include errorhandlers/ with HTTP error messages and messages/ with info and error messages. For actual messages, see the translation.json file in the locales/en/ subdirectory.
css/ and libs/ If you use a different bootstrap theme, you can replace the files in this and related subdirectories. For more information, see "UI Themes and Bootstrap".
fonts/ The font files in this directory are based on the Font Awesome CSS toolkit described in "Changing the UI Theme".
images/ and img/ IDM uses the image files in these directories, which you can choose to replace with your own.
locales/ Includes the associated translation.json file, by default in the en/ subdirectory.
org/Source files for the End User UI
partials/ Includes partial components of HTML pages in the End User UI, for assignments, authentication, connectors, dashboards, email, basic forms, login buttons, etc.
templates/ The files in the templates/ subdirectory are in actual use. For an example of how you can customize such files in the Admin UI, see "Customizing the End User UI".

To see an example of how this works, review "Customizing the End User UI". It includes examples of how you can customize parts of the End User UI. You can use the same technique to customize parts of the Admin UI.

Tip

The above table is not a complete list. To see a visual representation of customizable Admin UI files, from the Linux command line, run the following commands:

$ cd /path/to/openidm/ui/admin/extension
$ tree

4.4. Changing the UI Theme

You can customize the theme of the user interface. The default UI uses the Bootstrap framework and the Font Awesome CSS toolkit. You can download and customize the UI with the Bootstrap themes of your choice.

Note

If you use Brand Icons from the Font Awesome CSS Toolkit, be aware of the following statement:

All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by ForgeRock, nor vice versa.

4.4.1. UI Themes and Bootstrap

You can configure a few features of the UI in the ui-themeconfig.json file in your project's conf/ subdirectory. However, to change most theme-related features of the UI, you must copy target files to the appropriate extension subdirectory, and then modify them as discussed in "Customizing the Admin UI".

By default the UI reads the stylesheets and images from the respective openidm/ui/function/default directories. Do not modify the files in this directory. Your changes may be overwritten the next time you update or even patch your system.

The default Admin UI configuration files are located in openidm/ui/admin/default. To customize the UI, copy this directory to openidm/ui/admin/extension:

You may also need to update the "stylesheets" listing in the ui-themeconfig.json file for your project, in the project-dir/conf directory.

"stylesheets" : [
    "css/bootstrap-3.4.1-custom.css",
    "css/structure.css",
    "css/theme.css"
],

You can find these stylesheets in the /css subdirectory.

  • bootstrap-3.4.1-custom.css: Includes custom settings that you can get from various Bootstrap configuration sites, such as the Bootstrap Customize and Download website.

    You may find the ForgeRock version of this in the config.json file in the ui/admin/default/css/common/structure/ directory.

  • structure.css: Supports configuration of structural elements of the UI.

  • theme.css: Includes customizable options for UI themes such as colors, buttons, and navigation bars.

If you want to set up custom versions of these files, copy them to the extension/css subdirectories.

You can configure a few features of the UI in the ui-themeconfig.json file in your project's conf directory. However, to change most theme-related features of the UI, you must copy target files to the appropriate extension subdirectory, and then modify them as discussed in "Customizing the Admin UI".

By default the UI reads the stylesheets and images from the openidm/ui/admin/default directory. Do not modify the files in this directory. Your changes may be overwritten the next time you update or even patch your system.

To customize your UI, first set up matching subdirectories in (openidm/ui/admin/extension). For example, openidm/ui/admin/extension/libs and openidm/ui/admin/extension/css.

You might also need to update the "stylesheets" listing in the ui-themeconfig.json file for your project, in the project-dir/conf directory.

"stylesheets" : [
    "css/bootstrap-3.4.1-custom.css",
    "css/structure.css",
    "css/theme.css"
],

The default stylesheets have the following function:

  • bootstrap-3.4.1-custom.css: Includes custom settings that you can get from various Bootstrap configuration sites, such as the Bootstrap Customize and Download site. This site lets you upload a config.json file that makes it easier to create a customized Bootstrap file. The ForgeRock version of this file is in ui/admin/default/css/common/structure/. You can use this file as a starting point for your customization.

  • structure.css: For configuring structural elements of the UI.

  • theme.css: Includes customizable options for UI themes such as colors, buttons, and navigation bars.

To set up custom versions of these files, copy them to the extension/css subdirectories.

4.4.4. Custom Response Headers

You can specify custom response headers for your UI by using the responseHeaders property in UI context configuration files such as conf/ui.context-selfservice.json. For example, the X-Frame-Options header is a security measure used to prevent a web page from being embedded within the frame of another page. For more information about response headers, see the MDN page on HTTP Headers.

Since the responseHeaders property is specified in the configuration file for each UI context, you can set different custom headers depending on the needs of that part of IDM. For example, you may want different security headers included for the Admin and End User UIs.

4.5. Resetting User Passwords

When working with end users, administrators frequently have to reset their passwords. You can do so directly, through the Admin UI. Alternatively, you can configure an external system for that purpose, or set up password reset, as described in "User Password Reset".

4.5.1. Changing a User Password Through the Admin UI

From the Admin UI, you can change the passwords of accounts in the internal Managed User data store; to do so, take the following steps in the Admin UI:

  1. Select Manage > User. Choose a specific user from the list that appears.

  2. Select the Password tab for that user; you should be able to change that user's password there.

4.5.2. Using an External System for Password Reset

By default, the Password Reset mechanism is handled within IDM. You can reroute Password Reset in the event that a user has forgotten their password, by specifying an external URL to which Password Reset requests are sent. Note that this URL applies to the Password Reset link on the login page only, not to the security data change facility that is available after a user has logged in.

To set an external URL to handle Password Reset, set the passwordResetLink parameter in the UI configuration file (conf/ui-configuration.json) file. The following example sets the passwordResetLink to https://accounts.example.com/account/reset-password:

passwordResetLink: "https://accounts.example.com/reset-password"

The passwordResetLink parameter takes either an empty string as a value (which indicates that no external link is used) or a full URL to the external system that handles Password Reset requests.

Note

External Password Reset and security questions for internal Password Reset are mutually exclusive. Therefore, if you set a value for the passwordResetLink parameter, users will not be prompted with any security questions, regardless of the setting of the securityQuestions parameter.

4.6. Providing a Logout URL to External Applications

By default, a UI session is invalidated when a user clicks on the Log out link. In certain situations your external applications might require a distinct logout URL to which users can be routed, to terminate their UI session.

The logout URL is #logout, appended to the UI URL, for example, https://localhost:8443/#logout/.

The logout URL effectively performs the same action as clicking on the Log out link of the UI.

4.7. Changing the UI Path

By default, the End User UI is registered at the root context and is accessible at the URL https://localhost:8443. To specify a different URL, edit the project-dir/conf/ui.context-selfservice.json file, setting the urlContextRoot property to the new URL.

For example, to change the URL of the End User UI to https://localhost:8443/exampleui, edit the file as follows:

"urlContextRoot" : "/exampleui",

Alternatively, to change the End User UI URL in the Admin UI, follow these steps:

  1. Log in to the Admin UI.

  2. Select Configure > System Preferences, and select the Self-Service UI tab.

  3. Specify the new context route in the Relative URL field.

4.8. API Explorer

IDM includes an API Explorer, an implementation of the OpenAPI Initiative Specification, also known popularly as Swagger.

To access the API Explorer, log into the Admin UI, select the question mark in the upper right corner, and choose API Explorer from the drop-down menu.

Note

If the API Explorer does not appear, you may need to enable it in your resolver/boot.properties file, specifically with the openidm.apidescriptor.enabled property. For more information see, "Disabling the API Explorer".

The API Explorer covers most of the endpoints provided with a default IDM installation.

Each endpoint lists supported HTTP methods such as POST and GET. When custom actions are available, the API Explorer lists them as HTTP Method /path/to/endpoint?_action=something.

To see how this works, navigate to the User endpoint, select List Operations, and choose the GET option associated with the /managed/user#_query_id_query-all endpoint.

In this case, the defaults are set, and all you need to do is select the Try it out! button. The output you see includes:

  • The REST call, in the form of the curl command.

  • The request URL, which specifies the endpoint and associated parameters.

  • The response body, which contains the data that you requested.

  • The HTTP response code; if everything works, this should be 200.

  • Response headers.

Tip

If you see a 401 Access Denied code in the response body, your session may have timed out, and you'll have to log into the Admin UI again.

For details on common ForgeRock REST parameters, see "About ForgeRock Common REST".

You'll see examples of REST calls throughout this documentation set. You can try these calls with the API Explorer.

You can also generate an OpenAPI-compliant descriptor of the REST API to provide API reference documentation specific to your deployment. The following command saves the API descriptor of the managed/user endpoint to a file named my-openidm-api.json:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 --output "my-openidm-api.json" \
 "http://localhost:8080/openidm/managed/user?_api"

For information about publishing reference documentation using the API descriptor, see "To Publish OpenAPI Documentation".

4.9. Disabling the UI

The UI is packaged as a separate bundle that can be disabled in the configuration before server startup. To disable the registration of the UI servlet, edit the project-dir/conf/ui.context-selfservice.json file, setting the enabled property to false:

"enabled" : false,

Chapter 5. Configuring User Self-Service

ForgeRock Identity Management (IDM) allows you to configure a number of features of user self-service, including user self-registration, password reset, username retrieval, custom email notifications, Privacy & Consent, progressive profile completion, Terms & Conditions, and more, as described in the following sections:

Each of these sections are designed to help you as an IDM deployer, customize the End User UI. To that end, these sections discuss:

  • Required and supplementary configuration files, along with available functionality for each file.

  • REST endpoints, sometimes including REST calls to identify and change the configuration of each End User UI function.

When appropriate, this chapter includes the steps that you'd take to verify functionality from an end user point of view.

Note

Some of the options described in this chapter can be used to help support compliance with the General Data Protection Regulation (GDPR).

5.1. User Self-Registration

IDM supports user self-registration. When enabled, users can log into the IDM End User UI, and create their own accounts on your system, with customizable criteria. Once enabled, administrators no longer need to create user accounts manually.

5.1.1. Basic Setup: User Self-Registration Configuration Files

To set up basic user self-registration, you'll need at least the following configuration files:

  • selfservice-registration.json

    You can find a template version of this file in the following directory: openidm/samples/example-configurations/self-service.

  • ui-configuration.json

    You can find this file in the default IDM project configuration directory, openidm/conf.

Note

Depending on how you configure User Self-Registration, you may need to set up additional configuration files, as discussed in "Configuring the User Self-Registration Form".

To enable self-service registration in the UI, enable the following boolean in ui-configuration.json:

"selfRegistration" : true,

You can include several features with user self-registration, as shown in the following excerpts of the selfservice-registration.json file:

  • The allInOneRegistration property determines whether IDM collects all user registration information in one or multiple pages. By default, it's set to true:

    "allInOneRegistration" : true,
  • The idmUserDetails code block includes the IDM property for email addresses (mail), whether or not registration with social identity providers is enabled, along with data required from new users, as described in "Configuring the User Self-Registration Form".

  • The registrationPreferences code block includes preferences as defined in the managed.json file. For more information, see "Configuring End User Preferences".

  • If you've set up Terms & Conditions, users who self-register will have to accept them, based on criteria you create, as discussed in "Adding Terms & Conditions". If you've included Terms & Conditions with user self-registration, you'll see the following code block:

    {
         "name" : "termsAndConditions"
    },
  • If you've configured Privacy & Consent, you'll see a code block with the consent name. The following code block includes template Privacy & Consent terms in English (en) and French (fr):

    {
         "name" : "consent",
         "consentTranslations" : {
             "en" : "Please consent to sharing your data with whomever we like.",
             "fr" : "Veuillez accepter le partage de vos données avec les services de notre choix."
         }
    },

    Note

    Substitute Privacy & Consent content that meet the requirements of your legal authorities.

    New users will have to manually accept these conditions before they complete the self-registration process. For more information, see "Configuring Privacy & Consent".

  • If you've activated Google reCAPTCHA for user self-service registration, you'll see the following code block:

    {
         "name" : "captcha",
         "recaptchaSiteKey" : "<siteKey>",
         "recaptchaSecretKey" : "<secretKey>",
         "recaptchaUri" : "https://www.google.com/recaptcha/api/siteverify"
    },

    As suggested by the code, you'd substitute the actual siteKey and secretKey assigned by Google for your domain. For more information, see "Configuring Google reCAPTCHA".

  • If you've included email verification, be sure to configure an outgoing email server per "Configuring Outbound Email". For a discussion of the code block to add to selfservice-registration.json, see "Configuring Emails for Self-Service Registration".

  • If you've configured security questions, users who self-register will have to create them during registration, and as needed, answer them during the password reset process. If so configured, users who've been reconciled from external data stores will also be prompted to add security questions. The relevant code block is shown here, which includes security questions as a stage in the user self-registration process. For related configuration options, see "Configuring Security Questions".

    {
         "name" : "kbaSecurityAnswerDefinitionStage",
         "kbaConfig" : null
    },

For audit activity data related to user self-registration, see "Querying the Activity Audit Log".

5.1.2. Managing User Self-Registration Over REST

You can review the current user self-registration configuration over REST:

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

Unless you've disabled file writes per "Disabling Automatic Configuration Updates", the output will match the contents of your project's selfservice-registration.json file.

If needed, you can update this configuration by including the desired contents of the file:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request PUT \
--data '{ <Insert file contents here> }' \
"http://localhost:8080/openidm/config/selfservice/registration"

5.1.3. Configuring the User Self-Registration Form

During user self-registration, IDM lists the attributes that users see in the user registration form, as defined in the selfservice-registration.json file. You can modify the properties shown to users in the registrationProperties code block:

"registrationProperties" : [
    "userName",
    "givenName",
    "sn",
    "mail"
],

If you add a managed user property to the registrationProperties code block, IDM includes it in the user self-registration screen.

Alternatively, you can add a managed user property in the Admin UI. Select Configure > User Registration, and add a property under the Registration Form tab. This action also adds a managed user property to the noted code block.

In either case, you can change the order of properties; IDM shows the order you configure in the user self-registration screen.

You can also set up user self-registration via configuration files, as described in the following table:

User Self-Registration Configuration Files
File NameDescription
external.email.jsonIf you want to enable email validation, you'll need to configure this file, as discussed in "Configuring Outbound Email".
managed.jsonYou can customize user self-registration based on entries in this file. To change the labels seen by end users, change the associated title.
policy.json For more information, see "Adding Custom Policies for Self-Registration and Password Reset".
selfservice.kba.jsonSee "Configuring Security Questions".
selfservice-registration.jsonSee "User Self-Registration".
ui-configuration.jsonSee "User Self-Registration".
consent.jsonSpecifies whether Privacy & Consent is enabled; however, you'll need to set up additional configuration files, as described in "Configuring Privacy & Consent".

5.1.4. User Self-Registration: Social

Before you can activate Social Registration under the User Registration, Social tab, you'll need to configure registration with social identity providers. To review the process, see "Configuring Social Identity Providers".

When you've configured one or more social identity providers, you can activate the Social Registration option. This action adds:

Under the Social tab, you'll see a list of property mappings as defined in the selfservice.propertymap.json file.

One or more source properties in this file takes information from a social identity provider. When a user registers with their social identity account, that information is reconciled to the matching target property for IDM. For example, the email property from a social identity provider is normally reconciled to the IDM managed user mail property.

You can also find property mappings in the sync.json for your project. For details of these synchronization mappings, see "Mapping Source Objects to Target Objects".

5.1.5. Configuring User Self-Registration From the Admin UI

To configure user self-registration from the Admin UI, select Configure > User Registration and select Enable User Registration in the page that appears.

You'll see a pop-up window that specifies User Registration Settings, including the following:

  • Identity Resource, typically managed/user

  • Identity Email Field, typically mail or email

  • Success URL for the End User UI; users who successfully log in are redirected to that URL. By default, the success URL is http://localhost:8080/#dashboard/.

  • Preferences, which set up default marketing preferences for new users. New users can change these preferences during registration, or from the End User UI.

  • Advanced Options, Snapshot Token, typically a JSON Web Token (JWT)

  • Advanced Options, Token Lifetime, with a default of 300 seconds

You can also add these settings to the following configuration file: selfservice-registration.json. When you modify these settings in the Admin UI, IDM creates the file for you.

Once active, you'll see three tabs under User Registration in the Admin UI:

5.1.6. Verifying Self-Registration in the End User UI

After configuring user self-registration, test the result from the end user's point of view. Navigate to the End User UI at http://localhost:8080, and select Create an account. You'll see a single-page Sign Up screen with configured text boxes and required security questions. If included in your configuration files, you'll also see marketing preferences such as "Send me news and updates".

If you've configured Terms & Conditions, you'll see a link to those terms:

By clicking "Sign Up" you agree to our Terms & Conditions.

Tip

To modify the Terms & Conditions, use the Admin UI or edit the selfservice.terms.json file, as described in "Adding Terms & Conditions".

If you've activated the reCAPTCHA option as described in "Configuring Google reCAPTCHA", you'll need to satisfy the requirements before you can select the SAVE button to create your new user account.

If you've activated the Privacy & Consent option, you'll see a Privacy Notice pop-up. By default, users who try to register aren't allowed to select the Give Consent button, until they actually consent to sharing their information.

Tip

To activate and configure the wording for Privacy & Consent, use the Admin UI or edit the selfservice-registration.json file, as described in "Configuring Privacy & Consent".

Once the new user is created, you should be able to verify the account in the following ways:

  • Log into the End User UI as the new user.

  • Find the userName of the new user over REST; one method is shown in "Working with Managed Users".

  • Log into the Admin UI, and select Manage > User. You should see that new user in the list.

5.1.7. Configuring Multiple User Self-Registration Flows

You can set up multiple self-registration flows, with features limited only by the capabilities listed in "User Self-Registration".

Note

Multiple self-registration flows, and customization of the End User UI beyond what is described in this document (and the noted public Git repository), are not supported.

For additional information on customizing the End User UI, see the following ForgeRock Git repository: ForgeRock/end-user-ui: Identity Management (End User).

For example, you may want to set up different portals for regular employees and contractors. You'd configure each portal with different self-registration flows, managed by the same IDM backend. Each portal would use the appropriate registration API.

To prepare for this section, you'll need a selfservice-registration.json file. You can find a copy in the following directory: /path/to/openidm/samples/example-configurations/self-service.

To avoid errors when using this file, you should either:

  • Copy the following files from the same directory:

    selfservice.terms.json
    selfservice-termsAndConditions.json
  • Delete the termsAndConditions code block from the respective selfservice-registration*.json files.

User self-registration is normally coded in the selfservice-registration.json file. In preparation, copy this file to the selfservice-registration*.json to the names shown in the following list:

  • Employee Portal

    • Configuration file: selfservice-registrationEmployee.json

    • URL: https://localhost:8443/openidm/selfservice/registrationEmployee

    • verificationLink: https://localhost:8443/#/registrationEmployee

  • Contractor Portal

    • Configuration file: selfservice-registrationContractor.json

    • URL: https://localhost:8443/openidm/selfservice/registrationContractor

    • verificationLink: https://localhost:8443/#/registrationContractor

Edit the configuration file for each portal.

  1. Modify the verificationLink URL associated with each portal as described.

  2. Edit the access.js file. You can find it in the script/ subdirectory for your project.

    Add endpoint information for each new self-service registration file to the access.js, after the selfservice/registration code block. For example, the following code excerpt would apply to the registrationEmployee and registrationContractor endpoints.

    {
        "pattern"    : "selfservice/registrationEmployee",
        "roles"      : "*",
        "methods"    : "read,action",
        "actions"    : "submitRequirements"
    },
    {
        "pattern"    : "selfservice/registrationContractor",
        "roles"      : "*",
        "methods"    : "read,action",
        "actions"    : "submitRequirements"
    },
  3. Modify the functionality of each selfservice-registration*.json file as desired. For guidance, see the sections noted in the following table:

    Configuring selfservice-registration*.json Files for Different Portals
    FeatureCode BlockLink
    Social Registration
    "socialRegistrationEnabled" : true,
    "User Self-Registration: Social"
    Properties requested during self-registration
    "registrationProperties" : [
        "userName",
        "givenName",
        "sn",
        "mail"
    ],
    "Configuring the User Self-Registration Form"
    Terms & Conditions
    {
        "name" : "termsAndConditions"
    }
    "Adding Terms & Conditions"
    Privacy & Consent
    {
        "name" : "consent",
        "consentTranslations" : {
            "en" : "substitute appropriate Privacy & Consent wording",
            "fr" : "substitute appropriate Privacy & Consent wording, in French"
        }
    },
     
    reCAPTCHA
    {
        "name" : "captcha",
        "recaptchaSiteKey" : "<siteKey>",
        "recaptchaSecretKey" : "<secretKey>",
        "recaptchaUri" : "https://www.google.com/recaptcha/api/siteverify"
    }
    "Configuring Google reCAPTCHA"
    Email Validation "Configuring Emails for Self-Service Registration"
    Security Questions
    {
        "name" : "kbaSecurityAnswerDefinitionStage",
        "kbaConfig" : null
    },
    "Configuring Security Questions"

    If you leave out the code blocks associated with the feature, you won't see that feature in the self-service registration flow. In that way, you can set up different self-service registration flows for the Employee and Contractor portals.

Once you've configured both portals, you can make REST calls to both URLs:

https://localhost:8443/openidm/selfservice/registrationEmployee
https://localhost:8443/openidm/selfservice/registrationContractor

For more advice on how you can create custom registration flows, see the following public ForgeRock Git repository: Identity Management (End User) - UI.

Note

The changes described in this section require changes to the End User UI source code as described in the noted public Git repository. Pay particular attention to the instructions associated with the Registration.vue file.

5.2. User Password Reset

IDM supports self-service user password reset. When enabled, users who forget their passwords can log into the IDM End User UI, and can verify their identities with options such as email validation and security questions.

IDM includes the ability to set up random passwords, as described in "Generating Random Passwords".

5.2.1. Basic Setup: User Password Reset Configuration Files

To set up basic user password reset features, you'll need at least the following configuration files:

  • selfservice-reset.json

    You can find a template version of this file in the following directory: openidm/samples/example-configurations/self-service.

  • ui-configuration.json

    You can find this file in the default IDM project configuration directory, openidm/conf.

To set up self-service user password reset registration, enable the following boolean in ui-configuration.json:

"passwordReset" : true,

You can include several features with user password reset, as shown in the following excerpts of the selfservice-reset.json file:

  • If you've activated Google reCAPTCHA for user self-service registration, you'll see the following code block:

    {
         "name" : "captcha",
         "recaptchaSiteKey" : "<siteKey>",
         "recaptchaSecretKey" : "<secretKey>",
         "recaptchaUri" : "https://www.google.com/recaptcha/api/siteverify"
    },

    As suggested by the code, you'd substitute the actual siteKey and secretKey assigned by Google for your domain. For more information, see "Configuring Google reCAPTCHA".

  • For password reset, IDM needs to verify user identities. To ensure that password reset links are sent to the right user, include the following code block:

    {
        "name" : "userQuery",
        "validQueryFields" : [
            "userName",
            "mail",
            "givenName",
            "sn"
        ],
        "identityIdField" : "_id",
        "identityEmailField" : "mail",
        "identityUsernameField" : "userName",
        "identityServiceUrl" : "managed/user"
    },

    This code allows IDM to verify user identities by their username, email address, first name (givenName), or last name (sn, short for surname).

  • If you've included email verification, be sure to configure an outgoing email server per "Configuring Outbound Email". For a discussion of the code block to add to selfservice-registration.json, see "Configuring Emails for Password Reset".

  • If you've configured security questions, users who self-register will have to create questions and answers during the self-registration process.

    If the feature is enabled, users who've been reconciled from external data stores will also be prompted, once, upon their next login, to add security questions and answers. The relevant code block is shown here, which points IDM to other configuration files as discussed in links from this section.

    {
         "name" : "kbaSecurityAnswerDefinitionStage",
         "kbaConfig" : null
    },

5.2.2. Managing User Password Reset Over REST

You can review the current user password reset configuration over REST:

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

Unless you've disabled file writes per "Disabling Automatic Configuration Updates", the output should match the contents of your project's selfservice-reset.json file.

If needed, you can update this configuration by including the desired contents of the file:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request PUT \
--data '{ <Insert file contents here> }' \
"http://localhost:8080/openidm/config/selfservice/reset"

5.2.3. Configuring Password Reset From the Admin UI

To configure Password Reset from the Admin UI, select Configure > Password Reset. When you select Enable Password Reset, you'll see a Configure Password Reset Form that allows you to specify the:

  • Identity Resource, typically managed/user

  • Advanced Options, Snapshot Token, typically a JSON Web Token (JWT)

  • Advanced Options, Token Lifetime, with a default of 300 seconds

You can also add these settings to the following configuration file: selfservice-reset.json. When you modify these settings in the Admin UI, IDM creates the file for you.

5.2.4. Verifying Password Reset in the End User UI

After configuring password reset in "User Password Reset", you can test the result from the end user's point of view. Navigate to the End User UI at http://localhost:8080, select the Profile icon () > Account Security > Password > Reset your password.

You should see a Reset Your Password page with pre-configured queries. After providing an answer, IDM should send a password reset link to the email associated with the target user account.

5.3. Forgotten Username

You can set up IDM to allow users to recover forgotten usernames. You can require that users enter email addresses, or first and last names. Depending on your choices, IDM then will either display that username on the screen, and/or email such information to that user.

5.3.1. Basic Setup: Forgotten Username Configuration Files

To set up basic forgotten username configuration, you'll need at least the following configuration files:

  • selfservice-username.json

    You can find a template version of this file in the following directory: openidm/samples/example-configurations/self-service.

  • ui-configuration.json

    You can find this file in the default IDM project configuration directory, openidm/conf.

To set up forgotten username retrieval, enable the following boolean in ui-configuration.json:

"forgotUsername" : true,

You can include several features with forgotten username retrieval, as shown in the following excerpts of the selfservice-reset.json file:

  • If you've activated Google reCAPTCHA for forgotten username retrieval, you'll see the following code block:

    {
        "name" : "captcha",
        "recaptchaSiteKey" : "<siteKey>",
        "recaptchaSecretKey" : "<secretKey>",
        "recaptchaUri" : "https://www.google.com/recaptcha/api/siteverify"
    },

    As suggested by the code, you'd substitute actual siteKey and secretKey assigned by Google for your domain. For more information, see "Configuring Google reCAPTCHA".

  • For forgotten username retrieval, IDM needs to verify user identities. To ensure that usernames are sent to the right user, include the following code block:

    {
        "name" : "userQuery",
        "validQueryFields" : [
            "mail",
            "givenName",
            "sn"
        ],
        "identityIdField" : "_id",
        "identityEmailField" : "mail",
        "identityUsernameField" : "userName",
        "identityServiceUrl" : "managed/user"
    },

    This code allows IDM to verify user identities by their username, email address, first name (givenName), or last name (sn, short for surname).

  • If you've included email verification, you must also configure an outgoing email server per "Configuring Outbound Email". For a discussion of the code block to add to selfservice-username.json, see "Configuring Emails for Forgotten Username".

  • The following code block, after confirming user identity, allows IDM to display the username:

    {
         "name" : "retrieveUsername"
    }

5.3.2. Managing Forgotten Username Retrieval Over REST

You can review the current forgotten username configuration over REST:

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

Unless you've disabled file writes per "Disabling Automatic Configuration Updates", the output will match the contents of your project's selfservice-username.json file.

If needed, you can update this configuration by including the desired contents of the file:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request PUT \
--data '{ <Insert file contents here> }' \
"http://localhost:8080/openidm/config/selfservice/username"

5.3.3. Configuring Forgotten Username Retrieval From the Admin UI

To configure forgotten username retrieval from the Admin UI, select Configure > Forgotten Username. When you select Enable Forgotten Username Retrieval, you'll see a Configure Forgotten Username Form that allows you to specify the:

  • Identity Resource, typically managed/user

  • Advanced Options, Snapshot Token, typically a JSON Web Token (JWT).

  • Advanced Options, Token Lifetime, with a default of 300 seconds

You can also add these settings to the following configuration file: selfservice-username.json. When you modify these settings in the Admin UI, IDM creates the file for you.

5.3.4. Verifying Access to a Forgotten Username in the End User UI

After configuring forgotten username retrieval, you can test the result from the end user's point of view. Navigate to the End User UI at http://localhost:8080, and select Forgot Username?.

You should see a Retrieve Your Username page with pre-configured queries. After providing an answer, IDM should either display your username in the local browser, or send that username to the associated email address.

5.4. Common Steps: User Self-Registration, Password Reset, Forgotten Username

For each of the titled Self-Service features, you can configure several steps in the main configuration file for each feature: selfservice-registration.json, selfservice-reset.json, and selfservice-username.json. For more information, see the following sections:

5.4.1. Configuring Google reCAPTCHA

Google reCAPTCHA helps prevent bots from registering users or resetting passwords on your system. For Google documentation on this feature, see Google reCAPTCHA. IDM works with Google reCAPTCHA v2.

To use Google reCAPTCHA, you will need a Google account and your domain name (RFC 2606-compliant URLs such as localhost and example.com are acceptable for test purposes). Google then provides a Site key and a Secret key that you can include in the self-service function configuration.

For example, you can set up reCAPTCHA by adding the following code block to the configuration file for user self-registration selfservice-registration.json, password reset, selfservice-reset.json and forgotten username selfservice-username.json functionality.

{
    "name" : "captcha",
    "recaptchaSiteKey" : "< Insert Site Key Here >",
    "recaptchaSecretKey" : "< Insert Secret Key Here >",
    "recaptchaUri" : "https://www.google.com/recaptcha/api/siteverify"
},

You may also add the reCAPTCHA keys through the UI for each of these self-service features.

5.4.2. Configuring Self-Service Email Validation / Username

When a user requests a new account, a password reset, or a reminder of their username, you can configure IDM to confirm the request by sending an email message to that user.

Before you can configure email validation, you must first configure an outgoing email service. To do so, select Configure > Email Settings. For more information, read "Configuring Outbound Email".

To activate Email Validation, you'll need to include an appropriate code block, depending on whether you're setting up self-registration, password reset, or forgotten username functionality, in the corresponding configuration file.

Alternatively, in the Admin UI, select Configure > User Registration or Password Reset or Forgotten Username. Enable the feature. Under the Options tab, enable the Email option.

To configure the email message that informs the user of the new account, see "Configuring Notification Emails".

The following sections include the code blocks that are added to each configuration file:

5.4.2.1. Configuring Emails for Self-Service Registration

To configure emails for self-service registration, you can add the following code block to the selfservice-registration.json file:

{
    "name" : "emailValidation",
    "identityEmailField" : "mail",
    "emailServiceUrl" : "external/email",
    "emailServiceParameters" : {
        "waitForCompletion" : false
    },
    "from" : "info@example.com",
    "subject" : "Register new account",
    "mimeType" : "text/html",
    "subjectTranslations" : {
        "en" : "Register new account",
        "fr" : "Créer un nouveau compte"
    },
    "messageTranslations" : {
        "en" : "<h3>This is your registration email.</h3><h4><a href=\"%link%\">Email verification link</a></h4>",
        "fr" : "<h3>Ceci est votre mail d'inscription.</h3><h4><a href=\"%link%\">Lien de vérification email</a></h4>"
    },
    "verificationLinkToken" : "%link%",
    "verificationLink" : "https://localhost:8443/#/registration/"
},

As suggested by the code block, it includes default registration email messages in English (en) and French (fr). The verificationLink sent with the email takes users to the IDM self-registration URL.

As noted in "Managing User Self-Registration Over REST", you can make these changes over the following endpoint URI: /openidm/config/selfservice/registration

If desired, you can also configure self-service registration emails through the Admin UI. Select Configure > User Registration. If needed, activate the Enable User Registration Option. Under the Options tab, in the Email Validation box, select the icon. The Configure Validation Email pop-up should appear.

When you use the Admin UI to customize self-registration emails, you can review the changes in the selfservice-registration.json file.

5.4.2.2. Configuring Emails for Password Reset

To configure emails for password reset, you can add the following code block to the selfservice-reset.json file:

{
    "name" : "emailValidation",
    "identityEmailField" : "mail",
    "emailServiceUrl" : "external/email",
    "emailServiceParameters" : {
        "waitForCompletion" : false
    },
    "from" : "info@example.com",
    "subject" : "Reset password email",
    "mimeType" : "text/html",
    "subjectTranslations" : {
        "en" : "Reset your password",
        "fr" : "Réinitialisez votre mot de passe"
    },
    "messageTranslations" : {
        "en" : "<h3>Click to reset your password</h3><h4><a href=\"%link%\">Password reset link</a></h4>",
        "fr" : "<h3>Cliquez pour réinitialiser votre mot de passe</h3><h4><a href=\"%link%\">Mot de passe lien de réinitialisation</a></h4>"
    },
    "verificationLinkToken" : "%link%",
    "verificationLink" : "https://localhost:8443/#/passwordreset/"
},

As suggested by the code block, it includes default password reset email messages in English (en) and French (fr). The verificationLink sent with the email takes users to the IDM password reset URL.

As noted in "Managing User Password Reset Over REST", you can make these changes over the following endpoint URI: /openidm/config/selfservice/reset

If desired, you can also configure self-service password reset emails through the Admin UI. Select Configure > Password Reset. If needed, activate the Enable Password Reset option, and in the Email Validation box, select the icon. The Configure Validation Email pop-up should appear.

When you use the Admin UI to customize password reset emails, you can review the changes in the selfservice-reset.json file.

5.4.2.3. Configuring Emails for Forgotten Username

To configure emails for forgotten username functionality, you can add the following code block to the selfservice-username.json file:

{
    "name" : "emailUsername",
    "emailServiceUrl" : "external/email",
    "emailServiceParameters" : {
        "waitForCompletion" : false
    },
    "from" : "info@example.com",
    "mimeType" : "text/html",
    "subjectTranslations" : {
        "en" : "Account Information - username"
    },
    "messageTranslations" : {
        "en" : "<h3>Username is:</h3><br />%username%"
    },
    "usernameToken" : "%username%"
},

As suggested by the code block, it includes default email messages in English (en), with a usernameToken that includes the actual username in the message.

As noted in "Managing Forgotten Username Retrieval Over REST", you can make these changes over the following endpoint URI: /openidm/config/selfservice/username

If desired, you can also configure forgotten username retrieval emails through the Admin UI. Select Configure > Forgotten Username. If needed, activate the Enable Forgotten Username Retrieval option, and in the Email Username box, select the icon. The Configure Email Username pop-up should appear.

When you use the Admin UI to customize forgotten username retrieval emails, you can review the changes in the selfservice-username.json file.

5.4.3. Configuring Security Questions

IDM uses security questions to enable users to verify their identities. Security questions are sometimes referred to as Knowledge-Based Authentication (KBA). When an administrator has configured security questions, self-service users can choose from the questions set in the selfservice.kba.json file, as described in "Security Questions and Self-Registration".

You can prompt users to update their security questions. As these questions may be subject to risks, you can set up IDM to prompt the user to update and/or add security questions, courtesy of the selfservice-kbaUpdate.json file. For more information, see "Prompting to Update Security Questions".

5.4.3.1. Security Questions and Self-Registration

The user is prompted to enter answers to pre-configured or custom security questions, during the self-registration process. These questions are used to help verify an identity when a user requests a password reset. These questions do not apply for users who need username retrieval.

The template version of the selfservice.kba.json file is straightforward; it includes minimumAnswersToDefine, which requires a user to define at least that many security questions and answers, along with minimumAnswersToVerify, which requires a user to answer (in this case) at least one of those questions when asking for a password reset.

{
      "kbaPropertyName" : "kbaInfo",
      "minimumAnswersToDefine": 2,
      "minimumAnswersToVerify": 1,
      "questions" : {
          "1" : {
              "en" : "What's your favorite color?",
              "en_GB" : "What is your favourite colour?",
              "fr" : "Quelle est votre couleur préférée?"
          },
          "2" : {
              "en" : "Who was your first employer?"
          }
      }
}

To configure account lockout based on the security questions, add the following lines to your selfservice.kba.json file:

"numberOfAttemptsAllowed" : 2,
"kbaAttemptsPropertyName" : "lockoutproperty"

With this configuration, users who make more than two mistakes in answering security questions are prevented from using the password reset facility until the kbaAttemptsPropertyName field is removed or the number is set to a value lower than the numberOfAttemptsAllowed. The number of mistakes is recorded in whatever property you assign to kbaAttemptsPropertyName (lockoutproperty in this example).

If you are using an explicit mapping for managed user objects, you must add this lockoutproperty to your database schema and to the objectToColumn mapping in your repository configuration file.

For example, the previous configuration would require the following addition to your conf/repo.jdbc.json file:

"explicitMapping" : {
     "managed/user": {
     "table" : "managed_user",
     "objectToColumn": {
         ...
         "lockoutproperty" : "lockoutproperty",
         ...
}   

You would also need to create a lockoutproperty column in the openidm.managed_user table, with datatype VARCHAR. For example:

mysql> show columns from managed_user;

+----------------------+--------------+------+-----+---------+-------+
| Field                | Type         | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| objectid             | varchar(38)  | NO   | PRI | NULL    |       |
| rev                  | varchar(38)  | NO   |     | NULL    |       |
| username             | varchar(255) | YES  | UNI | NULL    |       |
| password             | varchar(511) | YES  |     | NULL    |       |
| accountstatus        | varchar(255) | YES  | MUL | NULL    |       |
| postalcode           | varchar(255) | YES  |     | NULL    |       |
| lockoutproperty      | varchar(255) | YES  |     | NULL    |       |
...

Warning

Once you deploy these IDM self-service features, you should never remove or change existing security questions, as users may have included those questions during the user self-registration process.

You may change or add the questions of your choice, in JSON format. If you're configuring user self-registration, you can also edit these questions through the Admin UI. In fact, the Admin UI allows you to localize these questions in different languages.

In the Admin UI, select Configure > User Registration. Enable User Registration, select Options > Security Questions and select the edit icon to add, edit, or delete these questions.

Any change you make to the security questions under User Registration also applies to Password Reset. To confirm, select Configure > Password Reset. Enable Password Reset, and edit the Security Questions. You'll see the same questions there.

In addition, individual users can configure their own questions and answers, in two ways:

  • During the user self-registration process

  • From the End User UI, in the user's Profile section (), under Account Security > Security Questions

Important

A managed user's security questions can only be changed through the selfservice/userupdate endpoint, or when the user is created through selfservice/registration and provides their own questions. You cannot manipulate a user's kbaInfo property directly through the managed/user endpoint.

When the answers to security questions are hashed, they are converted to lowercase. If you intend to pre-populate answers with a mapping, the openidm.hash function or the secureHash mechanism, you must provide the string in lowercase to match the value of the answer.

5.4.3.2. Prompting to Update Security Questions

IDM supports a requirement for users to update their security questions, in the selfservice-kbaUpdate.json file. You can find this file in the following directory: /path/to/openidm/samples/example-configurations/self-service.

Alternatively, if you set up security questions from the Admin UI, you can navigate to Configure > Security Questions > Update Form, and select Enable Update. This action adds a selfservice-kbaUpdate.json file to your project's conf/ subdirectory.

For more information on this configuration file, see "Conditional User Stage" in the Self-Service REST API Reference.

5.4.4. Adding Custom Policies for Self-Registration and Password Reset

IDM has specific policies for usernames and passwords, in the policy.js file in the openidm/bin/defaults/script directory. To enforce these policies for user self-registration and password reset, add the following objects to your conf/policy.json file, under resources:

{
    "resource" : "selfservice/registration",
    "calculatedProperties" : {
        "type" : "text/javascript",
        "source" : "require('selfServicePolicies').getRegistrationProperties()"
    }
},
{
    "resource" : "selfservice/reset",
    "calculatedProperties" : {
        "type" : "text/javascript",
        "source" : "require('selfServicePolicies').getResetProperties()"
    }
},

For more information on IDM policies, see "Using Policies to Validate Data".

5.5. Configuring Notification Emails

When you configure the outbound email service as described in "Configuring Outbound Email", IDM may use that service to notify users of significant events, primarily related to user self-service. For specifics, see the following table for related notification emails:

Configuring Notification Emails
SituationConfiguration FileDetails
When a user is successfully registeredemailTemplate-welcome.jsonSee "User Self-Registration Email Template"
When a user asks for their forgotten usernameselfservice-username.jsonSee "Configuring Emails for Forgotten Username"
When a user registers using self-service and needs to verify their email addressselfservice-registration.jsonSee "Configuring Emails for Self-Service Registration"
When a user asks for a password resetselfservice-reset.jsonSee "Configuring Emails for Password Reset"

Each email template can specify an email address to use in the From field. If this field is left blank, IDM will default to the address specified in Email Settings.

Note

Email templates utilize Handlebar expressions to reference object data dynamically. For example, to reference the userName of an object:

{{object.userName}}

Note

Some email providers, such as Google, will override the From address you specify in the templates, and instead use the address used to authenticate with the SMTP server. The email address specified in the template may still be present, but in an email header hidden from most users, such as X-Google-Original-From.

5.5.1. User Self-Registration Email Template

When a new user registers through the IDM self-registration interface, and if you've configured email per "Configuring Outbound Email", that user will get a welcome email as configured in the emailTemplate-welcome.json file:

{
    "enabled" : true,
    "from" : "",
    "subject" : {
        "en" : "Your account has been created"
    },
    "message" : {
        "en" : "<html><body><p>Welcome to OpenIDM. Your username is '{{object.userName}}'.</p></body></html>"
    },
    "defaultLocale" : "en"
}

You may want to make the following changes:

  • Add an email address to the from property, perhaps an email address for your organization's systems administrator.

  • Set up appropriate locale(s).

  • Modify the subject line as needed.

  • Include a welcome message appropriate to your organization.

5.5.2. Managing Email Templates from the Admin UI

The Admin UI includes tools that can help you customize email messages related to two administrative tasks: creating users and resetting passwords.

To configure these messages from the Admin UI, select Configure > Email Settings > Templates, where you'll see the following option:

  • Welcome: To configure emails that notify a user of a newly created account, as defined in emailTemplate-welcome.json.

    Note

    IDM sends the same welcome email to users created with a REST call. For an example of user creation over REST, see "Working with Managed Users".

5.8. Customizing the End User UI

For information on customizing the IDM End User UI, see the following ForgeRock Git repository: ForgeRock/end-user-ui: Identity Management (End User).

5.9. Setting Up User-Managed Access (UMA), Trusted Devices, and Privacy

In the following sections, you'll refer to AM documentation to set up User-Managed Access (UMA), Trusted Devices, and Privacy for your end users. These options require IDM working with AM. For a working implementation of both products, see "Integrating IDM With the ForgeRock Identity Platform" in the Samples Guide.

Tip

If you want to configure both UMA and Trusted Devices in AM, configure these features in the following order, as described in the sections that follow:

  1. Set up UMA

  2. Use AM to configure UMA-based resources

  3. Configure Trusted Devices

If you have to reconfigure UMA at a later date, you'll have to first disable Trusted Devices. You can enable Trusted Devices, once again, afterwards.

5.9.1. User Managed Access in IDM

When you integrate IDM with ForgeRock Access Management (AM) you can take advantage of AM's abilities to work with User-Managed Access (UMA) workflows. AM and IDM use a common installation of ForgeRock Directory Services (DS) to store user data.

For instructions on how to set up this integration, see "Integrating IDM With the ForgeRock Identity Platform" in the Samples Guide. Be sure to set up DS as the AM user data store. Once you've set up integration through that sample, you can configure AM to work with UMA. For more information, see the AM User-Managed Access (UMA) Guide. From that guide, you need to know how to:

  • Set up AM as an authorization server.

  • Register resource sets and client agents in AM.

  • Help users manage access to their protected resources through AM.

Pay close attention to the AM documentation on configuring an OAuth 2.0 UMA Client and UMA Server. You may need to add specific grant types to each OAuth 2.0 application.

If you follow AM documentation to set up UMA, you'll see instructions on setting up users as resource owners and requesting parties. If you set up users in AM, be sure to include the following information for each user:

  • First Name

  • Last Name

  • Email Address

AM writes this information to the common DS user data store. You can then synchronize these users to the IDM Managed User data store, with a command such as:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"http://localhost:8080/openidm/recon?_action=recon&mapping=systemLdapAccounts_managedUser"

After your users have shared UMA resources from the AM Self-Service UI, they can view what they've done and shared in the IDM End User UI, by selecting the Sharing icon ().

5.9.2. Configuring Trusted Devices on IDM

You can configure Trusted Devices through AM, using the following sections of the AM Authentication and Single Sign-On Guide: Configuring Authentication Chains and Device ID (Match) Authentication Module. You can use the techniques described in these sections to set up different authentication chains for administrators and regular users.

You can create an AM authentication chain with the following modules and criteria:

AM Authentication Chain Modules
ModuleCriteria
Data StoreRequisite
Device Id (Match)Sufficient
Device Id (Save)Required

This is different from the authentication chain described in the following section of the AM Authentication and Single Sign-On Guide: Device ID (Match) Authentication Module, as it does not include the HOTP Authentication Module

When trusted devices are enabled, users are presented with a prompt on a screen with the following question "Add to Trusted Devices?". If the user selects Yes, that user is prompted for the name of the Trusted Device.

Note

In default configurations, trusted devices are not saved for the AM amadmin account. However, you can set up different AM administrative users as described in the following section of the AM Setup and Maintenance Guide: Delegating Realm Administration Privileges.

You can set up different authentication chains for regular and administrative users, as described in the AM Authentication and Single Sign-On Guide.

5.10. Privacy: My Account Information in the End User UI

While end users can find their information in the End User UI, you can use REST calls and audit logs to find the same information. However, some of the information in this section, such as Trusted Devices and UMA-based sharing, may require integration with ForgeRock Directory Services (DS) or ForgeRock Access Management (AM), as described in "Integrating IDM With the ForgeRock Identity Platform" in the Samples Guide.

What the enduser sees upon log into the End User UI depends on which features are configured.

5.10.1. Personal Information

End users can find their account details in the End User UI, by selecting the Profile icon () > Edit Personal Info. By default, user information includes at least the following properties: Username, First Name, Last Name, and Email Address.

Each user can modify this information as needed, as long as "userEditable" : true for the property in your project's managed.json file. For more information, see "Creating and Modifying Managed Object Types".

5.10.2. Sign-In & Security

Under this tab, end users can change their passwords. They can also add, delete, or modify security questions, and link or unlink supported social identity accounts. For more information, see "Configuring Security Questions" and "Configuring Social Identity Providers".

5.10.3. Preferences

The preferences tab allows end users to modify marketing preferences, as defined in the managed.json file, and the Managed Object User property Preferences tab. For more information, see "Configuring End User Preferences".

End users can toggle marketing preferences. When IDM includes a mapping to a marketing database, these preferences are sent to that database. This can help administrators use IDM to target marketing campaigns and identify potential leads.

5.10.4. Trusted Devices

A trusted device uses AM's Device ID (Match) and Device ID (Save) authentication modules, as described in the AM Authentication and Single Sign-On Guide. When such modules are configured (see "Configuring Trusted Devices on IDM"), end users can add such devices the first time they log in from a new location.

During the login process, when an end user selects Log In, that user is prompted for a Trusted Device Name. Users see their added devices under the Trusted Devices tab.

A trusted device entry is paired with a specific browser on a specific system. The next time the same end user logs in from the same browser and system, in the same location, that user should not be prompted to enter a trusted device again.

End users can remove their trusted devices from the tab.

5.10.5. Authorized Applications

The Authorized Applications section is specific to end users as OAuth 2 clients. and reflects the corresponding section of the AM Self-Service dashboard, as described in the following section of the AM OAuth 2.0 Guide on: User Consent Management.

Note

The one exception is when IDM is configured to work with AM as described in "Integrating IDM With the ForgeRock Identity Platform" in the Samples Guide. You'll see an "Authorized Application" in this case, with a name such as openidm. While end users can select Remove, to try to delete something like openidm as an "Authorized Application", openidm will reappear the next time the user logs into the End User UI, in the "full stack" configuration.

5.10.6. Personal Data Sharing

This section assumes that as an administrator, you've followed the instructions in "Configuring Privacy & Consent" to enable Privacy & Consent.

End users who see a Personal Data Sharing section have control of whether personal data is shared with an external database, such as one that might contain marketing leads.

The managed object record for end users who consent to sharing such data is shown in REST output and the audit activity log as one consentedMappings object:

"consentedMappings" : [ {
   "mapping" : "managedUser_systemLdapAccounts",
   "consentDate" : "2017-08-25T18:13:08.358Z"
}

If enabled, end users will see a Personal Data Sharing section in their profiles. If they select the Allow link, they can see the data properties that would be shared with the external database.

This option supports the right to restrict processing of user personal data.

5.10.7. Account Controls

The Account Controls section allows end users to download their account data (in JSON format), and to delete their accounts from IDM.

Important

When end users delete their accounts, the change is propagated to external systems by implicit sync. However, it is then up to the administrator of the external system to make sure that any additional user information is purged from that system.

To modify the message associated with the Delete Your Account option, refer to the following section of the public ForgeRock Identity Management (End User) Git repository on Translations. You'll find content GitHub "Customizing the End User UI", find the translation.json file, search for the deleteAccount code block, and edit text information as desired.

The options shown in this section can help meet requirements related to data portability, as well as the right to be forgotten.

5.11. Progressive Profile Completion

Progressive profile completion can help you build relationships with end users. Once users have established a history in their accounts, you can collect more information based on customizable criteria. Ideally, you should be able to use that information to create better experiences for those end users.

After activating "User Self-Registration", users need only the following information to register:

  • User name

  • First name

  • Last name

  • Email address

Progressive profile completion allows you to collect additional information, limited by the attributes defined in the managed.json file for your project.

In the following sections, you'll examine how you use progressive profile completion to ask or require more information from users. You're limited only by the properties defined in your project's managed.json file.

For more information, see "Setting Up a Progressive Profile Completion Form With selfservice-profile.json".

5.11.1. Setting Up a Progressive Profile Completion Form With selfservice-profile.json

If you're testing progressive profile completion, you can start from the selfservice-profile.json file in the following directory: openidm/samples/example-configurations/self-service/

Copy this file to your project's conf/ subdirectory and start IDM. After the conditions shown in this configuration file are met, end users will see a form prompting them to add a telephone number.

{
    "stageConfigs" : [
        {
            "name" : "conditionaluser",
            "identityServiceUrl" : "managed/user",
            "condition" : {
                "type" : "loginCount",
                "interval" : "at",
                "amount" : 25
            },
            "evaluateConditionOnField" : "user",
            "onConditionTrue" : {
                "name" : "attributecollection",
                "identityServiceUrl" : "managed/user",
                "uiConfig" : {
                    "displayName" : "Add your telephone number",
                    "purpose" : "Help us verify your identity",
                    "buttonText" : "Save"
                },
                "attributes" : [
                    {
                        "name" : "telephoneNumber",
                        "isRequired" : true
                    }
                ]
            }
        }
    ]
}

The following table includes a detailed list of each property shown in this file:

The selfservice-profile.json File
PropertyDescription
stageConfigsProgressive profile completion is a stage user self-service
nameconditionaluser sets up conditions for end users
identityServiceUrlmanaged/user specifies IDM Managed Users
conditionCondition when to display the form
typeType of condition; for a list of conditions, see "Standard Progressive Profile Completion Conditions"
evaluateConditionOnFieldIDM evaluates the condition, per user
onConditionTruePresent the form with the following properties
nameData that you collect with the form is an attributeCollection
uiConfigLabels to include the in the form seen by the end user
displayNameForm title
purposeForm explanation
buttonTextCustomizable
attributesAttribute name from managed.json
isRequiredIf an end user has to enter data to complete a connection to IDM

5.11.1.1. Standard Progressive Profile Completion Conditions

You can set up a number of different conditions for when users are prompted to add information to their profiles. IDM includes the following pre-defined criteria:

loginCount

May specify at or every number of logins, as defined by the following value: amount.

Note

End users can bypass progressive profile completion screens, when configured with a loginCount. Every time they see such a request, they can open a new browser window to bypass that request, and log into the End User UI. They won't have to provide the information requested, even if you've set the attribute as Required under the Attributes tab.

timeSince

May specify a time since the user was created, the createDate, in years, months, weeks, days, hours, and minutes.

profileCompleteness

Based on the number of items completed by the user from managed.json, in percent, as defined by percentLessThan; for more information, see "Defining Overall Profile Completion".

propertyValue

Based on the value of a specific user entry, such as postalAddress, which can be defined by "Presence Expressions".

5.11.1.2. Custom Progressive Profile Conditions

You can also set up custom conditions with query filters and scripts. These criteria may deviate from standard query filters described in "Constructing Queries" and standard scripted conditions described in "Adding Conditional Policy Definitions".

  • A query filter (queryFilter), as defined in "Defining and Calling Queries". For example, the following query filter checks user information for users who live in the city of Portland:

    "condition" : {
       "type" : "queryFilter",
       "filter" : "/city eq \"Portland\""
    },

    In addition, you can also reference metadata, as described in "Tracking Metadata For Managed Objects". For example, the following query filter searches for users with:

    • A loginCount greater than or equal to five

    • Does not have a telephone number

    "filter" : "(/_meta/loginCount ge 5 and !(/telephoneNumber pr))"
          

    Warning

    If you include _meta in query filters, the Admin UI will not work for the subject progressive profiling form.

    While it's technically possible to include a number like 5 in the Admin UI with the query filter, IDM would write the number as a string to the selfservice-profile.json file. You'd still have to change that number directly in the noted file.

  • An inline script (scripted), or a reference to a script file; IDM works with scripts written in either JavaScript or Groovy. For example, you could set up a script here:

    "condition" : {
       "type" : "scripted",
       "script" : {
           "type" : "text/javascript",
           "globals" : { },
           "source" : "<some script code>"
    },

    Alternatively, you could point to some JavaScript or Groovy file:

    "condition" : {
       "type" : "scripted",
       "script" : {
           "type" : "text/javascript",
           "globals" : { },
           "file" : "path/to/someScript.js"
    },

    For the script code, you'll need to reference fields directly, and not by object.field. For example, the following code would test for the presence of a telephone number:

    typeof telephoneNumber === 'undefined' || telephoneNumber === ''
          

    While you can also reference metadata for scripts, you can't check for all available fields, as there is no outer object field. However, you can refer to fields that are part of the user object.

5.11.1.3. Defining Overall Profile Completion

A user profile is based on every item in managed.json where both viewable and userEditable are set to true. Every qualifying item has equal weight.

So if there are 20 qualifying items in managed.json, a user who has entries for 10 items has a Profile completion percentage of 50.

5.11.2. The auth.profile.json File

In some circumstances, you may wish to create a temporary role for users who are in the middle of progressive profile completion, such as if you wish to enable access to an endpoint, while prohibiting access to other parts of the End User UI (as well as the rest of IDM).

To do this, you may optionally define an authenticationRole in auth.profile.json, which you can use as a role assignment in access.js or elsewhere.

For example, if you wished to assign access to a custom endpoint for users who have incomplete profiles, you could modify auth.profile.json to include a custom authenticationRole called incomplete-profile:

{
  "profileEnhancementProcesses": [
    "selfservice/termsAndConditions",
    "selfservice/kbaUpdate",
    "selfservice/profile"
  ],
  "authenticationRole": "incomplete-profile",
  "authorizationRole": "internal/role/openidm-authorized"
}

You could then give access to this role to your custom endpoint in access.js:

{
    "pattern"    : "endpoint/extra-steps",
    "roles"      : "incomplete-profile",
    "methods"    : "read",
    ...
},

Access for these and other roles is governed by the access.js script. For more information, see "Understanding the Access Configuration Script (access.js)".

The role specified in authenticationRole can be an existing role, or it can be a placeholder string. If it is a placeholder, it will not function as a real role, but can still be used for access in access.js, and will appear in access and authentication log files in the openidim/audit directory.

5.11.3. Progressive Profile Completion and Metadata

Progressive profile completion requires that you track object metadata, as described in "Tracking Metadata For Managed Objects". Read that section to configure tracking of the following data:

  • createDate: The date the user was created; used in the onCreateUser.js script in the openidm/bin/defaults/script directory.

  • loginCount: The number of logins, by user.

  • stagesCompleted: Used to track progressive profile forms, and whether they've been completed, by user.

User acceptance of Terms & Conditions is tracked by default (see "Adding Terms & Conditions").

5.11.4. Configuring Progressive Profile Completion over REST

You can manage the progressive profile completion configuration through the following endpoint: openidm/config/selfservice/profile. To review your current configuration, run the following command:

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

Unless you've disabled file writes per "Disabling Automatic Configuration Updates", the output will match the contents of your project's selfservice-profile.json file.

In a similar fashion, you can update this configuration by including the desired contents of the file:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request PUT \
--data '{
    "stageConfigs" : [
        {
            "name" : "conditionaluser",
            "identityServiceUrl" : "managed/user",
            "condition" : {
                "type" : "loginCount",
                "interval" : "at",
                "amount" : 25
            },
            "evaluateConditionOnField" : "user",
            "onConditionTrue" : {
                "name" : "attributecollection",
                "identityServiceUrl" : "managed/user",
                "uiConfig" : {
                    "displayName" : "Add your telephone number",
                    "purpose" : "Help us verify your identity",
                    "buttonText" : "Save"
                },
                "attributes" : [
                    {
                        "name" : "telephoneNumber",
                        "isRequired" : true
                    }
                ]
            }
        }
    ]
}' \
"http://localhost:8080/openidm/config/selfservice/profile"

5.11.5. Configuring Progressive Profile Completion Through the Admin UI

The UI is straightforward; in the Admin UI, when you select Configure > Progressive Profile, you'll add a New Form, with:

  • Attributes defined in managed.json

  • Conditions that may be based on a query filter, a script, or pre-defined criteria such as number of logins.

What you configure in the Admin UI is written to the selfservice-profile.json file. The information under the following Admin UI Progressive Profile Completion page tabs is written to the following code blocks in that file:

  • Details: uiConfig

  • Display Condition: condition

  • Attributes: attributes

Warning

When you use the UI, you must specify a property under the Attributes tab. Otherwise, IDM won't display a Progressive Profile form. To specify a property, select Configure > Progressive Profile. Select a Progressive Profile form > Attributes tab > Add a Property. Be sure to select an Attribute Name based on user properties configured in the managed.json file.

5.12. Adding Terms & Conditions

Many organizations require their users to accept Terms & Conditions. When you activate this option for user self-registration, IDM includes a link to Terms & Conditions as part of the self-registration process.

You can also force existing IDM users to accept new Terms & Conditions when they log into the End User UI through the selfservice-termsAndConditions.json file described in "Terms & Conditions Configuration Files".

5.12.1. Terms & Conditions Configuration Files

If you want to try the IDM implementation of Terms & Conditions, look at these files from the openidm/samples/example-configurations/self-service directory:

  • selfservice.terms.json

  • selfservice-termsAndConditions.json

Copy these files to your project directory and start IDM. To see how these Terms & Conditions appear to end users, create a regular user. Log into the End User UI as that user. You will be prompted to accept default Terms & Conditions.

The Terms & Conditions that you see in the End User UI come from the selfservice.terms.json file:

{
  "versions": [
    {
      "version": "2.0",
      "termsTranslations": {
        "en": "Some 2.0 fake terms",
        "fr": "More 2.0 fake terms"
      },
      "createDate": "2017-12-19T03:54:16.865Z"
    },
    {
      "version": "1.5",
      "termsTranslations": {
        "en": "Some 1.5 fake terms",
        "fr": "More 1.5 fake terms"
      },
      "createDate": "2017-11-20T04:20:11.320Z"
    }
  ],
  "active": "1.5",
  "uiConfig" : {
    "displayName" : "We've updated our terms",
    "purpose" : "You must accept the updated terms in order to proceed.",
    "buttonText" : "Accept"
  }
}

Note

IDM does not support <form> elements or <script> tags in Terms & Conditions text.

Substitute Terms & Conditions content that meet the requirements of your legal authorities.

As suggested by this file, you can set up different versions of Terms & Conditions in multiple languages. What is seen by end users is driven by the active version.

For details, see the following table:

The selfservice.terms.json File
PropertyDescription
versionSpecifies a version number
termsTranslationsSupports Terms & Conditions in different languages
createDateCreation date
activeSpecifies the version of Terms & Conditions shown to users; must match an existing version
displayNameThe title of the Terms & Conditions page, as seen by end users
purposeHelp text shown below the displayName
buttonTextButton text shown to the end user for acceptance

The other Terms & Conditions configuration file is selfservice-termsAndConditions.json. If it exists, end users must accept the specified Terms & Conditions before logging into IDM. As shown here, this applies Terms & Conditions to the managed/user store.

{
    "stageConfigs" : [
        {
            "name" : "conditionaluser",
            "identityServiceUrl" : "managed/user",
            "condition" : {
                "type" : "terms"
            },
            "evaluateConditionOnField" : "user",
            "onConditionTrue" : {
                "name" : "termsAndConditions"
            }
        },
        {
            "name" : "patchObject",
            "identityServiceUrl" : "managed/user"
        }
    ]
}

When a user accepts Terms & Conditions, IDM records relevant information in the _meta data for that user, as described in "Identifying When a User Accepts Terms & Conditions".

You can set up user self-registration to require acceptance of Terms & Conditions as described in "User Self-Registration".

Note

If you've set up Terms & Conditions in multiple languages, what your end users see depends on the default language set in the browser, based on ISO-639 language codes:

First, IDM looks for the active version, as defined in the selfservice.terms.json file.

  • If the default language in the browser matches one of the Terms & Conditions languages that you've configured, that's what the end user will see.

  • If the default language in the browser does not match any Terms & Conditions locales, IDM looks for:

    • The en locale.

    • If there is no en locale, IDM uses the first locale shown for the active version.

5.12.2. Updating Terms & Conditions over REST

You can manage the configuration for Terms & Conditions over the following endpoints:

  • openidm/config/selfservice.terms

  • openidm/config/selfservice/termsAndConditions

For example, the following command would replace the value of buttonText:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request PATCH \
--data '[ {
   "operation" : "replace",
   "field" : "uiConfig/buttonText",
   "value" : "OK"
} ]' \
"http://localhost:8080/openidm/config/selfservice.terms"

5.12.3. Identifying When a User Accepts Terms & Conditions

You can identify when a user accepts Terms & Conditions, as well as the associated version. To do so, take the following steps:

  • If needed, find identifying information for all managed users:

    $ curl \
    --header "X-OpenIDM-Username: openidm-admin" \
    --header "X-OpenIDM-Password: openidm-admin" \
    --request GET \
    "http://localhost:8080/openidm/managed/user?_queryId=query-all"
  • Pick a desired user, and use REST to get that user's information. This example illustrates how a user with a userName of kvaughan has already accepted a specific version of Terms & Conditions:

    $ curl \
    --header "X-OpenIDM-Username: openidm-admin" \
    --header "X-OpenIDM-Password: openidm-admin" \
    --request GET \
    "http://localhost:8080/openidm/managed/user?_queryFilter=userName+eq+'kvaughan'&_fields=*,/_meta/*"
    {
      "result": [
        {
          ...
          "userName": "kvaughan",
          ...
            "termsAccepted": {
              "acceptDate": "2018-04-12T22:55:33.370Z",
              "termsVersion": "2.0"
            },
            "createDate": "2018-04-12T22:55:33.395Z",
            "lastChanged": {
              "date": "2018-04-12T22:55:33.395Z"
            },
            "loginCount": 1,
            "_rev": "00000000776f8be1",
            "_id": "69124007-05ec-46e1-a8a8-ecc3d94db124"
          }
        }
      ],
      ...
    }
         

5.12.4. Configuring Terms & Conditions in the Admin UI

From the Admin UI, select Configure > Terms & Conditions. You can then create a new version, which prompts you to configure the following:

  • Version number (must be unique).

  • If there are existing Terms & Conditions, you'll see a Make active switch for the new Terms & Conditions.

  • Locale, in ISO-639 format.

  • Terms & Conditions, in the specified language locales. You can set up Terms & Conditions in text and/or basic HTML.

Once you've added Terms & Conditions in all desired locales, select Save to save them in the selfservice.terms.json file.

Note

The Admin UI does not allow you to delete existing Terms & Conditions.

Once you have at least one set of Terms & Conditions, you should see a Settings tab, where you can:

  • Require acceptance; the next time any end user logs into IDM, that user will see a copy of your Terms & Conditions, with the Header, Description, and Button Text.

  • To make sure new users have to accept these Terms & Conditions, select Configure > User Registration in the Admin UI. Enable Terms & Conditions under the Options tab. For more information, see "User Self-Registration". Users who self-register will see the following message, with a link to those Terms & Conditions:

    By creating an account, you agree to the Terms & Conditions

These changes are recorded in _meta data for each user and can be retrieved through REST calls described in "Identifying When a User Accepts Terms & Conditions".

5.13. Localizing the End User UI

The End User UI is configured in US English. For more information on how to localize and modify the messages in the End User UI, see the following section of the ForgeRock Identity Management (End User) repository on Translations and Text.

5.14. Tokens and User Self-Service

Many processes within user self-service involve multiple stages, such as user self-registration, password reset, and forgotten username. As the user transitions from one stage to another, IDM uses JWT tokens to represent the current state of the process. As each stage is completed, IDM returns a new token. Each request that follows includes that latest token.

For example, users who use these features to recover their usernames and passwords get two tokens in the following scenario:

  • The user goes through the forgotten username process, gets a JWT Token with a lifetime (default = 300 seconds) that allows that user to get to the next step in the process.

  • With username in hand, that user may then start the password reset process. That user gets a second JWT token, with the token lifetime configured for that process.

Note

The default IDM JWT token is encrypted and stateless. However, if you need a token that can be included in a link that works in all email clients, change the snapshotToken type in the appropriate configuration file to uuid.

5.15. End User UI Notifications

Whenever there are changes related to individual users, IDM sends notifications to the affected user. When such users log into the End User UI, they can find their notifications by selecting the bell () icon.

Notifications are configured in notification-*.json files, as described in "Notification Configuration Files".

IDM includes a notifications endpoint, which can help you identify all notifications:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"http://localhost:8080/openidm/internal/notification?_queryFilter=true"

You can isolate notifications by user. As noted elsewhere, you can identify user IDs with the following command:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"http://localhost:8080/openidm/managed/user?_queryId=query-all-ids"

You can then isolate the notifications by user ID, with the _notifications field.

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"http://localhost:8080/openidm/managed/user/e3a9385b-733f-4a1c-891b-c89292b30d70?_fields=_notifications/*"

For other _queryFilter options, see "Defining and Calling Queries".

You can filter notifications with any of the properties shown in the following table:

End User Notification Properties
PropertyDescription
createDateCreation date
notificationTypeMessage type: limited to info, warning, or error
messageMessage seen by the end user

You can get additional information from the activity audit log, in the audit/activity.audit.json file. including the following:

  • The userId who made the change.

  • The runAs name of the user who made the change.

  • If configured in "Specifying Fields to Monitor", any watched fields that have changed.

  • If the password was changed, as indicated by the passwordChanged property.

Chapter 6. Managing the Repository

IDM stores managed objects, internal users, and configuration objects in a repository. By default, the server uses an embedded ForgeRock Directory Services (DS) instance as its repository. In production, you must replace this embedded instance with an external DS instance, or with a JDBC repository, as described in "Selecting a Repository" in the Installation Guide.

This chapter describes the repository configuration, the use of mappings in the repository, and how to configure a connection to the repository over SSL. It also describes how to interact with the repository over the REST interface.

6.1. Understanding the Repository Configuration Files

IDM provides configuration files for all supported repositories. These configuration files are located in the /path/to/openidm/db/database/conf directory. For JDBC repositories, the configuration is defined in two files:

  • datasource.jdbc-default.json, which specifies the connection details to the repository.

  • repo.jdbc.json, which specifies the mapping between IDM resources and the tables in the repository, and includes a number of predefined queries.

  • repo.init.json, which specifies IDM's initial internal roles and users. The file is used when first launching IDM, and can be used to create additional roles and users, but ignores roles and users that have already been created. For more information about internal roles, see "Authorization".

For a DS repository, the repo.ds.json file specifies the resource mapping and, in the case of an external repository, the connection details to the LDAP server.

Copy the configuration files for your specific database type to your project's conf/ directory.

6.1.1. Understanding the JDBC Connection Configuration File

The default database connection configuration file for a MySQL database follows:

{
    "driverClass" : "com.mysql.jdbc.Driver",
    "jdbcUrl" : "jdbc:mysql://&{openidm.repo.host}:&{openidm.repo.port}/openidm?allowMultiQueries=true&characterEncoding=utf8",
    "databaseName" : "openidm",
    "username" : "openidm",
    "password" : "openidm",
    "connectionTimeout" : 30000,
    "connectionPool" : {
        "type" : "hikari",
        "minimumIdle" : 20,
        "maximumPoolSize" : 50
    }
}

The configuration file includes the following properties:

driverClass

"driverClass" : string

To use the JDBC driver manager to acquire a data source, set this property, as well as "jdbcUrl", "username", and "password". The driver class must be the fully qualified class name of the database driver to use for your database.

Using the JDBC driver manager to acquire a data source is the most likely option, and the only one supported "out of the box". The remaining options in the sample repository configuration file assume that you are using a JDBC driver manager.

Example: "driverClass" : "com.mysql.jdbc.Driver"

jdbcUrl

The connection URL to the JDBC database. The URL should include all of the parameters required by your database. For example, to specify the encoding in MySQL use 'characterEncoding=utf8'.

Specify the values for openidm.repo.host and openidm.repo.port in one of the following ways:

  • Set the values in resolver/boot.properties or your project's conf/system.properties file, for example:

    openidm.repo.host = localhost
    openidm.repo.port = 3306
  • Set the properties in the OPENIDM_OPTS environment variable and export that variable before startup. You must include the JVM memory options when you set this variable. For example:

    $ export OPENIDM_OPTS="-Xmx1024m -Xms1024m -Dopenidm.repo.host=localhost -Dopenidm.repo.port=3306"
    $ ./startup.sh
    Executing ./startup.sh...
    Using OPENIDM_HOME:   /path/to/openidm
    Using PROJECT_HOME:   /path/to/openidm
    Using OPENIDM_OPTS:   -Xmx1024m -Xms1024m -Dopenidm.repo.host=localhost -Dopenidm.repo.port=3306
    Using LOGGING_CONFIG: -Djava.util.logging.config.file=/path/to/openidm/conf/logging.properties
    Using boot properties at /path/to/openidm/resolver/boot.properties
    -> OpenIDM version "6.5.2.0"
    OpenIDM ready
databaseName

The name of the database to which IDM connects. By default, this is openidm.

username

The username with which to access the JDBC database.

password

The password with which to access the JDBC database. IDM automatically encrypts clear string passwords. To replace an existing encrypted value, replace the whole crypto-object value, including the brackets, with a string of the new password.

connectionTimeout

The period of time, in milliseconds, after which IDM should consider an attempted connection to the database to have failed. The default period is 30000 milliseconds (30 seconds).

connectionPool

Database connection pooling configuration. The default connection pool library is HikariCP:

"connectionPool" : {
    "type" : "hikari"
}

IDM uses the default HikariCP configuration, except for the following parameters. You might need to adjust these parameters, according to your database workload:

  • minimumIdle

    This property controls the minimum number of idle connections that HikariCP maintains in the connection pool. If the number of idle connections drops below this value, HikariCP attempts to add additional connections.

    By default, HikariCP runs as a fixed-sized connection pool, that is, this property is not set. The connection configuration files provided with IDM set the minimum number of idle connections to 20.

  • maximumPoolSize

    This property controls the maximum number of connections to the database, including idle connections and connections that are being used.

    By default, HikariCP sets the maximum number of connections to 10. The connection configuration files provided with IDM set the maximum number of connections to 50.

For information about the HikariCP configuration parameters, see the HikariCPCP Project Page.

6.1.2. Understanding the JDBC Database Table Configuration

An excerpt of a MySQL database table configuration file follows:

{
     "dbType" : "MYSQL",
     "useDataSource" : "default",
     "maxBatchSize" : 100,
     "maxTxRetry" : 5,
     "queries" : {...},
     "commands" : {...},
     "resourceMapping" : {...}
 }

The configuration file includes the following properties:

dbType : string, optional

The type of database. The database type might affect the queries used and other optimizations. Supported database types include the following:

DB2
SQLSERVER (for Microsoft SQL Server)
MYSQL
ORACLE
POSTGRESQL
useDataSource : string, optional

This option refers to the connection details that are defined in the configuration file, described previously. The default configuration file is named datasource.jdbc-default.json. This is the file that is used by default (and the value of the "useDataSource" is therefore "default"). You might want to specify a different connection configuration file, instead of overwriting the details in the default file. In this case, set your connection configuration file datasource.jdbc-name.json and set the value of "useDataSource" to whatever name you have used.

maxBatchSize

The maximum number of SQL statements that will be batched together. This parameter allows you to optimize the time taken to execute multiple queries. Certain databases do not support batching, or limit how many statements can be batched. A value of 1 disables batching.

maxTxRetry

The maximum number of times that a specific transaction should be attempted before that transaction is aborted.

queries

Predefined queries that can be referenced from the configuration. For more information about predefined queries, see "Parameterized Queries". The queries are divided between those for genericTables and those for explicitTables.

The following sample extract from the default MySQL configuration file shows two credential queries, one for a generic mapping, and one for an explicit mapping. Note that the lines have been broken here for legibility only. In a real configuration file, the query would be all on one line:

 "queries" : {
     "genericTables" : {
         "credential-query" : "SELECT obj.objectid, obj.rev, obj.fullobject FROM ${_dbSchema}.${_mainTable} obj
         INNER JOIN ${_dbSchema}.objecttypes objtype ON objtype.id = obj.objecttypes_id
         AND objtype.objecttype = ${_resource} INNER JOIN ${_dbSchema}.${_propTable} usernameprop
         ON obj.id = usernameprop.${_mainTable}_id AND usernameprop.propkey='/userName'
         INNER JOIN ${_dbSchema}.${_propTable} statusprop ON obj.id = statusprop.${_mainTable}_id
         AND statusprop.propkey='/accountStatus' WHERE usernameprop.propvalue = ${username}
         AND statusprop.propvalue = 'active'",
         ...
     "explicitTables" : {
         "credential-query" : "SELECT * FROM ${_dbSchema}.${_table}
           WHERE username = ${username} and accountstatus = 'active'",
         ...
     }
 }    

Options supported for query parameters include the following:

  • A default string parameter, for example:

    openidm.query("managed/user", { "_queryId": "for-userName", "uid": "jdoe" });

    For more information about the query function, see "openidm.query(resourceName, params, fields)".

  • A list parameter (${list:propName}).

    Use this parameter to specify a set of indeterminate size as part of your query. For example:

    WHERE targetObjectId IN (${list:filteredIds})
  • An integer parameter (${int:propName}).

    Use this parameter to query non-string values in the database. This is particularly useful with explicit tables.

commands

Specific commands configured to manage the database over the REST interface. Currently, the following default commands are included in the configuration:

  • purge-by-recon-expired

  • purge-by-recon-number-of

  • delete-mapping-links

  • delete-target-ids-for-recon

These commands assist with removing stale reconciliation audit information from the repository, and preventing the repository from growing too large. The commands work by executing a query filter, then performing the specified operation on each result set. Currently the only supported operation is DELETE, which removes all entries that match the filter. For more information about repository commands, see "Running Queries and Commands on the Repository".

resourceMapping

Defines the mapping between IDM resource URIs (for example, managed/user) and JDBC tables. The structure of the resource mapping is as follows:

 "resourceMapping" : {
     "default" : {
         "mainTable" : "genericobjects",
         "propertiesTable" : "genericobjectproperties",
         "searchableDefault" : true
     },
     "genericMapping" : {...},
     "explicitMapping" : {...}
 }    

The default mapping object represents a default generic table in which any resource that does not have a more specific mapping is stored.

The generic and explicit mapping objects are described in the following section.

6.1.3. Understanding the DS Repository Configuration

An excerpt of a DS repository configuration file follows:

{
     "embedded" : false,
     "maxConnectionAttempts" : 5,
     "security" : {...},
     "ldapConnectionFactories" : {...},
     "queries" : {...},
     "commands" : {...},
     "rest2LdapOptions": {...},
     "indices": {...},
     "schemaProviders": {...},
     "resourceMapping" : {...}
 }

The configuration file includes the following properties:

embedded : boolean

Specifies an embedded or external DS instance.

IDM uses an embedded DS instance by default. The embedded instance is not supported in production.

maxConnectionAttempts : integer

Specifies the number of times IDM should attempt to connect to the DS instance. On startup, IDM will attempt to connect to DS indefinitely. The maxConnectionAttempts parameter controls the number of reconnection attempts in the event of a failure during normal operation, for example, if an attempt to access the DS repository times out.

By default, IDM will attempt to reconnect to the DS instance 5 times.

security

Specifies the DS key manager and trust manager provider types, both jvm by default. For example:

"security": {
    "trustManager": "jvm",
    "keyManager": "jvm"
}
ldapConnectionFactories

For an external DS repository, configures the connection to the DS instance. For example:

"ldapConnectionFactories": {
    "bind": {
        "connectionSecurity": "none",
        "sslCertAlias": "client-cert",
        "heartBeatIntervalSeconds": 60,
        "heartBeatTimeoutMilliSeconds": 10000,
        "primaryLdapServers": [{ "hostname": "localhost", "port": 31389 }],
        "secondaryLdapServers": []
    },
    "root": {
        "inheritFrom": "bind",
        "authentication": {
            "simple": { "bindDn": "cn=Directory Manager", "bindPassword": "password" }
        }
    }
}
queries

Predefined queries that can be referenced from the configuration. For a DS repository, all predefined queries are really filtered queries (using the _queryFilter parameter), for example:

"query-all-ids": {
    "_queryFilter": "true",
    "_fields": "_id,_rev"
},

The queries are divided between those for generic mappings and those for explicit mappings, but the queries themselves are the same for both mapping types.

commands

Specific commands configured to manage the repository over the REST interface. Currently, only two commands are included by default:

  • delete-mapping-links

  • delete-target-ids-for-recon

Both of these commands assist with removing stale reconciliation audit information from the repository, and preventing the repository from growing too large. For more information about repository commands, see "Running Queries and Commands on the Repository".

rest2LdapOptions

Specifies the configuration for accessing the LDAP data stored in DS. For more information, see Gateway REST2LDAP Configuration File in the DS Reference.

indices

For generic mappings, sets up LDAP indices on custom object properties. For more information, see "Improving Generic Mapping Search Performance (DS)".

schemaProviders

For generic mappings, lets you list custom objects whose properties should be indexed. For more information, see "Improving Generic Mapping Search Performance (DS)".

resourceMapping

Defines the mapping between IDM resource URIs (for example, managed/user) and the DS directory tree. The structure of the resource mapping object is as follows:

{
    "resourceMapping" : {
        "defaultMapping": {
            "dnTemplate": "ou=generic,dc=openidm,dc=forgerock,dc=com"
        },
        "explicitMapping" : {...},
        "genericMapping" : {...}
}    

The default mapping object represents a default generic organizational unit (ou) in which any resource that does not have a more specific mapping is stored.

The generic and explicit mapping objects are described in "Using Generic and Explicit Object Mappings" .

6.2. Using Generic and Explicit Object Mappings

There are two ways to map IDM objects to the tables in a JDBC database or to organizational units in DS:

  • Generic mapping, which allows you to store arbitrary objects without special configuration or administration.

  • Explicit mapping, which maps specific objects and properties to tables and columns in the JDBC database or to organizational units in DS.

These two mapping strategies are discussed in the following sections, for JDBC repositories and for DS repositories:

6.2.1. Generic and Explicit Mappings With a JDBC Repository

6.2.1.1. Using Generic Mappings With a JDBC Repository

Generic mapping speeds up development, and can make system maintenance more flexible by providing a stable database structure. However, generic mapping can have a performance impact and does not take full advantage of the database facilities (such as validation within the database and flexible indexing). In addition, queries can be more difficult to set up.

In a generic table, the entire object content is stored in a single large-character field named fullobject in the mainTable for the object. To search on specific fields, you can read them by referring to them in the corresponding properties table for that object. The disadvantage of generic objects is that, because every property you might like to filter by is stored in a separate table, you must join to that table each time you need to filter by anything.

The following diagram shows a pared down database structure for the default generic table, when using a MySQL repository. The diagram indicates the relationship between the main table and the corresponding properties table for each object.

Generic Tables Entity Relationship Diagram
Generic tables entity relationship diagram

These separate tables can make the query syntax particularly complex. For example, a simple query to return user entries based on a user name would need to be implemented as follows:

SELECT obj.objectid, obj.rev, obj.fullobject FROM ${_dbSchema}.${_mainTable} obj
INNER JOIN ${_dbSchema}.${_propTable} prop ON obj.id = prop.${_mainTable}_id
INNER JOIN ${_dbSchema}.objecttypes objtype ON objtype.id = obj.objecttypes_id
WHERE prop.propkey='/userName' AND prop.propvalue = ${uid} AND objtype.objecttype = ${_resource}",

The query can be broken down as follows:

  1. Select the full object, the object ID, and the object revision from the main table:

    SELECT obj.objectid, obj.rev, obj.fullobject FROM ${_dbSchema}.${_mainTable} obj
  2. Join to the properties table and locate the object with the corresponding ID:

    INNER JOIN ${_dbSchema}.${_propTable} prop  ON obj.id = prop.${_mainTable}_id
  3. Join to the object types table to restrict returned entries to objects of a specific type. For example, you might want to restrict returned entries to managed/user objects, or managed/role objects:

    INNER JOIN ${_dbSchema}.objecttypes objtype ON objtype.id = obj.objecttypes_id
  4. Filter records by the userName property, where the userName is equal to the specified uid and the object type is the specified type (in this case, managed/user objects):

    WHERE prop.propkey='/userName'
     AND prop.propvalue = ${uid}
     AND objtype.objecttype = ${_resource}",

    The value of the uid field is provided as part of the query call, for example:

    openidm.query("managed/user", { "_queryId": "for-userName", "uid": "jdoe" });

Tables for user definable objects use a generic mapping by default.

The following sample generic mapping object illustrates how managed/ objects are stored in a generic table:

"genericMapping" : {
       "managed/*" : {
           "mainTable" : "managedobjects",
           "propertiesTable" : "managedobjectproperties",
           "searchableDefault" : true,
           "properties" : {
               "/picture" : {
                   "searchable" : false
               }
           }
       }
   },
mainTable (string, mandatory)

Indicates the main table in which data is stored for this resource.

The complete object is stored in the fullobject column of this table. The table includes an objecttypes foreign key that is used to distinguish the different objects stored within the table. In addition, the revision of each stored object is tracked, in the rev column of the table, enabling multiversion concurrency control (MVCC). For more information, see "Manipulating Managed Objects Programmatically".

propertiesTable (string, mandatory)

Indicates the properties table, used for searches.

Note

PostgreSQL repositories do not use these properties tables to access specific properties. Instead, the PostgreSQL json_extract_path_text() function achieves this functionality.

The contents of the properties table is a defined subset of the properties, copied from the character large object (CLOB) that is stored in the fullobject column of the main table. The properties are stored in a one-to-many style separate table. The set of properties stored here is determined by the properties that are defined as searchable.

The stored set of searchable properties makes these values available as discrete rows that can be accessed with SQL queries, specifically, with WHERE clauses. It is not otherwise possible to query specific properties of the full object.

The properties table includes the following columns:

  • ${_mainTable}_id corresponds to the id of the full object in the main table, for example, manageobjects_id, or genericobjects_id.

  • propkey is the name of the searchable property, stored in JSON pointer format (for example /mail).

  • proptype is the data type of the property, for example java.lang.String. The property type is obtained from the Class associated with the value.

  • propvalue is the value of property, extracted from the full object that is stored in the main table.

    Regardless of the property data type, this value is stored as a string, so queries against it should treat it as such.

searchableDefault (boolean, optional)

Specifies whether all properties of the resource should be searchable by default. Properties that are searchable are stored and indexed. You can override the default for individual properties in the properties element of the mapping. The preceding example indicates that all properties are searchable, with the exception of the picture property.

For large, complex objects, having all properties searchable implies a substantial performance impact. In such a case, a separate insert statement is made in the properties table for each element in the object, every time the object is updated. Also, because these are indexed fields, the recreation of these properties incurs a cost in the maintenance of the index. You should therefore enable searchable only for those properties that must be used as part of a WHERE clause in a query.

Note

PostgreSQL repositories do not use the searchableDefault property.

properties

Lists any individual properties for which the searchable default should be overridden.

Note that if an object was originally created with a subset of searchable properties, changing this subset (by adding a new searchable property in the configuration, for example) will not cause the existing values to be updated in the properties table for that object. To add the new property to the properties table for that object, you must update or recreate the object.

6.2.1.2. Improving Generic Mapping Search Performance (JDBC)

All properties in a generic mapping are searchable by default. In other words, the value of the searchableDefault property is true unless you explicitly set it to false. Although there are no individual indexes in a generic mapping, you can improve search performance by setting only those properties that you need to search as searchable. Properties that are searchable are created within the corresponding properties table. The properties table exists only for searches or look-ups, and has a composite index, based on the resource, then the property name.

The sample JDBC repository configuration files (db/database/conf/repo.jdbc.json) restrict searches to specific properties by setting the searchableDefault to false for managed/user mappings. You must explicitly set searchable to true for each property that should be searched. The following sample extract from repo.jdbc.json indicates searches restricted to the userName property:

"genericMapping" : {
     "managed/user" : {
         "mainTable" : "manageduserobjects",
         "propertiesTable" : "manageduserobjectproperties",
         "searchableDefault" : false,
         "properties" : {
             "/userName" : {
             "searchable" : true
             }
         }
     }
 }, 

With this configuration, IDM creates entries in the properties table only for userName properties of managed user objects.

If the global searchableDefault is set to false, properties that do not have a searchable attribute explicitly set to true are not written in the properties table.

6.2.1.3. Using Explicit Mappings With a JDBC Repository

Explicit mapping is more difficult to set up and maintain, but can take complete advantage of the native database facilities.

An explicit table offers better performance and simpler queries. There is less work in the reading and writing of data, because the data is all in a single row of a single table. In addition, it is easier to create different types of indexes that apply to only specific fields in an explicit table. The disadvantage of explicit tables is the additional work required in creating the table in the schema. Also, because rows in a table are inherently more simple, it is more difficult to deal with complex objects. Any non-simple key:value pair in an object associated with an explicit table is converted to a JSON string and stored in the cell in that format. This makes the value difficult to use, from the perspective of a query attempting to search within it.

You can have a generic mapping configuration for most managed objects, and an explicit mapping that overrides the default generic mapping in certain cases.

IDM provides a sample configuration, for each JDBC repository, that sets up an explicit mapping for the managed user object and a generic mapping for all other managed objects. This configuration is defined in the files named /path/to/openidm/db/repository/conf/repo.jdbc-repository-explicit-managed-user.json. To use this configuration, copy the file that corresponds to your repository to your project's conf/ directory and rename it repo.jdbc.json. Run the sample-explicit-managed-user.sql data definition script (in the path/to/openidm/db/repository/scripts directory) to set up the corresponding tables when you configure your JDBC repository.

IDM uses explicit mapping for internal system tables, such as the tables used for auditing.

Depending on the types of usage your system is supporting, you might find that an explicit mapping performs better than a generic mapping. Operations such as sorting and searching (such as those performed in the default UI) tend to be faster with explicitly-mapped objects, for example.

The following sample explicit mapping object illustrates how internal/user objects are stored in an explicit table:

"explicitMapping" : {
     "internal/user" : {
         "table" : "internaluser",
         "objectToColumn" : {
             "_id" : "objectid",
             "_rev" : "rev",
             "password" : "pwd",
             "roles" : "roles"
         }
     },
     ...
 }   
<resource-uri> (string, mandatory)

Indicates the URI for the resources to which this mapping applies, for example, internal/user.

table (string, mandatory)

The name of the database table in which the object (in this case internal users) is stored.

objectToColumn (string, mandatory)

The way in which specific managed object properties are mapped to columns in the table.

The mapping can be a simple one to one mapping, for example "userName": "userName", or a more complex JSON map or list. When a column is mapped to a JSON map or list, the syntax is as shown in the following examples:

"messageDetail" : { "column" : "messagedetail", "type" : "JSON_MAP" }

or

"roles": { "column" : "roles", "type" : "JSON_LIST" }

Available column data types you can specify are STRING (the default), NUMBER, JSON_MAP, JSON_LIST, and FULLOBJECT.

Caution

Pay particular attention to the following caveats when you map properties to explicit columns in your database:

  • Support for data types in columns is restricted to numeric values (NUMBER) and strings (STRING). Although you can specify other data types, IDM handles all other data types as strings. Your database will need to convert these types from a string to the alternative data type. This conversion is not guaranteed to work.

    If the conversion does work, the format might not be the same when the data is read from the database as it was when it was saved. For example, your database might parse a date in the format 12/12/2012 and return the date in the format 2012-12-12 when the property is read.

  • Passwords are encrypted before they are stored in the repository. The length of the password column must be long enough to store the encrypted password value, which can vary depending on how it is encrypted and whether it is also hashed.

    The sample-explicit-managed-user.sql file referenced in this section sets the password column to a length of 511 characters (VARCHAR(511) to account for the additional space an encrypted password requires. For more information about IDM encryption and an example encrypted password value, see "Using the encrypt Subcommand" and "Encoding Attribute Values".

  • If your data objects include virtual properties, you must include columns in which to store these properties. If you don't explicitly map the virtual properties, you will see errors similar to the following when you attempt to create the corresponding object"

    {
        "code":400,
        "reason":"Bad Request",
        "message":"Unmapped fields [/property-name/0]
        for type managed/user and table openidm.managed_user"
    }

    When virtual properties are returned in the result of a query, the query previously persisted values of the requested virtual properties. To recalculate virtual property values in a query, you must set executeOnRetrieve to true in the query request parameters. For more information, see "Property Storage Triggers".

6.2.2. Generic and Explicit Mappings With a DS Repository

For both generic and explicit mappings, IDM maps object types using a dnTemplate property. The dnTemplate is effectively a pointer to where the object is stored in DS. For example, the following excerpt of the default repo.ds.json file shows how configuration objects are stored under the DN ou=config,dc=openidm,dc=forgerock,dc=com:

"config": {
    "dnTemplate": "ou=config,dc=openidm,dc=forgerock,dc=com"
},

6.2.2.1. Using Generic Mappings With a DS Repository

By default, IDM uses a generic mapping for all objects except the following:

  • Internal users, roles, and privileges

  • Links

  • Clustered reconciliation target IDs

    Note that clustered reconciliation is not currently supported with a DS repository.

  • Locks

  • Objects related to queued synchronization

With a generic mapping, all the properties of an object are stored as a single JSON blob in the fr-idm-json attribute. To create a new generic mapping, you need only specify the dnTemplate, that is, where the object will be stored in the directory tree.

You can specify a wildcard mapping, that stores all nested URIs under a particular branch of the directory tree, for example:

"managed/*": {
    "dnTemplate": "ou=managed,dc=openidm,dc=forgerock,dc=com"
},

With this mapping, all objects under managed/, such as managed/user and managed/device, will be stored in the branch ou=managed,dc=openidm,dc=forgerock,dc=com. You do not have to specify separate mappings for each of these objects. The mapping creates a new ou for each object. So, for example, managed/user objects will be stored under the DN ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com and managed/device objects will be stored under the DN ou=device,ou=managed,dc=openidm,dc=forgerock,dc=com.

6.2.2.1.1. Improving Generic Mapping Search Performance (DS)

By default, all generic objects are instances of the fr-idm-generic-obj object class and their properties are stored as a single JSON blob in the fr-idm-json attribute. The fr-idm-json attribute is indexed by default, which results in all attributes of a generic object being indexed. JDBC repositories behave in a similar way, with all generic objects being searchable by default.

To optimize search performance on specific generic resources, you can set up your own schema providers and indices as described in this section. For a detailed explanation of how indexes improve LDAP search performance, see Indexing Attribute Values in the DS Administration Guide.

For the embedded DS repository, or an external DS repository installed as described in "Using an External DS Repository" in the Installation Guide, the following managed user properties are indexed by default:

  • userName (cn)

  • givenName

  • sn

  • mail

  • telephoneNumber

You can configure managed user indexes in the repository configuration (repo.ds.json) by adding indices and schemaProviders objects, as follows:

"indices" : {
    ...
    "fr-idm-managed-user-json" : {
      "type" : [ "EQUALITY" ]
    },
    ...
  },
  "schemaProviders" : {
    "Managed User Json" : {
      "matchingRuleName" : "caseIgnoreJsonQueryMatchManagedUser",
      "matchingRuleOid" : "1.3.6.1.4.1.36733.2.....",
      "caseSensitiveStrings" : false,
      "fields" : [ "userName", "givenName", "sn", "mail", "telephoneNumber" ]
    },
    ...
  },
     

The indexed properties are listed in the array of fields for that managed object. To index additional managed user properties, add the property names to this array of fields.

To set up indexes on generic objects other than the managed user object, you must do the following:

  • Add the object to the DS schema.

    The schema for an embedded DS repository is stored in the /path/to/openidm/db/openidm/opendj/db/schema/60-repo-schema.ldif file.

    You can use the managed user object as an example of the schema syntax:

    ###
    # Managed User
    ###
    attributeTypes: ( 1.3.6.1.4.1.36733.2.3.1.13
      NAME 'fr-idm-managed-user-json'
      SYNTAX 1.3.6.1.4.1.36733.2.1.3.1
      EQUALITY caseIgnoreJsonQueryMatchManagedUser
      ORDERING caseIgnoreOrderingMatch
      SINGLE-VALUE
      X-ORIGIN 'OpenIDM DSRepoService')
    objectClasses: ( 1.3.6.1.4.1.36733.2.3.2.6
      NAME 'fr-idm-managed-user'
      SUP top
      STRUCTURAL
      MUST ( fr-idm-managed-user-json )
      X-ORIGIN 'OpenIDM DSRepoService' )

    For information about adding JSON objects to the DS schema, see Working With JSON in the DS Administration Guide.

    Warning

    If you delete the db/openidm directory, any additions you have made to the schema will be lost. If you have customized the schema, be sure to back up the 60-repo-schema.ldif file.

  • Add the object to the indices property in the conf/repo.ds.json file.

    The following example sets up an equality index for a managed devices object:

    "indices" : {
        ...
        "fr-idm-managed-devices-json" : {
          "type" : [ "EQUALITY" ]
        },
        ...
           },
  • Add the object to the schemaProviders property in the conf/repo.ds.json file and list the properties that should be indexed.

    The following example sets up indexes for the deviceName, brand, and assetNumber properties of the managed device object:

    "schemaProviders" : {
        "Managed Device Json" : {
          "matchingRuleName" : "caseIgnoreJsonQueryMatchManagedDevice",
          "matchingRuleOid" : "1.3.6.1.4.1.36733.2.....",
          "caseSensitiveStrings" : false,
          "fields" : [ "deviceName", "brand", "assetNumber" ]
        },

For more information about indexing JSON attributes, see Configuring an Index for a JSON Attribute in the DS Administration Guide.

Note

The OIDs shown in this section are reserved for ForgeRock internal use. If you set up additional objects and attributes, or if you change the default schema, you must specify your own OIDs here.

6.2.2.2. Using Explicit Mappings With a DS Repository

The default configuration uses generic mappings for all objects except internal users and roles, links, and clustered reconciliation target IDs. To use an explicit mapping for managed user objects, follow these steps:

  1. Stop IDM if it is running.

  2. Copy the repo.ds-explicit-managed-user.json file to your project's conf directory, and rename that file repo.ds.json:

    $ cd /path/to/openidm
    $ cp db/ds/conf/repo.ds-explicit-managed-user.json project-dir/conf/repo.ds.json

    Important

    This file is configured for an embedded DS repository by default. To set up an explicit mapping for an external DS repository, change the value of the "embedded" property to false and add the following properties:

    "security": {
        "trustManager": "jvm",
        "keyManager": "jvm"
    },
    "ldapConnectionFactories": {
        "bind": {
            "connectionSecurity": "none",
            "sslCertAlias": "client-cert",
            "heartBeatIntervalSeconds": 60,
            "heartBeatTimeoutMilliSeconds": 10000,
            "primaryLdapServers": [{ "hostname": "localhost", "port": 31389 }],
            "secondaryLdapServers": []
        },
        "root": {
            "inheritFrom": "bind",
            "authentication": {
                "simple": { "bindDn": "cn=Directory Manager", "bindPassword": "password" }
            }
        }
    },

    For more information on these properties, see "Understanding the DS Repository Configuration".

  3. Restart IDM.

IDM uses the DS REST to LDAP gateway to map JSON objects to LDAP objects stored in the directory. To create additional explicit mappings, you must specify the LDAP objectClasses to which the object is mapped, and how each property maps to its corresponding LDAP attributes. Specify at least the property type and the corresponding ldapAttribute.

The following excerpt of the explicit managed user object mapping provides an example:

"managed/user" : {
    "dnTemplate": "ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com",
    "objectClasses": [ "person", "organizationalPerson", "inetOrgPerson", "fr-idm-managed-user-explicit" ],
    "properties": {
        "_id": {
            "type": "simple", "ldapAttribute": "uid", "isRequired": true, "writability": "createOnly"
        },
        "userName": {
            "type": "simple", "ldapAttribute": "cn"
        },
        "password": {
            "type": "json", "ldapAttribute": "fr-idm-password"
        },
        "accountStatus": {
            "type": "simple", "ldapAttribute": "fr-idm-accountStatus"
        },
        "roles": {
            "type": "json", "ldapAttribute": "fr-idm-role", "isMultiValued": true
        },
        "effectiveRoles": {
            "type": "json", "ldapAttribute": "fr-idm-effectiveRole", "isMultiValued": true
        },
        "effectiveAssignments": {
            "type": "json", "ldapAttribute": "fr-idm-effectiveAssignment", "isMultiValued": true
        },
        ...
    }
},

You do not need to map the _rev (revision) property of an object as this property is implicit in all objects and maps to the DS etag operational attribute.

If your data objects include virtual properties, you must include property mappings for these properties. If you don't explicitly map the virtual properties, you will see errors similar to the following when you attempt to create the corresponding object:

{"code":400,"reason":"Bad Request","message":"Unmapped fields...}

For more information about the REST to LDAP property mappings, see Mapping Configuration File in the DS Reference.

For performance reasons, the DS repository does not apply unique constraints to links. This behavior is different to the JDBC repositories, where uniqueness on link objects is enforced.

Important

DS currently has a default index entry limit of 4000. Therefore, you cannot query more than 4000 records unless you create a Virtual List View (VLV) index. A VLV index is designed to help DS respond to client applications that need to browse through a long list of objects.

You cannot create a VLV index on a JSON attribute. For generic mappings, IDM avoids this restriction by using client-side sorting and searching. However, for explicit mappings you must create a VLV index for any filtered or sorted results, such as results displayed in a UI grid. To configure a VLV index, use the dsconfig command described in Configuring a Virtual List View Index in the DS Administration Guide.

6.2.2.2.1. Specifying How IDM IDs Map to LDAP Entry Names

The DS REST2LDAP configuration lets you specify a namingStrategy that determines how LDAP entry names are mapped to JSON resources. When IDM stores its objects in a DS repository, this namingStrategy determines how the IDM _id value maps to the Relative Distinguished Name (RDN) of the corresponding DS object.

The namingStrategy is specified as part of the explicitMapping of an object in the repo.ds.json file. The following example shows a naming strategy configuration for an explicit managed user mapping:

"resourceMapping": {
    "defaultMapping": {
        "dnTemplate": "ou=generic,dc=openidm,dc=forgerock,dc=com"
    },
    ...
    "explicitMapping": {
        "managed/user" : {
            "dnTemplate": "ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com",
            "objectClasses": [
                "person",
                "organizationalPerson",
                "inetOrgPerson",
                "fr-idm-managed-user-explicit"
            ],
            "namingStrategy" : {
                "type" : "clientDnNaming",
                "dnAttribute" : "uid"
            },
         ...
}

The namingStrategy can be one of the following:

  • clientDnNaming - IDM provides an _id to DS and that _id is used to generate the DS RDN. In the following example, the IDM _id maps to the LDAP uid attribute:

    {
         "namingStrategy": {
             "type": "clientDnNaming",
             "dnAttribute": "uid"
         }
     }     

    With this default configuration, entries are stored in DS with a DN similar to the following:

    "uid=idm-uuid,ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com"

    Note

    If these default DNs are suitable in your deployment, you do not have to change anything with regard to the naming strategy.

  • clientNaming - IDM provides an _id to DS but the DS RDN is derived from a different user attribute in the LDAP entry. In the following example, the RDN is the cn attribute. The _id that IDM provides for the object maps to the LDAP uid attribute:

    {
         "namingStrategy": {
             "type": "clientNaming",
             "dnAttribute": "cn",
             "idAttribute": "uid"
         }
     }     

    With this configuration, entries are stored in DS with a DN similar to the following:

    "cn=username,ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com"

Specifying a namingStrategy is optional. If you do not specify a strategy, the default is clientDnNaming with the following configuration:

{
     "namingStrategy" : {
         "type" : "clientDnNaming",
         "dnAttribute" : "uid"
     },
     "properties: : {
         "_id": {
             "type": "simple",
             "ldapAttribute": "uid",
             "isRequired": true,
             "writability": "createOnly"
         },
     ...
     }
 }

Note

If you do not set a dnAttribute as part of the naming strategy, the value of the dnAttribute is taken from the value of the ldapAttribute on the _id property.

6.3. Connect to a JDBC Repository Over SSL

This procedure assumes that you have already set up your JDBC repository, as described in "Selecting a Repository" in the Installation Guide. The exact steps to connect to a JDBC repository over SSL depend on your repository. This procedure describes the steps for a MySQL 8 repository. If you are using a different JDBC repository, use the corresponding documentation for that repository, and adjust the steps accordingly.

  1. Change the jdbcUrl property in your repository connection configuration file (conf/datasource.jdbc-default.json ).

    The exact value of the jdbcUrl property will depend on your JDBC database, and on the version of your JDBC driver:

    The following example shows the configuration for MySQL with JDBC driver version 8.0.12 or earlier:

    "jdbcUrl" : "jdbc:mysql://&{openidm.repo.host}:&{openidm.repo.port}/openidm?allowMultiQueries=true&characterEncoding=utf8&useSSL=true&verifyServerCertificate=true&requireSSL=true"

    The following example shows the configuration for MySQL with JDBC driver version 8.0.13 or later:

    "jdbcUrl" : "jdbc:mysql://&{openidm.repo.host}:&{openidm.repo.port}/openidm?allowMultiQueries=true&characterEncoding=utf8&sslMode=VERIFY_CA&requireSSL=true"

    Note

    For Azure MySQL, JDBC Driver Version 8.0.17+ is required.

  2. Create and verify the SSL certificate and key files required to support encrypted connections to the JDBC repository.

    For MySQL 8, use one of the procedures in the MySQL docs.

  3. Configure the JDBC repository to use encrypted connections.

    For MySQL 8, follow the MySQL docs.

  4. Check that the connection to the database is over SSL by running a command similar to the following:

    mysql -u root -P 3306 -p
    mysql>show variables like "%have_ssl%";
    
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | have_ssl      | YES   |
    +---------------+-------+
    1 row in set (0.00 sec)
  5. Convert your MySQL client key and certificate files to a PKCS #12 archive. For example:

    openssl pkcs12 -export \
     -in client-cert.pem \
     -inkey client-key.pem \
     -name "mysqlclient" \
     -passout pass:changeit \
     -out client-keystore.p12
  6. Import the client-keystore.p12 into the IDM keystore:

    keytool \
     -importkeystore \
     -srckeystore client-keystore.p12 \
     -srcstoretype pkcs12 \
     -srcstorepass changeit \
     -destkeystore /path/to/openidm/security/keystore.jceks \
     -deststoretype jceks \
     -deststorepass changeit

    Important

    For AWS RDS MySQL and Azure MySQL, no client certificates are provided. In this case, you must create an empty keystore for client certificates, and add the following to the jdbcUrl property in your repository connection configuration file (conf/datasource.jdbc-default.json ):

    &clientCertificateKeyStoreUrl=file:/opt/idm/security/empty.jks&clientCertificateKeyStorePassword=changeit
  7. Import your MySQL CA certificate into the IDM truststore.

    keytool \
     -importcert \
     -trustcacerts \
     -file ca-cert.pem \
     -alias "DB cert" \
     -keystore /path/to/openidm/security/truststore

    You are prompted for a keystore password. You must use the same password as is shown in your resolver/boot.properties file. The default truststore password is:

    openidm.truststore.password=changeit

    After entering a keystore password, you are prompted with the following question. Assuming you have included an appropriate ca-cert.pem file, enter yes.

    Trust this certificate? [no]: 
  8. Open your project's conf/system.properties file. Add the following line to that file. If appropriate, substitute the path to your own truststore:

    # Set the truststore
    javax.net.ssl.trustStore=&{idm.install.dir}/security/truststore

    Even if you are setting up this instance of IDM as part of a cluster, you must configure this initial truststore. After this instance joins a cluster, the SSL keys in this particular truststore are replaced.

6.4. Interacting With the Repository Over REST

The IDM repository is accessible over the REST interface, at the openidm/repo endpoint.

In general, you must ensure that external calls to the openidm/repo endpoint are protected. Native queries and free-form command actions on this endpoint are disallowed by default because the endpoint is vulnerable to injection attacks. For more information, see "Running Queries and Commands on the Repository".

6.4.1. Running Queries and Commands on the Repository

Free-form commands and native queries on the repository are disallowed by default and should remain so in production to reduce the risk of injection attacks.

Common filter expressions, called with the _queryFilter keyword, enable you to form arbitrary queries on the repository, using a number of supported filter operations. For more information on these filter operations, see "Constructing Queries". Parameterized or predefined queries and commands (using the _queryId and commandId keywords) can be authorized on the repository for external calls if necessary. For more information, see "Parameterized Queries".

Running commands on the repository is supported primarily from scripts. Certain scripts that interact with the repository are provided by default, for example, the scripts that enable you to purge the repository of reconciliation audit records.

You can define your own commands, and specify them in the database table configuration file (either repo.ds.json or repo.jdbc.json). In the following simple example, a command is called to clear out UI notification entries from the repository, for specific users.

The command is defined in the repository configuration file, as follows:

"commands" : {
"delete-notifications-by-id" : "DELETE FROM ui_notification WHERE receiverId = ${username}"
...
}, 

The command can be called from a script, as follows:

openidm.action("repo/ui/notification", "command", {},
{ "commandId" : "delete-notifications-by-id", "userName" : "scarter"});

Exercise caution when allowing commands to be run on the repository over the REST interface, as there is an attached risk to the underlying data.

Chapter 7. Configuring the Server

This chapter describes how IDM loads and stores its configuration, how the configuration can be changed, and specific configuration recommendations in a production environment.

The configuration is defined in a combination of .properties files, container configuration files, and dynamic configuration objects. Most of the configuration files are stored in your project's conf/ directory. Note that you might see files with a .patch extension in the conf/ and db/repo/conf/ directories. These files specify differences relative to the last released version of IDM and are used by the update mechanism. They do not affect your current configuration.

7.1. Configuration Objects

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

7.1.1. 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 following list describes the single instance configuration objects:

  • The audit configuration specifies how audit events are logged.

  • The authentication configuration controls REST access.

  • The cluster configuration defines how an IDM instance can be configured in a cluster.

  • The endpoint configuration controls any custom REST endpoints.

  • The info configuration points to script files for the customizable information service.

  • The managed configuration defines managed objects and their schemas.

  • The policy configuration defines the policy validation service.

  • The process access configuration defines access to configured workflows.

  • The repo.repo-type configuration such as repo.ds or repo.jdbc configures the IDM repository.

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

  • The script configuration defines the parameters that are used when compiling, debugging, and running JavaScript and Groovy scripts.

  • The sync configuration defines the mappings that IDM uses when it synchronizes and reconciles managed objects.

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

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

IDM stores managed objects in the repository, and exposes them under /openidm/managed. System objects on external resources are exposed under /openidm/system.

7.1.2. Multiple Instance Configuration Objects

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

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

IDM provides the following multiple instance configuration objects:

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

  • Multiple provisioner.openicf configurations correspond to connected resources.

  • Multiple servletfilter configurations can be used for different servlet filters such as the Cross Origin and GZip filters.

7.2. Making Configuration Changes

When you change configuration objects, take the following points into account:

  • IDM's authoritative configuration source is its repository. Although the JSON files provide a view of the configuration objects, they do not represent the authoritative source.

    Unless you have disabled file writes, as described in "Disabling Automatic Configuration Updates", IDM updates JSON files after you make configuration changes over REST. You can also edit those JSON files directly.

  • IDM recognizes changes to JSON files when it is running. The server 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 repository. Rather, edit the configuration over the REST API, or in the configuration JSON files to ensure consistent behavior and that operations are logged.

  • By default, IDM stores its configuration in the repository. If you remove an IDM instance and do not specifically drop the repository, the configuration remains in effect for a new instance that uses that repository. You can disable this persistent configuration in your project's conf/system.properties file by uncommenting the following line:

    # openidm.config.repo.enabled=false

    Disabling persistent configuration means that IDM stores its configuration in memory only.

7.3. Changing the Default REST Context

By default, IDM objects are accessible over REST at the context path /openidm/* where * indicates the remainder of the context path, for example /openidm/managed/user. You can change the default REST context (/openidm) by setting the openidm.servlet.alias property in your project's resolver/boot.properties file.

The following change to the boot.properties file sets the REST context to /example:

openidm.servlet.alias=/example

After this change, objects are accessible at the /example context path, for example:

$ $ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/example/managed/user?_queryId=query-all-ids"
{
  "result": [
    {
      "_id": "bjensen",
      "_rev": "0000000042b1dcd2"
    },
    {
      "_id": "scarter",
      "_rev": "000000009b54de8a"
    }
  ],
  ...
}

To ensure that the Admin UI works with the new REST context, also change the commonConstants.context property in the following file:

/path/to/openidm/ui/admin/default/org/forgerock/openidm/ui/common/util/Constants.js

Note

If you've set up a custom UI per "Customizing the Admin UI" and/or "Customizing the End User UI", the directory with the Constants.js file will vary.

Note that changing the REST context impacts the API Explorer, described in "API Explorer". If you want to use the API Explorer with the new REST context, change the baseUrl property in the following file:

/path/to/openidm/ui/api/default/index.html

Based on the change to the REST context earlier in this section, you'd set the following:

//base URL for accessing the OpenAPI JSON endpoint
var baseURL = '/example/';

7.4. Configuring the Server for Production

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

7.4.1. Configuring a Production Repository

By default, IDM installs an embedded ForgeRock Directory Services (DS) instance for use as its repository. This makes it easy to get started. Before you use IDM in production, you must replace the embedded DS repository with a supported repository. For more information, see "Selecting a Repository" in the Installation Guide.

For more information, see "Selecting a Repository" in the Installation Guide.

7.4.2. Disabling Automatic Configuration Updates

By default, IDM 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 for your project, and uncomment the following line:

# openidm.fileinstall.enabled=false

This setting also disables the file-based configuration view, which means that IDM reads its configuration only from the repository.

Before you disable automatic polling, you must have started the server at least once to ensure that the configuration has been loaded into the repository. Be aware, if automatic polling is enabled, IDM immediately uses changes to scripts called from a JSON configuration file.

When your configuration is complete, you can disable writes to configuration files. To do so, add the following line to the conf/config.properties file for your project:

felix.fileinstall.enableConfigSave=false

7.4.3. Communicating Through a Proxy Server

To set up IDM to communicate through a proxy server, you can use JVM parameters that identify the proxy host system, and the IDM port number.

If you've configured IDM behind a proxy server, include JVM properties from the following table, in the IDM startup script:

JVM Proxy Properties
JVM PropertyExample ValuesDescription
-Dhttps.proxyHostproxy.example.com, 192.168.0.1Hostname or IP address of the proxy server
-Dhttps.proxyPort8443, 9443Port number used by IDM

If an insecure port is acceptable, you can also use the -Dhttp.proxyHost and -Dhttp.proxyPort options. You can add these JVM proxy properties to the value of OPENIDM_OPTS in your startup script (startup.sh or startup.bat):

# Only set OPENIDM_OPTS if not already set
[ -z "$OPENIDM_OPTS" ] && OPENIDM_OPTS="-Xmx1024m -Xms1024m -Dhttps.proxyHost=localhost -Dhttps.proxyPort=8443"

7.5. Configuring the Server Over REST

IDM exposes configuration objects under the /openidm/config context path.

To list the configuration on the local host, perform a GET request on http://localhost:8080/openidm/config.

The following REST call includes excerpts of the default configuration for an IDM instance started with the sync-with-csv sample:

$ curl \
 --request GET \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 http://localhost:8080/openidm/config
{
  "_id": "",
  "configurations": [
    {
      "_id": "router",
      "pid": "router",
      "factoryPid": null
    },
    {
      "_id": "info/login",
      "pid": "info.f01fc3ed-5871-408d-a5f0-bef00ccc4c8f",
      "factoryPid": "info"
    },
    {
      "_id": "provisioner.openicf/csvfile",
      "pid": "provisioner.openicf.9009f4a1-ea47-4227-94e6-69c345864ba7",
      "factoryPid": "provisioner.openicf"
    },
    {
      "_id": "endpoint/usernotifications",
      "pid": "endpoint.e2751afc-d169-4a23-a88e-7211d340bccb",
      "factoryPid": "endpoint"
    },
    ...
  ]
}

Single instance configuration objects are located under openidm/config/object-name. The following example shows the audit configuration of the sync-with-csv. The output has been cropped for legibility:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 "http://localhost:8080/openidm/config/audit"
{
  "_id": "audit",
  "auditServiceConfig": {
    "handlerForQueries": "json",
    "availableAuditEventHandlers": [
      "org.forgerock.audit.handlers.csv.CsvAuditEventHandler",
      "org.forgerock.audit.handlers.elasticsearch.ElasticsearchAuditEventHandler",
      "org.forgerock.audit.handlers.jms.JmsAuditEventHandler",
      "org.forgerock.audit.handlers.json.JsonAuditEventHandler",
      "org.forgerock.audit.handlers.json.stdout.JsonStdoutAuditEventHandler",
      "org.forgerock.openidm.audit.impl.RepositoryAuditEventHandler",
      "org.forgerock.openidm.audit.impl.RouterAuditEventHandler",
      "org.forgerock.audit.handlers.splunk.SplunkAuditEventHandler",
      "org.forgerock.audit.handlers.syslog.SyslogAuditEventHandler"
    ],
    "filterPolicies": {
      "value": {
        "excludeIf": [
          "/access/http/request/cookies/&{com.iplanet.am.cookie.name}",
          "/access/http/request/cookies/session-jwt",
          "/access/http/request/headers/&{com.sun.identity.auth.cookieName}",
          "/access/http/request/headers/&{com.iplanet.am.cookie.name}",
          "/access/http/request/headers/accept-encoding",
          "/access/http/request/headers/accept-language",
          "/access/http/request/headers/Authorization",
          "/access/http/request/headers/cache-control",
          "/access/http/request/headers/connection",
          "/access/http/request/headers/content-length",
          "/access/http/request/headers/content-type",
          "/access/http/request/headers/proxy-authorization",
          "/access/http/request/headers/X-OpenAM-Password",
          "/access/http/request/headers/X-OpenIDM-Password",
          "/access/http/request/queryParameters/access_token",
          "/access/http/request/queryParameters/IDToken1",
          "/access/http/request/queryParameters/id_token_hint",
          "/access/http/request/queryParameters/Login.Token1",
          "/access/http/request/queryParameters/redirect_uri",
          "/access/http/request/queryParameters/requester",
          "/access/http/request/queryParameters/sessionUpgradeSSOTokenId",
          "/access/http/request/queryParameters/tokenId",
          "/access/http/response/headers/Authorization",
          "/access/http/response/headers/Set-Cookie",
          "/access/http/response/headers/X-OpenIDM-Password"
        ],
        "includeIf": []
      }
    },
    "caseInsensitiveFields": [
      "/access/http/request/headers",
      "/access/http/response/headers"
    ]
  },
  "eventHandlers": [
    {
      "class": "org.forgerock.audit.handlers.json.JsonAuditEventHandler",
      "config": {
        "name": "json",
        "logDirectory": "&{idm.data.dir}/audit",
        "buffering": {
          "maxSize": 100000,
          "writeInterval": "100 millis"
        },
        "topics": [
          "access",
          "activity",
          "recon",
          "sync",
          "authentication",
          "config"
        ]
      }
    }
    ...
  ],
  "eventTopics": {
    ...
  },
  "exceptionFormatter": {
    "type": "text/javascript",
    "file": "bin/defaults/script/audit/stacktraceFormatter.js"
  }
}  

Multiple instance configuration objects are found under openidm/config/object-name/instance-name.

The following example shows the configuration for the CSV connector shown in the sync-with-csv sample. The output has been cropped for legibility:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 "http://localhost:8080/openidm/config/provisioner.openicf/csvfile"
{
  "_id": "provisioner.openicf/csvfile",
  "connectorRef": {
    "bundleName": "org.forgerock.openicf.connectors.csvfile-connector",
    "bundleVersion": "[1.5.19.0,1.6.0.0)",
    "connectorName": "org.forgerock.openicf.csvfile.CSVFileConnector"
  },
  "poolConfigOption": {
    "maxObjects": 10,
    "maxIdle": 10,
    "maxWait": 150000,
    "minEvictableIdleTimeMillis": 120000,
    "minIdle": 1
  },
  "operationTimeout": {
    "CREATE": -1,
    "VALIDATE": -1,
    "TEST": -1,
    "SCRIPT_ON_CONNECTOR": -1,
    "SCHEMA": -1,
    "DELETE": -1,
    "UPDATE": -1,
    "SYNC": -1,
    "AUTHENTICATE": -1,
    "GET": -1,
    "SCRIPT_ON_RESOURCE": -1,
    "SEARCH": -1
  },
  "configurationProperties": {
    "csvFile": "&{idm.instance.dir}/data/csvConnectorData.csv"
  },
  "resultsHandlerConfig": {
    "enableAttributesToGetSearchResultsHandler": true
  },
  "syncFailureHandler": {
    "maxRetries": 5,
    "postRetryAction": "logged-ignore"
  },
  "objectTypes": {
    ...
  },
  "operationOptions": {}
}

You can change the configuration over REST by using an HTTP PUT or HTTP PATCH request to modify the required configuration object.

The following example uses a PUT request to modify the configuration of the scheduler service, increasing the maximum number of threads that are available for the concurrent execution of scheduled tasks:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request PUT \
 --data '{
    "threadPool": {
        "threadCount": 20
    },
    "scheduler": {
        "executePersistentSchedules": {"$bool" : "&{openidm.scheduler.execute.persistent.schedules}"
    }
}' \
 "http://localhost:8080/openidm/config/scheduler"
{
  "_id": "scheduler",
  "threadPool": {
    "threadCount": 20
  },
  "scheduler": {
    "executePersistentSchedules": {
      "$bool": "&{openidm.scheduler.execute.persistent.schedules}"
    }
  }
}

The following example uses a PATCH request to reset the number of threads to their original value.

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request PATCH \
 --data '[
    {
      "operation" : "replace",
      "field" : "/threadPool/threadCount",
      "value" : 10
    }
 ]' \
 "http://localhost:8080/openidm/config/scheduler"
{
  "_id": "scheduler",
  "threadPool": {
    "threadCount": 10
  },
  "scheduler": {
    "executePersistentSchedules": {
      "$bool": "&{openidm.scheduler.execute.persistent.schedules}"
    }
  }
}

Note

Multi-version concurrency control (MVCC) is not supported for configuration objects so you do not need to specify a revision during updates to the configuration, and no revision is returned in the output.

For more information about using the REST API to update objects, see "REST API Reference".

7.6. Using Property Value Substitution

In an environment where you have more than one IDM instance, you might require a configuration that is similar, but not identical, across the different instances.

Property value substitution lets you achieve the following:

  • Define a configuration that is specific to a single 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.

Property value substitution uses configuration expressions to introduce variables into the server configuration. You set configuration expressions as the values of configuration properties. The effective property values can be evaluated in a number of ways. For more information about property evaluation, see "Expression Evaluation and Order of Precedence".

Configuration expressions have the following characteristics:

  • To distinguish them from static values, configuration expressions are preceded by an ampersand and enclosed in braces. For example: &{openidm.port.http}. The configuration token in the example is openidm.port.http. The . serves as the separator character.

  • You can use a default value in a configuration expression by including it after a vertical bar following the token.

    For example, the following expression sets the default HTTP port value to 8080: &{openidm.port.http|8080}.

    With this configuration, the server attempts to substitute openidm.port.http with a defined configuration token. If no token definition is found, the server uses the default, 8080.

  • A configuration property can include a mix of static values and expressions.

    For example, suppose hostname is set to ds. Then &{hostname}.example.com evaluates to ds.example.com.

  • Configuration token evaluation is recursive.

    For example, suppose port is set to &{port.prefix}389, and port.prefix is set to 2. Then &{port} evaluates to 2389.

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

Important

Property substitution is not available for any configuration not processed by the IDM backend, such as ui-themeconfig or any user-supplied configuration.

7.6.1. Expression Evaluation and Order of Precedence

At server startup, expression resolvers evaluate property values to determine the effective configuration. You must define expression values before you start the IDM server that uses them.

When configuration tokens are resolved, the result is always a string. However, you can coerce the output type of the evaluated token to match the type that is required by the property. Ultimately, the expression must return the appropriate data type for the configuration property. For example, the port property takes an integer. If you set it using an expression, the result of the evaluated expression must be an integer. If the type is wrong, the server fails to start due to a syntax error. For more information about data type coercion, see "Transforming Data Types".

Expression resolvers can obtain values from the following sources:

  1. Environment variables

    You set an environment variable to hold the property value.

    For example: export OPENIDM_PORT_HTTP=8080

    The environment variable name must be composed of uppercase characters and underscores. The name maps to the expression token as follows:

    • Uppercase characters are lower cased.

    • Underscores, _, are replaced with . characters.

    In other words, the value of OPENIDM_PORT_HTTP replaces &{openidm.port.http} in the server configuration.

  2. Java system properties

    You set a Java system property to hold the value.

    Java system property names must match expression tokens exactly. In other words, the value of the openidm.repo.port system property replaces &{openidm.repo.port} in the server configuration.

    Java system properties can be set in a number of ways. One way of setting system properties for IDM servers is to pass them through the OPENIDM_OPTS environment variable.

    For example: export OPENIDM_OPTS="-Dopenidm.repo.port=3306"

    System properties can also be declared in your project's conf/system.properties.

    The following example uses property value substitution with a standard system property. The example modifies the audit configuration, changing the audit.json file to redirect JSON audit logs to the user's home directory. The user.home property is a default Java System property:

    "eventHandlers" : [
         {
             "class" : "org.forgerock.audit.handlers.json.JsonAuditEventHandler",
             "config" : {
                 "name" : "json",
                 "logDirectory" : "&{user.home}/audit",
                 ...
             }
         },
     ... 
  3. Expression files

    You set a key in a .json or .properties file to hold the value. To use an expression file, set the IDM_ENVCONFIG_DIRS environment variable, or the idm.envconfig.dirs Java system property as described below. By default, IDM sets idm.envconfig.dirs to &{idm.install.dir}/resolver/.

    The default property resolver file in IDM is resolver/boot.properties but you can specify additional files that might hold property values.

    Keys in .properties files must match expression tokens exactly. In other words, the value of the openidm.repo.port key replaces &{openidm.repo.port} in the server configuration.

    The following example expression properties file sets the repository port:

    openidm.repo.port=1389

    JSON expression files can contain nested objects.

    JSON field names map to expression tokens as follows:

    • The JSON path name matches the expression token.

    • The . character serves as the JSON path separator character.

    The following example JSON expression file uses property value substitution to set the host in the LDAP connector configuration:

    {
       "openidm" : {
         "provisioner" : {
           "ldap" : {
             "host" : "ds.example.com"
             }
           }
         }
       }
     }

    To substitute this value in the configuration, the LDAP provisioner file would include the following:

    {
       ...
       "configurationProperties" : {
         "host" : &{openidm.provisioner.ldap.host|localhost},
         ...
       }
     }

    If the server does not find a configuration token for the host name, it substitutes the default (localhost).

    To use expression files, set the environment variable, IDM_ENVCONFIG_DIRS, or the Java system property, idm.envconfig.dirs, to a comma-separated list of the directories containing the expression files.

    When reading these files, the server browses the directories in the order specified. It reads all the files with .json and .properties extensions, and attempts to use them to evaluate expression tokens.

    For example, if you define idm.envconfig.dirs=/directory1,/directory2 and a configuration token is defined in both directory1 and directory2, the resolved value will be the value defined in directory1. If the configuration token is defined only in directory2, the resolved value will be the value defined in directory2.

    Note the following constraints when using expression files:

    • Although IDM scans the directories in a specified order, within a directory IDM scans the files in a nondeterministic order.

    • IDM does not scan subdirectories.

    • Do not define the same configuration token more than once in a file.

      If you define the same property twice in the same file, one definition will be used and the other will be ignored. The server will not throw an error, but because files are scanned in a nondeterministic order, you have no way of knowing which value will be used.

    • You cannot define the same configuration token in more than one file in a single directory. The server generates an error in this case.

      Important

      This constraint implies that you cannot have backup .properties and .json files, in a single directory if they define the same tokens.

    • If the same token occurs once in several files that are located in different directories, IDM uses the first value that is read.

  4. Framework configuration properties

    You can use the conf/config.properties file to override values used by the OSGI framework.

  5. Configuration files

    All the properties declared in the .json files in your project's conf/ directory.

The preceding list reflects the order of precedence:

  • Environment variables override system properties, default token settings, and settings in expression files.

  • System properties override default token settings, and any settings in expression files.

  • Default token settings.

  • If IDM_ENVCONFIG_DIRS or idm.envconfig.dirs is set, the server uses the settings found in expression files.

  • Framework configuration properties

  • Hardcoded property values

7.6.2. Transforming Data Types

When configuration tokens are resolved, the result is always a string. However, you can transform the output type of the evaluated token to match the type that is required by the property.

The following example JSON expression file sets the value of the port in the LDAP connector configuration:

{
   "openidm" : {
     "provisioner" : {
       "ldap" : {
         "port" : 6389
       }
     }
   }
 }

When this expression is evaluated, the port would be evaluated as a string value, which would cause an error. To coerce the port value to an integer, you would substitute the value in the LDAP provisioner file as follows:

{
   ...
   "configurationProperties" : {
     "port" : {
       "$int" : "&{openidm.provisioner.ldap.port|1389}",
     ...
   }
 }

With this configuration, the server evaluates the LDAP port property to the integer 6389. If the server does not find a configuration token for the port, it substitutes the default (1389).

The following coercion types are supported:

  • integer ($int)

  • number ($number)

    This type can coerce integers, doubles, longs, and floats.

  • boolean ($bool)

  • array ($array)

  • object ($object)

    This type can coerce a JSON object such as an encrypted password.

  • decodeBase64 ($base64:decode)

    Transforms a base64-encoded string into a decoded string.

  • encodeBase64 ($base64:encode)

    Transforms a string into a base64-encoded string.

7.6.3. Limitations of Property Value Substitution

The work you've done to set up property value substitution is limited; different rules apply in the following areas:

7.6.3.1. Property Value Substitution in the Admin UI

Support for property value substitution in the Admin UI is limited to the following categories:

  • String substitution, where &{some.property|DefaultValue}

  • Number and integer substitution, including:

    • "$number" : "&{openidm.port|1234}"

    • "$int" : "&{openidm.port|5678}"

  • Base64 substitution, such as: "$base64:decode" : "&{openidm.felix.web.console.password|YWRtaW4=}"

  • Cryptographic substitution, where for passwords and client secrets, IDM substitutes "********" for $crypto

7.6.3.2. Property Value Substitution for Connectors

You cannot use property substitution for connector reference (connectorRef) properties. For example, the following configuration would not be valid:

"connectorRef" : {
    "connectorName" : "&{connectorName}",
    "bundleName" : "org.forgerock.openicf.connectors.ldap-connector",
    "bundleVersion" : "&{LDAP.BundleVersion}"
    ...
}

The "connectorName" must be the precise string from the connector configuration. If you need to specify multiple connector version numbers, use a range of versions, for example:

"connectorRef" : {
    "connectorName" : "org.identityconnectors.ldap.LdapConnector",
    "bundleName" : "org.forgerock.openicf.connectors.ldap-connector",
    "bundleVersion" : "[1.5.19.0,1.6.0.0)",
    ...
}

7.6.3.3. Property Value Substitution and the Repository

Configuration fields that use property substitution are stored in the repository as variables. You'll need to store the actual values of each variable in *.properties files.

You can use different *.properties files to vary the configuration for multiple nodes in a cluster.

The properties in the following table can be set through environment variables and more. They're evaluated during the IDM start process, as defined:

Configuration Property Variables
VariableDescriptionEnvironment VariablesSystem Variablesboot.properties
idm.install.dirDirectory of files from unpacked IDM binaryXXX
idm.data.dirWorking location directoryXXX
idm.instance.dirProject directory with IDM configuration filesXXX
idm.envconfig.dirsDirectory with environment files, including boot.propertiesXX

In contrast, configuration properties that are explicitly set in project-dir/conf/*.json files are stored in the repository. You can manage these configuration objects by using the REST interface or by using the JSON files themselves. Most aspects of the configuration can also be managed by using the Admin UI, as described in "Configuring the Server from the Admin UI".

You can access configuration properties in scripts using identityServer.getProperty(). For more information, see "The identityServer Variable".

7.7. Setting the Script Configuration

The script configuration file (conf/script.json) lets you modify the parameters that are used when compiling, debugging, and running JavaScript and Groovy scripts.

The default script.json file includes the following parameters:

properties

Any custom properties that should be provided to the script engine.

ECMAScript

Specifies JavaScript debug and compile options. JavaScript is an ECMAScript language.

  • javascript.debug - the JavaScript debugging configuration. By default this is set to the value of the openidm.script.javascript.debug property in IDM's resolver/boot.properties file.

  • javascript.recompile.minimumInterval - minimum time after which a script can be recompiled.

    The default value is 60000, or 60 seconds. This means that any changes made to scripts will not get picked up for up to 60 seconds. If you are developing scripts, reduce this parameter to around 100 (100 milliseconds).

    If you set the javascript.recompile.minimumInterval to -1, or remove this property from the script.json file, IDM does not poll JavaScript files to check for changes.

Groovy

Specifies compilation and debugging options related to Groovy scripts. Many of these options are commented out in the default script configuration file. Remove the comments to set these properties:

  • groovy.warnings - the log level for Groovy scripts. Possible values are none, likely, possible, and paranoia.

  • groovy.source.encoding - the encoding format for Groovy scripts. Possible values are UTF-8 and US-ASCII.

  • groovy.target.directory - the directory to which compiled Groovy classes will be output. The default directory is install-dir/classes.

  • groovy.target.bytecode - the bytecode version that is used to compile Groovy scripts. The default version is 1.5.

  • groovy.classpath - the directory in which the compiler should look for compiled classes. The default classpath is install-dir/lib.

    To call an external library from a Groovy script, you must specify the complete path to the .jar file or files, as a value of this property. For example:

    "groovy.classpath" : "/&{idm.install.dir}/lib/http-builder-0.7.1.jar:
             /&{idm.install.dir}/lib/json-lib-2.3-jdk15.jar:
             /&{idm.install.dir}/lib/xml-resolver-1.2.jar:
             /&{idm.install.dir}/lib/commons-collections-3.2.1.jar",

    Note

    If you're deploying on Microsoft Windows, use a semicolon (;) instead of a colon to separate directories in the groovy.classpath.

  • groovy.output.verbose - specifies the verbosity of stack traces. Boolean, true or false.

  • groovy.output.debug - specifies whether debugging messages are output. Boolean, true or false.

  • groovy.errors.tolerance - sets the number of non-fatal errors that can occur before a compilation is aborted. The default is 10 errors.

  • groovy.script.extension - specifies the file extension for Groovy scripts. The default is .groovy.

  • groovy.script.base - defines the base class for Groovy scripts. By default any class extends groovy.lang.Script.

  • groovy.recompile - indicates whether scripts can be recompiled. Boolean, true or false, with default true.

  • groovy.recompile.minimumInterval - sets the minimum time between which Groovy scripts can be recompiled.

    The default value is 60000, or 60 seconds. This means that any changes made to scripts will not get picked up for up to 60 seconds. If you are developing scripts, reduce this parameter to around 100 (100 milliseconds).

  • groovy.target.indy - specifies whether a Groovy indy test can be used. Boolean, true or false, with default true.

  • groovy.disabled.global.ast.transformations - specifies a list of disabled Abstract Syntax Transformations (ASTs).

sources

Specifies the locations in which IDM expects to find JavaScript and Groovy scripts that are referenced in the configuration.

The following excerpt of the script.json file shows the default locations:

...
"sources" : {
    "default" : {
        "directory" : "&{idm.install.dir}/bin/defaults/script"
    },
    "install" : {
        "directory" : "&{idm.install.dir}"
    },
    "project" : {
        "directory" : "&{idm.instance.dir}"
    },
    "project-script" : {
        "directory" : "&{idm.instance.dir}/script"
    }
...

Note

The order in which locations are listed in the sources property is important. Scripts are loaded from the bottom up in this list, that is, scripts found in the last location on the list are loaded first.

Note

By default, debug information (such as file name and line number) is excluded from JavaScript exceptions. To troubleshoot script exceptions, you can include debug information by changing the following setting to true in IDM's resolver/boot.properties file:

javascript.exception.debug.info=false

Including debug information in a production environment is not recommended.

7.8. Calling a Script From a Configuration File

You can call a script from within a configuration file by providing the script source, or by referencing a file that contains the script source. For example:

{
    "type" : "text/javascript",
    "source": string
} 

or

{
    "type" : "text/javascript",
    "file" : file location
} 
type

string, required

Specifies the type of script to be executed. Supported types include text/javascript, and groovy.

source

string, required if file is not specified

Specifies the source code of the script to be executed.

file

string, required if source is not specified

Specifies the file containing the source code of the script to execute.

The file path must be relative to the project-dir. Full file paths are not supported.

The following sample excerpts from configuration files indicate how scripts can be called.

The following example (included in the sync.json file) returns true if the employeeType is equal to external, otherwise returns false. This script can be useful during reconciliation to establish whether a target object should be included in the reconciliation process, or should be ignored:

"validTarget": {
    "type" : "text/javascript",
    "source": "target.employeeType == 'external'"
}  

The following example (included in the sync.json file) sets the __PASSWORD__ attribute to defaultpwd when IDM creates a target object:

"onCreate" : {
    "type" : "text/javascript",
    "source": "target.__PASSWORD__ = 'defaultpwd'"
} 

The following example (included in the router.json file) shows a trigger to create Solaris home directories using a script. The script is located in the file, project-dir/script/createUnixHomeDir.js:

{
    "filters" : [ {
        "pattern" : "^system/solaris/account$",
        "methods" : [ "create" ],
        "onResponse" : {
            "type" : "text/javascript",
            "file" : "script/createUnixHomeDir.js"
        }
    } ]
} 

Often, script files are reused in different contexts. You can pass variables to your scripts to provide these contextual details at runtime. You pass variables to the scripts that are referenced in configuration files by declaring the variable name in the script reference.

The following example of a scheduled task configuration calls a script named triggerEmailNotification.js. The example sets the sender and recipient of the email in the schedule configuration, rather than in the script itself:

{
    "enabled" : true,
    "type" : "cron",
    "schedule" : "0 0/1 * * * ?",
    "persisted" : true,
    "invokeService" : "script",
    "invokeContext" : {
        "script": {
            "type" : "text/javascript",
            "file" : "script/triggerEmailNotification.js",
            "fromSender" : "admin@example.com",
            "toEmail" : "user@example.com"
        }
    }
} 

Tip

In general, you should namespace variables passed into scripts with the globals map. Passing variables in this way prevents collisions with the top-level reserved words for script maps, such as file, source, and type. The following example uses the globals map to namespace the variables passed in the previous example.

"script": {
    "type" : "text/javascript",
    "file" : "script/triggerEmailNotification.js",
    "globals" : {
        "fromSender" : "admin@example.com",
        "toEmail" : "user@example.com"
    }
} 

Script variables are not necessarily simple key:value pairs. A script variable can be any arbitrarily complex JSON object.

7.9. Configuring HTTP Clients

Several IDM modules, such as the external REST service and identity provider service, need to make HTTP(S) requests to external systems.

HTTP client settings can be configured through any expression resolver (in resolver/boot.properties, environment variables, or Java system properties). Configuration for specific clients can be set in that client's JSON configuration file. For example conf/external.rest.json configures the external REST service and properties set there override the expression resolvers. For more information on property resolution, see "Expression Evaluation and Order of Precedence".

You can set the following properties for HTTP clients:

openidm.http.client.sslAlgorithm

The cipher to be used when making SSL/TLS connections, for example, AES, CBC, or PKCS5Padding. Defaults to the system SSL algorithm.

openidm.http.client.socketTimeout

The TCP socket timeout, in seconds, when waiting for HTTP responses. The default timeout is 10 seconds.

openidm.http.client.connectionTimeout

The TCP connection timeout for new HTTP connections, in seconds. The default timeout is 10 seconds.

openidm.http.client.reuseConnections (true or false)

Specifies whether HTTP connections should be kept alive and reused for additional requests. By default, connections will be reused if possible.

openidm.http.client.retryRequests (true or false)

Specifies whether requests should be retried if a failure is detected. By default requests will be retried.

openidm.http.client.maxConnections (integer)

The maximum number of connections that should be pooled by the HTTP client. At most 64 connections will be pooled by default.

openidm.http.client.hostnameVerifier (string)

Specifies whether the client should check that the hostname to which it has connected is allowed by the certificate that is presented by the server.

The property can take the following values:

  • STRICT - hostnames are validated

  • ALLOW_ALL - the external REST service does not attempt to match the URL hostname to the SSL certificate Common Name, as part of its validation process

If you do not set this property, the behavior is to validate hostnames (the equivalent of setting "hostnameVerifier": "STRICT"). In production environments, you should set this property to STRICT.

openidm.http.client.proxy.uri

Specifies that the client should make its HTTP(S) requests through the specified proxy server.

openidm.http.client.proxy.userName

The username of the account for the specified proxy.

openidm.http.client.proxy.password

The password of the account for the specified proxy.

openidm.http.client.proxy.useSystem (true or false)

If true>, specifies a system-wide proxy with the JVM system properties, http.proxyHost, http.proxyPort, and (optionally) http.nonProxyHosts.

If openidm.http.client.proxy.uri is set, and not empty, that setting overrides the system proxy setting.

Chapter 8. Accessing Data Objects

IDM supports a variety of objects that can be addressed via a URL or URI. You can access data objects by using scripts (through the Resource API) or by using direct HTTP calls (through the REST API).

The following sections describe these two methods of accessing data objects, and provide information on constructing and calling data queries.

8.1. Accessing Data Objects By Using Scripts

IDM's uniform programming model means that all objects are queried and manipulated in the same way, using the Resource API. The URL or URI that is used to identify the target object for an operation depends on the object type. For an explanation of object types, see "Data Models and Objects Reference". For more information about scripts and the objects available to scripts, see "Scripting Reference".

You can use the Resource API to obtain managed, system, configuration, and repository objects, as follows:

val = openidm.read("managed/organization/mysampleorg")
val = openidm.read("system/mysystem/account")
val = openidm.read("config/custom/mylookuptable")
val = openidm.read("repo/custom/mylookuptable")

For information about constructing an object ID, see "URI Scheme".

You can update entire objects with the update() function, as follows:

openidm.update("managed/organization/mysampleorg", rev, object)
openidm.update("system/mysystem/account", rev, object)

You can apply a partial update to a managed or system object by using the patch() function:

openidm.patch("managed/organization/mysampleorg", rev, value)

The create(), delete(), and query() functions work the same way.

8.2. Accessing Data Objects By Using the REST API

IDM provides RESTful access to data objects through the ForgeRock Common REST API. To access objects over REST, you can use a browser-based REST client, such as the Simple REST Client for Chrome, or RESTClient for Firefox. Alternatively you can use the curl command-line utility.

For a comprehensive overview of the REST API, see "REST API Reference".

To obtain a managed object through the REST API, depending on your security settings and authentication configuration, perform an HTTP GET on the corresponding URL, for example http://localhost:8080/openidm/managed/organization/mysampleorg.

By default, the HTTP GET returns a JSON representation of the object.

In general, you can map any HTTP request to the corresponding openidm.method call. The following example shows how the parameters provided in an openidm.query request correspond with the key-value pairs that you would include in a similar HTTP GET request:

Reading an object using the Resource API:

openidm.query("managed/user", { "_queryId": "query-all" }, ["userName","sn"])

Reading an object using the REST API:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user?_queryId=query-all&_fields=userName,sn"

8.3. Defining and Calling Queries

An advanced query model lets you define queries and to call them over the REST or Resource API. Three types of queries are supported, on both managed, and system objects:

  • Common filter expressions

  • Parameterized, or predefined queries

  • Native query expressions

Each of these mechanisms is discussed in the following sections.

Tip

For limits on queries in progressive profiling, see "Custom Progressive Profile Conditions".

8.3.1. Common Filter Expressions

The ForgeRock REST API defines common filter expressions that enable you to form arbitrary queries using a number of supported filter operations. This query capability is the standard way to query data if no predefined query exists, and is supported for all managed and system objects.

Common filter expressions are useful in that they do not require knowledge of how the object is stored and do not require additions to the repository configuration.

Common filter expressions are called with the _queryFilter keyword. The following example uses a common filter expression to retrieve managed user objects whose user name is Smith:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 'http://localhost:8080/openidm/managed/user?_queryFilter=userName+eq+"smith"'

The filter is URL encoded in this example. The corresponding filter using the resource API would be:

openidm.query("managed/user", { "_queryFilter" : '/userName eq "smith"' });

Note that, this JavaScript invocation is internal and is not subject to the same URL-encoding requirements that a GET request would be. Also, because JavaScript supports the use of single quotes, it is not necessary to escape the double quotes in this example.

For a list of supported filter operations, see "Constructing Queries".

Note

Using common filter expressions to retrieve values from arrays is currently not supported. If you need to search within an array, set up a predefined (parameterized) query in your repository configuration. For more information, see "Parameterized Queries".

8.3.2. Parameterized Queries

Managed objects in the supported repositories can be accessed using a parameterized query mechanism. Parameterized queries on repositories are defined in the repository configuration (repo.*.json) and are called by their _queryId.

Parameterized queries provide precise control over the query that is executed. Such control might be useful for tuning, or for performing database operations such as aggregation (which is not possible with a common filter expression.)

Parameterized queries provide security and portability for the query call signature, regardless of the backend implementation. Queries that are exposed over the REST interface must be parameterized queries to guard against injection attacks and other misuse. Queries on the officially supported repositories have been reviewed and hardened against injection attacks.

For system objects, support for parameterized queries is restricted to _queryId=query-all-ids. There is currently no support for user-defined parameterized queries on system objects. Typically, parameterized queries on system objects are not called directly over the REST interface, but are issued from internal calls, such as correlation queries.

A typical query definition is as follows:

"query-all-ids" : "SELECT objectid FROM ${_dbSchema}.${_table} LIMIT ${int:_pageSize} OFFSET ${int:_pagedResultsOffset}",

To call this query, you would reference its ID, as follows:

?_queryId=query-all-ids

The following example calls query-all-ids over the REST interface:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 "http://localhost:8080/openidm/managed/user?_queryId=query-all-ids"

Note

In repo.jdbc.json, the queries configuration object has a property, validInRelationshipQuery, which is an array specifying the query IDs of queries that make use of relationships. If you create additional queries that you expect to use as part of a relationship query, be sure to add the query ID to this array. If no query IDs are specified or the property is missing, relationship information will not be returned in query results, even if requested. For more information about relationships, see "Managing Relationships Between Objects".

8.3.3. Native Query Expressions

Native query expressions are supported for all managed objects and system objects, and can be called directly, rather than being defined in the repository configuration.

Native queries are intended specifically for internal callers, such as custom scripts, and should be used only in situations where the common filter or parameterized query facilities are insufficient. For example, native queries are useful if the query needs to be generated dynamically.

The query expression is specific to the target resource. For repositories, queries use the native language of the underlying data store. For system objects that are backed by ICF connectors, queries use the applicable query language of the system resource.

Important

Native query expressions are not supported with the default DS repository.

Native queries on the repository are made using the _queryExpression keyword. For example:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 "http://localhost:8080/openidm/managed/user?_queryExpression=select+*+from+managed_user"

Unless you have specifically enabled native queries over REST, the previous command returns a 403 access denied error message. Native queries are not portable and do not guard against injection attacks. Such query expressions should therefore not be used or made accessible over the REST interface or over HTTP in production environments. They should be used only via the internal Resource API. If you want to enable native queries over REST for development, see "Protecting Sensitive REST Interface URLs".

Alternatively, if you really need to expose native queries over HTTP, in a selective manner, you can design a custom endpoint to wrap such access.

8.3.4. Constructing Queries

The openidm.query function lets you query managed and system objects. The query syntax is openidm.query(id, params), where id specifies the object on which the query should be performed and params provides the parameters that are passed to the query, either _queryFilter or _queryId. For example:

var params = {
    '_queryFilter' : 'givenName co "' + sourceCriteria + '" or ' + 'sn co "' + sourceCriteria + '"'
};
var results = openidm.query("system/ScriptedSQL/account", params)

Over the REST interface, the query filter is specified as _queryFilter=filter, for example:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=userName+eq+"Smith"'

Note the use of double-quotes around the search term: Smith. In _queryFilter expressions, string values must use double-quotes. Numeric and boolean expressions should not use quotes.

When called over REST, you must URL encode the filter expression. The following examples show the filter expressions using the resource API and the REST API, but do not show the URL encoding, to make them easier to read.

Note that, for generic mappings, any fields that are included in the query filter (for example userName in the previous query), must be explicitly defined as searchable, if you have set the global searchableDefault to false. For more information, see "Improving Generic Mapping Search Performance (JDBC)".

The filter expression is constructed from the building blocks shown in this section. In these expressions the simplest json-pointer is a field of the JSON resource, such as userName or id. A JSON pointer can, however, point to nested elements.

Note

You can also use the negation operator (!) in query construction. For example, a _queryFilter=!(userName+eq+"jdoe") query would return every userName except for jdoe.

You can set up query filters with the following expression types:

8.3.4.1. Comparison Expressions

Note

Certain system endpoints also support EndsWith and ContainsAllValues queries. However, such queries are not supported for managed objects and have not been tested with all supported ICF connectors.

8.3.4.1.1. Querying Objects That Equal a Specified Value

This is the associated JSON comparison expression: json-pointer eq json-value.

Consider the following example:

"_queryFilter" : '/givenName eq "Dan"'

The following REST call returns the user name and given name of all managed users whose first name (givenName) is "Dan":

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=givenName+eq+"Dan"&_fields=userName,givenName'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 3,
  "result": [
    {
      "givenName": "Dan",
      "userName": "dlangdon"
    },
    {
      "givenName": "Dan",
      "userName": "dcope"
    },
    {
      "givenName": "Dan",
      "userName": "dlanoway"
    }
}
8.3.4.1.2. Querying Objects That Contain a Specified Value

This is the associated JSON comparison expression: json-pointer co json-value.

Consider the following example:

"_queryFilter" : '/givenName co "Da"'

The following REST call returns the user name and given name of all managed users whose first name (givenName) contains "Da":

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=givenName+co+"Da"&_fields=userName,givenName'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 10,
  "result": [
    {
      "givenName": "Dave",
      "userName": "djensen"
    },
    {
      "givenName": "David",
      "userName": "dakers"
    },
    {
      "givenName": "Dan",
      "userName": "dlangdon"
    },
    {
      "givenName": "Dan",
      "userName": "dcope"
    },
    {
      "givenName": "Dan",
      "userName": "dlanoway"
    },
    {
      "givenName": "Daniel",
      "userName": "dsmith"
    },
...
}
8.3.4.1.3. Querying Objects That Start With a Specified Value

This is the associated JSON comparison expression: json-pointer sw json-value.

Consider the following example:

"_queryFilter" : '/sn sw "Jen"'

The following REST call returns the user names of all managed users whose last name (sn) starts with "Jen":

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=sn+sw+"Jen"&_fields=userName'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 4,
  "result": [
    {
      "userName": "bjensen"
    },
    {
      "userName": "djensen"
    },
    {
      "userName": "cjenkins"
    },
    {
      "userName": "mjennings"
    }
  ]
}
8.3.4.1.4. Querying Objects That Are Less Than a Specified Value

This is the associated JSON comparison expression: json-pointer lt json-value.

Consider the following example:

"_queryFilter" : '/employeeNumber lt 5000'

The following REST call returns the user names of all managed users whose employeeNumber is lower than 5000:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=employeeNumber+lt+5000&_fields=userName,employeeNumber'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 4999,
  "result": [
    {
      "employeeNumber": 4907,
      "userName": "jnorris"
    },
    {
      "employeeNumber": 4905,
      "userName": "afrancis"
    },
    {
      "employeeNumber": 3095,
      "userName": "twhite"
    },
    {
      "employeeNumber": 3921,
      "userName": "abasson"
    },
    {
      "employeeNumber": 2892,
      "userName": "dcarter"
    }
...
  ]
}
8.3.4.1.5. Querying Objects That Are Less Than or Equal to a Specified Value

This is the associated JSON comparison expression: json-pointer le json-value.

Consider the following example:

"_queryFilter" : '/employeeNumber le 5000'

The following REST call returns the user names of all managed users whose employeeNumber is 5000 or less:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=employeeNumber+le+5000&_fields=userName,employeeNumber'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 5000,
  "result": [
    {
      "employeeNumber": 4907,
      "userName": "jnorris"
    },
    {
      "employeeNumber": 4905,
      "userName": "afrancis"
    },
    {
      "employeeNumber": 3095,
      "userName": "twhite"
    },
    {
      "employeeNumber": 3921,
      "userName": "abasson"
    },
    {
      "employeeNumber": 2892,
      "userName": "dcarter"
    }
...
  ]
}
8.3.4.1.6. Querying Objects That Are Greater Than a Specified Value

This is the associated JSON comparison expression: json-pointer gt json-value

Consider the following example:

"_queryFilter" : '/employeeNumber gt 5000'

The following REST call returns the user names of all managed users whose employeeNumber is higher than 5000:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=employeeNumber+gt+5000&_fields=userName,employeeNumber'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 1458,
  "result": [
    {
      "employeeNumber": 5003,
      "userName": "agilder"
    },
    {
      "employeeNumber": 5011,
      "userName": "bsmith"
    },
    {
      "employeeNumber": 5034,
      "userName": "bjensen"
    },
    {
      "employeeNumber": 5027,
      "userName": "cclarke"
    },
    {
      "employeeNumber": 5033,
      "userName": "scarter"
    }
...
  ]
}
8.3.4.1.7. Querying Objects That Are Greater Than or Equal to a Specified Value

This is the associated JSON comparison expression: json-pointer ge json-value.

Consider the following example:

"_queryFilter" : '/employeeNumber ge 5000'

The following REST call returns the user names of all managed users whose employeeNumber is 5000 or greater:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=employeeNumber+ge+5000&_fields=userName,employeeNumber'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 1457,
  "result": [
    {
      "employeeNumber": 5000,
      "userName": "agilder"
    },
    {
      "employeeNumber": 5011,
      "userName": "bsmith"
    },
    {
      "employeeNumber": 5034,
      "userName": "bjensen"
    },
    {
      "employeeNumber": 5027,
      "userName": "cclarke"
    },
    {
      "employeeNumber": 5033,
      "userName": "scarter"
    }
...
  ]
}

8.3.4.2. Presence Expressions

The following examples show how you can build filters using a presence expression, shown as pr. The presence expression is a filter that returns all records with a given attribute.

A presence expression filter evaluates to true when a json-pointer pr matches any object in which the json-pointer is present, and contains a non-null value. Consider the following expression:

"_queryFilter" : '/mail pr'

The following REST call uses that expression to return the mail addresses for all managed users with a mail property:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=mail+pr&_fields=mail'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 2,
  "result": [
    {
      "mail": "jdoe@exampleAD.com"
    },
    {
      "mail": "bjensen@example.com"
    }
  ]
}

Depending on the connector, you can apply the presence filter on system objects. The following query returns the email address of all users in a CSV file who have the email attribute in their entries:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/system/csvfile/account?_queryFilter=email+pr&_fields=email'
{
  "result": [
    {
      "_id": "bjensen",
      "email": "bjensen@example.com"
    },
    {
      "_id": "scarter",
      "email": "scarter@example.com"
    }
  ],
  "resultCount": 2,
  "pagedResultsCookie": "MA%3D%3D",
  "totalPagedResultsPolicy": "NONE",
  "totalPagedResults": -1,
  "remainingPagedResults": -1
}

Not all connectors support the presence filter. In most cases, you can replicate the behavior of the presence filter with an "equals" (eq) query such as _queryFilter=email+eq"*"

8.3.4.3. Literal Expressions

A literal expression is a boolean:

  • true matches any object in the resource.

  • false matches no object in the resource.

For example, you can list the _id of all managed objects as follows:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=true&_fields=_id'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 2,
  "result": [
    {
      "_id": "d2e29d5f-0d74-4d04-bcfe-b1daf508ad7c"
    },
    {
      "_id": "709fed03-897b-4ff0-8a59-6faaa34e3af6"
    }
  ]
}
    

8.3.4.4. Complex Expressions

You can combine expressions using the boolean operators and, or, and ! (not). The following example queries managed user objects located in London, with last name Jensen:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user/?_queryFilter=city+eq+"London"+and+sn+eq+"Jensen"&_fields=userName,givenName,sn'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 3,
  "result": [
    {
      "sn": "Jensen",
      "givenName": "Clive",
      "userName": "cjensen"
    },
    {
      "sn": "Jensen",
      "givenName": "Dave",
      "userName": "djensen"
    },
    {
      "sn": "Jensen",
      "givenName": "Margaret",
      "userName": "mjensen"
    }
  ]
}

8.3.5. Paging Query Results

The common filter query mechanism supports paged query results for managed objects, and for some system objects, depending on the system resource. There are two ways to page objects in a query:

  • Using a cookie based on the value of a specified sort key.

  • Using an offset that specifies how many records should be skipped before the first result is returned.

These methods are implemented with the following query parameters:

_pagedResultsCookie

Opaque cookie used by the server to keep track of the position in the search results. The format of the cookie is a base-64 encoded version of the value of the unique sort key property. The value of the returned cookie is URL-encoded to prevent values such as + from being incorrectly translated.

You cannot page results without sorting them (using the _sortKeys parameter). If you do not specify a sort key, the _id of the record is used as the default sort key. At least one of the specified sort key properties must be a unique value property, such as _id.

Tip

For paged searches on generic mappings with the default DS repository, you should sort on the _id property, as this is the only property that is stored outside of the JSON blob. If you sort on something other than _id, the search will incur a performance hit because IDM effectively has to pull the entire result set, and then sort it.

The server provides the cookie value on the first request. You should then supply the cookie value in subsequent requests until the server returns a null cookie, meaning that the final page of results has been returned.

The _pagedResultsCookie parameter is supported only for filtered queries, that is, when used with the _queryFilter parameter. You cannot use the _pagedResultsCookie with a _queryExpression or a _queryId.

The _pagedResultsCookie and _pagedResultsOffset parameters are mutually exclusive, and cannot be used together.

Paged results are enabled only if the _pageSize is a non-zero integer.

_pagedResultsOffset

Specifies the index within the result set of the number of records to be skipped before the first result is returned. The format of the _pagedResultsOffset is an integer value. When the value of _pagedResultsOffset is greater than or equal to 1, the server returns pages, starting after the specified index.

This request assumes that the _pageSize is set, and not equal to zero.

For example, if the result set includes 10 records, the _pageSize is 2, and the _pagedResultsOffset is 6, the server skips the first 6 records, then returns 2 records, 7 and 8. The _remainingPagedResults value would be 2, the last two records (9 and 10) that have not yet been returned.

If the offset points to a page beyond the last of the search results, the result set returned is empty.

_pageSize

An optional parameter indicating that query results should be returned in pages of the specified size. For all paged result requests other than the initial request, a cookie should be provided with the query request.

The default behavior is not to return paged query results. If set, this parameter should be an integer value, greater than zero.

When a _pageSize is specified, and non-zero, the server calculates the totalPagedResults, in accordance with the totalPagedResultsPolicy, and provides the value as part of the response. If a count policy is specified (_totalPagedResultsPolicy=EXACT, The totalPagedResults returns the total result count. If no count policy is specified in the query, or if _totalPagedResultsPolicy=NONE, result counting is disabled, and the server returns a value of -1 for totalPagedResults. The following example shows a query that requests two results with a totalPagedResultsPolicy of EXACT:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user?_queryFilter=true&_pageSize=2&_totalPagedResultsPolicy=EXACT"
{
  "result": [
    {
      "_id": "adonnelly",
      "_rev": "0",
      "userName": "adonnelly",
      "givenName": "Abigail",
      "sn": "Donnelly",
      "telephoneNumber": "12345678",
      "active": "true",
      "mail": "adonnelly@example.com",
      "accountStatus": "active",
      "effectiveRoles": [],
      "effectiveAssignments": []
    },
    {
      "_id": "bjensen",
      "_rev": "0",
      "userName": "bjensen",
      "givenName": "Babs",
      "sn": "Jensen",
      "telephoneNumber": "12345678",
      "active": "true",
      "mail": "bjensen@example.com",
      "accountStatus": "active",
      "effectiveRoles": [],
      "effectiveAssignments": []
    }
  ],
  "resultCount": 2,
  "pagedResultsCookie": "eyIvX2lkIjoiYm11cnJheSJ9",
  "totalPagedResultsPolicy": "EXACT",
  "totalPagedResults": 22,
  "remainingPagedResults": -1
}

The totalPagedResults and _remainingPagedResults parameters are not supported for all queries. Where they are not supported, their returned value is always -1. In addition, counting query results using these parameters is not currently supported for a ForgeRock Directory Services (DS) repository.

Requesting the total result count (with _totalPagedResultsPolicy=EXACT) incurs a performance cost on the query.

Queries that return large data sets will have a significant impact on heap requirements, particularly if they are run in parallel with other large data requests. To avoid out of memory errors, analyze your data requirements, set the heap configuration appropriately, and modify access controls to restrict requests on large data sets.

8.3.6. Sorting Query Results

For common filter query expressions, you can sort the results of a query using the _sortKeys parameter. This parameter takes a comma-separated list as a value and orders the way in which the JSON result is returned, based on this list.

The _sortKeys parameter is not supported for predefined queries.

Note

When using DS as a repo, pagination using _pageSize is recommended if you intend to use _sortKeys. If you do not plan to paginate your query, the data you are querying must at least be indexed in DS. For more information about how to set up indexes in DS, see Indexing Attribute Values in the DS Administration Guide.

The following query returns all users with the givenName Dan, and sorts the results alphabetically, according to surname (sn):

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/system/ldap/account?_queryFilter=givenName+eq+"Dan"&_fields=givenName,sn&_sortKeys=sn'
{
  "remainingPagedResults": -1,
  "pagedResultsCookie": null,
  "resultCount": 3,
  "result": [
    {
      "sn": "Cope",
      "givenName": "Dan"
    },
    {
      "sn": "Langdon",
      "givenName": "Dan"
    },
    {
      "sn": "Lanoway",
      "givenName": "Dan"
    }
  ]
}   

8.3.7. Recalculating Virtual Property Values in Queries

For managed objects IDM includes an onRetrieve script hook that lets you recalculate property values when an object is retrieved as the result of a query. To use the onRetrieve trigger, the query must include the executeOnRetrieve parameter, for example:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 'http://localhost:8080/openidm/managed/user?_queryFilter=sn+eq+"Jensen"&executeOnRetrieve=true'

If a query includes executeOnRetrieve, the query recalculates virtual property values, based on the current state of the system. The result of the query will be the same as a read on a specific object, because reads always recalculate virtual property values.

If a query does not include executeOnRetrieve, the query returns the virtual properties of an object, based on the value that is persisted in the repository. Virtual property values are not recalculated.

For performance reasons, executeOnRetrieve is false by default.

8.4. Uploading Files to the Server

IDM provides a generic file upload service that lets you upload and save files either to the filesystem or to the repository. The service uses the multipart/form-data Content-Type to accept file content, store it, and return that content when it is called over the REST interface.

To configure the file upload service, add one or more file-description.json files to your project's conf directory, where description provides an indication of the purpose of the upload service. For example, you might create a file-images.json configuration file to handle uploading image files. Each file upload configuration file sets up a separate instance of the upload service. The description in the filename also specifies the endpoint at which the file service will be accessible over REST. In the previous example, file-images.json, the service would be accessible at the endpoint openidm/file/images.

A sample file upload service configuration file is available in the /path/to/openidm/samples/example-configurations/conf directory. The configuration is as follows:

{
    "enabled" : true,
    "fileHandler" : {
    "type" : file handler type,
    "root" : directory
    }
}

The service supports two file handlersfile and repo. The file handlers are configured as follows:

  • "type" : "file" specifies that the uploaded content will be stored in the filesystem. If you use the file type, you must specify a root property to indicate the directory (relative to the IDM installation directory) in which uploaded content is stored. In the following example, uploaded content is stored in the /path/to/openidm/images directory:

    {
        "enabled" : true,
        "fileHandler" : {
            "type" : "file",
            "root" : "images"
        }
    }

    You cannot use the file upload service to access any files outside the configured root directory.

  • "type" : "repo" specifies that the uploaded content will be stored in the repository. The root property does not apply to the repository file handler so the configuration is as follows:

    {
        "enabled" : true,
        "fileHandler" : {
            "type" : "repo"
        }
    }

The file upload service performs a multi-part CREATE operation. Each upload request includes two --form options. The first option indicates that the uploaded file content will be converted to a base 64-encoded string and inserted into the JSON object as a field named content with the following structure:

{
    "content" : {
        "$ref" : "cid:filename#content"
    }
}

The second --form option specifies the file to be uploaded, and the file type. The request loads the entire file into memory, so file size will be constrained by available memory.

You can upload any mime type using this service, however, you must specify a whitelist of mime types that can be retrieved over REST. If you specify a mime type that is not in the whitelist during retrieval of the file, the response content defaults to application/json. To configure the list of supported mime types, specify a comma-separated list as the value of the org.forgerock.json.resource.http.safemimetypes property in the conf/system.properties file. For example:

org.forgerock.json.resource.http.safemimetypes=application/json,application/pkix-cert,application/x-pem-file

You can only select from the following list:

image/*
text/plain
text/css
application/json
application/pkix-cert
application/x-pem-file

The following request uploads an image (PNG) file named test.png to the filesystem. The file handler configuration file provides the REST endpoint. In this case openidm/file/images references the configuration in the file-images.json file:

curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --form 'json={"content" : {"$ref" : "cid:test#content"}};type=application/json' \
 --form 'test=@test.png;type=image/png' \
 --request PUT \
 "http://localhost:8080/openidm/file/images/test.png"
{
  "_id": "test.png",
  "content": "aW1hZ2UvcG5n"
}

Note that the resource ID is derived directly from the upload filename—system-generated IDs are not supported.

The following request uploads a stylesheet (css) file named test.css to the same location on the filesystem as the previous request:

curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --form 'json={"content" : {"$ref" : "cid:test#content"}};type=application/json' \
 --form '@test.css;type=text/css' \
 --request PUT \
 "http://localhost:8080/openidm/file/images/test.css"
{
  "_id": "test.css",
  "content": "aW1hZ2UvY3N2"
}

Files uploaded to the repository are stored as JSON objects in the openidm.files table. The following request uploads the same image (PNG) file (test.png) to the repository:

curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --form 'json={"content" : {"$ref" : "cid:test#content"}};type=application/json' \
 --form 'test=@test.png;type=image/png' \
 --request PUT \
 "http://localhost:8080/openidm/file/repo/test.png"
{
  "_id": "test.png",
  "_rev": "00000000970b4454",
  "content": "aW1hZ2UvcG5n"
}

Note that the preceding example assumes the following file upload service configuration (in file-repo.json:

{
    "enabled" : true,
    "fileHandler" : {
        "type" : "repo"
    }
}

The file type is not stored with the file. By default, a READ on uploaded file content returns the content as a base 64-encoded string within the JSON object. For example:

curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/file/repo/test.png"
{
  "_id": "test.png",
  "_rev": "00000000970b4454",
  "content": "aW1hZ2UvcG5n"
}

Your client can retrieve the file in the correct format by specifying the content and mimeType parameters in the read request. For example:

curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/file/repo/test.css?_fields=content&_mimeType=text/css"

To delete uploaded content, send a DELETE request as follows:

curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request DELETE \
 "http://localhost:8080/openidm/file/repo/test.png"
{
  "_id": "test.png",
  "_rev": "00000000970b4454",
  "content": "aW1hZ2UvcG5n"
}

Chapter 9. Working With Managed Objects

IDM provides a default schema for typical managed object types, such as users and roles, but does not control the structure of objects that you store in the repository. You can modify or extend the schema for the default object types, and you can set up a new managed object type for any item that can be collected in a data set. For example, with the right schema, you can set up any device associated with the Internet of Things (IoT).

This chapter describes how to work with the default managed object types and how to create new object types as required by your deployment. For more information about the IDM object model, see "Data Models and Objects Reference".

9.1. Defining the Managed Object Schema

Managed objects and their properties are defined in your project's conf/managed.json file. The schema defined in this file is not a comprehensive list of all the properties that can be stored in the managed object repository. If you use a generic object mapping, you can create a managed object with any arbitrary property, and that property will be stored in the repository. However, if you create an object with properties that are not defined in conf/managed.json, those properties will not be visible in the UI. In addition, you will not be able configure the "sub-properties" that are described in the following section.

Important

The IDM Admin UI depends on the presence of specific core schema elements, such as users, roles, and assignments (and the default properties nested within them). If you remove such schema elements, and you use the Admin UI to configure IDM, you must modify the Admin UI code accordingly. For example, if you remove the entire assignment object from conf/managed.json, the UI will throw exceptions wherever it queries this schema element.

For explicit object mappings, the schema must be mapped to tables and columns in the JDBC database or to organizational units in DS.

For more information about explicit and generic object mappings, see "Using Generic and Explicit Object Mappings".

9.2. Creating and Modifying Managed Object Types

If the managed object types provided in the default configuration are not sufficient for your deployment, you can create any number of new managed object types.

The easiest way to create a new managed object type is to use the Admin UI, as follows:

  1. Navigate to the Admin UI URL (https://localhost:8443/admin) then select Configure > Managed Objects > New Managed Object.

  2. Enter a name and readable title for the new managed object. The readable title controls how that object will be referred to in the UI. Optionally, specify an icon that will be displayed for that object type, and a description.

    Click Save.

  3. On the Properties tab, specify the schema for the object type, that is, the properties that make up the object.

  4. On the Scripts tab, specify any scripts that should be applied on various events associated with that object type, for example, when an object of that type is created, updated or deleted.

You can also create a new managed object type by adding its configuration, in JSON, to your project's conf/managed.json file. The following excerpt of the managed.json file shows the configuration of a "Phone" object, that was created through the UI.

{
    "name": "Phone",
    "schema": {
        "$schema": "http://forgerock.org/json-schema#",
        "type": "object",
        "properties": {
            "brand": {
                "description": "The supplier of the mobile phone",
                "title": "Brand",
                "viewable": true,
                "searchable": true,
                "userEditable": false,
                "policies": [],
                "returnByDefault": false,
                "minLength": "",
                "pattern": "",
                "isVirtual": false,
                "type": [
                    "string",
                    "null"
                ]
            },
            "assetNumber": {
                "description": "The asset tag number of the mobile device",
                "title": "Asset Number",
                "viewable": true,
                "searchable": true,
                "userEditable": false,
                "policies": [],
                "returnByDefault": false,
                "minLength": "",
                "pattern": "",
                "isVirtual": false,
                "type": "string"
            },
            "model": {
                "description": "The model number of the mobile device, such as 6 plus, Galaxy S4",
                "title": "Model",
                "viewable": true,
                "searchable": false,
                "userEditable": false,
                "policies": [],
                "returnByDefault": false,
                "minLength": "",
                "pattern": "",
                "isVirtual": false,
                "type": "string"
            }
        },
        "required": [],
        "order": [
            "brand",
            "assetNumber",
            "model"
        ]
    }
}

Every managed object type has a name and a schema that describes the properties associated with that object. The managed object name can only include the characters a-z, A-Z, 0-9, and _ (underscore).

You can add any arbitrary properties to the schema of a managed object type. A property definition typically includes the following fields:

title

The name of the property, in human-readable language, used to display the property in the UI.

description

A brief description of the property.

viewable

Specifies whether this property is viewable in the object's profile in the UI. Boolean, true or false (true by default).

searchable

Specifies whether this property can be searched in the UI. A searchable property is visible within the Managed Object data grid in the End User UI. Note that for a property to be searchable in the UI, it must be indexed in the repository configuration. For information on indexing properties in a repository, see "Using Generic and Explicit Object Mappings".

Boolean, true or false (false by default).

userEditable

Specifies whether users can edit the property value in the UI. This property applies in the context of the End User UI, where users are able to edit certain properties of their own accounts. Boolean, true or false (false by default).

isProtected

Specifies whether reauthentication is required if the value of this property changes.

For certain properties, such as passwords, changing the value of the property should force an end user to reauthenticate. These properties are referred to as protected properties. Depending on how the user authenticates (which authentication module is used), the list of protected properties is added to the user's security context. For example, if a user logs in with the login and password of their managed user entry (MANAGED_USER authentication module), their security context will include this list of protected properties. The list of protected properties is not included in the security context if the user logs in with a module that does not support reauthentication (such as through a social identity provider).

minLength

The minimum number of characters that the value of this property must have.

pattern

Any specific pattern to which the value of the property must adhere. For example, a property whose value is a date might require a specific date format.

policies

Any policy validation that must be applied to the property. For more information on managed object policies, see "Configuring the Default Policy for Managed Objects".

required

Specifies whether the property must be supplied when an object of this type is created. Boolean, true or false.

Important

The required policy is assessed only during object creation, not when an object is updated. You can effectively bypass the policy by updating the object and supplying an empty value for that property. To prevent this inconsistency, set both required and notEmpty to true for required properties. This configuration indicates that the property must exist, and must have a value.

type

The data type for the property value; can be string, array, boolean, integer, number, object, Resource Collection, or null.

Note

If a property (such as a telephoneNumber) might not exist for a particular user, you must include null as one of the property types. You can set a null property type in the Admin UI (Configure > Managed Objects > User, select the property, and under the Details tab, Advanced Options, set Nullable to true).

You can also set a null property type directly in your managed.json file by setting "type" : '[ "string","null" ]' for that property (where string can be any other valid property type. This information is validated by the policy.js script, as described in "Validation of Managed Object Data Types".

If you're configuring a data type of array through the Admin UI, you're limited to two values.

isVirtual

Specifies whether the property takes a static value, or whether its value is calculated "on the fly" as the result of a script. Boolean, true or false.

returnByDefault

For non-core attributes (virtual attributes and relationship fields), specifies whether the property will be returned in the results of a query on an object of this type if it is not explicitly requested. Virtual attributes and relationship fields are not returned by default. Boolean, true or false. When the property is in an array within a relationship, always set to false.

relationshipGrantTemporalConstraintsEnforced

For attributes with relationship fields. Specifies whether this relationship should have temporal constraints enforced. Boolean, true or false. For more information about temporal constraints, see "Using Temporal Constraints to Restrict Effective Roles".

9.3. Working with Managed Users

User objects that are stored in the repository are referred to as managed users. For a JDBC repository, IDM stores managed users in the managedobjects table. A second table, managedobjectproperties, serves as the index table.

IDM provides RESTful access to managed users, at the context path /openidm/managed/user. For more information, see "Getting Started With the REST Interface" in the Installation Guide.

You can add, change, and delete managed users by using the Admin UI or over the REST interface. To use the Admin UI, select Manage > User. The UI is intuitive as regards user management.

If you are viewing users through the Admin UI, the User List page supports specialized filtering with the Advanced Filter option, which allows you to build many of the queries shown in "Defining and Calling Queries".

The following examples show how to add, change and delete users over the REST interface. For a reference of all managed user endpoints and actions, see "Managing Users Over REST". You can also use the API Explorer as a reference to the managed object REST API. For more information, see "API Explorer".

The following example retrieves the JSON representation of all managed users in the repository:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"http://localhost:8080/openidm/managed/user?_queryId=query-all-ids"

The following two examples query all managed users for a user named scarter:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
 "http://localhost:8080/openidm/managed/user?_queryFilter=userName+eq+%22scarter%22"

In this second example, note the use of single quotes around the URL, to avoid conflicts with the double quotes around the user named smith. Note also that the _queryFilter requires double quotes (or the URL encoded equivalent %22) around the search term:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
'http://localhost:8080/openidm/managed/user?_queryFilter=userName+eq+"scarter"'

The following example retrieves the JSON representation of a managed user, specified by his ID, scarter:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/scarter"

Note

Some of the examples in this documentation set use client-assigned IDs (such as bjensen and scarter) when creating objects because it makes the examples easier to read. If you create objects using the Admin UI, they are created with server-assigned IDs (such as 55ef0a75-f261-47e9-a72b-f5c61c32d339). Generally, immutable server-assigned UUIDs are used in production environments.

The following example adds a user with a specific user ID, bjensen:

$ curl \
 --header "Content-Type: application/json" \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "If-None-Match: *" \
 --request PUT \
 --data '{
    "userName":"bjensen",
    "sn":"Jensen",
    "givenName":"Barbara",
    "mail": "bjensen@example.com",
    "telephoneNumber": "082082082",
    "password":"Passw0rd"
  }' \
"http://localhost:8080/openidm/managed/user/bjensen"

The following example adds the same user, but allows IDM to generate the ID:

$ curl \
 --header "Content-Type: application/json" \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request POST \
 --data '{
    "userName":"bjensen",
    "sn":"Jensen",
    "givenName":"Barbara",
    "mail": "bjensen@example.com",
    "telephoneNumber": "082082082",
    "password":"Passw0rd"
  }' \
"http://localhost:8080/openidm/managed/user?_action=create"

The following example checks whether user bjensen exists, then replaces her telephone number with the new data provided in the request body:

$ curl \
 --header "Content-Type: application/json" \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request POST \
 --data '[{
  "operation":"replace",
  "field":"/telephoneNumber",
  "value":"1234567"
  }]' \
  "http://localhost:8080/openidm/managed/user?_action=patch&_queryId=for-userName&uid=bjensen"

The following example deletes user bjensen:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request DELETE \
 "http://localhost:8080/openidm/managed/user/bjensen"

9.4. Working With Managed Groups

IDM provides support for a managed group object. For a JDBC repository, IDM stores managed groups with all other managed objects, in the managedobjects table, and uses the managedobjectproperties for indexing.

The managed group object is not provided by default. To use managed groups, add an object similar to the following to your conf/managed.json file:

{
   "name" : "group"
},  

With this addition, IDM provides RESTful access to managed groups, at the context path /openidm/managed/group.

For an example of a deployment that uses managed groups, see "Synchronizing LDAP Groups" in the Samples Guide.

9.5. Tracking Metadata For Managed Objects

Certain self-service features, such as progressive profile completion, privacy and consent, and terms and conditions acceptance, rely on user metadata that tracks information related to a managed object state. Such data might include when the object was created, or the date of the most recent change, for example. This metadata is not stored within the object itself, but in a separate resource location.

Because object metadata is stored outside the managed object, state change situations (such as the time of an update) are separate from object changes (the update itself). This separation reduces unnecessary synchronization to targets when the only data that has changed is metadata. Metadata is not returned in a query unless it is specifically requested. Therefore, the volume of data that is retrieved when metadata is not required, is reduced.

To specify which metadata you want to track for an object, add a meta stanza to the object definition in your managed object configuration (managed.json file). The following default configuration tracks the createDate and lastChanged date for managed user objects:

{
  "objects" : [
    {
      "name" : "user",
      ...
      "schema" : {
        ...
      },
      "meta" : {
        "property" : "_meta",
        "resourceCollection" : "internal/usermeta",
        "trackedProperties" : [
          "createDate",
          "lastChanged"
        ]
      },
      ...
    },
    ...
  ]
} 

Important

If you are not using the self-service features that require metadata, you can remove the meta stanza from your user object definition in managed.json. Preventing the creation and tracking of metadata where it is not required will improve performance in that scenario.

The metadata configuration includes the following properties:

property

The property that will be dynamically added to the managed object schema for this object.

resourceCollection

The resource location in which the metadata will be stored.

Adjust your repository to match the location you specify here. It's recommended that you use an internal object path and define the storage in your repo.jdbc.json or repo.ds.json file.

For a JDBC repository, metadata is stored in the metaobjects table by default. The metaobjectproperties table is used for indexing.

For a DS repository, metadata is stored under ou=usermeta,ou=internal,dc=openidm,dc=forgerock,dc=com by default.

User objects stored in a DS repository must include the ou specified in the preceding dnTemplate attribute. For example:

dn: ou=usermeta,ou=internal,dc=openidm,dc=forgerock,dc=com
objectclass: organizationalunit
objectclass: top
ou: usermeta
     
trackedProperties

Lists the properties that will be tracked as metadata for this object. In the previous example, the createDate (when the object was created) and the lastChanged date (when the object was last modified) are tracked.

You cannot search on metadata and it is not returned in the results of a query unless it is specifically requested. To return all metadata for an object, include _fields=,_meta/* in your request. The following example returns a user entry without requesting the metadata:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/bjensen"
{
  "_id": "bjensen",
  "_rev": "000000000444dd1a",
  "mail": "bjensen@example.com",
  "givenName": "Barbara",
  "sn": "Jensen",
  "description": "Created By CSV",
  "userName": "bjensen",
  "telephoneNumber": "1234567",
  "accountStatus": "active",
  "effectiveRoles": [],
  "effectiveAssignments": []
}

The following example returns the same user entry, with their metadata:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/bjensen?_fields=,_meta/*"
{
  "_id": "bjensen",
  "_rev": "000000000444dd1a",
  "mail": "bjensen@example.com",
  "givenName": "Barbara",
  "sn": "Jensen",
  "description": "Created By CSV",
  "userName": "bjensen",
  "telephoneNumber": "1234567",
  "accountStatus": "active",
  "effectiveRoles": [],
  "effectiveAssignments": []
  "_meta": {
    "_ref": "internal/usermeta/284273ff-5e50-4fa4-9d30-4a3cf4a5f642",
    "_refResourceCollection": "internal/usermeta",
    "_refResourceId": "284273ff-5e50-4fa4-9d30-4a3cf4a5f642",
    "_refProperties": {
      "_id": "30076e2e-8db5-4b4d-ab91-5351d2da4620",
      "_rev": "000000001ad09f00"
    },
    "createDate": "2018-04-12T19:53:19.004Z",
    "lastChanged": {
      "date": "2018-04-12T19:53:19.004Z"
    },
    "loginCount": 0,
    "_rev": "0000000094605ed9",
    "_id": "284273ff-5e50-4fa4-9d30-4a3cf4a5f642"
  }
}

Note

Apart from the createDate and lastChanged shown previously, the request also returns the loginCount. This property is stored by default for all objects, and increments with each login request based on password or social authentication. If the object for which metadata is tracked is not an object that "logs in," this field will remain 0.

The request also returns a _meta property that includes relationship information. IDM uses the relationship model to store the metadata. When the meta stanza is added to the user object definition, the attribute specified by the property ("property" : "_meta", in this case) is added to the schema as a uni-directional relationship to the resource collection specified by resourceCollection. In this example, the user object's _meta field is stored as an internal/usermeta object. The _meta/_ref property shows the full resource path to the internal object where the metadata for this user is stored.

9.6. Working With Virtual Properties

Properties can be defined to be strictly derived from other properties within an object. This allows computed and composite values to be created in the object. Such properties are named virtual properties. The value of a virtual property is calculated only when that property is retrieved, using a script called by onRetrieve script hook.

In some cases, the value of a virtual property might change without its object being updated. For example, a change to a related object might affect the value of the virtual property. In this case, you can use the triggerSyncCheck action to refresh the managed object, including the values of any virtual attributes. The following command refreshes all properties for the user with ID 9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request POST \
"http://localhost:8080/openidm/managed/user/9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb?_action=triggerSyncCheck"

For relationship type properties, you can configure how objects are refreshed using the relationship notification mechanism. For more information, see "Configuring Relationship Change Notification".

9.7. Running Scripts on Managed Objects

IDM provides a number of hooks that enable you to manipulate managed objects using scripts. These scripts can be triggered during various stages of the lifecycle of the managed object, and are defined in the managed objects configuration file (managed.json).

The scripts can be triggered when a managed object is created (onCreate), updated (onUpdate), retrieved (onRetrieve), deleted (onDelete), validated (onValidate), or stored in the repository (onStore). A script can also be triggered when a change to a managed object triggers an implicit synchronization operation (onSync).

You can also use post-action scripts for managed objects, including after the creation of an object (postCreate), after the update of an object (postUpdate), and after the deletion of an object (postDelete).

The following sample extract of a managed.json file runs a script to calculate the effective assignments of a managed object, whenever that object is retrieved from the repository:

"effectiveAssignments" : {
   "type" : "array",
   "title" : "Effective Assignments",
   "description" : "Effective Assignments",
   "viewable" : false,
   "returnByDefault" : true,
   "isVirtual" : true,
   "usageDescription" : "",
   "isPersonal" : false,
   "onRetrieve" : {
       "type" : "text/javascript",
       "file" : "roles/effectiveAssignments.js",
       "effectiveRolesPropName" : "effectiveRoles"
   },
   "items" : {
       "type" : "object",
       "title" : "Effective Assignments Items"
   }
},

9.8. Encoding Attribute Values

There are two ways to encode attribute values for managed objects—reversible encryption and salted hashing algorithms. Attribute values that might be encoded include passwords, authentication questions, credit card numbers, and social security numbers. If passwords are already encoded on the external resource, they are generally excluded from the synchronization process. For more information, see "Managing Passwords".

You configure attribute value encoding, per schema property, in the managed object configuration (in your project's conf/managed.json file). The following sections show how to use reversible encryption and salted hash algorithms to encode attribute values.

9.8.1. Encoding Attribute Values With Reversible Encryption

The following excerpt of a managed.json file shows a managed object configuration that encrypts and decrypts the password attribute using the default symmetric key:

{
    "objects" : [
        {
            "name" : "user",
            ...
            "schema" : {
                ...
                "properties" : {
                    ...
                    "password" : {
                        "title" : "Password",
                        ...
                        "encryption" : {
                            "purpose" : "idm.password.encryption"
                        },
                        "scope" : "private",
         ...
        }
    ]
} 

Tip

To configure encryption of properties by using the Admin UI:

  1. Select Configure > Managed Objects, and select the object type whose property values you want to encrypt (for example User).

  2. On the Properties tab, select the property whose value should be encrypted and select the Encrypt checkbox.

For information about encrypting attribute values from the command-line, see "Using the encrypt Subcommand".

Important

Hashing is a one way operation - property values that are hashed can not be "unhashed" in the way that they can be decrypted. Therefore, if you hash the value of any property, you cannot synchronize that property value to an external resource. For managed object properties with hashed values, you must either exclude those properties from the mapping or set a random default value if the external resource requires the property.

9.8.2. Encoding Attribute Values by Using Salted Hash Algorithms

To encode attribute values with salted hash algorithms, add the secureHash property to the attribute definition, and specify the algorithm that should be used to hash the value.

IDM supports the following hash algorithms:

SHA-256
SHA-384
SHA-512
Bcrypt
Scrypt
Password-Based Key Derivation Function 2 (PBKDF2)

If you do not specify an algorithm, SHA-256 is used by default. MD5 and SHA-1 are supported for legacy reasons but you should use a more secure algorithm in production environments.

Warning

Some one-way hash functions are designed to be computationally expensive. Functions such as PBKDF2, Bcrypt, and Scrypt are designed to be relatively slow even on modern hardware. This makes them generally less susceptible to brute force attacks. However, computationally expensive functions can dramatically increase response times. If you use these functions, be aware of the performance impact and perform extensive testing before deploying your service in production. Do not use functions like PBKDF2 and Bcrypt for any accounts that are used for frequent, short-lived connections.

The following excerpt of a managed.json file shows a managed object configuration that hashes the values of the password attribute using the SHA-256 algorithm:

{
    "objects" : [
        {
            "name" : "user",
            ...
            "schema" : {
                ...
                "properties" : {
                    ...
                    "password" : {
                        "title" : "Password",
                        ...
                        "secureHash" : {
                            "algorithm" : "SHA-256"
                        },
                        "scope" : "private",
         ...
        }
    ]
} 

Tip

To configure hashing of properties by using the Admin UI:

  1. Select Configure > Managed Objects, and select the object type whose property values you want to hash (for example User).

  2. On the Properties tab, select the property whose value must be hashed and select the Hash checkbox.

  3. Select the algorithm that should be used to hash the property value.

For information about hashing attribute values from the command-line, see "Using the secureHash Subcommand".

Chapter 10. Managing Relationships Between Objects

Relationships are references between managed objects. Roles (described in "Working With Managed Roles") are implemented using relationships, but you can create relationships between any managed object type.

10.1. Defining a Relationship Type

Relationships are defined in your project's managed object configuration file (conf/managed.json). The default configuration includes a relationship named manager that lets you configure a management relationship between two managed users. The manager relationship is a good example from which to understand how relationships work.

The default manager relationship is configured as follows:

"manager" : {
    "type" : "relationship",
    "validate" : true,
    "reverseRelationship" : true,
    "reversePropertyName" : "reports",
    "description" : "Manager",
    "title" : "Manager",
    "viewable" : true,
    "searchable" : false,
    "usageDescription" : "",
    "isPersonal" : false,
    "properties" : {
        "_ref" : {
            "description" : "References a relationship from a managed object",
            "type" : "string"
        },
        "_refProperties" : {
            "description" : "Supports metadata within the relationship",
            "type" : "object",
            "title" : "Manager _refProperties",
            "properties" : {
                "_id" : {
                    "description" : "_refProperties object ID",
                    "type" : "string"
                }
            }
        }
    },
    "resourceCollection" : [
        {
            "path" : "managed/user",
            "label" : "User",
            "query" : {
                "queryFilter" : "true",
                "fields" : [
                    "userName",
                    "givenName",
                    "sn"
                ]
            }
        }
    ],
    "userEditable" : false
},

Most of these properties apply to any managed object type, and are described in "Creating and Modifying Managed Object Types". Relationships have the following specific configurable properties:

type (string)

The object type. Must be relationship for a relationship object.

returnByDefault (boolean true, false)

Specifies whether the relationship should be returned as part of the response. The returnByDefault property is not specific to relationships — the flag applies to all managed object types. However, it is important to note that by default relationship properties are not returned, unless explicitly requested.

reverseRelationship (boolean true, false)

Specifies whether this is a bidirectional relationship. For more information, see "Working With Bidirectional Relationships".

reversePropertyName (string)

Specifies the corresponding property name in the case of a reverse relationship. For example, the manager property has a reversePropertyName of reports. For more information, see "Working With Bidirectional Relationships".

_ref (JSON object)

Specifies how the relationship between two managed objects is referenced.

In the relationship definition, the value of this property is { "type" : "string" }. In a managed user entry, the value of the _ref property is the reference to the other resource. The _ref property is described in more detail in "Establishing a Relationship Between Two Objects".

_refProperties (JSON object)

Specifies any required properties from the relationship that should be included in the managed object. The _refProperties field includes a unique ID (_id) and the revision (_rev) of the object. _refProperties can also contain arbitrary fields to support metadata within the relationship.

resourceCollection (JSON object)

The collection of resources (objects) on which this relationship is based (for example, managed/user objects).

Both managed objects and internal objects can use resourceCollection. Resource collections on managed objects are added directly in managed.json. Since the schema for internal objects is not editable, resource collections for internal object relationships are made available in internal.json in your conf/ directory.

10.2. Establishing a Relationship Between Two Objects

When you have defined a relationship type, (such as the manager relationship, described in the previous section), you can reference one managed user from another, using the _ref* relationship properties. Three properties make up a relationship reference:

  • _refResourceCollection specifies the container of the referenced object (for example, managed/user).

  • _refResourceId specifies the ID of the referenced object. This is generally a system-generated UUID, such as 9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb. For clarity, this section uses client-assigned IDs such as bjensen and psmith.

  • _ref is a derived path that is a combination of _refResourceCollection and a URL-encoded _refResourceId.

For example, imagine that you are creating a new user, psmith, and that psmith's manager will be bjensen. You would add psmith's user entry, and reference bjensen's entry with the _ref property, as follows:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "If-None-Match: *" \
 --header "Content-Type: application/json" \
 --request PUT \
 --data '{
    "sn":"Smith",
    "userName":"psmith",
    "givenName":"Patricia",
    "displayName":"Patti Smith",
    "description" : "psmith - new user",
    "mail" : "psmith@example.com",
    "phoneNumber" : "0831245986",
    "password" : "Passw0rd",
    "manager" : {"_ref" : "managed/user/bjensen"}
  }' \
"http://localhost:8080/openidm/managed/user/psmith"
{
  "_id": "psmith",
  "_rev": "00000000ec41097c",
  "sn": "Smith",
  "userName": "psmith",
  "givenName": "Patricia",
  "displayName": "Patti Smith",
  "description": "psmith - new user",
  "mail": "psmith@example.com",
  "phoneNumber": "0831245986",
  "accountStatus": "active",
  "effectiveRoles": [],
  "effectiveAssignments": []
}

Note that the relationship information is not returned by default. To show the relationship in psmith's entry, you must explicitly request her manager entry, as follows:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
"http://localhost:8080/openidm/managed/user/psmith?_fields=manager"
{
  "_id": "psmith",
  "_rev": "00000000ec41097c",
  "manager": {
    "_ref": "managed/user/bjensen",
    "_refResourceCollection": "managed/user",
    "_refResourceId": "bjensen",
    "_refProperties": {
      "_id": "ffc6f0f3-93db-4939-b9eb-1f8389a59a52",
      "_rev": "0000000081aa991a"
    }
  }
}

When a relationship changes, the updated relationship state can be queried when any referenced managed objects are queried. So, after creating user psmith with manager bjensen, a query on bjensen's user entry will show a reference to psmith's entry in her reports property (because the reports property is configured as the reversePropertyName of the manager property). The following query shows the updated relationship state for bjensen:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/bjensen?_fields=reports"
{
  "_id": "bjensen",
  "_rev": "0000000057b5fe9d",
  "reports": [
    {
      "_ref": "managed/user/psmith",
      "_refResourceCollection": "managed/user",
      "_refResourceId": "psmith",
      "_refProperties": {
        "_id": "ffc6f0f3-93db-4939-b9eb-1f8389a59a52",
        "_rev": "0000000081aa991a"
      }
    }
  ]
}

IDM maintains referential integrity by deleting the relationship reference, if the object referred to by that relationship is deleted. In our example, if bjensen's user entry is deleted, the corresponding reference in psmith's manager property is removed.

10.3. Configuring Relationship Change Notification

A relationship exists between two managed objects. By default, when a relationship changes (when it is created, updated, or deleted), the managed objects on either side of the relationship are not notified of that change. This means that the state of each object with respect to that relationship field is not recalculated until the object is read. This default behavior improves performance, especially in the case where many objects are affected by a single relationship change.

For roles, a special kind of relationship, change notification is configured by default. The purpose of this default configuration is to notify managed users when any of the relationships that link users, roles, and assignments are manipulated. For more information about relationship change notification in the specific case of managed roles, see "Roles and Relationship Change Notification".

To change the default configuration, or to set up notification for other relationship changes, use the notify* properties in the relationship definition, as described in this section.

A relationship exists between an origin object and a referenced object. These terms reflect which managed object is specified in the URL (for example managed/user/psmith), and which object is referenced by the relationship (_ref*) properties. For more information about the relationship properties, see "Establishing a Relationship Between Two Objects".

In the previous example, a PUT on managed/user/psmith with "manager" : {_ref : "managed/user/bjensen"}, causes managed/user/psmith to be the origin object, and managed/user/bjensen to be the referenced object for that relationship, as shown in the following illustration:

Relationship Objects
Origin and referenced objects in a relationship

Note that for the reverse relationship (a PUT on managed/user/bjensen with "reports" : [{_ref = "managed/user/psmith"}]) managed/user/bjensen would be the origin object, and managed/user/psmith would be the referenced object.

By default, when a relationship changes, neither the origin object nor the referenced object is notified of the change. So, with the PUT on managed/user/psmith with "manager" : {_ref : "managed/user/bjensen"}, neither psmith's object nor bjensen's object is notified.

Note

Auditing is not tied to relationship change notification and is always triggered when a relationship changes. Therefore, relationship changes are audited, regardless of the notify and notifySelf properties.

To configure relationship change notification, set the following properties in your managed object schema (conf/managed.json):

The notify and notifySelf properties specify whether objects that reference relationships are notified of a relationship change:

notifySelf

Notifies the origin object of the relationship change.

In our example, if the manager definition includes "notifySelf" : true, and if the relationship is changed through a URL that references psmith, then psmith's object would be notified of the change. For example, for a CREATE, UPDATE or DELETE request on the psmith/manager, psmith would be notified, but the managed object referenced by this relationship (bjensen) would not be notified.

If the relationship were manipulated through a request to bjensen/reports, then bjensen would only be notified if the reports relationship specified "notifySelf" : true.

notify

Notifies the referenced object of the relationship change.

This property must be set on the resourceCollection of the relationship property. In our example, assume that the manager definition has a resourceCollection with a path of managed/user, and that this object specifies "notify" : true. If relationship is changed through a CREATE, UPDATE, or DELETE on the URL psmith/manager, then the reference object (managed/user/bjensen) would be notified of the change to the relationship.

notifyRelationships

This property controls the propagation of notifications out of a managed object when one of its properties changes through an update or patch, or when that object receives a notification through one of these fields.

The notifyRelationships property takes an array of relationships as a value, for example "notifyRelationships" : ["relationship1", "relationship2"]. The relationships specified here are fields defined on the managed object type (which might itself be a relationship).

Notifications are propagated according to the recipient’s notifyRelationships configuration. If a managed object type is notified of a change through one if its relationship fields, the notification is done according to the configuration of the recipient object. To illustrate, look at the attributes property in the default managed/assignment object:

{
    "name" : "assignment",
    "schema" : {
        ...
        "properties" : {
            ...
            "attributes" : {
                "description" : "The attributes operated on by this assignment.",
                "title" : "Assignment Attributes",
                ....
                "notifyRelationships" : ["roles"]
            },
...

This configuration means that if an assignment is updated or patched and the assignment's attributes change in some way, all the roles connected to that assignment are notified. Because the role managed object has "notifyRelationships" : ["members"] defined on its assignments field, the notification that originated from the change to the assignment attribute is propagated to the connected roles, and then out to the members of those roles.

So the role is notified through its assignments field because an attribute in the assignment changed. This notification is propagated out of the members field because the role definition has "notifyRelationships" : ["members"] on its assignments field.

The default implementation of roles, assignments and members uses relationship change notification to ensure that relationship changes are accurately provisioned.

For example, the default user object includes a roles property with notifySelf set to true:

{
   "name" : "user",
   ...
   "schema" : {
       ...
       "properties" : {
           ....
           "roles" : {
               "description" : "Provisioning Roles",
               ...
               "items" : {
                   "type" : "relationship",
                   ...
                   "reverseRelationship" : true,
                   "reversePropertyName" : "members",
                   "notifySelf" : true,
                   ...
               }
}

In this case, notifySelf indicates the origin or user object. If any changes are made to a relationship referencing a role through a URL that includes a user, the user will be notified of the change. For example, if there is a CREATE on managed/user/psmith/roles which specifies a set of references to existing roles, user psmith will be notified of the change.

Similarly, the role object includes a members property. That property includes the following schema definition:

{
    "name" : "role",
    ...
    "schema" : {
        ...
        "properties" : {
            ...
            "members" : {
                ...
                "items" : {
                    "type" : "relationship",
                    ...
                    "properties" : {
                        ...
                        "resourceCollection" : [
                            {
                                "notify" : true,
                                "path" : "managed/user",
                                "label" : "User",
                                ...
                            }
                        ]
                    }
...

Notice the "notify" : true setting on the resourceCollection. This setting indicates that if the relationship is created, updated, or deleted through a URL that references that role, all objects in that resource collection (in this case, managed/user objects) that are identified as members of that role must be notified of the change.

Important

  • To notify an object at the end of a relationship that the relationship has changed (using the notify property), the relationship must be bidirectional ("reverseRelationship" : true). For more information about bidirectional relationships, see "Working With Bidirectional Relationships".

    When an object is notified of a relationship state change (create, delete, or update), part of that notification process involves calculating the changed object state with respect to the changed relationship field. For example, if a managed user is notified that a role has been created, the user object calculates its base state, and the state of its roles field, before and after the new role was created. This before and after state is then reconciled. An object that is referenced by a forward (unidirectional) relationship does not have a field that references that relationship — the object is "pointed-to", but does not "point-back". Because this object cannot calculate its before and after state with respect to the relationship field, it cannot be notified.

    Similarly, relationships that are notified of changes to the objects that reference them must be bidirectional relationships.

    If you configure relationship change notification on a unidirectional relationship, IDM throws an exception.

  • You cannot configure relationship change notification in the Admin UI — you must update the managed object schema in the conf/managed.json file directly.

10.4. Validating Relationships Between Objects

Optionally, you can specify that a relationship between two objects must be validated when the relationship is created. For example, you can indicate that a user cannot reference a role, if that role does not exist.

When you create a new relationship type, validation is disabled by default as it entails a query to the relationship that can be expensive, if it is not required. To configure validation of a referenced relationship, set "validate": true in the object configuration (in managed.json). The managed.json files provided with the sample configurations enable validation for the following relationships:

  • For user objects ‒ roles, managers, and reports

  • For role objects ‒ members and assignments

  • For assignment objects ‒ roles

The following configuration of the manager relationship enables validation, and prevents a user from referencing a manager that has not already been created:

"manager" : {
   "type" : "relationship",
   ...
   "validate" : true,

10.5. Working With Bidirectional Relationships

In most cases, you define a relationship between two objects in both directions. For example, a relationship between a user and his manager might indicate a reverse relationship between the manager and her direct report. Reverse relationships are particularly useful in querying. You might want to query jdoe's user entry to discover who his manager is, or query bjensen's user entry to discover all the users who report to bjensen.

You declare a reverse relationship as part of the relationship definition in conf/managed.json. Consider the following sample excerpt of the default managed object configuration:

"reports" : {
   "description" : "Direct Reports",
   "title" : "Direct Reports",
   ...
   "type" : "array",
   "returnByDefault" : false,
   "items" : {
       "type" : "relationship",
       "reverseRelationship" : true,
       "reversePropertyName" : "manager",
       "validate" : true,
   ...
       }
   ...

The reports property is a relationship between users and managers. So, you can refer to a managed user's reports by referencing the reports. However, the reports property is also a reverse relationship ("reverseRelationship" : true) which means that you can list all users that reference that report.

You can list all users whose manager property is set to the currently queried user.

The reverse relationship includes an optional resourceCollection that allows you to query a set of objects, based on specific fields:

"resourceCollection" : [
   {
       "path" : "managed/user",
       "label" : "User",
       "query" : {
           "queryFilter" : "true",
           "fields" : [
               "userName",
               "givenName",
               "sn"
           ]
       }
   }
]

The path property of the resourceCollection points to the set of objects to be queried. If this path is not in the local repository, the link expansion can incur a significant performance cost. Although the resourceCollection is optional, the same performance cost is incurred if the property is absent.

The query property indicates how you will query this resource collection to configure the relationship. In this case, "queryFilter" : "true", indicates that you can search on any of the properties listed in the fields array when you are assigning a manager to a user or a new report to a manager. To configure these relationships from the Admin UI, see "Managing Relationships Through the Admin UI".

10.6. Working with Conditional Relationships

Relationships can be granted dynamically, based on a specified condition. In order to conditionally grant a relationship, the schemas for the resources you are creating a relationship between need to be configured to support conditional association. To do this, three fields in the schema are used:

conditionalAssociation

Boolean. This property is applied to the resourceCollection for the grantor of the relationship. For example, the members relationship on managed/role specifies that there is a conditional association with the managed/user resource:

"resourceCollection" : [
    {
        "notify" : true,
        "conditionalAssociation" : true,
        "path" : "managed/user",
        "label" : "User",
        "query" : {
            "queryFilter" : "true",
            "fields" : [
                "userName",
                "givenName",
                "sn"
            ]
        }
    }
]
conditionalAssociationField

This property is a string, specifying the field used to determine whether a conditional relationship is granted. The field is applied to the resourceCollection of the grantee of the relationship. For example, the roles relationship on managed/user specifies that the conditional association with managed/role is defined by the condition field in managed/role:

"resourceCollection" : [
    {
        "path" : "managed/role",
        "label" : "Role",
        "conditionalAssociationField" : "condition",
        "query" : {
            "queryFilter" : "true",
            "fields" : [
                "name"
            ]
        }
    }
]

The field name specified will usually be condition if you are using default schema, but can be any field that evaluates a condition and has been flagged as isConditional.

isConditional

Boolean. This is applied to the field you wish to check to determine whether membership in a relationship is granted. Only one field on a resource can be marked as isConditional. For example, in the relationship between managed/user and managed/role, conditional membership in the relationship is determined by the query filter specified in the managed/role condition field:

"condition" : {
    "description" : "A conditional filter for this role",
    "title" : "Condition",
    "viewable" : false,
    "searchable" : false,
    "isConditional" : true,
    "type" : "string"
},

Conditions can be a powerful tool for dynamically creating relationships between two objects. An example of conditional relationships in use can be seen in "Granting Roles Based on a Condition".

10.7. Viewing Relationships Over REST

By default, information about relationships is not returned as the result of a GET request on a managed object. You must explicitly include the relationship property in the request, for example:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/psmith?_fields=manager"
{
  "_id": "psmith",
  "_rev": "000000007e0e0a09",
  "manager": {
    "_ref": "managed/user/bjensen",
    "_refResourceCollection": "managed/user",
    "_refResourceId": "bjensen",
    "_refProperties": {
      "_id": "6714cf83-c32e-45fa-9cba-faecfdb700d1",
      "_rev": "000000009e919882"
    }
  }
}

To obtain more information about the referenced object (psmith's manager, in this case), you can include additional fields from the referenced object in the query, using the syntax object/property (for a simple string value) or object/*/property (for an array of values).

The following example returns the email address and contact number for psmith's manager:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/psmith?_fields=manager/mail,manager/telephoneNumber"
{
  "_id": "psmith",
  "_rev": "000000007e0e0a09",
  "manager": {
    "_ref": "managed/user/bjensen",
    "_refResourceCollection": "managed/user",
    "_refResourceId": "bjensen",
    "_refProperties": {
      "_id": "6714cf83-c32e-45fa-9cba-faecfdb700d1",
      "_rev": "000000009e919882"
    },
    "mail": "bjensen@example.com",
    "telephoneNumber": "1234567",
    "_rev": "000000001ed4ff4f",
    "_id": "bjensen"
  }
}

To query all the relationships associated with a managed object, query the reference (*_ref) property of that object. For example, the following query shows all the objects that are referenced by psmith's entry:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/psmith?_fields=*_ref"
{
  "_id": "psmith",
  "_rev": "000000007e0e0a09",
  "reports": [],
  "manager": {
    "_ref": "managed/user/bjensen",
    "_refResourceCollection": "managed/user",
    "_refResourceId": "bjensen",
    "_refProperties": {
      "_id": "6714cf83-c32e-45fa-9cba-faecfdb700d1",
      "_rev": "000000009e919882"
    }
  },
  "authzRoles": [
    {
      "_ref": "internal/role/openidm-authorized",
      "_refResourceCollection": "internal/role",
      "_refResourceId": "openidm-authorized",
      "_refProperties": {
        "_id": "6e2ddf00-d693-4038-ae63-b56b2447b49e",
        "_rev": "000000000508a08f"
      }
    }
  ],
  "roles": []
}

To expand that query to show all fields within each relationship, add a wildcard as follows:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/psmith?_fields=*_ref/*"
{
  "_id": "psmith",
  "_rev": "000000007e0e0a09",
  "reports": [],
  "roles": [],
  "authzRoles": [
    {
      "_ref": "internal/role/openidm-authorized",
      "_refResourceCollection": "internal/role",
      "_refResourceId": "openidm-authorized",
      "_refProperties": {
        "_id": "6e2ddf00-d693-4038-ae63-b56b2447b49e",
        "_rev": "000000000508a08f"
      },
      "_id": "openidm-authorized",
      "description": "Basic minimum user",
      "_rev": "0000000068832d1e"
    }
  ],
  "manager": {
    "_ref": "managed/user/bjensen",
    "_refResourceCollection": "managed/user",
    "_refResourceId": "bjensen",
    "_refProperties": {
      "_id": "6714cf83-c32e-45fa-9cba-faecfdb700d1",
      "_rev": "000000009e919882"
    },
    "mail": "bjensen@example.com",
    "givenName": "Barbara",
    "sn": "Jensen",
    "description": "Created By CSV",
    "userName": "bjensen",
    "telephoneNumber": "1234567",
    "accountStatus": "active",
    "_meta": {
      "_ref": "internal/usermeta/8a4ec527-7a8d-4873-ae5c-7a9bafe43cbd",
      "_refResourceCollection": "internal/usermeta",
      "_refResourceId": "8a4ec527-7a8d-4873-ae5c-7a9bafe43cbd",
      "_refProperties": {
        "_id": "a4d045eb-527f-42df-a6d1-6cb136014457",
        "_rev": "000000002d5a9e93"
      },
      "createDate": "2018-04-12T21:50:18.097Z",
      "lastChanged": {
        "date": "2018-04-12T21:50:18.097Z"
      },
      "loginCount": 0,
      "_rev": "0000000008e85fab",
      "_id": "8a4ec527-7a8d-4873-ae5c-7a9bafe43cbd"
    }
    "effectiveRoles": [],
    "effectiveAssignments": [],
    "_rev": "000000001ed4ff4f",
    "_id": "bjensen"
  }
}

Note

Metadata is implemented using the relationships mechanism so when you request all relationships for a user (with _ref/), you will also get all the metadata for that user, if metadata is being tracked. For more information, see "Tracking Metadata For Managed Objects".

10.8. Viewing Relationships in Graph Form

The Identity Relationships widget gives a visual display of the relationships between objects.

This widget is not displayed on any dashboard by default. You can add it as follows:

  1. Log into the Admin UI.

  2. Select Dashboards, and choose the dashboard to which you want to add the widget.

    For more information about managing dashboards in the UI, see "Managing Dashboards".

  3. Select Add Widget.

  4. In the Add Widget window, scroll down to the Utilities item, select Identity Relationships, then click Settings.

  5. Choose the Widget Size (small, medium, or large).

  6. From the Chart Type list, select Collapsible Tree Layout or Radial Layout.

    The Collapsible Tree Layout looks something like this:

    Relationships graph showing manager and direct reports

    The Radial Layout looks something like this:

    Relationships graph showing manager and direct reports
  7. Select the object for which you want to display relationships, for example, User.

  8. Select the property or properties that will be used to search on that object, and that will be displayed in the widget, for example, userName and city.

    Optionally, select Preview for an idea of what the data represented by widget will look like. Select Settings to return to the Add Widget window.

  9. Click Add to add the widget to the dashboard.

When you have added the Identity Relationships widget, select the user whose relationships you want to search.

The following graph shows all of imartinez's relationships. The graph shows imartinez's manager and her direct reports.

Relationships graph showing manager and direct reports

Select or deselect the Data Types on the left of the screen to control how much information is displayed.

Select and move the graph for a better view. Double-click on any user in the graph to view that user's profile.

10.9. Managing Relationships Through the Admin UI

This section describes how to set up relationships between managed objects by using the Admin UI. You can set up a relationship between any object types. The examples in this section demonstrate how to set up a relationship between users and devices, such as IoT devices.

For illustration purposes, these examples assume that you have started IDM and already have some managed users. If this is not the case, start the server with the sample configuration described in "Synchronizing Data From a CSV File to IDM" in the Samples Guide, and run a reconciliation to populate the managed user repository.

In the following procedures, you will:

To Create a New Device Object Type

This procedure illustrates how to set up a new Device managed object type, adding properties to collect information such as model, manufacturer, and serial number for each device. In the next procedure, you will set up the relationship.

  1. Click Configure > Managed Objects > New Managed Object.

    Give the object an appropriate name and Readable Title. For this procedure, specify Device for both these fields.

    Enter a description for the object, select an icon that represents the object, and click Save.

    You should now see three tabs: Properties, Details, and Scripts. Select the Properties tab.

  2. Click Add a Property to set up the schema for the device.

    For each property, enter a Name, and Label, select the data Type for the property, and specify whether that property is required for an object of this type.

    For the purposes of this example, include the properties shown in the following image: model, serialNumber, manufacturer, description, and category.

    Devices - All Properties

    When you save the properties for the new managed object type, IDM saves those entries in your project's conf/managed.json file.

  3. Now select Manage > Device > New Device and add a device as shown in the following image:

    Devices - All Properties
  4. Continue adding new devices to the Device object.

    When you have finished, select Manage > Device to view the complete list of Devices.

    The remaining procedures in this section assume that you have added devices similar to the following:

    List of Managed Devices
  5. (Optional) To change the order in which properties of the Device managed object are displayed, select Configure > Managed Objects > Device. Select the property that you want to move and drag it up or down the list.

    Alternatively, you can make the same changes to this schema (or any managed object schema) in your project's conf/managed.json file.

To Configure the Relationship Between a Device and a User

To set up a relationship between the Device object type and the User object type, you must identify the specific property on each object that will form the basis of the relationship. For example, a device must have an owner and a user can own one or more devices. The property type for each of these must be relationship.

In this procedure, you will update the managed Device object type to add a new Relationship type property named owner. You will then link that property to a new property on the managed User object, named device. At the end of the procedure, the updated object types will look as follows:

Relationship Properties on User and Device Objects
Updating the managed user and managed device objects with relationship properties

  1. Create a new relationship property on the Device object:

    1. Select Configure > Managed Objects and select the Device object that you created previously.

    2. On the Properties tab, add a new property named owner. Select Relationship as the property Type. Select Required, as all device objects must have an owner:

      Creating a new device property on device objects

      Note

      You cannot change the Type of a property after it has been created. If you create the property with an incorrect Type, you must delete the property and recreate it.

  2. When you have saved the Owner property, select it to show the relationship on the Details tab:

    Details of a Relationship Property
  3. Click the + Related Resource item and select user as the Resource.

    This sets up a relationship between the new Device object and the managed User object.

    Under Display Properties, select all of the properties of the user object that should be visible when you display a user's devices in the UI. For example, you might want to see the user's name, email address and telephone number.

    Note that this list of Display Properties also specifies how you can search for user objects when you are assigning a device to a user.

    Click Show advanced options. Notice that the Query Filter field is set to true. This setting allows you to search on any of the Display Properties that you have selected, when you are assigning a device to a user.

    Click Save to continue.

    You now have a one-way relationship between a device and a user.

  4. Click the + Two-way Relationship item to configure the reverse relationship:

    1. Select Has Many to indicate that a single user can have more than one device.

    2. In the Reverse property name field, enter the new property name that will be created in the managed User object type. As shown in "Relationship Properties on User and Device Objects", that property is device in this example.

    3. Under Display Properties, select all of the properties of the device object that should be visible when you display a user in the UI. For example, you might want to see the model and serial number of each device.

    4. Click Show advanced options. Notice that the Query Filter field is set to true. This setting allows you to search on any of the Display Properties that you have selected, when you are assigning a device to a user.

    5. Select Validate relationship.

      This setting ensures that the relationship is valid when a device is assigned to a user. IDM verifies that both the user and device objects exist, and that that specific device has not already been assigned to user.

    6. Click Save to continue.

  5. You should now have the following reverse relationship configured between User objects and Device objects:

    Reverse relationship configured between users and devices

    Select Configure > Managed Objects > User.

    Scroll down to the end of the Properties tab and notice that the device property was created automatically when you configured the relationship.

To Demonstrate the Relationship

This procedure demonstrates how devices can be assigned to users, based on the relationship configuration that you set up in the previous two procedures.

  1. Select Manage > User, click on a user entry and select the new Device tab.

  2. Click Add Device and click in the Device field to display the list of devices that you added in the previous procedure.

    Assigning a Device to a User
  3. Select two devices and click Add.

  4. On the Device tab, click the Show Chart icon at the top right.

    A graphical representation of the relationship between the user and her devices is displayed:

    Assigning a Device to a User
  5. You can also assign an owner to a device.

    Select Manage > Device, and select one of the devices that you did not assign in the previous step.

    Click Add Owner and search for the user to whom the device should be assigned.

  6. To demonstrate the relationship validation, try to assign a device that has already been assigned to a different user.

    The UI displays the error: Conflict with Existing Relationship.

10.10. Viewing the Relationship Configuration in the UI

The Managed Objects Relationship Diagram provides a visual display of the relationship configuration between managed objects. Unlike the Identity Relationships widget, described in "Viewing Relationships in Graph Form", this widget does not show the actual relationship data, but rather shows the configured relationship types.

This widget is not displayed on any dashboard by default. You can add it as follows:

  1. Log into the Admin UI.

  2. Select Dashboards, and choose the dashboard to which you want to add the widget.

    For more information about managing dashboards in the UI, see "Managing Dashboards".

  3. Select Add Widget.

  4. In the Add Widget window, scroll down to the Utilities item and select Managed Objects Relationship Diagram.

    There are no configurable settings for this widget.

  5. The Preview button shows the current relationship configuration. The following image shows the relationship configuration for a basic IDM installation with no specific configuration:

    Managed Object Relationships Diagram showing relationship configuration for a base install

    The legend indicates which relationships are required, which are optional, and which are one to one or one to many. In the default relationship configuration shown in the previous image, you can see that a user can have one or more roles and a role can have one or more users. A manager can have one or more reports but a user can have only one manager. There are no mandatory relationships in this default configuration.

Chapter 11. Working With Managed Roles

This chapter describes a specific managed object type — the managed role object. Managed roles use the relationships mechanism, described in "Managing Relationships Between Objects". It is useful to understand how relationships work before you read about roles in IDM.

IDM supports two types of roles:

  • Provisioning roles - used to specify how objects are provisioned to an external system.

  • Authorization roles - used to specify the authorization rights of a managed object internally, within IDM.

Provisioning roles are always created as managed roles, at the context path openidm/managed/role/role-name. Provisioning roles are granted to managed users as values of the user's roles property.

Authorization roles can be created either as managed roles (at the context path openidm/managed/role/role-name) or as internal roles (at the context path openidm/internal/role/role-name). Authorization roles are granted to managed users as values of the user's authzRoles property.

Both provisioning roles and authorization roles use the relationships mechanism to link the role to the managed object to which it applies. For more information about relationships between objects, see "Managing Relationships Between Objects".

This section describes how to create and use managed roles, either managed provisioning roles, or managed authorization roles. For more information about internal authorization roles, and how IDM controls authorization to its own endpoints, see "Authorization".

Managed roles are defined like any other managed object, and are granted to users through the relationships mechanism.

A managed role can be granted manually, as a static value of the user's roles or authzRoles attribute, or dynamically, as a result of a condition or script. For example, a user might be granted a role such as sales-role dynamically, if that user is in the sales organization.

A managed user's roles and authzRoles attributes take an array of references as a value, where the references point to the managed roles. For example, if user bjensen has been granted two provisioning roles (employee and supervisor), the value of bjensen's roles attribute would look something like the following:

"roles": [
  {
    "_ref": "managed/role/employee",
    "_refResourceCollection": "managed/role",
    "_refResourceId": "employee",
    "_refProperties": {
      "_grantType": "",
      "_id": "bb399428-21a9-4b01-8b74-46a7ac43e0be",
      "_rev": "00000000e43e9ba7"
    }
  },
  {
    "_ref": "managed/role/supervisor",
    "_refResourceCollection": "managed/role",
    "_refResourceId": "supervisor",
    "_refProperties": {
      "_grantType": "",
      "_id": "9f7d124b-c7b1-4bcf-9ece-db4900e37c31",
      "_rev": "00000000e9c19d26"
    }
  }
]

The _refResourceCollection is the container that holds the role and the _refResourceId the ID of the role. The _ref property is a resource path that is derived from the _refResourceCollection and the URL-encoded _refResourceId. The _refProperties property provides more information about the relationship.

Important

Some of the examples in this documentation set use client-assigned IDs (such as bjensen and scarter) for the user objects because it makes the examples easier to read. If you create objects using the Admin UI, they are created with server-assigned IDs (such as 55ef0a75-f261-47e9-a72b-f5c61c32d339). This particular example uses a client-assigned role ID that is the same as the role name. All other examples in this chapter use server-assigned IDs. Generally, immutable server-assigned UUIDs are used for all managed objects in production environments.

The following sections describe how to create, read, update, and delete managed roles, and how to grant roles to users. For information about how roles are used to provision users to external systems, see "Working With Role Assignments".

11.1. Creating a Role

The easiest way to create a new role is by using the Admin UI. Select Manage > Role and select New Role on the Role List page. Enter a name and description for the new role and select Save.

Optionally, select Temporal Constraint to restrict the role grant to a set time period or Condition to define a query filter that will allow the role to be granted to members dynamically. For more information on these options, see "Using Temporal Constraints to Restrict Effective Roles" and "Granting Roles Dynamically".

To create a managed role over REST, send a PUT or POST request to the /openidm/managed/role context path. The following example creates a managed role named employee:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request POST \
 --data '{
     "name" : "employee",
     "description" : "Role granted to workers on the company payroll"
 }' \
 "http://localhost:8080/openidm/managed/role?_action=create"
{
  "_id": "5790220a-719b-49ad-96a6-6571e63cbaf1",
  "_rev": "0000000079c6644f",
  "name": "employee",
  "description": "Role granted to workers on the company payroll"
}

At this stage, the employee role has no corresponding assignments. Assignments are what enables the provisioning logic to the external system. Assignments are created and maintained as separate managed objects, and are referred to within role definitions. For more information about assignments, see "Working With Role Assignments".

11.2. Listing Existing Roles

You can display a list of all configured managed roles over REST or by using the Admin UI.

To list the managed roles in the Admin UI, select Manage > Role.

If you have many managed roles, the Role List page now supports specialized filtering, with the Advanced Filter option, which allows you to build many of the queries shown in "Defining and Calling Queries".

To list the managed roles over REST, query the openidm/managed/role endpoint. The following example shows the employee role that you created in the previous section:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/role?_queryFilter=true"
{
  "result": [
    {
      "_id": "5790220a-719b-49ad-96a6-6571e63cbaf1",
      "_rev": "0000000079c6644f",
      "name": "employee",
      "description": "Role granted to workers on the company payroll"
    }
  ],
...
}

11.3. Granting a Role to a User

Roles are granted to users through the relationship mechanism. Relationships are essentially references from one managed object to another, in this case from a user object to a role object. For more information about relationships, see "Managing Relationships Between Objects".

Roles can be granted manually or dynamically.

To grant a role manually, you must do one of the following:

  • Update the value of the user's roles property (if the role is a provisioning role) or authzRoles property (if the role is an authorization role) to reference the role.

  • Update the value of the role's members property to reference the user.

Manual role grants are described further in "Granting Roles Manually".

Dynamic role grants use the result of a condition or script to update a user's list of roles. Dynamic role grants are described in detail in "Granting Roles Dynamically".

11.3.1. Granting Roles Manually

To grant a role to a user manually, use the Admin UI or the REST interface as follows:

Using the Admin UI

Use one of the following UI methods to grant a role to a user:

  • Update the user entry:

    1. Select Manage > User and select the user to whom you want to grant the role.

    2. Select the Provisioning Roles tab and select Add Provisioning Roles.

    3. Select the role from the dropdown list and select Add.

  • Update the role entry:

    1. Select Manage > Role and select the role that you want to grant.

    2. Select the Role Members tab and select Add Role Members.

    3. Select the user from the dropdown list and select Add.

Over the REST interface

Use one of the following methods to grant a role to a user over REST:

  • Update the user's roles property to refer to the role.

    The following sample command grants the employee role (with ID 5790220a-719b-49ad-96a6-6571e63cbaf1) to user scarter:

    $ curl \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --header "Content-Type: application/json" \
     --request PATCH \
     --data '[
        {
           "operation": "add",
           "field": "/roles/-",
           "value": {"_ref" : "managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1"}
        }
     ]' \
     "http://localhost:8080/openidm/managed/user/scarter"
    {
      "_id": "scarter",
      "_rev": "000000003be825ce",
      "mail": "scarter@example.com",
      "givenName": "Steven",
      "sn": "Carter",
      "description": "Created By CSV",
      "userName": "scarter",
      "telephoneNumber": "1234567",
      "accountStatus": "active",
      "effectiveRoles": [
        {
          "_ref": "managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1"
        }
      ],
      "effectiveAssignments": []
    }

    Note that scarter's effectiveRoles attribute has been updated with a reference to the new role. For more information about effective roles and effective assignments, see "Understanding Effective Roles and Effective Assignments".

    When you update a user's existing roles array, you must use the - special index to add the new value to the set. For more information, see Set semantic arrays in "Patch Operation: Add".

  • Update the role's members property to refer to the user.

    The following sample command makes scarter a member of the employee role:

    $ curl \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --header "Content-Type: application/json" \
     --request PATCH \
     --data '[
        {
           "operation": "add",
           "field": "/members/-",
           "value": {"_ref" : "managed/user/scarter"}
        }
     ]' \
     "http://localhost:8080/openidm/managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1"
    {
      "_id": "5790220a-719b-49ad-96a6-6571e63cbaf1",
      "_rev": "0000000079c6644f",
      "name": "employee",
      "description": "Role granted to workers on the company payroll"
    }

    Note that the members property of a role is not returned by default in the output. To show all members of a role, you must specifically request the relationship properties (*_ref) in your query. The following sample command lists the members of the employee role (currently only scarter):

    $ curl \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request GET \
     "http://localhost:8080/openidm/managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1?_fields=*_ref,name"
    {
      "_id": "5790220a-719b-49ad-96a6-6571e63cbaf1",
      "_rev": "0000000079c6644f",
      "name": "employee",
      "authzMembers": [],
      "assignments": [],
      "members": [
        {
          "_ref": "managed/user/scarter",
          "_refResourceCollection": "managed/user",
          "_refResourceId": "scarter",
          "_refProperties": {
            "_id": "7ad15a7b-6806-487b-900d-db569927f56d",
            "_rev": "0000000075e09cbf"
          }
        }
      ]
    }
  • You can replace an existing role grant with a new one by using the replace operation in your patch request.

    The following command replaces scarter's entire roles entry (that is, overwrites any existing roles) with a single entry, the reference to the employee role (ID 5790220a-719b-49ad-96a6-6571e63cbaf1):

    $ curl \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --header "Content-Type: application/json" \
     --request PATCH \
     --data '[
       {
         "operation": "replace",
         "field":"/roles",
         "value":[
              {"_ref":"managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1"}
         ]
       }
     ]' \
     "http://localhost:8080/openidm/managed/user/scarter"
    {
      "_id": "scarter",
      "_rev": "00000000da112702",
      "mail": "scarter@example.com",
      "givenName": "Steven",
      "sn": "Carter",
      "description": "Created By CSV",
      "userName": "scarter",
      "telephoneNumber": "1234567",
      "accountStatus": "active",
      "effectiveRoles": [
        {
          "_ref": "managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1"
        }
      ],
      "effectiveAssignments": []
    }

11.3.2. Granting Roles Dynamically

The previous section showed how to grant roles to a user manually, by listing a reference to the role as a value of the user's roles attribute. You can also grant a role dynamically by using one of the following methods:

  • Granting a role based on a condition, where that condition is expressed in a query filter in the role definition. If the condition is true for a particular member, that member is granted the role. Conditions can be used in both managed and internal roles.

  • Using a custom script to define a more complex role granting strategy.

11.3.2.1. Granting Roles Based on a Condition

A role that is granted based on a defined condition is called a conditional role. To create a conditional role, include a query filter in the role definition.

Important

Properties that are used as the basis of a conditional role query must be configured as searchable and must be indexed in the repository configuration. To configure a property as searchable, update the schema in your conf/managed.json file. For more information, see "Creating and Modifying Managed Object Types".

To create a conditional role by using the Admin UI, select Condition on the role Details page, then define the query filter that will be used to assess the condition.

To create a conditional role over REST, include the query filter as a value of the condition property in the role definition. The following command creates a role, fr-employee, that will be granted only to those users who live in France (whose country property is set to FR):

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request POST \
 --data '{
    "name": "fr-employee",
    "description": "Role granted to employees resident in France",
    "condition": "/country eq \"FR\""
 }' \
 "http://localhost:8080/openidm/managed/role?_action=create"
 {
  "_id": "eb18a2e2-ee1e-4cca-83fb-5708a41db94f",
  "_rev": "000000004085704c",
  "name": "fr-employee",
  "description": "Role granted to employees resident in France",
  "condition": "/country eq \"FR\""
}

When a conditional role is created or updated, IDM automatically assesses all managed users, and recalculates the value of their roles property, if they qualify for that role. When a condition is removed from a role, that is, when the role becomes an unconditional role, all conditional grants removed. So, users who were granted the role based on the condition have that role removed from their roles property.

Caution

When a conditional role is defined in an existing data set, every user entry (including the mapped entries on remote systems) must be updated with the assignments implied by that conditional role. The time that it takes to create a new conditional role is impacted by the following items:

  • The number of managed users affected by the condition

  • The number of assignments related to the conditional role

  • The average time required to provision updates to all remote systems affected by those assignments

In a data set with a very large number of users, creating a new conditional role can therefore incur a significant performance cost at the time of creation. Ideally, you should set up your conditional roles at the beginning of your deployment to avoid performance issues later.

11.3.2.2. Granting Roles By Using Custom Scripts

The easiest way to grant roles dynamically is to use conditional roles, as described in "Granting Roles Based on a Condition". If your deployment requires complex conditional logic that cannot be achieved with a query filter, you can create a custom script to grant the role, as follows:

  1. Create a roles directory in your project's script directory and copy the default effective roles script to that new directory:

    $ mkdir project-dir/script/roles/
    $ cp /path/to/openidm/bin/defaults/script/roles/effectiveRoles.js \
     project-dir/script/roles/

    The new script will override the default effective roles script.

  2. Modify the script to reference additional roles that have not been granted manually, or as the result of a conditional grant. The effective roles script calculates the grants that are in effect when the user is retrieved.

    For example, the following addition to the effectiveRoles.js script grants the roles dynamic-role1 and dynamic-role2 to all active users (managed user objects whose accountStatus value is active). This example assumes that you have already created the managed roles, dynamic-role1 (with ID d2e29d5f-0d74-4d04-bcfe-b1daf508ad7c) and dynamic-role2 (with ID 709fed03-897b-4ff0-8a59-6faaa34e3af6, and their corresponding assignments:

    // This is the location to expand to dynamic roles,
    // project role script return values can then be added via
    // effectiveRoles = effectiveRoles.concat(dynamicRolesArray);
    
    if (object.accountStatus === 'active') {
        effectiveRoles = effectiveRoles.concat([
          {"_ref": "managed/role/d2e29d5f-0d74-4d04-bcfe-b1daf508ad7c"},
          {"_ref": "managed/role/709fed03-897b-4ff0-8a59-6faaa34e3af6"}
        ]);
    }

Note

For conditional roles, the user's roles property is updated if the user meets the condition. For custom scripted roles, the user's effectiveRoles property is calculated when the user is retrieved and includes the dynamic roles according to the custom script.

If you make any of the following changes to a scripted role grant, you must perform a manual reconciliation of all affected users before assignment changes will take effect on an external system:

  • If you create a new scripted role grant.

  • If you change the definition of an existing scripted role grant.

  • If you change any of the assignment rules for a role that is granted by a custom script.

11.4. Using Temporal Constraints to Restrict Effective Roles

You can use temporal constraints to restrict the period a role is effective in. Temporal constraints can be applied to both managed and internal roles, and can also be applied to role grants on a per-user basis.

For example, you might want a role such as contractors-2018 which you want to apply to all contract employees for the year 2018. In this case, you would set the temporal constraint on the role. Alternatively, you might want to assign a contractors role to apply to an individual user only for the period of their contract of employment.

The following sections describe how to set temporal constraints on role definitions, and on individual role grants.

11.4.1. Adding a Temporal Constraint to a Role Definition

When you create a role, you can include a temporal constraint in the role definition that restricts the validity of the entire role, regardless of how that role is granted. Temporal constraints are expressed as a time interval in ISO 8601 date and time format. For more information on this format, see the ISO 8601 standard.

To restrict the period during which a role is valid by using the Admin UI, select Temporal Constraint on the role Details tab, then select a timezone offset relative to GMT and the start and end dates for the required period.

The following example adds a contractor role over the REST interface. The role is effective from March 1st, 2018 to August 31st, 2018:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request POST \
 --data '{
     "name" : "contractor",
     "description" : "Role granted to contract workers for 2018",
     "temporalConstraints" : [
        {
            "duration": "2018-03-01T00:00:00.000Z/2018-08-31T00:00:00.000Z"
        }
     ]
 }' \
 "http://localhost:8080/openidm/managed/role?_action=create"
{
  "_id": "6c0afad4-645f-4573-a896-2ad2ae76c29a",
  "_rev": "00000000533c7a94",
  "name": "contractor",
  "description": "Role granted to contract workers for 2018",
  "temporalConstraints": [
    {
      "duration": "2018-03-01T00:00:00.000Z/2018-08-31T00:00:00.000Z"
    }
  ]
}

The preceding example specifies the time zone as Coordinated Universal Time (UTC) by appending Z to the time. If no time zone information is provided, the time zone is assumed to be local time. To specify a different time zone, include an offset (from UTC) in the format ±hh:mm. For example, an interval of 2018-03-01T00:00:00.000-07:00/2018-08-31T00:00:00.000-07:00 specifies a time zone that is seven hours behind UTC.

When the period defined by the constraint has ended, the role object remains in the repository but the effective roles script will not include the role in the list of effective roles for any user.

The following example assumes that user scarter has been granted a role contractor-february. A temporal constraint has been included in the contractor-february definition that specifies that the role should be applicable only during the month of February 2018. At the end of this period, a query on scarter's entry shows that his roles property still includes the contractor-february role (with ID 6c0afad4-645f-4573-a896-2ad2ae76c29a), but his effectiveRoles property does not:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/scarter?_fields=_id,userName,roles,effectiveRoles"
{
  "_id": "scarter",
  "_rev": "00000000c1481582",
  "userName": "scarter",
  "effectiveRoles": [],
  "roles": [
    {
      "_ref": "managed/role/6c0afad4-645f-4573-a896-2ad2ae76c29a",
      "_refResourceCollection": "managed/role",
      "_refResourceId": "6c0afad4-645f-4573-a896-2ad2ae76c29a",
      "_refProperties": {
        "_grantType": "",
        "_id": "d3e045ea-af80-4699-9aae-120bc2a75cab",
        "_rev": "00000000d5a1a32c"
      }
    }
  ]
}

The role is still in place but is no longer effective.

11.4.2. Adding a Temporal Constraint to a Role Grant

To restrict the validity of a role for individual users, you can apply a temporal constraint at the grant level, rather than as part of the role definition. In this case, the temporal constraint is taken into account per user, when the user's effective roles are calculated. Temporal constraints that are defined at the grant level can be different for each user who is a member of that role.

To restrict the period during which a role grant is valid by using the Admin UI, set a temporal constraint when you add the member to the role.

For example, to specify that bjensen be added to a Contractor role only for the period of her employment contract, select Manage > Role, select the Contractor role, then select Add Role Members. On the Add Role Members screen, select bjensen from the list, then enable the Temporal Constraint and specify the start and end date of her contract.

To apply a temporal constraint to a grant over the REST interface, include the constraint as one of the _refProperties of the relationship between the user and the role. The following example assumes a contractor role, with ID 6c0afad4-645f-4573-a896-2ad2ae76c29a. The command adds user bjensen as a member of that role, with a temporal constraint that specifies that she be a member of the role only for one year, from January 1st, 2018 to January 1st, 2019:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request PATCH \
 --data '[
    {
     "operation": "add",
     "field": "/members/-",
     "value": {
      "_ref" : "managed/user/bjensen",
      "_refProperties": {
       "temporalConstraints": [{"duration": "2018-01-01T00:00:00.000Z/2019-01-01T00:00:00.000Z"}]
      }
     }
    }
 ]' \
 "http://localhost:8080/openidm/managed/role/6c0afad4-645f-4573-a896-2ad2ae76c29a"
{
  "_id": "6c0afad4-645f-4573-a896-2ad2ae76c29a",
  "_rev": "000000007b0475fc",
  "name": "contractor",
  "description": "Role granted to contract workers"
}

A query on bjensen's roles property shows that the temporal constraint has been applied to this grant:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/bjensen/roles?_queryFilter=true"
{
  "result": [
    {
      "_id": "ff9ed5a7-4cb1-461e-a59a-d793b6f35808",
      "_rev": "0000000035aab598",
      "_ref": "managed/role/6c0afad4-645f-4573-a896-2ad2ae76c29a",
      "_refResourceCollection": "managed/role",
      "_refResourceId": "6c0afad4-645f-4573-a896-2ad2ae76c29a",
      "_refProperties": {
        "temporalConstraints": [
          {
            "duration": "2018-01-01T00:00:00.000Z/2019-01-01T00:00:00.000Z"
          }
        ],
        "_id": "ff9ed5a7-4cb1-461e-a59a-d793b6f35808",
        "_rev": "0000000035aab598"
      }
    }
  ],
  ...
}

11.5. Querying a User's Manual and Conditional Roles

The easiest way to check what roles have been granted to a user, either manually, or as the result of a condition, is to look at the user's entry in the Admin UI. Select Manage > User, select the user whose roles you want to see, and select the Provisioning Roles tab.

If you have many managed roles, use the Advanced Filter option on the Role List page to build a custom query.

To obtain a similar list over the REST interface, query the user's roles property. The following sample query shows that scarter has been granted two roles - an employee role (with ID 5790220a-719b-49ad-96a6-6571e63cbaf1) and an fr-employee role (with ID eb18a2e2-ee1e-4cca-83fb-5708a41db94f).

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/scarter/roles?_queryFilter=true&_fields=_ref/*,name"
{
  "result": [
    {
      "_id": "053705c1-1759-4776-80de-3af89fe7b107",
      "_rev": "000000005e55a064",
      "_ref": "managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1",
      "_refResourceCollection": "managed/role",
      "_refResourceId": "5790220a-719b-49ad-96a6-6571e63cbaf1",
      "_refProperties": {
        "_grantType": "",
        "_id": "053705c1-1759-4776-80de-3af89fe7b107",
        "_rev": "000000005e55a064"
      }
    },
    {
      "_id": "16e5e25e-eb92-43b1-9013-806289574d44",
      "_rev": "00000000a0f6a6d6",
      "_ref": "managed/role/eb18a2e2-ee1e-4cca-83fb-5708a41db94f",
      "_refResourceCollection": "managed/role",
      "_refResourceId": "eb18a2e2-ee1e-4cca-83fb-5708a41db94f",
      "_refProperties": {
        "_grantType": "conditional",
        "_id": "16e5e25e-eb92-43b1-9013-806289574d44",
        "_rev": "00000000a0f6a6d6"
      }
    }
  ],
  ...
}

Note that the fr-employee role indicates a _grantType of conditional. This property indicates how the role was granted to the user. If the _grantType is empty, the role was granted manually.

Querying a user's roles in this way does not return any roles that would be in effect as a result of a custom script, or of any temporal constraint applied to the role. To return a complete list of all the roles in effect at a specific time, you need to query the user's effectiveRoles property, as follows:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/user/scarter?_fields=effectiveRoles"

11.6. Deleting a User's Roles

Roles that have been granted manually can be removed from a user's entry in two ways:

  • Update the value of the user's roles property (if the role is a provisioning role) or authzRoles property (if the role is an authorization role) to remove the reference to the role.

  • Update the value of the role's members property to remove the reference to that user.

Both of these actions can be achieved by using the Admin UI, or over REST.

Using the Admin UI

Use one of the following methods to remove a user's roles:

  • Select Manage > User and select the user whose role or roles you want to remove.

    Select the Provisioning Roles tab, select the role that you want to remove, then select Remove Selected Provisioning Roles.

  • Select Manage > Role and select on the role whose members you want to remove.

    Select the Role Members tab, select the member or members that that you want to remove, then select Remove Selected Role Members.

Over the REST interface

Use one of the following methods to remove a role grant from a user:

  • Delete the role from the user's roles property, including the reference ID (the ID of the relationship between the user and the role) in the delete request:

    The following sample command removes the employee role from user scarter. The role ID is 5790220a-719b-49ad-96a6-6571e63cbaf1 but the ID required in the DELETE request is the reference ID (053705c1-1759-4776-80de-3af89fe7b107):

    $ curl \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request DELETE \
     "http://localhost:8080/openidm/managed/user/scarter/roles/053705c1-1759-4776-80de-3af89fe7b107"
    {
      "_id": "053705c1-1759-4776-80de-3af89fe7b107",
      "_rev": "000000005e55a064",
      "_ref": "managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1",
      "_refResourceCollection": "managed/role",
      "_refResourceId": "5790220a-719b-49ad-96a6-6571e63cbaf1",
      "_refProperties": {
        "_grantType": "",
        "_id": "053705c1-1759-4776-80de-3af89fe7b107",
        "_rev": "000000005e55a064"
      }
    }
  • PATCH the user entry to remove the role from the array of roles, specifying the value of the role object in the JSON payload.

    Caution

    When you remove a role in this way, you must include the entire object in the value, as shown in the following example:

    $ curl \
     --header "Content-type: application/json" \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request PATCH \
     --data '[
        {
          "operation" : "remove",
          "field" : "/roles",
          "value" : {
            "_ref": "managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1",
            "_refResourceCollection": "managed/role",
            "_refResourceId": "5790220a-719b-49ad-96a6-6571e63cbaf1",
            "_refProperties": {
              "_grantType": "",
              "_id": "cec1fabc-894b-4963-ab44-e7dc8ca89927",
              "_rev": "000000002c5fa279"
            }
          }
        }
      ]' \
     "http://localhost:8080/openidm/managed/user/scarter"
    {
      "_id": "scarter",
      "_rev": "000000009f853b33",
      "mail": "scarter@example.com",
      "givenName": "Steven",
      "sn": "Carter",
      "description": "Created By CSV",
      "userName": "scarter",
      "telephoneNumber": "1234567",
      "accountStatus": "active",
      "effectiveRoles": [
        {
          "_ref": "managed/role/eb18a2e2-ee1e-4cca-83fb-5708a41db94f"
        }
      ],
      "effectiveAssignments": [],
      "preferences": {
        "updates": false,
        "marketing": false
      },
      "country": "FR"
    }
  • Delete the user from the role's members property, including the reference ID (the ID of the relationship between the user and the role) in the delete request.

    The following example first queries the members of the employee role, to obtain the ID of the relationship, then removes bjensen's membership from that role:

    $ curl \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request GET \
     "http://localhost:8080/openidm/managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1/members?_queryFilter=true"
    {
      "result": [
        {
          "_id": "0d7ded4c-600e-42ae-ac99-3edbd5348d3f",
          "_rev": "000000002651a299",
          "_ref": "managed/user/bjensen",
          "_refResourceCollection": "managed/user",
          "_refResourceId": "bjensen",
          "_refProperties": {
            "_grantType": "",
            "_id": "0d7ded4c-600e-42ae-ac99-3edbd5348d3f",
            "_rev": "000000002651a299"
          }
        }
      ],
      ...
    }
    $ curl \
     --header "X-OpenIDM-Username: openidm-admin" \
     --header "X-OpenIDM-Password: openidm-admin" \
     --request DELETE \
     "http://localhost:8080/openidm/managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1/members/0d7ded4c-600e-42ae-ac99-3edbd5348d3f"
    {
      "_id": "0d7ded4c-600e-42ae-ac99-3edbd5348d3f",
      "_rev": "000000002651a299",
      "_ref": "managed/user/bjensen",
      "_refResourceCollection": "managed/user",
      "_refResourceId": "bjensen",
      "_refProperties": {
        "_grantType": "",
        "_id": "0d7ded4c-600e-42ae-ac99-3edbd5348d3f",
        "_rev": "000000002651a299"
      }
    }

Note

Roles that have been granted as the result of a condition can only be removed when the condition is changed or removed, or when the role itself is deleted.

11.7. Deleting a Role Definition

You can delete a managed provisioning or authorization role by using the Admin UI, or over the REST interface.

To delete a role by using the Admin UI, select Manage > Role, select the role you want to remove then Delete Selected.

To delete a role over the REST interface, simply delete that managed object. The following command deletes the employee role created in the previous section:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request DELETE \
 "http://localhost:8080/openidm/managed/role/5790220a-719b-49ad-96a6-6571e63cbaf1"
{
  "_id": "5790220a-719b-49ad-96a6-6571e63cbaf1",
  "_rev": "0000000079c6644f",
  "name": "employee",
  "description": "Role granted to workers on the company payroll"
}

Note

You cannot delete a role if it is currently granted to one or more users. If you attempt to delete a role that is granted to a user (either over the REST interface, or by using the Admin UI), IDM returns an error. The following command indicates an attempt to remove the contractor role while it is still granted to user scarter:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request DELETE \
 "http://localhost:8080/openidm/managed/role/6c0afad4-645f-4573-a896-2ad2ae76c29a"
{
  "code": 409,
  "reason": "Conflict",
  "message": "Cannot delete a role that is currently granted"
}

11.8. Working With Role Assignments

Authorization roles control access to IDM itself. Provisioning roles define rules for how attribute values are updated on external systems. These rules are configured through assignments that are attached to a provisioning role definition. The purpose of an assignment is to provision an attribute or set of attributes, based on an object's role membership.

The synchronization mapping configuration between two resources (defined in the sync.json file) provides the basic account provisioning logic (how an account is mapped from a source to a target system). Role assignments provide additional provisioning logic that is not covered in the basic mapping configuration. The attributes and values that are updated by using assignments might include group membership, access to specific external resources, and so on. A group of assignments can collectively represent a role.

Assignment objects are created, updated and deleted like any other managed object, and are attached to a role by using the relationships mechanism, in much the same way as a role is granted to a user. Assignment are stored in the repository and are accessible at the context path /openidm/managed/assignment.

This section describes how to manipulate managed assignments over the REST interface, and by using the Admin UI. When you have created an assignment, and attached it to a role definition, all user objects that reference that role definition will, as a result, reference the corresponding assignment in their effectiveAssignments attribute.

11.8.1. Creating an Assignment

The easiest way to create an assignment is by using the Admin UI, as follows:

  1. Select Manage > Assignment then select New Assignment on the Assignment List page.

  2. Enter a name and description for the new assignment.

  3. Select the mapping to which the assignment should apply. The mapping indicates the target resource, that is, the resource on which the attributes specified in the assignment will be adjusted.

    Select Save to add the assignment.

  4. Select the Attributes tab and select the attribute or attributes whose values will be adjusted by this assignment.

    • If a regular text field appears, specify what the value of the attribute should be, when this assignment is applied.

    • If an Item button appears, you can specify a managed object type, such as an object, relationship, or string.

    • If a Properties button appears, you can specify additional information such as an array of role references.

  5. Select the assignment operation from the dropdown list:

    • Merge With Target - the attribute value will be added to any existing values for that attribute. This operation merges the existing value of the target object attribute with the value(s) from the assignment. If duplicate values are found (for attributes that take a list as a value), each value is included only once in the resulting target. This assignment operation is used only with complex attribute values like arrays and objects, and does not work with strings or numbers. (Property: mergeWithTarget.)

    • Replace Target - the attribute value will overwrite any existing values for that attribute. The value from the assignment becomes the authoritative source for the attribute. (Property: replaceTarget.)

    Select the unassignment operation from the dropdown list. You can set the unassignment operation to one of the following:

    • Remove From Target - the attribute value is removed from the system object when the user is no longer a member of the role, or when the assignment itself is removed from the role definition. (Property: removeFromTarget.)

    • No Operation - removing the assignment from the user's effectiveAssignments has no effect on the current state of the attribute in the system object. (Property: noOp.)

  6. (Optional) Select the Events tab to specify any scriptable events associated with this assignment.

    The assignment and unassignment operations described in the previous step operate at the attribute level. That is, you specify what should happen with each attribute affected by the assignment when the assignment is applied to a user, or removed from a user.

    The scriptable On assignment and On unassignment events operate at the assignment level, rather than the attribute level. You define scripts here to apply additional logic or operations that should be performed when a user (or other object) receives or loses an entire assignment. This logic can be anything that is not restricted to an operation on a single attribute.

    For information about the variables available to these scripts, see "Variables Available to Role Assignment Scripts".

  7. Select the Roles tab to attach this assignment to an existing role definition.

To create a new assignment over REST, send a PUT or POST request to the /openidm/managed/assignment context path.

The following example creates a new managed assignment named employee. The JSON payload in this example shows the following:

  • The assignment is applied for the mapping managedUser_systemLdapAccounts, so attributes will be updated on the external LDAP system specified in this mapping.

  • The name of the attribute on the external system whose value will be set is employeeType and its value will be set to Employee.

  • When the assignment is applied during a sync operation, the attribute value Employee will be added to any existing values for that attribute. When the assignment is removed (if the role is deleted, or if the managed user is no longer a member of that role), the attribute value Employee will be removed from the values of that attribute.

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request POST \
 --data '{
   "name" : "employee",
   "description": "Assignment for employees.",
   "mapping" : "managedUser_systemLdapAccount",
   "attributes": [
       {
           "name": "employeeType",
           "value": [
               "Employee"
           ],
           "assignmentOperation" : "mergeWithTarget",
           "unassignmentOperation" : "removeFromTarget"
       }
   ]
 }' \
 "http://localhost:8080/openidm/managed/assignment?_action=create"
{
  "_id": "5a145b08-d885-4fba-be21-08f2733ac1c5",
  "_rev": "00000000f26f9b5c",
  "name": "employee",
  "description": "Assignment for employees.",
  "mapping": "managedUser_systemLdapAccount",
  "attributes": [
    {
      "name": "employeeType",
      "value": [
        "Employee"
      ],
      "assignmentOperation": "mergeWithTarget",
      "unassignmentOperation": "removeFromTarget"
    }
  ]
}

Note that at this stage, the assignment is not linked to any role, so no user can make use of the assignment. You must add the assignment to a role, as described in the following section.

11.8.2. Adding an Assignment to a Role

When you have created a managed role, and a managed assignment, you create a relationship between the assignment and the role, in much the same way as a user references a role.

You can update a role definition to include one or more assignments, either by using the Admin UI, or over the REST interface.

Using the Admin UI
  1. Select Manage > Role and select the role to which you want to add an assignment.

  2. Select the Managed Assignments tab and select Add Managed Assignments.

  3. Select the assignment that you want to add to the role then select Add.

Over the REST interface

Update the role definition to include a reference to the ID of the assignment in the assignments property of the role. The following sample command adds the employee assignment (with ID 5a145b08-d885-4fba-be21-08f2733ac1c5) to an existing employee role (whose ID is a2e7a145-3d7d-4878-8b41-4d1a224ab53f):

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-Type: application/json" \
 --request PATCH \
 --data '[
   {
       "operation" : "add",
       "field" : "/assignments/-",
       "value" : { "_ref": "managed/assignment/5a145b08-d885-4fba-be21-08f2733ac1c5" }
   }
 ]' \
 "http://localhost:8080/openidm/managed/role/a2e7a145-3d7d-4878-8b41-4d1a224ab53f"
{
  "_id": "a2e7a145-3d7d-4878-8b41-4d1a224ab53f",
  "_rev": "00000000fd4060d9",
  "name": "employee",
  "description": "Role granted to members on the payroll"
}

To check that the assignment was added successfully, query the assignments property of the role:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/managed/role/a2e7a145-3d7d-4878-8b41-4d1a224ab53f/assignments?_queryFilter=true&_fields=_ref/*,name"
{
  "result": [
    {
      "_id": "ef3ed499-8a66-4020-8cc0-3924054188dc",
      "_rev": "000000004318a7d5",
      "_ref": "managed/assignment/5a145b08-d885-4fba-be21-08f2733ac1c5",
      "_refResourceCollection": "managed/assignment",
      "_refResourceId": "5a145b08-d885-4fba-be21-08f2733ac1c5",
      "_refProperties": {
        "_id": "ef3ed499-8a66-4020-8cc0-3924054188dc",
        "_rev": "000000004318a7d5"
      }
    }
  ],
...
}

Note that the role's assignments property now references the assignment that you created in the previous step.

To remove an assignment from a role definition, remove the reference to the assignment from the role's assignments property.

11.8.3. Deleting an Assignment

You can delete an assignment by using the Admin UI, or over the REST interface.

To delete an assignment by using the Admin UI, select Manage > Assignment, select the assignment you want to remove, then select Delete.

To delete an assignment over the REST interface, simply delete that object. The following command deletes the employee assignment created in the previous section:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request DELETE \
 "http://localhost:8080/openidm/managed/assignment/5a145b08-d885-4fba-be21-08f2733ac1c5"
{
  "_id": "5a145b08-d885-4fba-be21-08f2733ac1c5",
  "_rev": "00000000f26f9b5c",
  "name": "employee",
  "description": "Assignment for employees.",
  "mapping": "managedUser_systemLdapAccount",
  "attributes": [
    {
      "name": "employeeType",
      "value": [
        "Employee"
      ],
      "assignmentOperation": "mergeWithTarget",
      "unassignmentOperation": "removeFromTarget"
    }
  ]
}

Note

You can delete an assignment, even if it is referenced by a managed role. When the assignment is removed, any users to whom the corresponding roles were granted will no longer have that assignment in their list of effectiveAssignments. For more information about effective roles and effective assignments, see "Understanding Effective Roles and Effective Assignments".

11.8.4. Synchronizing Roles and Assignments

If you have mapped roles and assignments to properties on a target system, and you are preloading the result set into memory, make sure that your targetQuery returns the mapped property. For example, if you have mapped a specific role to the ldapGroups property on the target system, the target query must include the ldapGroups property when it returns the object.

The following excerpt of a mapping indicates that the target query must return the _id of the object as well as its ldapGroups property:

"targetQuery": {
    "_queryFilter" : true,
    "_fields" : "_id,ldapGroups"
},  

For more information about preloading the result set for reconciliation operations, see "Improving Reconciliation Query Performance".

11.9. Understanding Effective Roles and Effective Assignments

Effective roles and effective assignments are virtual properties of a user object. Their values are calculated on the fly by the openidm/bin/defaults/script/roles/effectiveRoles.js and openidm/bin/defaults/script/roles/effectiveAssignments.js scripts. These scripts are triggered when a managed user is retrieved and are referenced in onRetrieve hooks in the managed user schema.

The effectiveRoles.js and effectiveAssignments.js scripts must be executed in a specific order. First the effectiveRoles.js script determines the role grants for a user, processes any temporal constraints, and sets the effectiveRoles field in the user object. Then the effectiveAssignments.js script calculates the set of effective assignments, based on the value of the user's effectiveRoles property. The scripts are executed in the order in which they appear in the managed.json file, so you must ensure that the effectiveRoles property is declared first.

The following excerpt of a managed.json file shows how these two virtual properties are constructed for each managed user object:

"effectiveRoles" : {
    "type" : "array",
    "title" : "Effective Roles",
    "description" : "Effective Roles",
    "viewable" : false,
    "returnByDefault" : true,
    "isVirtual" : true,
    "usageDescription" : "",
    "isPersonal" : false,
    "onRetrieve" : {
        "type" : "text/javascript",
        "source" : "require('roles/effectiveRoles').calculateEffectiveRoles(object, 'roles');"
    },
    "items" : {
        "type" : "object",
        "title" : "Effective Roles Items"
    }
},
    "effectiveAssignments" : {
    "type" : "array",
    "title" : "Effective Assignments",
    "description" : "Effective Assignments",
    "viewable" : false,
    "returnByDefault" : true,
    "isVirtual" : true,
    "usageDescription" : "",
    "isPersonal" : false,
    "onRetrieve" : {
        "type" : "text/javascript",
        "file" : "roles/effectiveAssignments.js",
        "effectiveRolesPropName" : "effectiveRoles"
    },
    "items" : {
        "type" : "object",
        "title" : "Effective Assignments Items"
    }
},

When a role references an assignment, and a user references the role, that user automatically references the assignment in its list of effective assignments.

The effectiveRoles.js script uses the roles attribute of a user entry to calculate the grants (manual or conditional) that are currently in effect at the time of retrieval, based on temporal constraints or other custom scripted logic.

The effectiveAssignments.js script uses the virtual effectiveRoles attribute to calculate that user's effective assignments. The synchronization engine reads the calculated value of the effectiveAssignments attribute when it processes the user. The target system is updated according to the configured assignmentOperation for each assignment.

Do not change the default effectiveRoles.js and effectiveAssignments.js scripts. If you need to change the logic that calculates effectiveRoles and effectiveAssignments, create your own custom script and include a reference to it in your project's conf/managed.json file. For more information about using custom scripts, see "Scripting Reference".

When a user entry is retrieved, IDM calculates the effectiveRoles and effectiveAssignments for that user based on the current value of the user's roles property, and on any roles that might be granted dynamically through a custom script. The previous set of examples showed the creation of a role employee that referenced an assignment employee and was granted to user bjensen. Querying that user entry would show the following effective roles and effective assignments:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin"  \
 --request GET \
 "http://localhost:8080/openidm/managed/user/bjensen?_fields=userName,roles,effectiveRoles,effectiveAssignments"
{
  "_id": "bjensen",
  "_rev": "00000000edea91fa",
  "userName": "bjensen",
  "effectiveRoles": [
    {
      "_ref": "managed/role/a2e7a145-3d7d-4878-8b41-4d1a224ab53f"
    }
  ],
  "effectiveAssignments": [
    {
      "name": "employee",
      "description": "Assignment for employees.",
      "mapping": "managedUser_systemLdapAccount",
      "attributes": [
        {
          "assignmentOperation": "mergeWithTarget",
          "name": "employeeType",
          "unassignmentOperation": "removeFromTarget",
          "value": [
            "employee"
          ]
        }
      ],
      "_rev": "00000000e2c8b067",
      "_id": "4038e228-7477-4b70-b059-542f30c5be19"
    }
  ],
  "roles": [
    {
      "_ref": "managed/role/a2e7a145-3d7d-4878-8b41-4d1a224ab53f",
      "_refResourceCollection": "managed/role",
      "_refResourceId": "a2e7a145-3d7d-4878-8b41-4d1a224ab53f",
      "_refProperties": {
        "_grantType": "",
        "_id": "71d12cf2-3c33-4ec8-9c66-b78c33012bbf",
        "_rev": "00000000f007a17e"
      }
    }
  ]
}

In this example, synchronizing the managed/user repository with the external LDAP system defined in the mapping should populate user bjensen's employeeType attribute in LDAP with the value employee.

11.10. Roles and Relationship Change Notification

Before you read this section, see "Configuring Relationship Change Notification" to understand the notify and notifyRelationships properties, and how change notification works for relationships in general. In the case of roles, the change notification configuration exists to ensure that managed users are notified when any of the relationships that link users, roles, and assignments are manipulated (that is, created, updated, or deleted).

Consider the situation where a user has role R. A new assignment A is created that references role R. Ultimately, we want to notify all users that have role R so that their reconciliation state will reflect any attributes in the new assignment A. We achieve this notification with the following configuration:

In the managed object schema, the assignment object definition has a roles property that includes a resourceCollection. The path of this resource collection is managed/role and "notify" : true for the resource collection:

{
    "name" : "assignment",
    "schema" : {
        ...
        "properties" : {
            ...
            "roles" : {
                ...
                "items" : {
                    ...
                    "resourceCollection" : [
                        {
                            "notify" : true,
                            "path" : "managed/role",
                            "label" : "Role",
                            "query" : {
                                "queryFilter" : "true",
                                "fields" : [
                                    "name"
                                ]
                            }
                        }
                    ...
}

With this configuration, when assignment A is created, with a reference to role R, role R is notified of the change. However, we still need to propagate that notification to any users who are members of role R. To do this, we configure the role object as follows:

{
    "name" : "role",
    "schema" : {
        ...
        "properties" : {
            ...
            "assignments" : {
                ...
                "notifyRelationships" : ["members"]
            }
    ...
}

When role R is notified of the creation of a new relationship to assignment A, the notification is propagated through the assignments property. Because "notifyRelationships" : ["members"] is set on the assignments property, the notification is propagated across role R to all members of role R.

11.11. Managed Role Script Hooks

Like any other managed object, a role has script hooks that enable you to configure role behavior. The default role definition in conf/managed.json includes the following script hooks:

{
    "name" : "role",
    "onDelete" : {
        "type" : "text/javascript",
        "file" : "roles/onDelete-roles.js"
    },
    "postCreate" : {
        "type" : "text/javascript",
        "source" : "require('roles/postOperation-roles').manageTemporalConstraints(resourceName);"
    },
    "postUpdate" : {
        "type" : "text/javascript",
        "source" : "require('roles/postOperation-roles').manageTemporalConstraints(resourceName);"
    },
    "postDelete" : {
        "type" : "text/javascript",
        "source" : "require('roles/postOperation-roles').manageTemporalConstraints(resourceName);"
    },
    ...

When a role is deleted, the onDelete script hook calls the bin/default/script/roles/onDelete-roles.js script.

Directly after a role is created, updated or deleted, the postCreate, postUpdate, and postDelete hooks call roles/postOperation-roles, which can be found in bin/defaults/script/roles/postOperation-roles.js. Depending on when this script is called, it either creates or removes the scheduled jobs required to manage temporal constraints on roles.

Chapter 12. Configuring Social Identity Providers

IDM provides a standards-based solution for social authentication requirements, based on the OAuth 2.0 and OpenID Connect 1.0 standards. They are similar, as OpenID Connect 1.0 is an authentication layer built on OAuth 2.0.

This chapter describes how to configure IDM to register and authenticate users with multiple social identity providers.

To configure different social identity providers, you'll take the same general steps:

  • Set up the provider. You'll need information such as a Client ID and Client Secret to set up an interface with IDM.

  • Configure the provider on IDM.

  • Set up User Registration. Activate Social Registration in the applicable Admin UI screen or configuration file.

  • After configuration is complete, test the result. For a common basic procedure, see "Testing Social Identity Providers".

You can configure how IDM handles authentication using social identity providers by opening the Admin UI and selecting Configure > Authentication > Modules > Social Providers. The Social Providers authentication module is enabled by default. For more information, see "Configuring the Social Providers Authentication Module".

To understand how data is transmitted between IDM and a social identity provider, read "OpenID Connect Authorization Code Flow".

Note

For all social identity providers, set up a FQDN for IDM, along with information in a DNS server, or system hosts files. For test purposes, FQDNs that comply with RFC 2606, such as localhost and openidm.example.com, are acceptable.

12.1. OpenID Connect Authorization Code Flow

The OpenID Connect Authorization Code Flow specifies how IDM (Relying Party) interacts with the OpenID Provider (Social ID Provider), based on the use of the OAuth 2.0 authorization grant. The following sequence diagram illustrates successful processing from the authorization request, through grant of the authorization code, access token, ID token, and provisioning from the social identity provider to IDM.

OpenID Connect Authorization Code Flow for Social ID Providers
OpenID Connect Authorization Code Flow for Social ID Providers

The following list describes details of each item in the authorization flow:

  1. A user navigates to the IDM End User UI, and selects the Sign In link for the desired social identity provider.

  2. IDM prepares an authorization request.

  3. IDM sends the request to the Authorization Endpoint that you configured for the social identity provider, with a Client ID.

  4. The social identity provider requests end user authentication and consent.

  5. The end user transmits authentication and consent.

  6. The social identity provider sends a redirect message, with an authorization code, to the end user's browser. The redirect message goes to an oauthReturn endpoint, configured in ui.context-oauth.json in your project's conf/ directory.

    When you configure a social identity provider, you'll find the endpoint in the applicable configuration file with the following property: redirectUri.

  7. The browser transmits the redirect message, with the authorization code, to IDM.

  8. IDM records the authorization code, and sends it to the social identity provider Token Endpoint.

  9. The social identity provider token endpoint returns access and ID tokens.

  10. IDM validates the token, and sends it to the social identity provider User Info Endpoint.

  11. The social identity provider responds with information on the user's account, that IDM can provision as a new Managed User.

You'll configure these credentials and endpoints, in some form, for each social identity provider.

12.2. Many Social Identity Providers, One Schema

Most social identity providers include common properties, such as name, email address, icon configuration, and location.

IDM includes two sets of property maps that translate information from a social identity provider to your managed user objects. These property maps are as follows:

  • The identityProviders.json file includes a propertyMap code block for each supported provider. This file maps properties from the provider to a generic managed user object. You should not customize this file.

  • The selfservice.propertymap.json file translates the generic managed user properties to the managed user schema that you have defined in managed.json. If you have customized the managed user schema, this is the file that you must change, to indicate how your custom schema maps to the generic managed user schema.

Examine the identityProviders.json file in the conf/ subdirectory for your project. The following excerpt represents the Facebook propertyMap code block from that file:

"propertyMap" : [
   {
      "source" : "id",
      "target" : "id"
   },
   {
      "source" : "name",
      "target" : "displayName"
   },
   {
      "source" : "first_name",
      "target" : "givenName"
   },
   {
      "source" : "last_name",
      "target" : "familyName"
   },
   {
      "source" : "email",
      "target" : "email"
   },
   {
      "source" : "email",
      "target" : "username"
   },
   {
      "source" : "locale",
      "target" : "locale"
   }
]

The source lists the Facebook property, the target lists the corresponding property for a generic managed user.

IDM then processes that information through the selfservice.propertymap.json file, where the source corresponds to the generic managed user and the target corresponds to your customized managed user schema (defined in your project's managed.json file).

{
   "properties" : [
      {
         "source" : "givenName",
         "target" : "givenName"
      },
      {
         "source" : "familyName",
         "target" : "sn"
      },
      {
         "source" : "email",
         "target" : "mail"
      },
      {
         "source" : "postalAddress",
         "target" : "postalAddress",
         "condition" : "/object/postalAddress  pr"
      },
      {
         "source" : "addressLocality",
         "target" : "city",
         "condition" : "/object/addressLocality  pr"
      },
      {
         "source" : "addressRegion",
         "target" : "stateProvince",
         "condition" : "/object/addressRegion  pr"
      },
      {
         "source" : "postalCode",
         "target" : "postalCode",
         "condition" : "/object/postalCode  pr"
      },
      {
         "source" : "country",
         "target" : "country",
         "condition" : "/object/country  pr"
      },
      {
         "source" : "phone",
         "target" : "telephoneNumber",
         "condition" : "/object/phone  pr"
      },
      {
         "source" : "username",
         "target" : "userName"
      }
   ]
}

Tip

To take additional information from a social identity provider, make sure the property is mapped through the identityProviders.json and selfservice.propertymap.json files.

Several of the property mappings include a pr presence expression which is a filter that returns all records with the given attribute. For more information, see "Presence Expressions".

12.3. Setting Up Google as a Social Identity Provider

Take the following basic steps to configure Google as a social identity provider for IDM:

12.3.1. Setting Up Google

To set up Google as a social identity provider, navigate to the Google API Manager. You'll need a Google account. If you have GMail, you already have a Google account. While you could use a personal Google account, it is best to use an organizational account to avoid problems if specific individuals leave your organization. When you set up a Google social identity provider, you'll need to perform the following tasks:

Plan ahead. It may take some time before the Google+ API that you configure for IDM is ready for use.

  • In the Google API Manager, select and enable the Google+ API. It is one of the Google "social" APIs.

  • Create a project for IDM.

  • Create OAuth client ID credentials. You'll need to configure an OAuth consent screen with at least a product name and email address.

  • When you set up a Web application for the client ID, you'll need to set up a web client with:

    • Authorized JavaScript origins

      The origin URL for IDM, typically a URL such as https://openidm.example.com:8443

    • Authorized redirect URIs

      The redirect URI after users are authenticated, typically, https://openidm.example.com:8443/

  • In the list of credentials, you'll see a unique Client ID and Client secret. You'll need this information when you configure the Google social identity provider, as described in "Configuring a Google Social Identity Provider".

For Google's procedure, see the Google Identity Platform documentation on Setting Up OAuth 2.0.

12.3.2. Configuring a Google Social Identity Provider

  1. To configure a Google social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Google social identity provider, and if needed, select the edit icon.

  3. Include the Google values for Client ID and Client Secret for your project, as described earlier in this section.

  4. Under regular and Advanced Options, include the options shown in the following appendix: "Google Social Identity Provider Configuration Details".

When you enable a Google social identity provider in the Admin UI, IDM generates the identityProvider-google.json file in your project's conf/ subdirectory.

When you review that file, you should see information from what you configured in the Admin UI, and beyond. The first part of the file includes the name of the provider, endpoints, as well as the values for clientId and clientSecret.

{
    "enabled" : true,
    "authorizationEndpoint" : "https://accounts.google.com/o/oauth2/v2/auth",
    "tokenEndpoint" : "https://www.googleapis.com/oauth2/v4/token",
    "userInfoEndpoint" : "https://www.googleapis.com/oauth2/v3/userinfo",
    "wellKnownEndpoint" : "https://accounts.google.com/.well-known/openid-configuration"
    "clientId" : "<someUUID>",
    "clientSecret" : {
        "$crypto" : {
            "type" : "x-simple-encryption",
            "value" : {
               "cipher" : "AES/CBC/PKCS5Padding",
               "stableId" : "openidm-sym-default",
               "salt" : "<hashValue>",
               "data" : "<encryptedValue>",
               "keySize" : 16,
               "purpose" : "idm.config.encryption",
               "iv" : "<encryptedValue>",
               "mac" : "<hashValue>"
            }
        }
    },
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, scopes, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Google social identity, you can verify this by selecting Manage > Google, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "Google Social Identity Provider Configuration Details".

12.3.3. Configuring User Registration to Link to Google

Once you've configured the Google social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and under the Social tab, enable the option associated with Social Registration. For more information on user self-service features, see "Configuring User Self-Service".

When you enable social registration, you're allowing users to register on IDM through all active social identity providers.

12.4. Setting Up LinkedIn as a Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure LinkedIn as a social identity provider for IDM:

12.4.1. Setting Up LinkedIn

To set up LinkedIn as a social identity provider, navigate to the LinkedIn Developers page for My Applications. You'll need a LinkedIn account. While you could use a personal LinkedIn account, it is best to use an organizational account to avoid problems if specific individuals leave your organization. When you set up a LinkedIn social identity provider, you'll need to perform the following tasks:

  • In the LinkedIn Developers page for My Applications, select Create Application.

  • You'll need to include the following information when creating an application:

    • Company Name

    • Application Name

    • Description

    • Application Logo

    • Application Use

    • Website URL

    • Business Email

    • Business Phone

  • When you see Authentication Keys for your LinkedIn application, save the Client ID and Client Secret.

  • Enable the following default application permissions:

    • r_basicprofile

    • r_emailaddress

  • When you set up a Web application for the client ID, you'll need to set up a web client with OAuth 2.0 Authorized Redirect URLs. For example, if your IDM FQDN is openidm.example.com, add the following URL:

    • http://openidm.example.com:8080/

    You can ignore any LinkedIn URL boxes related to OAuth 1.0a.

For LinkedIn's procedure, see their documentation on Authenticating with OAuth 2.0.

12.4.2. Configuring a LinkedIn Social Identity Provider

  1. To configure a LinkedIn social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the LinkedIn social identity provider.

  3. Include the values that LinkedIn created for Client ID and Client Secret, as described in "Setting Up LinkedIn".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "LinkedIn Social Identity Provider Configuration Details".

When you enable a LinkedIn social identity provider, IDM generates the identityProvider-linkedIn.json file in your project's conf/ subdirectory.

When you review that file, you should see information beyond what you see in the Admin UI. The first part of the file includes the name of the provider, endpoints, as well as the values for clientId and clientSecret.

{
   "provider" : "linkedIn",
   "authorizationEndpoint" : "https://www.linkedin.com/oauth/v2/authorization",
   "tokenEndpoint" : "https://www.linkedin.com/oauth/v2/accessToken",
   "userInfoEndpoint" : "https://api.linkedin.com/v1/people/~:(id,formatted-name,first-name,last-name,email-address,location)?format=json"
   "provider" : "linkedIn",
   "clientId" : "<someUUID>",
   "clientSecret" : {
       "$crypto" : {
           "type" : "x-simple-encryption",
           "value" : {
               "cipher" : "AES/CBC/PKCS5Padding",
               "stableId" : "openidm-sym-default",
               "salt" : "<hashValue>",
               "data" : "<encryptedValue>",
               "keySize" : 16,
               "purpose" : "idm.config.encryption",
               "iv" : "<encryptedValue>",
               "mac" : "<hashValue>"
           }
       }
   },
   "scope" : [
       "r_basicprofile",
       "r_emailaddress"
   ],
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a LinkedIn social identity, you can verify this by selecting Manage > LinkedIn, and then selecting a user.

If you need more information about the properties in this file, refer to the following appendix: "LinkedIn Social Identity Provider Configuration Details".

12.4.3. Configuring User Registration With LinkedIn

Once you've configured the LinkedIn social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration. Under the Social tab, enable the option associated with Social Registration. For more information about user self-service features, see "Configuring User Self-Service".

When you enable social registration, you're allowing users to register on IDM through all active social identity providers.

12.5. Setting Up Facebook as a Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Facebook as a social identity provider for IDM:

Note

As of October 2018, Facebook as a social identity provider requires access over secure HTTP (HTTPS).

12.5.1. Setting Up Facebook

To set up Facebook as a social identity provider, navigate to the Facebook for Developers page. You'll need a Facebook account. While you could use a personal Facebook account, it is best to use an organizational account to avoid problems if specific individuals leave your organization. When you set up a Facebook social identity provider, you'll need to perform the following tasks:

  • In the Facebook for Developers page, select My Apps and Add a New App. For IDM, you'll create a Website application.

  • You'll need to include the following information when creating a Facebook website application:

    • Display Name

    • Contact Email

    • IDM URL

  • When complete, you should see your App. Navigate to Basic Settings.

  • Make a copy of the App ID and App Secret for when you configure the Facebook social identity provider in IDM.

  • In the settings for your App, you should see an entry for App Domains, such as example.com, as well as a Website Site URL, such as https://idm.example.com/.

For Facebook's documentation on the subject, see Facebook Login for the Web with the JavaScript SDK.

12.5.2. Configuring a Facebook Social Identity Provider

  1. To configure a Facebook social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Facebook social identity provider.

  3. Include the values that Facebook created for App ID and App Secret, as described in "Setting Up Facebook".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "Facebook Social Identity Provider Configuration Details".

When you enable a Facebook social identity provider in the Admin UI, IDM generates the identityProvider-facebook.json file in your project's conf/ subdirectory.

It includes parts of the file that you may have configured through the Admin UI. While the labels in the UI specify App ID and App Secret, you'll see them as clientId and clientSecret, respectively, in the configuration file.

{
   "provider" : "facebook",
   "authorizationEndpoint" : "https://www.facebook.com/dialog/oauth",
   "tokenEndpoint" : "https://graph.facebook.com/v2.7/oauth/access_token",
   "userInfoEndpoint" : "https://graph.facebook.com/me?fields=id,name,picture,email,first_name,last_name,locale"
   "clientId" : "<someUUID>",
   "clientSecret" : {
       "$crypto" : {
           "type" : "x-simple-encryption",
           "value" : {
             "cipher" : "AES/CBC/PKCS5Padding",
             "stableId" : "openidm-sym-default",
             "salt" : "<hashValue>",
             "data" : "<encryptedValue>",
             "keySize" : 16,
             "purpose" : "idm.config.encryption",
             "iv" : "<encryptedValue>",
             "mac" : "<hashValue>"
           }
       }
   },
   "scope" : [
       "email",
       "user_birthday"
   ],
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Facebook social identity, you can verify this by selecting Manage > Facebook, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "Facebook Social Identity Provider Configuration Details".

12.5.3. Configuring User Registration to Link to Facebook

Once you've configured the Facebook social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and under the Social tab, enable the option associated with Social Registration. For more information about user self-service features, see "Configuring User Self-Service".

When you enable social registration, you're allowing users to register on IDM through all active social identity providers.

12.6. Setting Up Amazon as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Amazon as a social identity provider for IDM:

Note

Amazon as a social identity provider requires access over secure HTTP (HTTPS).

12.6.1. Setting Up Amazon

To set up Amazon as a social identity provider, navigate to the following Amazon page: Register Your Website With Login With Amazon . You'll need an Amazon account. You'll also need to register a security profile.

When you set up Amazon as a social identity provider, navigate to the Amazon Security Profile Management page. You'll need to enter the following:

  • Security Profile Name (The name of your app)

  • Security Profile Description

  • Consent Privacy Notice URL

  • Consent Logo Image (optional)

When complete and saved, you should see a list of security profiles with OAuth2 credentials. You should be able to find the Client ID and Client Secret from this screen.

However, you still need to configure the web settings for your new Security Profile. You can find a list of your existing Security Profiles on the Login with Amazon Developer Console Page . You can access that page from the Amazon Developer Console dashboard by selecting Apps and Services > Login with Amazon. You can then Manage the Web Settings for that app.

In the Web Settings for your app, you'll need to set either of the following properties:

  • Allowed Origins, which should match the URL for your registration page, such as https://openidm.example.com:8443

  • Allowed Return URLs, which should match the redirect URIs described in "Configuring an Amazon Social Identity Provider". You may see URIs such as https://openidm.example.com:8443/.

12.6.2. Configuring an Amazon Social Identity Provider

  1. To configure an Amazon social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Amazon social identity provider.

    In the Amazon Provider pop-up that appears, the values for Redirect URI should match the values that you've entered for Allowed Return URLs in "Setting Up Amazon".

  3. Include the values that Amazon created for Client ID and Client Secret, as described in "Setting Up Amazon".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "Amazon Social Identity Provider Configuration Details".

When you enable an Amazon social identity provider in the Admin UI, IDM generates the identityProvider-amazon.json file in your project's conf/ subdirectory.

When you review that file, you should see information beyond what you see in the Admin UI. The first part of the file includes the name of the provider, endpoints, as well as the values for clientId and clientSecret.

{
   "provider" : "amazon",
   "authorizationEndpoint" : "https://www.amazon.com/ap/oa",
   "tokenEndpoint" : "https://api.amazon.com/auth/o2/token",
   "userInfoEndpoint" : "https://api.amazon.com/user/profile"
   "enabled" : true,
   "clientId" : "<someUUID>",
   "clientSecret" : {
       "$crypto" : {
           "type" : "x-simple-encryption",
           "value" : {
               "cipher" : "AES/CBC/PKCS5Padding",
               "stableId" : "openidm-sym-default",
               "salt" : "<hashValue>",
               "data" : "<encryptedValue>",
               "keySize" : 16,
               "purpose" : "idm.config.encryption",
               "iv" : "<encryptedValue>",
               "mac" : "<hashValue>"
           }
       }
   },
   "scope" : [
       "profile"
   ],
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with an Amazon social identity, you can verify this by selecting Manage > Amazon, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "Amazon Social Identity Provider Configuration Details".

12.6.3. Configuring User Registration to Link to Amazon

Once you've configured the Amazon social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.7. Setting Up Microsoft as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Microsoft as a social identity provider for IDM:

Note

Microsoft as a social identity provider requires access over secure HTTP (HTTPS). This example assumes that you've configured IDM on https://openidm.example.com:8443. Substitute your URL for openidm.example.com.

12.7.1. Setting Up Microsoft

For Microsoft documentation on how to set up a social identity provider, navigate to the following article: Sign-in Microsoft Account & Azure AD users in a single app . You'll need a Microsoft account.

To set up Microsoft as a social identity provider:

  • Navigate to the Microsoft app registration portal at https://apps.dev.microsoft.com/ and sign in with your Microsoft account.

  • Select Add an App and give your app a name.

    The portal will assign your app a unique Application ID.

  • To find your Application Secret, select Generate New Password. That password is your Application Secret.

    Tip

    Save your new password. It is the only time you'll see the Application Secret for your new app.

  • Select Add Platform. You'll choose a Web platform, enable Allow Implicit Flow and set up the following value for Redirect URI:

    • https://openidm.example.com:8443/

If desired, you can also enter the following information:

  • Logo image

  • Terms of Service URL

  • Privacy Statement URL

The OAuth2 credentials for your new Microsoft App include an Application ID and Application Secret for your app.

12.7.2. Configuring a Microsoft Social Identity Provider

  1. To configure a Microsoft social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Microsoft social identity provider.

    In the Microsoft Provider pop-up that appears, the values for Redirect URI should match the values that you've entered for Allowed Return URLs in "Setting Up Microsoft".

  3. Include the values that Microsoft created for Client ID and Client Secret, as described in "Setting Up Microsoft".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "Microsoft Social Identity Provider Configuration Details".

When you enable a Microsoft social identity provider in the Admin UI, IDM generates the identityProvider-microsoft.json file in your project's conf/ subdirectory.

It includes parts of the file that you may have configured through the Admin UI. While the labels in the UI specify Application ID and Application Secret, you'll see them as clientId and clientSecret, respectively, in the configuration file.

"provider" : "microsoft",
   "authorizationEndpoint" : "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
   "tokenEndpoint" : "https://login.microsoftonline.com/common/oauth2/v2.0/token",
   "userInfoEndpoint" : "https://graph.microsoft.com/v1.0/me"
   "clientId" : "<someUUID>",
   "clientSecret" : {
       "$crypto" : {
           "type" : "x-simple-encryption",
           "value" : {
               "cipher" : "AES/CBC/PKCS5Padding",
               "stableId" : "openidm-sym-default",
               "salt" : "<hashValue>",
               "data" : "<encryptedValue>",
               "keySize" : 16,
               "purpose" : "idm.config.encryption",
               "iv" : "<encryptedValue>",
               "mac" : "<hashValue>"
           }
       }
   },
   "scope" : [
       "User.Read"
   ],
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Microsoft social identity, you can verify this by selecting Manage > Microsoft, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "Microsoft Social Identity Provider Configuration Details".

12.7.3. Configuring User Registration to Link to Microsoft

Once you've configured the Microsoft social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.8. Setting Up WordPress as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure WordPress as a social identity provider for IDM:

12.8.1. Setting Up WordPress

To set up WordPress as a social identity provider, navigate to the following WordPress Developers page: Developer Resources . You'll need a WordPress account. You can then navigate to the WordPress My Applications page, where you can create a new web application, with the following information:

  • Name

  • Description

  • Website URL, which becomes your Application URL

  • Redirect URL(s); for IDM, normally http://openidm.example.com:8080/

  • Type, which allows you to select Web clients

When complete and saved, you should see a list of OAuth Information for your new web application. That information should include your Client ID and Client Secret.

12.8.2. Configuring a WordPress Social Identity Provider

  1. To configure a WordPress social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the WordPress social identity provider.

    In the WordPress Provider pop-up that appears, the values for Redirect URI should match the values that you've entered for Allowed Return URLs in "Setting Up WordPress".

  3. Include the values that WordPress created for Client ID and Client Secret, as described in "Setting Up WordPress".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "WordPress Social Identity Provider Configuration Details".

When you enable a WordPress social identity provider in the Admin UI, IDM generates the identityProvider-wordpress.json file in your project's conf/ subdirectory.

When you review that file, you should see information beyond what you see in the Admin UI. The first part of the file includes the name of the provider, endpoints, as well as the values for clientId and clientSecret.

{
    "provider" : "wordpress",
    "authorizationEndpoint" : "https://public-api.wordpress.com/oauth2/authorize",
    "tokenEndpoint" : "https://public-api.wordpress.com/oauth2/token",
    "userInfoEndpoint" : "https://public-api.wordpress.com/rest/v1.1/me/",
    "enabled" : true,
    "clientId" : "<someUUID>",
    "clientSecret" : {
       "$crypto" : {
           "type" : "x-simple-encryption",
           "value" : {
               "cipher" : "AES/CBC/PKCS5Padding",
               "stableId" : "openidm-sym-default",
               "salt" : "<hashValue>",
               "data" : "<encryptedValue>",
               "keySize" : 16,
               "purpose" : "idm.config.encryption",
               "iv" : "<encryptedValue>",
               "mac" : "<hashValue>"
           }
       }
    },
    "scope" : [
        "auth"
    ],
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Wordpress social identity, you can verify this by selecting Manage > Wordpress, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "WordPress Social Identity Provider Configuration Details".

12.8.3. Configuring User Registration to Link to WordPress

Once you've configured the WordPress social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.9. Setting Up WeChat as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure WeChat as a social identity provider for IDM:

These requirements assume that you have a WeChat developer account where you can get access to create WeChat web application credentials. To verify access, you'll need the WeChat app on your mobile phone.

12.9.1. Setting Up WeChat

To set up WeChat as a social identity provider, you'll need to get the following information for your WeChat app. The name may be different in WeChat.

  • Client ID (WeChat uses appid as of this writing.)

  • Client Secret (WeChat uses secret as of this writing.)

  • Scope

  • Authorization Endpoint URL

  • Token Endpoint URL

  • User Info Endpoint URL

  • Redirect URI, normally something like http://openidm.example.com/

WeChat Unique Requirements

Before testing WeChat, be prepared for the following special requirements:

  • WeChat works only if you deploy IDM on one of the following ports: 80 or 443.

    For more information on how to configure IDM to use these ports, see "Host and Port Information".

  • For registration and sign-in, WeChat requires the use of a mobile device with a Quick Response (QR) code reader.

  • For sign-in, you'll also need to install the WeChat app on your mobile device.

12.9.2. Configuring a WeChat Social Identity Provider

  1. To configure a WeChat social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the WeChat social identity provider.

    In the WeChat Provider pop-up that appears, the values for Redirect URI should match the values that you've entered for Allowed Return URLs in "Setting Up WeChat".

  3. Include the values that WeChat created for Client ID and Client Secret, as described in "Setting Up WeChat".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "WeChat Social Identity Provider Configuration Details".

When you enable a WeChat social identity provider in the Admin UI, IDM generates the identityProvider-wechat.json file in your project's conf/ subdirectory.

When you review that file, you should see information from what you configured in the Admin UI, and beyond. The first part of the file includes the name of the provider, endpoints, scopes, as well as the values for clientId and clientSecret.

{
    "provider" : "wechat",
    ...
    "clientId" : "<someUUID>",
    "clientSecret" : {
       "$crypto" : {
           "type" : "x-simple-encryption",
              "value" : {
               "cipher" : "AES/CBC/PKCS5Padding",
               "stableId" : "openidm-sym-default",
               "salt" : "<hashValue>",
               "data" : "<encryptedValue>",
               "keySize" : 16,
               "purpose" : "idm.config.encryption",
               "iv" : "<encryptedValue>",
               "mac" : "<hashValue>"
           }
       }
    },
    "authorizationEndpoint" : "https://open.weixin.qq.com/connect/qrconnect",
    "tokenEndpoint" : "https://api.wechat.com/sns/oauth2/access_token",
    "refreshTokenEndpoint" : "https://api.wechat.com/sns/oauth2/refresh_token",
    "userInfoEndpoint" : "https://api.wechat.com/sns/userinfo",
    "redirectUri" : "http://openidm.example.com:8080/",
    "scope" : [
        "snsapi_login"
    ],
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a WeChat social identity, you can verify this by selecting Manage > WeChat, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "WeChat Social Identity Provider Configuration Details".

12.9.3. Configuring User Registration to Link to WeChat

Once you've configured the WeChat social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.10. Setting Up Instagram as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Instagram as a social identity provider for IDM:

12.10.1. Setting Up Instagram

To set up Instagram as a social identity provider, navigate to the following page: Instagram Developer Documentation . You'll need an Instagram account. You can then navigate to the Manage Clients page, where you can follow the Instagram process to create a new web application. As of this writing, you can do so on their Register a new Client ID page, where you'll need the following information:

  • Application Name

  • Description

  • Website URL for your app, such as http://openidm.example.com:8080

  • Redirect URL(s); for IDM: http://openidm.example.com:8080/

When complete and saved, you should see a list of OAuth Information for your new webapp. That information should be included in your Client ID and Client Secret.

12.10.2. Configuring an Instagram Social Identity Provider

  1. To configure an Instagram social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Instagram social identity provider.

    In the Instagram Provider pop-up that appears, the values for Redirect URI should match the values that you've entered for Valid Redirect URIs in "Setting Up Instagram".

  3. Include the values that Instagram created for Client ID and Client Secret, as described in "Setting Up Instagram".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "Instagram Social Identity Provider Configuration Details".

When you enable an Instagram social identity provider in the Admin UI, IDM generates the identityProvider-instagram.json file in your project's conf/ subdirectory.

When you review that file, you should see information from what you configured in the Admin UI, and beyond. The first part of the file includes the name of the provider, endpoints, scopes, as well as the values for clientId and clientSecret.

{
   "provider" : "instagram",
   ...
   "clientId" : "<Client_ID_Name>",
   "clientSecret" : {
      "$crypto" : {
         "type" : "x-simple-encryption",
         "value" : {
            "cipher" : "AES/CBC/PKCS5Padding",
            "stableId" : "openidm-sym-default",
            "salt" : "<hashValue>",
            "data" : "<encryptedValue>",
            "keySize" : 16,
            "purpose" : "idm.config.encryption",
            "iv" : "<encryptedValue>",
            "mac" : "<hashValue>"
         }
      }
   },
   "authorizationEndpoint" : "https://api.instagram.com/oauth/authorize/",
   "tokenEndpoint" : "https://api.instagram.com/oauth/access_token",
   "userInfoEndpoint" : "https://api.instagram.com/v1/users/self/",
   "redirectUri" : "http://openidm.example.com:8080/",
   "scope" : [
       "basic",
       "public_content"
   ],
...

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with an Instagram social identity, you can verify this by selecting Manage > Instagram, and then selecting a user.

If you need more information about the properties in this file, refer to the following appendix: "Instagram Social Identity Provider Configuration Details".

12.10.3. Configuring User Registration to Link to Instagram

Once you've configured the Instagram social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.11. Setting Up Vkontakte as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Vkontakte as a social identity provider for IDM:

Note

When you configure a Vkontakte app, look for an Application ID and a Secure Key. IDM uses this information as a clientId and clientSecret, respectively.

12.11.1. Setting Up Vkontakte

To set up Vkontakte as a social identity provider, navigate to the following Vkontakte page: Vkontakte Developers Page . You'll need a Vkontakte account. Find a My Apps link. You can then create an application with the following information:

  • Title (The name of your app)

  • Platform (Choose Website)

  • Site Address (The URL of your IDM deployment, such as http://openidm.example.com:8080/

  • Base domain (Example: example.com)

  • Authorized Redirect URI (Example: http://openidm.example.com:8080/)

  • API Version; for the current VKontakte API version, see VK Developers Documentation, API Versions section. The default VKontakte API version used for IDM 6.5 is 5.73.

If you leave and need to return to Vkontakte, navigate to https://vk.com/dev and select My Apps. You can then Manage the new apps that you've created.

Navigate to the Settings for your app, where you'll find the Application ID and Secure Key for your app. You'll use that information as shown here:

  • Vkontakte Application ID = IDM Client ID

  • Vkontakte Secure Key = IDM Client Secret

12.11.2. Configuring a Vkontakte Social Identity Provider

  1. To configure a Vkontakte social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Vkontakte social identity provider.

    In the Vkontakte Provider pop-up that appears, the values for Redirect URI should match the values that you've entered for Authorized Redirect URI in "Setting Up Vkontakte".

  3. Include the values that Vkontakte created for Client ID and Client Secret, as described in "Setting Up Vkontakte".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "Vkontakte Social Identity Provider Configuration Details".

When you enable a Vkontakte social identity provider in the Admin UI, IDM generates the identityProvider-vkontakte.json file in your project's conf/ subdirectory.

When you review that file, you should see information beyond what you see in the Admin UI. The first part of the file includes the name of the provider, endpoints, as well as information from the Consumer Key and Consumer Secret, you'll see them as clientId and clientSecret, respectively, in the configuration file.

{
    "provider" : "vkontakte",
    "configClass" : "org.forgerock.oauth.clients.vk.VKClientConfiguration",
    "basicAuth" : false,
    "clientId" : "<someUUID>",
    "clientSecret" : {
        "$crypto" : {
            "type" : "x-simple-encryption",
            "value" : {
                "cipher" : "AES/CBC/PKCS5Padding",
                "stableId" : "openidm-sym-default",
                "salt" : "<hashValue>",
                "data" : "<encryptedValue>",
                "keySize" : 16,
                "purpose" : "idm.config.encryption",
                "iv" : "<encryptedValue>",
                "mac" : "<hashValue>"
            }
        }
    },
    "authorizationEndpoint" : "https://oauth.vk.com/authorize",
    "tokenEndpoint" : "https://oauth.vk.com/access_token",
    "userInfoEndpoint" : "https://api.vk.com/method/users.get",
    "redirectUri" : "http://openidm.example.com:8080/",
    "apiVersion" : "5.73",
    "scope" : [
        "email"
    ],
...

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Vkontakte social identity, you can verify this by selecting Manage > Vkontakte, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "Vkontakte Social Identity Provider Configuration Details".

12.11.3. Configuring User Registration to Link to Vkontakte

Once you've configured the Vkontakte social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.12. Setting Up Salesforce as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Salesforce as a social identity provider for IDM:

Note

When you configure a Salesforce app, look for a Consumer Key and a Consumer Secret. IDM uses this information as a clientId and clientSecret, respectively.

For reference, read through the following Salesforce documentation: Connected Apps Overview.

12.12.1. Setting Up Salesforce

To set up Salesforce as a social identity provider, you will need a Salesforce developer account. Log in to the Salesforce Developers Page with your developer account credentials and create a new Connected App.

Note

These instructions were written with the Winter '19 Release of the Salesforce API. The menu items might differ slightly if you are working with a different version of the API.

Under App Setup, select Create > Apps > Connected Apps > New. You will need to add the following information:

  • Connected App Name

  • API Name (defaults to the Connected App Name)

  • Contact Email

  • Activate the following option: Enable OAuth Settings

  • Callback URL (also known as the Redirect URI for other providers), for example https://localhost:8443/.

    The Callback URL must correspond to the URL that you use to log in to the IDM Admin UI.

  • Add the following OAuth scopes:

    • Access and Manage your data (api)

    • Access your basic information (id, profile, email, address, phone)

    • Perform requests on your behalf at any time (refresh_token, offline_access)

    • Provide access to your data via the Web (web)

    Note that these must be added even if you are otherwise planning to use the full OAuth scope.

After you have saved the Connected App, it might take a few minutes for the new app to appear under Administration Setup > Manage Apps > Connected Apps.

Select the new Connected App then locate the Consumer Key and Consumer Secret (under the API list). You'll use that information as shown here:

  • Salesforce Consumer Key = IDM Client ID

  • Salesforce Consumer Secret = IDM Client Secret

12.12.2. Configuring a Salesforce Social Identity Provider

  1. To configure a Salesforce social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Salesforce social identity provider.

    In the Salesforce Provider pop-up that appears, the values for Redirect URI should match the value that you've entered for Callback URL in "Setting Up Salesforce".

  3. Include the values that Salesforce created for Consumer Key and Consumer Secret, as described in "Setting Up Salesforce".

  4. Under regular and Advanced Options, include the options shown in the following appendix: "Salesforce Social Identity Provider Configuration Details".

When you enable a Salesforce social identity provider in the Admin UI, IDM generates the identityProvider-salesforce.json file in your project's conf/ subdirectory.

It includes parts of the file that you may have configured through the Admin UI. While the labels in the UI specify Consumer Key and Consumer Secret, you'll see them as clientId and clientSecret, respectively, in the configuration file.

{
    "provider" : "salesforce",
    "authorizationEndpoint" : "https://login.salesforce.com/services/oauth2/authorize",
    "tokenEndpoint" : "https://login.salesforce.com/services/oauth2/token",
    "userInfoEndpoint" : "https://login.salesforce.com/services/oauth2/userinfo",
    "clientId" : "<someUUID>",
    "clientSecret" : {
       "$crypto" : {
           "type" : "x-simple-encryption",
           "value" : {
               "cipher" : "AES/CBC/PKCS5Padding",
               "stableId" : "openidm-sym-default",
               "salt" : "<hashValue>",
               "data" : "<encryptedValue>",
               "keySize" : 16,
               "purpose" : "idm.config.encryption",
               "iv" : "<encryptedValue>",
               "mac" : "<hashValue>"
           }
       }
    },
    "scope" : [
        "id",
        "api",
        "web"
    ],

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass; the location may vary.

The file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Salesforce social identity, you can verify this by selecting Manage > Salesforce, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "Salesforce Social Identity Provider Configuration Details".

12.12.3. Configuring User Registration to Link to Salesforce

Once you've configured the Salesforce social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.13. Setting Up Yahoo as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Yahoo as a social identity provider for IDM:

12.13.1. Setting Up Yahoo

To set up Yahoo as a social identity provider, navigate to the following page: Yahoo OAuth 2.0 Guide . You'll need a Yahoo account. You can then navigate to the Create an App page, where you can follow the Yahoo process to create a new web application with the following information:

  • Application Name

  • Web Application

  • Callback Domain, such as openidm.example.com; required for IDM

  • API Permissions; for whatever you select, choose Read/Write. IDM only reads Yahoo user information.

When complete and saved, you should see a Client ID and Client Secret for your new web app.

Note

Yahoo supports URLs using only HTTPS, only on port 443. For more information on how to configure IDM to use these ports, see "Host and Port Information".

12.13.2. Configuring Yahoo as a Social Identity Provider

  1. To configure Yahoo as a social identity provider, log in to the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Yahoo social identity provider.

    In the Yahoo Provider pop-up that appears, the values for Redirect URI should use the same Callback Domain as shown in "Setting Up Yahoo".

  3. Include the values that Yahoo created for Client ID and Client Secret, as described in "Setting Up Yahoo".

  4. Under regular and Advanced Options, if necessary, include the options shown in the following appendix: "Yahoo Social Identity Provider Configuration Details".

When you enable a Yahoo social identity provider in the Admin UI, IDM generates the identityProvider-yahoo.json file in your project's conf/ subdirectory.

When you review that file, you should see information beyond what you see in the Admin UI. The first part of the file includes the name of the provider, the scope, and UI settings related to the social identity provider icon (badge) and the sign-in button. For more information on the icon and button, see "Social Identity Provider Button and Badge Properties".

{
    "provider" : "yahoo",
    "scope" : [
        "openid",
        "sdpp-w"
    ],
    "uiConfig" : {
        "iconBackground" : "#7B0099",
        "iconClass" : "fa-yahoo",
        "iconFontColor" : "white",
        "buttonClass" : "fa-yahoo",
        "buttonDisplayName" : "Yahoo",
        "buttonCustomStyle" : "background-color: #7B0099; border-color: #7B0099; color:white;",
        "buttonCustomStyleHover" : "background-color: #7B0099; border-color: #7B0099; color:white;"
    },

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

The next part of the file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Yahoo social identity, you can verify this by selecting Manage > Yahoo, and then selecting a user.

Next, there's the part of the file that you may have configured through the Admin UI, plus additional information on the redirectUri, the configClass, and the authenticationIdKey:

    "authorizationEndpoint" : "https://api.login.yahoo.com/oauth2/request_auth",
    "tokenEndpoint" : "https://api.login.yahoo.com/oauth2/get_token",
    "wellKnownEndpoint" : "https://login.yahoo.com/.well-known/openid-configuration",
    "clientId" : "<Client_ID_Name>",
    "clientSecret" : {
      "$crypto" : {
        "type" : "x-simple-encryption",
        "value" : {
          "cipher" : "AES/CBC/PKCS5Padding",
          "stableId" : "openidm-sym-default",
          "salt" : "<hashValue>",
          "data" : "<encryptedValue>",
          "keySize" : 16,
          "purpose" : "idm.config.encryption",
          "iv" : "<encryptedValue>",
          "mac" : "<hashValue>"
        }
      }
    },
    "authenticationIdKey" : "sub",
    "redirectUri" : "https://openidm.example.com/",
    "basicAuth" : false,
    "configClass" : "org.forgerock.oauth.clients.oidc.OpenIDConnectClientConfiguration",
    "enabled" : true
  }

If you need more information about the properties in this file, refer to the following appendix: "Yahoo Social Identity Provider Configuration Details".

12.13.3. Configuring User Registration to Link to Yahoo

Once you've configured the Yahoo social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.14. Setting Up Twitter as an IDM Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take the following basic steps to configure Twitter as a social identity provider for IDM:

12.14.1. Setting Up Twitter

To set up Twitter as a social identity provider, navigate to the following page: Single-user OAuth with Examples . You'll need a Twitter account. You can then navigate to the Twitter Application Management page, where you can select Create New App and enter at least the following information:

  • Name

  • Description

  • Website, such as http://openidm.example.com:8080

  • Callback URL, such as http://openidm.example.com:8080/; required for IDM; for other providers, known as RedirectURI

When complete and saved, you should see a Consumer Key and Consumer Secret for your new web app.

Note

Twitter Apps use the OAuth 1.0a protocol. Fortunately, with IDM, you can use the same process used to configure OIDC and OAuth 2 social identity providers.

12.14.2. Configuring Twitter as a Social Identity Provider

  1. To configure Twitter as a social identity provider, log in to the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the Twitter social identity provider.

    In the Twitter Provider pop-up that appears, the values for Callback URL should use the same value shown in "Setting Up Twitter".

  3. Include the values that Twitter created for Consumer Key and Consumer Secret, as described in "Setting Up Twitter".

  4. Under regular and Advanced Options, if necessary, include the options shown in the following appendix: "Twitter Social Identity Provider Configuration Details".

When you enable a Twitter social identity provider in the Admin UI, IDM generates the identityProvider-twitter.json file in your project's conf/ subdirectory.

When you review that file, you should see information beyond what you see in the Admin UI. The first part of the file includes the name of the provider, endpoints, as well as information from the Consumer Key and Consumer Secret, you'll see them as clientId and clientSecret, respectively, in the configuration file.

{
    "provider" : "twitter",
    "requestTokenEndpoint" : "https://api.twitter.com/oauth/request_token",
    "authorizationEndpoint" : "https://api.twitter.com/oauth/authenticate",
    "tokenEndpoint" : "https://api.twitter.com/oauth/access_token",
    "userInfoEndpoint" : "https://api.twitter.com/1.1/account/verify_credentials.json",
    "clientId" : "<Client_ID_Name>",
    "clientSecret" : {
      "$crypto" : {
          "type" : "x-simple-encryption",
          "value" : {
              "cipher" : "AES/CBC/PKCS5Padding",
              "stableId" : "openidm-sym-default",
              "salt" : "<hashValue>",
              "data" : "<encryptedValue>",
              "keySize" : 16,
              "purpose" : "idm.config.encryption",
              "iv" : "<encryptedValue>",
              "mac" : "<hashValue>"
          }
      }
    },

You should also see UI settings related to the social identity provider icon (badge) and the sign-in button, described in "Social Identity Provider Button and Badge Properties".

You'll see links related to the authenticationIdKey, redirectUri, and configClass.

The next part of the file includes schema information, which includes properties for each social identity account, as collected by IDM, as well as the order in which it appears in the Admin UI. When you've registered a user with a Twitter social identity, you can verify this by selecting Manage > Twitter, and then selecting a user.

Another part of the file includes a propertyMap, which maps user information entries between the source (social identity provider) and the target (IDM).

If you need more information about the properties in this file, refer to the following appendix: "Twitter Social Identity Provider Configuration Details".

12.14.3. Configuring User Registration to Link to Twitter

Once you've configured the Twitter social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and activate that feature. Under the Social tab that appears, enable Social Registration. For more information on IDM user self-service features, see "Configuring User Self-Service".

When you enable Social Registration, you're allowing users to register on IDM through all active social identity providers.

12.15. Set Up Apple as an IDM Social Identity Provider

To configure "Sign in with Apple", you'll need an Apple developer account.

Configure Apple Login

You need a client ID and client secret for your application. In the Apple developer portal, the client ID is called a Services ID.

  1. Log into the Apple Developer Portal.

  2. Select Certificates, Identifiers and Profiles > Identifiers.

  3. On the Identifiers page, select Register a New Identifier, then select Services IDs.

  4. Enter a Description and Identifier for this Services ID, and make sure that Sign in With Apple is enabled.

    Important

    The Identifier you specify here will be your OAuth Client ID.

  5. Click Configure.

  6. On the Web Authentication Configuration screen, enter the Web Domain on which IDM runs, and specify the redirect URL used during the OAuth flow (Return URLs).

    The redirect URL must have the following format:

    https://idm.example.com?redirect=apple

    Note

    You must use a real domain (FQDN) here. Apple does not allow localhost URLs. If you enter an IP address such as 127.0.0.1, it will fail later in the OAuth flow.

  7. Click Save > Continue > Register.

  8. Generate the client secret.

    Instead of using simple strings as OAuth client secrets, Apple uses a public/private key pair, where the client secret is a signed JWT. To register the private key with Apple:

    1. Select Certificates, Identifiers and Profiles > Keys, then click the + icon to register a new key.

    2. Enter a Key Name and enable Sign In with Apple.

    3. Click Configure, then select the primary App ID that you created previously.

    4. Apple generates a new private key, in a .p8 file.

      Caution

      You can only download this key once. Ensure that you save this file, because you will not be able to download it again.

      Rename the file to key.txt, then locate the Key ID in that file.

    5. Use this private key to generate a client secret JWT. Sign the JWT with your private key, using an ES256 algorithm.

Configure an Apple Identity Provider
  1. To configure an Apple social identity provider, log into the Admin UI and select Configure > Social ID Providers.

  2. Enable the Apple social identity provider.

    In the Apple Provider window, enter the Redirect URI that you set up in "Configure Apple Login".

  3. Enter your Client ID and Client Secret.

Configure User Registration through Apple

When you have configured the Apple social identity provider, you can activate it through User Registration.

  1. In the Admin UI, select Configure > User Registration> Enable User Registration.

  2. On the Social tab, enable Social Registration.

    For more information, see "Configuring User Self-Service".

12.16. Setting Up a Custom Social Identity Provider

As suggested in the introduction to this chapter, you'll need to take four basic steps to configure a custom social identity provider:

Note

These instructions require the social identity provider to be fully compliant with The OAuth 2.0 Authorization Framework or the OpenID Connect standards.

12.16.1. Preparing IDM

While IDM includes provisions to work with OpenID Connect 1.0 and OAuth 2.0 social identity providers, connections to those providers are not supported, other than those specifically listed in this chapter.

To set up another social provider, first add a code block to the identityProviders.json file, such as:

{
    "provider" : "<providerName>",
    "authorizationEndpoint" : "",
    "tokenEndpoint" : "",
    "userInfoEndpoint" : "",
    "wellKnownEndpoint" : "",
    "clientId" : "",
    "clientSecret" : "",
    "uiConfig" : {
         "iconBackground" : "",
         "iconClass" : "",
         "iconFontColor" : "",
         "buttonImage" : "",
         "buttonClass" : "",
         "buttonCustomStyle" : "",
         "buttonCustomStyleHover" : "",
         "buttonDisplayName" : ""
    },
    "scope" : [ ],
    "authenticationIdKey" : "",
    "schema" : {
       "id" : "urn:jsonschema:org:forgerock:openidm:identityProviders:api:<providerName>",
       "viewable" : true,
       "type" : "object",
       "$schema" : "http://json-schema.org/draft-03/schema",
       "properties" : {
          "id" : {
             "title" : "ID",
             "viewable" : true,
             "type" : "string",
             "searchable" : true
          },
          "name" : {
             "title" : "Name",
             "viewable" : true,
             "type" : "string",
             "searchable" : true
          },
          "first_name" : {
             "title" : "First Name",
             "viewable" : true,
             "type" : "string",
             "searchable" : true
          },
          "last_name" : {
             "title" : "Last Name",
             "viewable" : true,
             "type" : "string",
             "searchable" : true
          },
          "email" : {
             "title" : "Email Address",
             "viewable" : true,
             "type" : "string",
             "searchable" : true
          },
          "locale" : {
             "title" : "Locale Code",
             "viewable" : true,
             "type" : "string",
             "searchable" : true
          }
       },
       "order" : [
          "id",
          "name",
          "first_name",
          "last_name",
          "email",
          "locale"
       ],
       "required" : [ ]
    },
    "propertyMap" : [
       {
          "source" : "id",
          "target" : "id"
       },
       {
          "source" : "name",
          "target" : "displayName"
       },
       {
          "source" : "first_name",
          "target" : "givenName"
       },
       {
          "source" : "last_name",
          "target" : "familyName"
       },
       {
          "source" : "email",
          "target" : "email"
       },
       {
          "source" : "email",
          "target" : "username"
       },
       {
          "source" : "locale",
          "target" : "locale"
       }
    ],
    "redirectUri" : "http://openidm.example.com:8080/",
    "configClass" : "org.forgerock.oauth.clients.oidc.OpenIDConnectClientConfiguration",
    "basicAuth" : false,
    "enabled" : true
},

Modify this code block for your selected social provider. Some of these properties may appear under other names. For example, some providers specify an App ID that you'd include as a clientId.

Additional changes may be required, especially depending on how the provider implements the OAuth2 or OpenID Connect standards.

In the propertyMap code block, you should substitute the properties from the selected social identity provider for various values of source. Make sure to trace the property mapping through selfservice.propertymap.json to the Managed User property shown in managed.json. For more information on this multi-step mapping, see "Many Social Identity Providers, One Schema".

As shown in "OpenID Connect Authorization Code Flow", user provisioning information goes through the User Info Endpoint. Some providers, such as LinkedIn and Facebook, may require a list of properties with the endpoint. Consult the documentation for your provider for details.

For more information on the uiConfig code block, see "Social Identity Provider Button and Badge Properties".

Both files, identityProviders.json and identityProvider-custom.json, should include the same information for the new custom identity provider. For property details, see "Custom Social Identity Provider Configuration Details".

Once you've included information from your selected social identity provider, proceed with the configuration process. You'll use the same basic steps described for other specified social providers.

12.16.2. Setting Up a Custom Social Identity Provider

Every social identity provider should be able to provide the information you need to specify properties in the code block shown in "Preparing IDM".

In general, you'll need an authorizationEndpoint, a tokenEndpoint and a userInfoEndpoint. To link to the custom provider, you'll also have to copy the clientId and clientSecret that you created with that provider. In some cases, you'll get this information in a slightly different format, such as an App ID and App Secret.

For the propertyMap, check the source properties. You may need to revise these properties to match those available from your custom provider.

For examples, refer to the specific social identity providers documented in this chapter.

12.16.3. Configuring a Custom Social Identity Provider

  1. To configure a custom social identity provider, log into the Admin UI and navigate to Configure > Social ID Providers.

  2. Enable the custom social identity provider. The name you see is based on the name property in the relevant code block in the identityProviders.json file.

  3. If you haven't already done so, include the values provided by your social identity provider for the properties shown. For more information, see the following appendix: "Custom Social Identity Provider Configuration Details".

12.16.4. Configuring User Registration to Link to a Custom Provider

Once you've configured a custom social identity provider, you can activate it through User Registration. To do so in the Admin UI, select Configure > User Registration, and under the Social tab, enable the option associated with Social Registration. For more information about user self-service features, see "Configuring User Self-Service".

When you enable social identity providers, you're allowing users to register on IDM through all active social identity providers.

12.17. Configuring the Social Providers Authentication Module

The SOCIAL_PROVIDERS authentication module incorporates the requirements from social identity providers who rely on either the OAuth2 or the OpenID Connect standards. The Social Providers authentication module is turned on by default. To configure or disable this module in the Admin UI, select Configure > Authentication, choose the Modules tab, then select Social Providers from the list of modules.

Authentication settings can be configured from the Admin UI, or by making changes directly in the authentication.json file for your project. IDM includes the following code block in the authentication.json file for your project:

{
   "name" : "SOCIAL_PROVIDERS",
   "properties" : {
       "defaultUserRoles" : [
           "internal/role/openidm-authorized"
       ],
       "augmentSecurityContext" : {
           "type" : "text/javascript",
           "globals" : { },
           "file" : "auth/populateAsManagedUserFromRelationship.js"
       },
       "propertyMapping" : {
           "userRoles" : "authzRoles"
       }
   },
   "enabled" : true
}

For more information on these options, see "Common Module Properties".

12.18. Managing Social Identity Providers Over REST

You can identify the current status of configured social identity providers with the following REST call:

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

The output that you see includes JSON information from each configured social identity provider, as described in the identityProvider-provider file in your project's conf/ subdirectory.

One key line from this output specifies whether the social identity provider is enabled:

"enabled" : true

If the SOCIAL_PROVIDERS authentication module is disabled, you'll see the following output from that REST call:

{
   "providers" : [ ]
}

For more information, see "Configuring the Social Providers Authentication Module".

If the SOCIAL_PROVIDERS module is disabled, you can still review the standard configuration of each social provider (enabled or not) by running the same REST call on a different endpoint (do not forget the s at the end of identityProviders):

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

Note

If you have not configured a social identity provider, you'll see the following output from the REST call on the openidm/identityProviders endpoint:

{
    "providers" : [ ]
}

You can still get information about the available configuration for social identity providers on a slightly different endpoint:

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

The config in the endpoint refers to the configuration, starting with the identityProviders.json configuration file. Note how it matches the corresponding term in the endpoint.

You can review information for a specific provider by including the name with the endpoint. For example, if you've configured LinkedIn as described in "Setting Up LinkedIn as a Social Identity Provider", run the following command:

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

The above command differs in subtle ways. The config in the endpoint points to configuration data. The identityProvider at the end of the endpoint is singular, which matches the corresponding configuration file, identityProvider-linkedIn.json. And linkedIn includes a capital I in the middle of the word.

In a similar fashion, you can delete a specific provider:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request DELETE \
http://localhost:8080/openidm/config/identityProvider/linkedIn

If you have the information needed to set up a provider, such as the output from the previous two REST calls, you can use the following command to add a provider:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --header "Content-type: application/json" \
 --request PUT \
--data '{
 <Include content from an identityProvider-linkedIn.json file>
}' \
http://localhost:8080/openidm/config/identityProvider/linkedIn

IDM incorporates the given information in a file named for the provider, in this case, identityProvider-linkedIn.json.

You can even disable a social identity provider with a PATCH REST call, as shown:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-type: application/json" \
--request PATCH \
--data '[
   {
      "operation":"replace",
      "field" : "enabled",
      "value" : false
   }
]' \
http://localhost:8080/openidm/config/identityProvider/linkedIn

You can reverse the process by substituting true for false in the previous PATCH REST call.

You can manage the social identity providers associated with individual users over REST, as described in "Managing Social Identity Providers Over REST".

12.19. Testing Social Identity Providers

In all cases, once configuration is complete, you should test the social identity provider. To do so, go through the steps in the following procedure:

  1. Navigate to the login screen for the End User UI, https://openidm.example.com:8443.

  2. Select the Register link (after the "Don't have an account?" question) on the login page.

  3. You should see a link to sign in with your selected social identity provider. Select that link.

    Note

    If you do not see a link to sign in with any social identity provider, you probably did not enable the option associated with Social Registration. To make sure, access the Admin UI, and select Configure > User Registration.

    Warning

    If you see a redirect URI error from a social identity provider, check the configuration for your web application in the social identity provider developer console. There may be a mistake in the redirect URI or redirect URL.

  4. Follow the prompts from your social identity provider to log into your account.

    Note

    If there is a problem with the interface to the social identity provider, you might see a Register Your Account screen with information acquired from that provider.

  5. Because security questions are enabled by default, you must add at least one security question and answer to proceed. For more information, see "Configuring Security Questions".

    When the Social ID registration process is complete, you are redirected to the End User UI at https://openidm.example.com:8443.

  6. You should now be able to use the sign in link for your social identity provider to log into IDM.

12.20. Scenarios When Registering With a Social ID

When users connect to IDM with a social identity provider, it could be the first time they're connecting to your system. They could already have an regular IDM account. They could already have registered with a different social identity provider. This section describes what happens during the self-registration process. The process varies depending on whether there's an existing account in the IDM managed user store.

When Registering Social Identity Providers on IDM
Flow When Registering With a Social Identity Provider

The following list describes each item in the flow shown in the adjacent figure:

  1. From the IDM End User UI, the user selects the Register link

  2. The self-registration Interface returns a Register Your Account page at http://localhost:8080/#/registration with a list of configured providers.

  3. The user then selects one configured social identity provider.

  4. IDM connects to the selected social identity provider.

  5. The social identity provider requests end user authentication.

  6. The end user authenticates with the social identity provider.

  7. The social identity provider prompts the user to accept sharing selected account information.

  8. The user accepts the conditions presented by the social identity provider.

  9. The social identity provider notifies IDM of the user registration request.

  10. IDM passes responsibility to the administrative interface.

  11. IDM uses the email address from the social identity provider, and compares it with email addresses of existing managed users.

  12. If the email address is found, IDM links the social identity information to that account (and skips to step 16).

  13. IDM returns to the self-registration (Self-Service) interface.

  14. The self-registration interface prompts the user for additional information, such as security questions, and reCAPTCHA, if configured per "Configuring Google reCAPTCHA".

  15. The user responds appropriately.

  16. IDM creates a new managed user. If the user has already been created, IDM reviews data from the social identity provider, and updates the user data for the managed/provider to conform. In this case, the provider is a social identity provider such as Google.

  17. The user is redirected to the Success URL.

12.21. Social Identity Widgets

The Admin UI includes widgets that can help you measure the success of your social identity efforts. To add these widgets, take the following steps:

  1. Log into the Admin UI.

  2. Select Dashboards, and choose the dashboard to which you want to add the widget.

    For more information about managing dashboards in the UI, see "Managing Dashboards".

  3. Select Add Widget.

    In the Add Widget window, scroll down to the Social item which includes the following graphical widgets:

    • Social Registration (year)

    • Daily Social Registration

    • Daily Social Logins

  4. Select the widget you want to add and select Settings to configure the widget.

    Optionally, select Preview to see what the widget will look like with the configuration you have applied. Your IDM system must contain some social data to display the preview.

The following example shows daily social registrations, in pie chart form:

Daily Social Registrations on IDM
Pie chart view, three providers

Chapter 13. Using Policies to Validate Data

IDM provides an extensible policy service that lets you apply specific validation requirements to various components and properties. This chapter describes the policy service, and provides instructions on configuring policies for managed objects.

The policy service provides a REST interface for reading policy requirements and validating the properties of components against configured policies. Objects and properties are validated automatically when they are created, updated, or patched. Policies are generally applied to user passwords, but can also be applied to any managed or system object, and to internal user objects.

The policy service lets you accomplish the following tasks:

  • Read the configured policy requirements of a specific component.

  • Read the configured policy requirements of all components.

  • Validate a component object against the configured policies.

  • Validate the properties of a component against the configured policies.

The router service limits policy application to managed, system, and internal user objects. To apply policies to additional objects, such as the audit service, you must modify your project's conf/router.json file. For more information about the router service, see "Router Service Reference".

A default policy applies to all managed objects. You can configure this default policy to suit your requirements, or you can extend the policy service by supplying your own scripted policies.

13.1. Configuring the Default Policy for Managed Objects

Policies applied to managed objects are configured in two files:

  • A policy script file (openidm/bin/defaults/script/policy.js) that defines each policy and specifies how policy validation is performed. For more information, see "Understanding the Policy Script File".

  • A managed object policy configuration element, defined in your project's conf/managed.json file, that specifies which policies are applicable to each managed resource. For more information, see "Understanding the Policy Configuration Element".

    Note

    The configuration for determining which policies apply to resources other than managed objects is defined in your project's conf/policy.json file. The default policy.json file includes policies that are applied to internal user objects, but you can extend the configuration in this file to apply policies to system objects.

13.1.1. Understanding the Policy Script File

The policy script file (openidm/bin/defaults/script/policy.js) separates policy configuration into two parts:

  • A policy configuration object, which defines each element of the policy. For more information, see "Policy Configuration Objects".

  • A policy implementation function, which describes the requirements that are enforced by that policy.

Together, the configuration object and the implementation function determine whether an object is valid in terms of the applied policy. The following excerpt of a policy script file configures a policy that specifies that the value of a property must contain a certain number of capital letters:

...
{   "policyId" : "at-least-X-capitals",
    "policyExec" : "atLeastXCapitalLetters",
    "clientValidation": true,
    "validateOnlyIfPresent":true,
    "policyRequirements" : ["AT_LEAST_X_CAPITAL_LETTERS"]
},
...

policyFunctions.atLeastXCapitalLetters = function(fullObject, value, params, property) {
  var isRequired = _.find(this.failedPolicyRequirements, function (fpr) {
      return fpr.policyRequirement === "REQUIRED";
    }),
    isNonEmptyString = (typeof(value) === "string" && value.length),
    valuePassesRegexp = (function (v) {
      var test = isNonEmptyString ? v.match(/[(A-Z)]/g) : null;
      return test !== null && test.length >= params.numCaps;
    }(value));

  if ((isRequired || isNonEmptyString) && !valuePassesRegexp) {
    return [ { "policyRequirement" : "AT_LEAST_X_CAPITAL_LETTERS", "params" : {"numCaps": params.numCaps} } ];
  }

  return [];
}     
...

To enforce user passwords that contain at least one capital letter, the policyId from the preceding example is applied to the appropriate resource (managed/user/*). The required number of capital letters is defined in the policy configuration element of the managed object configuration file (see "Understanding the Policy Configuration Element".

13.1.1.1. Policy Configuration Objects

Each element of the policy is defined in a policy configuration object. The structure of a policy configuration object is as follows:

{
    "policyId" : "minimum-length",
    "policyExec" : "minLength",
    "clientValidation": true,
    "validateOnlyIfPresent": true,
    "policyRequirements" : ["MIN_LENGTH"]
}   
  • policyId - a unique ID that enables the policy to be referenced by component objects.

  • policyExec - the name of the function that contains the policy implementation. For more information, see "Policy Implementation Functions".

  • clientValidation - indicates whether the policy decision can be made on the client. When "clientValidation": true, the source code for the policy decision function is returned when the client requests the requirements for a property.

  • validateOnlyIfPresent - notes that the policy is to be validated only if it exists.

  • policyRequirements - an array containing the policy requirement ID of each requirement that is associated with the policy. Typically, a policy will validate only one requirement, but it can validate more than one.

13.1.1.2. Policy Implementation Functions

Each policy ID has a corresponding policy implementation function that performs the validation. Implementation functions take the following form:

function <name>(fullObject, value, params, propName) {	
	<implementation_logic>
}   
  • fullObject is the full resource object that is supplied with the request.

  • value is the value of the property that is being validated.

  • params refers to the params array that is specified in the property's policy configuration.

  • propName is the name of the property that is being validated.

The following example shows the implementation function for the required policy:

function required(fullObject, value, params, propName) {
    if (value === undefined) {
        return [ { "policyRequirement" : "REQUIRED" } ];
    }
    return [];
}      

13.1.2. Understanding the Policy Configuration Element

The configuration of a managed object property (in the managed.json file) can include a policies element that specifies how policy validation should be applied to that property. The following excerpt of the default managed.json file shows how policy validation is applied to the password and _id properties of a managed/user object:

{
    "objects" : [
        {
            "name" : "user",
            ...
            "schema" : {
                "id" : "http://jsonschema.net",
                ...
                "properties" : {
                    "_id" : {
                        "description" : "User ID",
                        "type" : "string",
                        "viewable" : false,
                        "searchable" : false,
                        "userEditable" : false,
                        "usageDescription" : "",
                        "isPersonal" : false,
                        "policies" : [
                            {
                                "policyId" : "cannot-contain-characters",
                                "params" : {
                                    "forbiddenChars" : [ "/" ]
                                }
                            }
                        ]
                    },
                    "password" : {
                        "title" : "Password",
                        "description" : "Password",
                        "type" : "string",
                        "viewable" : false,
                        "searchable" : false,
                        "minLength" : 8,
                        "userEditable" : true,
                        "encryption" : {
                            "purpose" : "idm.password.encryption"
                        },
                        "scope" : "private",
                        "isProtected": true,
                        "usageDescription" : "",
                        "isPersonal" : false,
                        "policies" : [
                            {
                                "policyId" : "at-least-X-capitals",
                                "params" : {
                                    "numCaps" : 1
                                }
                            },
                            {
                                "policyId" : "at-least-X-numbers",
                                "params" : {
                                    "numNums" : 1
                                }
                            },
                            {
                                "policyId" : "cannot-contain-others",
                                "params" : {
                                    "disallowedFields" : [
                                        "userName",
                                        "givenName",
                                        "sn"
                                    ]
                                }
                            }
                        ]
                    }
                    ...
                }

Note that the policy for the _id property references the function cannot-contain-characters, that is defined in the policy.js file. The policy for the password property references the functions at-least-X-capitals, at-least-X-numbers, and cannot-contain-others, that are defined in the policy.js file. The parameters that are passed to these functions (number of capitals required, and so forth) are specified in the same element.

13.1.3. Validation of Managed Object Data Types

The type property of a managed object specifies the data type of that property, for example, array, boolean, integer, number, null, object, or string. For more information about data types, see the JSON Schema Primitive Types section of the JSON Schema standard.

The type property is subject to policy validation when a managed object is created or updated. Validation fails if data does not match the specified type, such as when the data is an array instead of a string. The valid-type policy in the default policy.js file enforces the match between property values and the type defined in the managed.json file.

IDM supports multiple valid property types. For example, you might have a scenario where a managed user can have more than one telephone number, or a null telephone number (when the user entry is first created and the telephone number is not yet known). In such a case, you could specify the accepted property type as follows in your managed.json file:

"telephoneNumber" : {
    "description" : "",
    "title" : "Telephone Number",
    "viewable" : true,
    "searchable" : false,
    "userEditable" : true,
    "policies" : [ ],
    "returnByDefault" : false,
    "minLength" : null,
    "pattern" : "^\\+?([0-9\\- \\(\\)])*$",
    "type" : [
        "string",
        "null"
    ]
},

In this case, the valid-type policy from the policy.js file checks the telephone number for an accepted type and pattern, either for a real telephone number or a null entry.

13.1.4. Configuring Policy Validation in the UI

The Admin UI provides rudimentary support for applying policy validation to managed object properties. To configure policy validation for a managed object type update the configuration of the object type in the UI. For example, to specify validation policies for specific properties of managed user objects, select Configure > Managed Objects then click on the User object. Scroll down to the bottom of the Managed Object configuration, then update, or add, a validation policy. The Policy field here refers to a function that has been defined in the policy script file. For more information, see "Understanding the Policy Script File". You cannot define additional policy functions by using the UI.

Note

Take care with Validation Policies. If it relates to an array of relationships, such as between a user and multiple devices, "Return by Default" should always be set to false. You can verify this in the managed.json file for your project, with the "returnByDefault" : false entry for the applicable managed object, whenever there are items of "type" : "relationship".

13.2. Extending the Policy Service

You can extend the policy service by adding custom scripted policies, and by adding policies that are applied only under certain conditions.

13.2.1. Adding Custom Scripted Policies

If your deployment requires additional validation functionality that is not supplied by the default policies, you can add your own policy scripts to your project's script directory, and reference them from your project's conf/policy.json file.

Do not modify the default policy script file (openidm/bin/defaults/script/policy.js) as doing so might result in interoperability issues in a future release. To reference additional policy scripts, set the additionalFiles property conf/policy.json.

The following example creates a custom policy that rejects properties with null values. The policy is defined in a script named mypolicy.js:

var policy = {   "policyId" : "notNull",
       "policyExec" : "notNull",  
       "policyRequirements" : ["NOT_NULL"]
}

addPolicy(policy);

function notNull(fullObject, value, params, property) {
   if (value == null) {
      var requireNotNull = [
        {"policyRequirement": "NOT_NULL"}
      ];
      return requireNotNull;
   }
   return [];
}  

The mypolicy.js policy is referenced in the policy.json configuration file as follows:

{
    "type" : "text/javascript",
    "file" : "policy.js",
    "additionalFiles" : ["script/mypolicy.js"],
    "resources" : [
        {
...
   

Note

In cases where you are using the Admin UI, both policy.js and mypolicy.js will be run within the client, and then again by the the server. When creating new policies, be aware that these policies may be run in both contexts.

13.2.2. Adding Conditional Policy Definitions

You can extend the policy service to support policies that are applied only under specific conditions. To apply a conditional policy to managed objects, add the policy to your project's managed.json file. To apply a conditional policy to other objects, add it to your project's policy.json file.

The following excerpt of a managed.json file shows a sample conditional policy configuration for the "password" property of managed user objects. The policy indicates that sys-admin users have a more lenient password policy than regular employees:

{
    "objects" : [
        {
            "name" : "user",
            ...
                "properties" : {
                ...
                    "password" : {
                        "title" : "Password",
                        "type" : "string",
                        ...
                        "conditionalPolicies" : [
                            {
                                "condition" : {
                                    "type" : "text/javascript",
                                    "source" : "(fullObject.org === 'sys-admin')"
                                },
                                "dependencies" : [ "org" ],
                                "policies" : [
                                    {
                                        "policyId" : "max-age",
                                        "params" : {
                                            "maxDays" : ["90"]
                                        }
                                    }
                                ]
                            },
                            {
                                "condition" : {
                                    "type" : "text/javascript",
                                    "source" : "(fullObject.org === 'employees')"
                                },
                                "dependencies" : [ "org" ],
                                "policies" : [
                                    {
                                        "policyId" : "max-age",
                                        "params" : {
                                            "maxDays" : ["30"]
                                        }
                                    }
                                ]
                            }
                        ],
                        "fallbackPolicies" : [
                            {
                                "policyId" : "max-age",
                                "params" : {
                                    "maxDays" : ["7"]
                                }
                            }
                        ]
            }

To understand how a conditional policy is defined, examine the components of this sample policy. For more information on the policy function, see "Policy Implementation Functions".

There are two distinct scripted conditions (defined in the condition elements). The first condition asserts that the user object, contained in the fullObject argument, is a member of the sys-admin org. If that assertion is true, the max-age policy is applied to the password attribute of the user object, and the maximum number of days that a password may remain unchanged is set to 90.

The second condition asserts that the user object is a member of the employees org. If that assertion is true, the max-age policy is applied to the password attribute of the user object, and the maximum number of days that a password may remain unchanged is set to 30.

In the event that neither condition is met (the user object is not a member of the sys-admin org or the employees org), an optional fallback policy can be applied. In this example, the fallback policy also references the max-age policy and specifies that for such users, their password must be changed after 7 days.

The dependencies field prevents the condition scripts from being run at all, if the user object does not include an org attribute.

Note

This example assumes that a custom max-age policy validation function has been defined, as described in "Adding Custom Scripted Policies".

Tip

These scripted conditions do not apply to progressive profiling. For more information, see "Custom Progressive Profile Conditions".

13.3. Disabling Policy Enforcement

Policy enforcement is the automatic validation of data when it is created, updated, or patched. In certain situations you might want to disable policy enforcement temporarily. You might, for example, want to import existing data that does not meet the validation requirements with the intention of cleaning up this data at a later stage.

You can disable policy enforcement by setting openidm.policy.enforcement.enabled to false in your resolver/boot.properties file. This setting disables policy enforcement in the back-end only, and has no impact on direct policy validation calls to the Policy Service (which the UI makes to validate input fields). So, with policy enforcement disabled, data added directly over REST is not subject to validation, but data added with the UI is still subject to validation.

You should not disable policy enforcement permanently, in a production environment.

13.4. Managing Policies Over REST

You can manage the policy service over the REST interface, by calling the REST endpoint https://localhost:8443/openidm/policy, as shown in the following examples.

13.4.1. Listing the Defined Policies

The following REST call displays a list of all the policies defined in policy.json (policies for objects other than managed objects). The policy objects are returned in JSON format, with one object for each defined policy ID:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"http://localhost:8080/openidm/policy"
{
  "_id": "",
  "resources": [
    ...
    {
      "resource": "internal/user/*",
      "properties": [
        {
          "name": "_id",
          "policies": [
            {
              "policyId": "cannot-contain-characters",
              "params": {
                "forbiddenChars": [ "/" ]
              },
              "policyFunction": "\nfunction (fullObject, value, params, property) {\n    ...",
              "policyRequirements": [
                "CANNOT_CONTAIN_CHARACTERS"
              ]
            }
          ],
          "policyRequirements": [
            "CANNOT_CONTAIN_CHARACTERS"
          ]
        }
        ...
      ]
      ...
    }
  ]
}

To display the policies that apply to a specific resource, include the resource name in the URL. For example, the following REST call displays the policies that apply to managed users:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request GET \
 "http://localhost:8080/openidm/policy/managed/user/*"
{
  "_id": "*",
  "resource": "managed/user/*",
  "properties": [
    {
      "policyRequirements": [
        "VALID_TYPE",
        "CANNOT_CONTAIN_CHARACTERS"
      ],
      "fallbackPolicies": null,
      "name": "_id",
      "policies": [
        {
          "policyRequirements": [
            "VALID_TYPE"
          ],
          "policyId": "valid-type",
          "params": {
            "types": [
              "string"
            ]
          }
        },
        {
          "policyId": "cannot-contain-characters",
          "params": {
            "forbiddenChars": [ "/" ]
          },
          "policyFunction": "...",
          "policyRequirements": [
            "CANNOT_CONTAIN_CHARACTERS"
          ]
        }
      ],
      "conditionalPolicies": null
    }
    ...
  ]
}

13.4.2. Validating Objects and Properties Over REST

To verify that an object adheres to the requirements of all applied policies, include the validateObject action in the request.

The following example verifies that a new managed user object is acceptable, in terms of the policy requirements. Note that the ID in the URL (test in this example) is ignored—the action simply validates the object in the JSON payload:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{
  "sn":"Jones",
  "givenName":"Bob",
  "telephoneNumber":"0827878921",
  "passPhrase":null,
  "mail":"bjones@example.com",
  "accountStatus":"active",
  "userName":"bjones@example.com",
  "password":"123"
}' \
"http://localhost:8080/openidm/policy/managed/user/test?_action=validateObject"
{
  "result": false,
  "failedPolicyRequirements": [
    {
      "policyRequirements": [
        {
          "policyRequirement": "MIN_LENGTH",
          "params": {
            "minLength": 8
          }
        }
      ],
      "property": "password"
    },
    {
      "policyRequirements": [
        {
          "policyRequirement": "AT_LEAST_X_CAPITAL_LETTERS",
          "params": {
            "numCaps": 1
          }
        }
      ],
      "property": "password"
    }
  ]
}

The result (false) indicates that the object is not valid. The unfulfilled policy requirements are provided as part of the response - in this case, the user password does not meet the validation requirements.

Use the validateProperty action to verify that a specific property adheres to the requirements of a policy.

The following example checks whether a user's new password (12345) is acceptable:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{ "password" : "12345" }' \
"http://localhost:8080/openidm/policy/managed/user/9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb?_action=validateProperty"
{
  "result": false,
  "failedPolicyRequirements": [
    {
      "policyRequirements": [
        {
          "policyRequirement": "MIN_LENGTH",
          "params": {
            "minLength": 8
          }
        }
      ],
      "property": "password"
    },
    {
      "policyRequirements": [
        {
          "policyRequirement": "AT_LEAST_X_CAPITAL_LETTERS",
          "params": {
            "numCaps": 1
          }
        }
      ],
      "property": "password"
    }
  ]
}

The result (false) indicates that the password is not valid. The unfulfilled policy requirements are provided as part of the response - in this case, the minimum length and the minimum number of capital letters.

Validating a property that fulfills the policy requirements returns a true result, for example:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{ "password" : "1NewPassword" }' \
"http://localhost:8080/openidm/policy/managed/user/9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb?_action=validateProperty"
{
  "result": true,
  "failedPolicyRequirements": []
}

13.4.2.1. Validate Field Removal

To validate field removal, specify the fields to remove when calling the policy validateProperty action. You cannot remove fields that:

  • Are required in the required schema array.

  • Have a required policy.

  • Have a default value.

The following example validates the removal of the fields description and givenName:

curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Accept-API-Version: resource=1.0" \
--header "Content-Type: application/json" \
--request POST \
--data '{
  "_remove": [ "description", "givenName" ]
}' \
"http://localhost:8080/openidm/policy/managed/user/ca5a3196-2ed3-4a76-8881-30403dee70e9?_action=validateProperty"
{
  "result": false,
  "failedPolicyRequirements": [
    {
      "policyRequirements": [
        {
          "policyRequirement": "REQUIRED"
        }
      ],
      "property": "givenName"
    }
  ]
}

13.4.2.2. Validate Properties to Unknown Resource Paths

To perform a validateProperty action to a path that is unknown (*), such as managed/user/* or managed/user/userDoesntExistYet, the payload must include:

  • An object field that contains the object details.

  • A properties field that contains the properties to be evaluated.

A common use case for validating properties for unknown resources is prior to object creation, such as during pre-registration.

  1. Always pass the object and properties content in the POST body because IDM has no object to look up.

  2. Use any placeholder id in the request URL, as * has no special meaning in the API.

This example uses a conditional policy for any object with the description test1:

"password" : {
    ...
    "conditionalPolicies" : [
        {
            "condition" : {
                "type" : "text/javascript",
                "source" : "(fullObject.description === 'test1')"
            },
            "dependencies" : [ "description" ],
            "policies" : [
                {
                    "policyId" : "at-least-X-capitals",
                    "params" : {
                        "numCaps" : 1
                    }
                }
            ]
        }
    ],

Using the above conditional policy, you could perform a validateProperty action to managed/user/* with the request:

curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Accept-API-Version: resource=1.0" \
--header "Content-Type: application/json" \
--request POST \
--data '{
  "object": {
    "description": "test1"
  },
  "properties": {
    "password": "passw0rd"
  }
}' \
"http://localhost:8080/openidm/policy/managed/user/*?_action=validateProperty"
{
  "result": false,
  "failedPolicyRequirements": [
    {
      "policyRequirements": [
        {
          "params": {
            "numCaps": 1
          },
          "policyRequirement": "AT_LEAST_X_CAPITAL_LETTERS"
        }
      ],
      "property": "password"
    }
  ]
}

Chapter 14. Configuring Server Logs

In this chapter, you will learn about server logging, that is, the messages that IDM logs related to server activity.

Server logging is separate from auditing. Auditing logs activity on the IDM system, such as access and synchronization. For information about audit logging, see "Setting Up Audit Logging". To configure server logging, edit the logging.properties file in your project-dir/conf directory.

Important

When you change the logging settings you must restart the server for those changes to take effect. Alternatively, you can use JMX via jconsole to change the logging settings, in which case changes take effect without restarting the server.

14.1. Specify Where Messages Are Logged

The way in which messages are logged is set in the handlers property in the logging.properties file. This property has the following value by default:

handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler

Two handlers are listed by default:

  • FileHandler writes formatted log records to a single file or to a set of rotating log files. By default, log files are written to logs/openidm*.log files.

  • ConsoleHandler writes formatted logs to System.err.

Additional log message handlers are listed in the logging.properties file.

14.2. Set the Log Message Format

IDM supports the two default log formatters included with Java. These are set in the conf/logging.properties file:

  • java.util.logging.SimpleFormatter.format outputs a text log file that is human-readable. This formatter is used by default.

  • java.util.logging.XMLFormatter outputs logs as XML, for use in logging software that can read XML logs.

IDM extends the Java SimpleFormatter with the following formatting options:

  • org.forgerock.openidm.logger.SanitizedThreadIdLogFormatter

    This is the default formatter for console and file logging. It extends the SimpleFormatter to include the thread ID of the thread that generated each message. The thread ID helps with debugging when reviewing the logs.

    In the following example log excerpt, the thread ID is [19]:

    [19] May 23, 2018 10:30:26.959 AM org.forgerock.openidm.repo.opendj.impl.Activator start
    INFO: Registered bootstrap repository service
    [19] May 23, 2018 10:30:26.960 AM org.forgerock.openidm.repo.opendj.impl.Activator start
    INFO: DS bundle started

    The SanitizedThreadIdLogFormatter also encodes all control characters (such as newline characters) using URL-encoding, to protect against log forgery. Control characters in stack traces are not encoded.

  • org.forgerock.openidm.logger.ThreadIdLogFormatter

    Similar to the SanitizedThreadIdLogFormatter, but does not encode control characters. If you do not want to encode control characters in file and console log messages, change the file and console handlers in conf/logging.properties as follows:

    java.util.logging.FileHandler.formatter = org.forgerock.openidm.logger.ThreadIdLogFormatter

    java.util.logging.ConsoleHandler.formatter = org.forgerock.openidm.logger.ThreadIdLogFormatter

The SimpleFormatter (and, by extension, the SanitizedThreadIdLogFormatter and ThreadIdLogFormatter) lets you customize what information to include in log messages, and how this information is laid out. By default, log messages include the date, time (down to the millisecond), log level, source of the message, and the message sent (including exceptions). To change the defaults, adjust the value of java.util.logging.SimpleFormatter.format in your conf/logging.properties file. For more information on how to customize the log message format, see the related Java documentation.

14.3. Set the Logging Level

By default, IDM logs messages at the INFO level. This logging level is specified with the following global property in conf/logging.properties:

.level=INFO

You can specify different separate logging levels for individual server features which override the global logging level. Set the log level, per package to one of the following:

SEVERE (highest value)
WARNING
INFO
CONFIG
FINE
FINER
FINEST (lowest value)

For example, the following setting decreases the messages logged by the embedded PostgreSQL database:

# reduce the logging of embedded postgres since it is very verbose
ru.yandex.qatools.embed.postgresql.level = SEVERE

Set the log level to OFF to disable logging completely (see in "Disable Logs"), or to ALL to capture all possible log messages.

If you use logger functions in your JavaScript scripts, set the log level for the scripts as follows:

org.forgerock.openidm.script.javascript.JavaScript.level=level

You can override the log level settings, per script, with the following setting:

org.forgerock.openidm.script.javascript.JavaScript.script-name.level

For more information about using logger functions in scripts, see "Logging Functions".

Important

It is strongly recommended that you do not log messages at the FINE or FINEST levels in a production environment. Although these levels are useful for debugging issues in a test environment, they can result in accidental exposure of sensitive data. For example, a password change patch request can expose the updated password in the Jetty logs.

14.4. Disable Logs

If required, you can also disable logs. For example, to disable ConsoleHandler logging, make the following changes in your project's conf/logging.properties file before you start IDM.

Set java.util.logging.ConsoleHandler.level = OFF, and comment out other references to ConsoleHandler, as shown in the following excerpt:

   # ConsoleHandler: A simple handler for writing formatted records to System.err
   #handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
   handlers=java.util.logging.FileHandler
   ...
   # --- ConsoleHandler ---
   # Default: java.util.logging.ConsoleHandler.level = INFO
   java.util.logging.ConsoleHandler.level = OFF
   #java.util.logging.ConsoleHandler.formatter = ...
   #java.util.logging.ConsoleHandler.filter=...

Chapter 15. Connecting to External Resources

This chapter describes how to connect to external resources such as LDAP, Active Directory, flat files, and others. Configurations shown here are simplified to show essential aspects. Not all resources support all IDM operations; however, the resources shown here support most of the CRUD operations, and also reconciliation and liveSync.

Resources refer to external systems, databases, directory servers, and other sources of identity data that are managed and audited by the identity management system. To connect to resources, IDM loads the ForgeRock Open Identity Connector Framework (OpenICF). ICF avoids the need to install agents to access resources, instead using the resources' native protocols. For example, ICF connects to database resources using the database's Java connection libraries or JDBC driver. It connects to directory servers over LDAP. It connects to UNIX systems by using ssh.

IDM provides several connectors by default, in the path/to/openidm/connectors directory. You can download additional connectors from the ForgeRock BackStage download site.

For details about all connectors supported for use with IDM, see Connector Reference.

15.1. The ForgeRock Identity Connector Framework (ICF)

ICF provides a common interface to allow identity services access to the resources that contain user information. IDM loads the ICF API as one of its OSGi modules. ICF uses connectors to separate the IDM implementation from the dependencies of the resource to which IDM is connecting. A specific connector is required for each remote resource. Connectors can run locally (on the IDM host) or remotely.

Local connectors are loaded by ICF as regular bundles in the OSGi container. Most connectors run locally. Remote connectors must be executed on a remote connector server. If a resource requires access libraries that cannot be included as part of the IDM process, you must use a connector server. For example, ICF connects to Microsoft Active Directory through a remote connector server that is implemented as a .NET service.

Connections to remote connector servers are configured in a single connector info provider configuration file, located in your project's conf/ directory.

Connectors themselves are configured through provisioner files. One provisioner file must exist for each connector. Provisioner files are named provisioner.openicf-name where name corresponds to the name of the connector, and are also located in the conf/ directory.

A number of sample connector configurations are available in the openidm/samples/example-configurations/provisioners directory. To use these connectors, edit the configuration files as required, and copy them to your project's conf/ directory.

The following figure shows how IDM connects to resources by using connectors and remote connector servers. The figure shows one local connector (LDAP) and two remote connectors (Scripted SQL and PowerShell). In this example, the remote Scripted SQL connector uses a remote Java connector server. The remote PowerShell connector always requires a remote .NET connector server.

How IDM Uses the ICF Framework and Connectors
ICF architecture

Tip

Connectors that use the .NET framework must run remotely. Java connectors can be run locally or remotely. You might run a Java connector remotely for security reasons (firewall constraints), for geographical reasons, or if the JVM version that is required by the connector conflicts with the JVM version that is required by IDM.

15.2. Configuring Connectors

Connectors are configured through the ICF provisioner service. Each connector configuration is stored in a file in your project's conf/ directory, and accessible over REST at the openidm/conf endpoint. Connector configuration files are named project-dir/conf/provisioner.openicf-name where name corresponds to the name of the connector.

If you are creating your own connector configuration files, do not include additional dash characters ( - ) in the connector name, as this might cause problems with the OSGi parser. For example, the name provisioner.openicf-hrdb.json is fine. The name provisioner.openicf-hr-db.json is not.

You can create a connector configuration in the following ways:

15.2.1. Using the Sample Provisioner Files

A number of sample connector configurations are available in the openidm/samples/example-configurations/provisioners directory. To use these connector configurations, edit the configuration files as required, and copy them to your project's conf directory.

The following example shows a high-level connector configuration. The individual configuration objects are described in detail later in this section:

{
  "connectorRef"              : connector-ref-object,
  "producerBufferSize"        : integer,
  "connectorPoolingSupported" : boolean, true/false,
  "poolConfigOption"          : pool-config-option-object,
  "operationTimeout"          : operation-timeout-object,
  "configurationProperties"   : configuration-properties-object,
  "syncFailureHandler"        : sync-failure-handler-object,
  "resultsHandlerConfig"      : results-handler-config-object,
  "objectTypes"               : object-types-object,
  "operationOptions"          : operation-options-object
 }

15.2.2. Creating Connector Configurations With the Admin UI

To configure connectors in the Admin UI, select Configure > Connector. If your project has an existing connector configuration (for example, if you have started IDM with one of the sample configurations) click on that connector to edit it. If you're starting with a new project, click New Connector to configure a new connector.

The connectors displayed on the Connectors page reflect the provisioner files that are in your project's conf/ directory. To add a new connector configuration, you can also copy a provisioner file from the /path/to/openidm/samples/example-configurations/provisioners directory, then edit it to fit your deployment.

When you add a new connector, the Connector Type dropdown list reflects the actual connector JARs that are in the /path/to/openidm/connectors directory. You can have more than one connector configuration for a specific connector type. For example, you might use the LDAP connector to set up two connector configurations - one to an Active Directory server and one to a ForgeRock Directory Services (DS) instance. The Connector Types listed here do not include all supported connectors - only those that are bundled with IDM. You can download additional connectors from the ForgeRock BackStage download site and place them in the /path/to/openidm/connectors directory. For information on all supported connectors and how to configure them, see the Connector Reference.

The tabs on the connector configuration screens correspond to the objects and properties described in the remaining sections of this chapter.

When a connector configuration is complete, and IDM is able to establish the connection to the remote resource, the Data tab displays the objects in that remote resource. For example, the following image shows the contents of a connected LDAP resource:

Data Tab For a Connected LDAP Resource
Image shows the data tab for a connected LDAP resource

You can search through these objects with either the Basic Filter shown in each column, or the Advanced Filter option, which allows you to build many of the queries shown in "Defining and Calling Queries".

15.2.3. Creating Connector Configurations Over REST

You create a new connector configuration over REST in three stages:

  1. List the available connectors.

  2. Generate the core configuration.

  3. Connect to the target system and generate the final configuration.

List the available connectors by using the following command:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request POST \
 "http://localhost:8080/openidm/system?_action=availableConnectors"

Available connectors are installed in openidm/connectors. IDM bundles the connectors described in "Supported Connector Versions" in the Release Notes.

The preceding command therefore returns the following output:

{
  "connectorRef": [
    {
      "displayName": "Workday Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.workday-connector",
      "connectorName": "org.forgerock.openicf.connectors.workday.WorkdayConnector"
    },
    {
      "displayName": "SSH Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.ssh-connector",
      "connectorName": "org.forgerock.openicf.connectors.ssh.SSHConnector"
    },
    {
      "displayName": "ServiceNow Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.servicenow-connector",
      "connectorName": "org.forgerock.openicf.connectors.servicenow.ServiceNowConnector"
    },
    {
      "displayName": "Scripted SQL Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.scriptedsql-connector",
      "connectorName": "org.forgerock.openicf.connectors.scriptedsql.ScriptedSQLConnector"
    },
    {
      "displayName": "Scripted REST Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.scriptedrest-connector",
      "connectorName": "org.forgerock.openicf.connectors.scriptedrest.ScriptedRESTConnector"
    },
    {
      "displayName": "Scim Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.scim-connector",
      "connectorName": "org.forgerock.openicf.connectors.scim.ScimConnector"
    },
    {
      "displayName":"Salesforce Connector",
      "bundleVersion":"1.5.20.8",
      "systemType":"provisioner.openicf",
      "bundleName":"org.forgerock.openicf.connectors.salesforce-connector",
      "connectorName":"org.forgerock.openicf.connectors.salesforce.SalesforceConnector"
    },
    {
      "displayName": "MongoDB Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.mongodb-connector",
      "connectorName": "org.forgerock.openicf.connectors.mongodb.MongoDBConnector"
    },
    {
      "displayName": "Marketo Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.marketo-connector",
      "connectorName": "org.forgerock.openicf.connectors.marketo.MarketoConnector"
    },
    {
      "displayName": "LDAP Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.ldap-connector",
      "connectorName": "org.identityconnectors.ldap.LdapConnector"
    },
    {
      "displayName": "Kerberos Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.kerberos-connector",
      "connectorName": "org.forgerock.openicf.connectors.kerberos.KerberosConnector"
    },
    {
      "displayName": "Scripted Poolable Groovy Connector",
      "bundleVersion": "${scriptedPoolableConnectorVersion}",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.groovy-connector",
      "connectorName": "org.forgerock.openicf.connectors.groovy.ScriptedPoolableConnector"
    },
    {
      "displayName": "Scripted Groovy Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.groovy-connector",
      "connectorName": "org.forgerock.openicf.connectors.groovy.ScriptedConnector"
    },
    {
      "displayName": "GoogleApps Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.googleapps-connector",
      "connectorName": "org.forgerock.openicf.connectors.googleapps.GoogleAppsConnector"
    },
    {
      "displayName": "Database Table Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.databasetable-connector",
      "connectorName": "org.identityconnectors.databasetable.DatabaseTableConnector"
    },
    {
      "displayName": "CSV File Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.csvfile-connector",
      "connectorName": "org.forgerock.openicf.csvfile.CSVFileConnector"
    },
    {
      "displayName": "Adobe Marketing Cloud Connector",
      "bundleVersion": "1.5.20.8",
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.adobecm-connector",
      "connectorName": "org.forgerock.openicf.acm.ACMConnector"
    }
  ]
}

To generate the core configuration, choose one of the available connectors by copying one of the JSON objects from the generated list into the body of the REST command, as shown in the following command for the CSV file connector:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{"connectorRef":
    {
      "systemType": "provisioner.openicf",
      "bundleName": "org.forgerock.openicf.connectors.csvfile-connector",
      "connectorName": "org.forgerock.openicf.csvfile.CSVFileConnector",
      "displayName": "CSV File Connector",
      "bundleVersion": "[1.5.19.0,1.6.0.0)"
    }
 }' \
 "http://localhost:8080/openidm/system?_action=createCoreConfig"

This command returns a core connector configuration, similar to the following:

{
  "connectorRef": {
    "systemType": "provisioner.openicf",
    "bundleName": "org.forgerock.openicf.connectors.csvfile-connector",
    "connectorName": "org.forgerock.openicf.csvfile.CSVFileConnector",
    "displayName": "CSV File Connector",
    "bundleVersion": "[1.5.19.0,1.6.0.0)"
  },
  "poolConfigOption": {
    "maxObjects": 10,
    "maxIdle": 10,
    "maxWait": 150000,
    "minEvictableIdleTimeMillis": 120000,
    "minIdle": 1
  },
  "resultsHandlerConfig": {
    "enableNormalizingResultsHandler": false,
    "enableFilteredResultsHandler": false,
    "enableCaseInsensitiveFilter": false,
    "enableAttributesToGetSearchResultsHandler": true
  },
  "operationTimeout": {
    "CREATE": -1,
    "UPDATE": -1,
    "DELETE": -1,
    "TEST": -1,
    "SCRIPT_ON_CONNECTOR": -1,
    "SCRIPT_ON_RESOURCE": -1,
    "GET": -1,
    "RESOLVEUSERNAME": -1,
    "AUTHENTICATE": -1,
    "SEARCH": -1,
    "VALIDATE": -1,
    "SYNC": -1,
    "SCHEMA": -1
  },
  "configurationProperties": {
    "headerPassword": "password",
    "spaceReplacementString": "_",
    "csvFile": null,
    "newlineString": "\n",
    "headerUid": "uid",
    "quoteCharacter": "\"",
    "fieldDelimiter": ",",
    "syncFileRetentionCount": 3
  }
}

The configuration that is returned is not yet functional. It does not contain the required system-specific configurationProperties, such as the host name and port for an external system, or the csvFile for the CSV file connector. In addition, the configuration does not include the complete list of objectTypes and operationOptions.

To generate the final configuration, add values for the required configurationProperties to the core configuration, and use the updated configuration as the body for the next command:

$ curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{
  "configurationProperties": {
    "headerPassword": "password",
    "spaceReplacementString": "_",
    "csvFile": "&{idm.instance.dir}/data/csvConnectorData.csv",
    "newlineString": "\n",
    "headerUid": "uid",
    "quoteCharacter": "\"",
    "fieldDelimiter": ",",
    "syncFileRetentionCount": 3
  },
  "connectorRef": {
    "systemType": "provisioner.openicf",
    "bundleName": "org.forgerock.openicf.connectors.csvfile-connector",
    "connectorName": "org.forgerock.openicf.csvfile.CSVFileConnector",
    "displayName": "CSV File Connector",
    "bundleVersion": "[1.5.19.0,1.6.0.0)"
  },
  "poolConfigOption": {
    "maxObjects": 10,
    "maxIdle": 10,
    "maxWait": 150000,
    "minEvictableIdleTimeMillis": 120000,
    "minIdle": 1
  },
  "resultsHandlerConfig": {
    "enableNormalizingResultsHandler": true,
    "enableFilteredResultsHandler": true,
    "enableCaseInsensitiveFilter": false,
    "enableAttributesToGetSearchResultsHandler": true
  },
  "operationTimeout": {
    "CREATE": -1,
    "UPDATE": -1,
    "DELETE": -1,
    "TEST": -1,
    "SCRIPT_ON_CONNECTOR": -1,
    "SCRIPT_ON_RESOURCE": -1,
    "GET": -1,
    "RESOLVEUSERNAME": -1,
    "AUTHENTICATE": -1,
    "SEARCH": -1,
    "VALIDATE": -1,
    "SYNC": -1,
    "SCHEMA": -1
  }
 }   ' \
 "http://localhost:8080/openidm/system?_action=createFullConfig"

Note

Notice the single quotes around the argument to the --data option in the preceding command. For most UNIX shells, single quotes around a string prevent the shell from executing the command when encountering a new line in the content. You can therefore pass the --data '...' option on a single line, or including line feeds.

IDM attempts to read the schema, if available, from the external resource in order to generate output. IDM then iterates through schema objects and attributes, creating JSON representations for objectTypes and operationOptions for supported objects and operations.

The output includes the basic --data input, along with operationOptions and objectTypes.

Because IDM produces a full property set for all attributes and all object types in the schema from the external resource, the resulting configuration can be large. For an LDAP server, IDM can generate a configuration containing several tens of thousands of lines, for example. You might therefore want to reduce the schema to a minimum on the external resource before you run the createFullConfig command.

When you have the complete connector configuration, save that configuration in a file named provisioner.openicf-name.json (where name corresponds to the name of the connector) and place it in the conf directory of your project.

15.2.4. Setting the Connector Reference Properties

The following example shows a connector reference object:

"connectorRef" : {
    "bundleName"    : "org.forgerock.openicf.connectors.csvfile-connector",
    "bundleVersion" : "[1.5.19.0,1.6.0.0)",
    "connectorName" : "org.forgerock.openicf.csvfile.CSVFileConnector",
    "connectorHostRef" : "csv"
},
bundleName

string, required

The ConnectorBundle-Name of the ICF connector.

bundleVersion

string, required

The ConnectorBundle-Version of the ICF connector. The value can be a single version (such as 1.4.0.0) or a range of versions, which lets you support multiple connector versions in a single project.

You can specify a range of versions as follows:

  • [1.1.0.0,1.4.0.0] indicates that all connector versions from 1.1 to 1.4, inclusive, are supported.

  • [1.1.0.0,1.4.0.0) indicates that all connector versions from 1.1 to 1.4, including 1.1 but excluding 1.4, are supported.

  • (1.1.0.0,1.4.0.0] indicates that all connector versions from 1.1 to 1.4, excluding 1.1 but including 1.4, are supported.

  • (1.1.0.0,1.4.0.0) indicates that all connector versions from 1.1 to 1.4, exclusive, are supported.

When a range of versions is specified, IDM uses the latest connector that is available within that range. If your project requires a specific connector version, you must explicitly state the version in your connector configuration file, or constrain the range to address only the version that you need.

connectorName

string, required

The connector implementation class name.

connectorHostRef

string, optional

If the connector runs remotely, the value of this field must match the name field of the RemoteConnectorServers object in the connector server configuration file (provisioner.openicf.connectorinfoprovider.json). For example:

...
    "remoteConnectorServers" :
        [
            {
                "name" : "dotnet",
...

If the connector runs locally, the value of this field can be one of the following:

  • If the connector .jar is installed in openidm/connectors/, the value must be "#LOCAL". This is currently the default, and recommended location.

  • If the connector .jar is installed in openidm/bundle/ (not recommended), the value must be "osgi:service/org.forgerock.openicf.framework.api.osgi.ConnectorManager".

15.2.5. Setting the Pool Configuration

The poolConfigOption specifies the pool configuration for poolable connectors only (connectors that have "connectorPoolingSupported" : true). Non-poolable connectors ignore this parameter.

The following example shows a pool configuration option object for a poolable connector:

{
  "maxObjects"                 : 10,
  "maxIdle"                    : 10,
  "maxWait"                    : 150000,
  "minEvictableIdleTimeMillis" : 120000,
  "minIdle"                    : 1
}
maxObjects

The maximum number of idle and active instances of the connector.

maxIdle

The maximum number of idle instances of the connector.

maxWait

The maximum time, in milliseconds, that the pool waits for an object before timing out. A value of 0 means that there is no timeout.

minEvictableIdleTimeMillis

The maximum time, in milliseconds, that an object can be idle before it is removed. A value of 0 means that there is no idle timeout.

minIdle

The minimum number of idle instances of the connector.

15.2.6. Setting the Operation Timeouts

The operation timeout property lets you configure timeout values per operation type. By default, no timeout is configured for any operation type. A sample configuration follows:

{
  "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
}
operation-name

Timeout in milliseconds

A value of -1 disables the timeout.

15.2.7. Setting the Connection Configuration

The configurationProperties object specifies the configuration for the connection between the connector and the resource, and is therefore resource-specific.

The following example shows a configuration properties object for the default CSV sample resource connector:

"configurationProperties" : {
    "csvFile" : "&{idm.instance.dir}/data/csvConnectorData.csv"
},
property

Individual properties depend on the type of connector.

15.2.8. Setting the Synchronization Failure Configuration

The syncFailureHandler object specifies what should happen if a liveSync operation reports a failure for an operation. The following example shows a synchronization failure configuration:

{
    "maxRetries" : 5,
    "postRetryAction" : "logged-ignore"
}  
maxRetries

positive integer or -1, required

The number of attempts that IDM should make to process a failed modification. A value of zero indicates that failed modifications should not be reattempted. In this case, the post retry action is executed immediately when a liveSync operation fails. A value of -1 (or omitting the maxRetries property, or the entire syncFailureHandler object) indicates that failed modifications should be retried an infinite number of times. In this case, no post retry action is executed.

postRetryAction

string, required

The action that should be taken if the synchronization operation fails after the specified number of attempts. The post retry action can be one of the following:

  • logged-ignore - IDM ignores the failed modification, and logs its occurrence.

  • dead-letter-queue - IDM saves the details of the failed modification in a table in the repository (accessible over REST at repo/synchronisation/deadLetterQueue/provisioner-name).

  • script specifies a custom script that should be executed when the maximum number of retries has been reached.

For more information, see "Configuring the LiveSync Retry Policy".

15.2.9. Configuring How Results Are Handled

The resultsHandlerConfig object specifies how OpenICF returns results. These configuration properties do not apply to all connectors and depend on the interfaces that are implemented by each connector. For information about the interfaces that connectors support, see the Connector Reference.

The following example shows a results handler configuration object:

"resultsHandlerConfig" : {
    "enableNormalizingResultsHandler" : true,
    "enableFilteredResultsHandler" : false,
    "enableCaseInsensitiveFilter" : false,
    "enableAttributesToGetSearchResultsHandler" : false
}  
enableNormalizingResultsHandler

boolean, false by default

When this property is enabled, ICF normalizes returned attributes to ensure that they are filtered consistently. If the connector implements the attribute normalizer interface, enable the interface by setting this property to true. If the connector does not implement the attribute normalizer interface, the value of this property has no effect.

enableFilteredResultsHandler

boolean, false by default

Most connectors use the filtering and search capabilities of the remote connected system. In these cases, you can leave this property set to false. If the connector does not use the remote system's filtering and search capabilities, you must set this property to true.

All the non-scripted connectors, apart from the CSV connector use the filtering mechanism of the remote system. In the case of the CSV connector, the remote resource has no filtering mechanism, so you must set enableFilteredResultsHandler to true. For the scripted connectors, the setting will depend on how you have implemented the connector.

enableCaseInsensitiveFilter

boolean, false by default

This property applies only if enableFilteredResultsHandler is set to true. The filtered results handler is case-sensitive by default. For example, a search for lastName = "Jensen" will not match a stored user with lastName : jensen. When the filtered results handler is enabled, you can use this property to enable case-insensitive filtering. If you leave this property set to false, searches on that resource will be case-sensitive.

enableAttributesToGetSearchResultsHandler

boolean, false by default

By default, IDM determines which attributes should be retrieved in a search. If you set this property to true, the ICF framework removes all attributes from the READ/QUERY response, except for those that are specifically requested. For performance reasons, you should set this property to false for local connectors and to true for remote connectors.

15.2.10. Specifying the Supported Object Types

The objectTypes configuration specifies the object types (user, group, account, and so on) that are supported by the connector. The object names that you define here determine how the object is accessed in the URI. For example:

system/systemName/objectType

This configuration is based on the JSON Schema with the extensions described in the following section.

Attribute names that start or end with __ are regarded as special attributes by OpenICF. The purpose of the special attributes in ICF is to enable someone who is developing a new connector to create a contract regarding how a property can be referenced, regardless of the application that is using the connector. In this way, the connector can map specific object information between an arbitrary application and the resource, without knowing how that information is referenced in the application.

These attributes have no specific meaning in the context of IDM, although some of the connectors that are bundled with IDM use these attributes. The generic LDAP connector, for example, can be used with ForgeRock Directory Services (DS), Active Directory, OpenLDAP, and other LDAP directories. Each of these directories might use a different attribute name to represent the same type of information. For example, Active Directory uses unicodePassword and DS uses userPassword to represent the same thing, a user's password. The LDAP connector uses the special OpenICF __PASSWORD__ attribute to abstract that difference. In the same way, the LDAP connector maps the __NAME__ attribute to an LDAP dn.

The ICF __UID__ is a special case. The __UID__ must not be included in the IDM configuration or in any update or create operation. This attribute denotes the unique identity attribute of an object and IDM always maps it to the _id of the object.

The following excerpt shows the configuration of an account object type:

{
  "account" :
  {
    "$schema" : "http://json-schema.org/draft-03/schema",
    "id" : "__ACCOUNT__",
    "type" : "object",
    "nativeType" : "__ACCOUNT__",
    "absentIfEmpty" : false,
    "absentIfNull" : true,
    "properties" :
    {
      "name" :
      {
        "type" : "string",
        "nativeName" : "__NAME__",
        "nativeType" : "JAVA_TYPE_PRIMITIVE_LONG",
        "flags" :
        [
          "NOT_CREATABLE",
          "NOT_UPDATEABLE",
          "NOT_READABLE",
          "NOT_RETURNED_BY_DEFAULT"
        ]
      },
      "groups" :
      {
        "type" : "array",
        "items" :
        {
          "type" : "string",
          "nativeType" : "string"
        },
        "nativeName" : "__GROUPS__",
        "nativeType" : "string",
        "flags" :
        [
          "NOT_RETURNED_BY_DEFAULT"
        ]
      },                
      "givenName" : {
         "type" : "string",
         "nativeName" : "givenName",
         "nativeType" : "string"
         },
    }
  }
}

ICF supports an __ALL__ object type that ensures that objects of every type are included in a synchronization operation. The primary purpose of this object type is to prevent synchronization errors when multiple changes affect more than one object type.

For example, imagine a deployment synchronizing two external systems. On system A, the administrator creates a user, jdoe, then adds the user to a group, engineers. When these changes are synchronized to system B, if the __GROUPS__ object type is synchronized first, the synchronization will fail, because the group contains a user that does not yet exist on system B. Synchronizing the __ALL__ object type ensures that user jdoe is created on the external system before he is added to the group engineers.

The __ALL__ object type is assumed by default - you do not need to declare it in your provisioner configuration file. If it is not declared, the object type is named __ALL__. If you want to map a different name for this object type, declare it in your provisioner configuration. The following excerpt from a sample provisioner configuration uses the name allobjects:

"objectTypes": {
    "allobjects": {
        "$schema": "http://json-schema.org/draft-03/schema",
        "id": "__ALL__",
        "type": "object",
        "nativeType": "__ALL__"
    },
...

A liveSync operation invoked with no object type assumes an object type of __ALL__. For example, the following call invokes a liveSync operation on all defined object types in an LDAP system:

$ curl \
 --header "X-OpenIDM-Username: openidm-admin" \
 --header "X-OpenIDM-Password: openidm-admin" \
 --request POST \
 "http://localhost:8080/openidm/system/ldap?_action=liveSync"

Note

Using the __ALL__ object type requires a mechanism to ensure the order in which synchronization changes are processed. Servers that use the cn=changelog mechanism to order sync changes, such as ForgeRock Directory Services (DS), Oracle DSEE, and the legacy Sun Directory Server, cannot use the __ALL__ object type by default. Such servers must be forced to use time stamps to order their sync changes. For these LDAP server types, set useTimestampsForSync to true in the provisioner configuration.

LDAP servers that use timestamps by default (such as Active Directory GCs and OpenLDAP) can use the __ALL__ object type without any additional configuration. Active Directory and Active Directory LDS, which use Update Sequence Numbers, can also use the __ALL__ object type without additional configuration.

15.2.10.1. Adding Objects and Properties Using the UI

To add object types and properties to a connector configuration by using the Admin UI, select Configure > Connectors. Select the connector that you want to change, then select the Object Types tab.

In the case of the LDAP connector, the connector reads the schema from the remote resource to determine the object types and properties that can be added to its configuration. When you select one of these object types, you can think of it as a template. Edit the basic object type, as required, to suit your deployment.

To add a property to an object type, select the Edit icon next to the object type, then select Add Property.

15.2.10.2. Extending the Object Type Configuration

nativeType

string, optional

The native ICF object type.

The list of supported native object types is dependent on the resource, or on the connector. For example, an LDAP connector might have object types such as __ACCOUNT__ and __GROUP__.

15.2.10.3. Specifying the Behavior For Empty Attributes

The absentIfEmpty and absentIfNull object class properties enable you to specify how attributes are handled during synchronization if their values are null (for single-valued attributes) or empty (for multi-valued attributes). You can set these properties per object type.

By default, these properties are set as follows:

"absentIfEmpty" : false

Multi-valued attributes whose values are empty are included in the resource response during synchronization.

"absentIfNull" : true

Single-valued attributes whose values are null are removed from the resource response during synchronization.

15.2.10.4. Extending the Property Type Configuration

nativeType

string, optional

The native ICF attribute type.

The following native types are supported:

JAVA_TYPE_BIGDECIMAL
JAVA_TYPE_BIGINTEGER
JAVA_TYPE_BYTE
JAVA_TYPE_BYTE_ARRAY
JAVA_TYPE_CHAR
JAVA_TYPE_CHARACTER
JAVA_TYPE_DATE
JAVA_TYPE_DOUBLE
JAVA_TYPE_FILE
JAVA_TYPE_FLOAT
JAVA_TYPE_GUARDEDBYTEARRAY
JAVA_TYPE_GUARDEDSTRING
JAVA_TYPE_INT
JAVA_TYPE_INTEGER
JAVA_TYPE_LONG
JAVA_TYPE_OBJECT
JAVA_TYPE_PRIMITIVE_BOOLEAN
JAVA_TYPE_PRIMITIVE_BYTE
JAVA_TYPE_PRIMITIVE_DOUBLE
JAVA_TYPE_PRIMITIVE_FLOAT
JAVA_TYPE_PRIMITIVE_LONG
JAVA_TYPE_STRING

Note

The JAVA_TYPE_DATE property is deprecated. Functionality may be removed in a future release. This property-level extension is an alias for string. Any dates assigned to this extension should be formatted per ISO 8601.

nativeName

string, optional

The native ICF attribute name.

flags

string, optional

The native ICF attribute flags. ICF supports the following attribute flags:

  • MULTIVALUED - specifies that the property can be multivalued.

    For multi-valued properties, if the property value type is anything other than a string, you must include an items property that declares the data type.

    The following example shows the entries property of the authentication object in a provisioner file. The entries property is multi-valued, and its elements are of type object:

    "authentication" : {
    ...
        "properties" : {
            ...
            "entries" : {
                "type" : "object",
                "required" : false,
                "nativeName" : "entries",
                "nativeType" : "object",
                    "items" : {
                        "type" : "object"
                    },
                "flags" : [
                    "MULTIVALUED"
                ]
            },
    ...
  • NOT_CREATABLE, NOT_READABLE, NOT_UPDATEABLE

    In some cases, the connector might not support manipulating an attribute because the attribute can only be changed directly on the remote system. For example, if the name attribute of an account can only be created by Active Directory, and never changed by IDM, you would add NOT_CREATABLE and NOT_UPDATEABLE to the provisioner configuration for that attribute.

  • NOT_RETURNED_BY_DEFAULT

    Certain attributes such as LDAP groups or other calculated attributes might be expensive to read. To avoid returning these attributes in a default read of the object, unless they are explicitly requested, add the NOT_RETURNED_BY_DEFAULT flag to the provisioner configuration for that attribute.

    You can also use this flag to prevent properties from being read by default during a synchronization operation. To synchronize changes to a target object, IDM performs an UPDATE rather than a PATCH. This causes all attributes that are mapped from the source to the target to be modified when the synchronization is processed (rather than only those attributes that have changed). Although the value of a property might not change, the property still registers an update. This behavior can be problematic for properties such as the password, which might have restrictions on updating with a similar value. To prevent such properties from being updated during synchronization, set the NOT_RETURNED_BY_DEFAULT flag, which effectively prevents the property from being read from the source during the synchronization. For example:

    "__PASSWORD__" : {
        "type" : "string",
        "nativeName" : "__PASSWORD__",
        "nativeType" : "JAVA_TYPE_GUARDEDSTRING",
        "flags" : [
            "NOT_RETURNED_BY_DEFAULT"
        ],
        "runAsUser" : true
    },        
  • REQUIRED - specifies that the property is required in create operations. This flag sets the required property of an attribute as follows:

    "required" : true

You can configure connectors to enable provisioning of any arbitrary property. For example, the following property definitions would enable you to provision image files, used as avatars, to account objects in a system resource. The first definition would work for a single photo encoded as a base64 string. The second definition would work for multiple photos encoded in the same way:

"attributeByteArray" : {
     "type" : "string",
     "nativeName" : "attributeByteArray",
     "nativeType" : "JAVA_TYPE_BYTE_ARRAY"
 },  
"attributeByteArrayMultivalue": {
     "type": "array",
     "items": {
         "type": "string",
         "nativeType": "JAVA_TYPE_BYTE_ARRAY"
     },
     "nativeName": "attributeByteArrayMultivalue"
 }, 

Note

Do not use the dash character ( - ) in property names, like last-name. Dashes in names make JavaScript syntax more complex. If you cannot avoid the dash, write source['last-name'] instead of source.last-name in your JavaScript scripts.

15.2.11. Configuring the Operation Options

The operationOptions object lets you deny specific operations on a resource. For example, you can use this configuration object to deny CREATE and DELETE operations on a read-only resource to avoid IDM accidentally updating the resource during a synchronization operation.

The following example defines the options for the "SYNC" operation:

"operationOptions" : {
  {
    "SYNC" :
    {
      "denied" : true,
      "onDeny" : "DO_NOTHING",
      "objectFeatures" :
      {
        "__ACCOUNT__" :
        {
          "denied" : true,
          "onDeny" : "THROW_EXCEPTION",
          "operationOptionInfo" :
          {
            "$schema" : "http://json-schema.org/draft-03/schema",
            "type" : "object",
            "properties" :
            {
              "_OperationOption-float" :
              {
                 "type" : "number",
                 "nativeType" : "JAVA_TYPE_PRIMITIVE_FLOAT"
              }
            }
          }
        },
        "__GROUP__" :
        {
          "denied" : false,
          "onDeny" : "DO_NOTHING"
        }
      }
    }
  }
...

The ICF Framework supports the following operations:

  • AUTHENTICATE

  • CREATE

  • DELETE

  • GET

  • RESOLVEUSERNAME

  • SCHEMA

  • SCRIPT_ON_CONNECTOR

  • SCRIPT_ON_RESOURCE

  • SEARCH

  • SYNC

  • TEST

  • UPDATE

  • VALIDATE

For detailed information on these operations, see the ICF API documentation.

The operationOptions object has the following configurable properties:

denied

boolean, optional

This property prevents operation execution if the value is true.

onDeny

string, optional

If denied is true, then the service uses this value. Default value: DO_NOTHING.

  • DO_NOTHING: On operation the service does nothing.

  • THROW_EXCEPTION: On operation the service throws a ForbiddenException exception.

15.3. Accessing Remote Connectors

When you configure a remote connector, you use the connector info provider service to connect through a remote connector server. To configure a connector info provider service, you'll need to set up a