Appendix C. Data Models and Objects Reference

Table of Contents
C.1. Managed Objects
C.2. Configuration Objects
C.3. System Objects
C.4. Audit Objects
C.5. Links

OpenIDM allows you to customize a variety of objects that can be addressed via a URL or URI, and that have a common set of functions that OpenIDM can perform on them such as CRUD, query, and action.

Depending on how you intend to use them, different objects are appropriate.

Table C.1. OpenIDM Objects
Object TypeIntended UseSpecial Functionality
Managed objectsServe as targets and sources for synchronization, and to build virtual identities.Provide appropriate auditing, script hooks, declarative mappings and so forth in addition to the REST interface.
Configuration objectsIdeal for look-up tables or other custom configuration, which can be configured externally like any other system configuration.Adds file view, REST interface, and so forth
Repository objectsThe equivalent of arbitrary database table access. Appropriate for managing data purely through the underlying data store or repository API.Persistence and API access
System objectsRepresentation of target resource objects, such as accounts, but also resource objects such as groups. 
Audit objectsHouses audit data in the OpenIDM internal repository. 
LinksDefines a relation between two objects. 

C.1. Managed Objects

A managed object in OpenIDM is an object which represents the identity-related data managed by OpenIDM. Managed objects are stored by OpenIDM in its data store. All managed objects are JSON-based data structures.

C.1.1. Managed Object Schema

Managed objects have an associated schema to enforce a specific data structure. Schema is specified using the JSON Schema specification. This is currently an Internet-Draft, with implementations in multiple programming languages.

C.1.1.1. Managed Object Reserved Properties

Top-level properties in a managed object that begin with an underscore ( _ ) are reserved by OpenIDM for internal use, and are not explicitly part of its schema. Internal properties are read-only, and are ignored when provided by the REST API client.

The following properties exist for all managed objects in OpenIDM.

_id

string

The unique identifier for the object. This value forms a part of the managed object's URI.

_rev

string

The revision of the object. This is the same value that is exposed as the object's ETag through the REST API. The content of this attribute is not defined. No consumer should make any assumptions of its content beyond equivalence comparison. This attribute may be provided by the underlying data store.

_schema_id

string

The a reference to the schema object that the managed object is associated with.

_schema_rev

string

The revision of the schema that was used for validation when the object was last stored.

C.1.1.2. Managed Object Schema Validation

Schema validation is performed unequivocally whenever an object is stored, and conditionally whenever an object is retrieved from the data store and exhibits a _schema_rev value that differs from the _rev of the schema that the OpenIDM instance currently has for that managed object type. Whenever schema validation is performed, the _schema_rev of the object is updated to contain the _rev value of the current schema.

C.1.1.3. Managed Object Derived Properties

Properties can be defined to be strictly derived from other properties within the object. This allows computed and composite values to be created in the object. Whenever an object undergoes a change, all derived properties are recomputed. The values of derived properties are stored in the data store, and are not recomputed upon retrieval.

C.1.2. Data Consistency

Single-object operations shall be consistent within the scope of the operation performed, limited by capabilities of the underlying data store. Bulk operations shall not have any consistency guarantees. OpenIDM does not expose any transactional semantics in the managed object access API.

All access through the REST API uses the ETag and associated conditional headers: If-Match, If-None-Match. In operations that modify model objects, conditional headers are mandatory.

C.1.3. Managed Object Triggers

Triggers are user-definable functions that validate or modify object or property state.

C.1.3.1. State Triggers

Managed objects are resource-oriented. A set of triggers is defined to intercept the supported request methods on managed objects. Such triggers are intended to perform authorization, redact, or modify objects before the action is performed. The object being operated on is in scope for each trigger, meaning that the object is retrieved by the data store before the trigger is fired.

If retrieval of the object fails, the failure occurs before any trigger is called. Triggers are executed before any optimistic concurrency mechanisms are invoked. The reason for this is to prevent a potential attacker from getting information about an object (including its presence in the data store) before authorization is applied.

onCreate

Called upon a request to create a new object. Throwing an exception causes the create to fail.

onRead

Called upon a request to retrieve a whole object or portion of an object. Throwing an exception causes the object to not be included in the result. This method is also called when lists of objects are retrieved via requests to its container object; in this case, only the requested properties are included in the object. Allows for uniform access control for retrieval of objects, regardless of the method in which they were requested.

onUpdate

Called upon a request to store an object. The "old" and "new" objects are in-scope for the trigger. The "old" object represents a complete object as retrieved from the data store. The trigger can elect to change "new" object properties. If as a result of the trigger the object's "old" and "new" values are identical (that is, update is reverted), the update ends prematurely, though successfully. Throwing an exception causes the update to fail.

onDelete

Called upon a request to delete an object. Throwing an exception causes the deletion to fail.

C.1.3.2. Object Storage Triggers

An object-scoped trigger applies to an entire object. Unless otherwise specified, the object itself is in scope for the trigger.

onValidate

Validates an object prior to its storage in the data store. Throws an exception in the event of a validation failure.

onRetrieve

Called when an object is retrieved from the data store. Typically used to transform an object after it has been retrieved (for example decryption, JIT data conversion).

onStore

Called just prior to when an object is stored in the data store. Typically used to transform an object just prior to its storage (for example, encryption).

C.1.3.3. Property Storage Triggers

A property-scoped trigger applies to a specific property within an object. Only the property itself is in scope for the trigger. No other properties in the object should be accessed during execution of the trigger. Unless otherwise specified, the order of execution of property-scoped triggers is intentionally left undefined.

onValidate

Validates a given property value after its retrieval from and prior to its storage in the data store. Throws an exception in the event of a validation failure.

onRetrieve

Called after an object is retrieved from the data store. Typically used to transform a given property after its object's retrieval.

onStore

Called prior to when an object is stored in the data store. Typically used to transform a given property prior to its object's storage.

C.1.3.4. Storage Trigger Sequences

Triggers are executed in the following order:

Object Retrieval Sequence
  1. Retrieve the raw object from the data store

  2. Call object onRetrieve trigger

  3. Per-property within the object:

    • Call property onRetrieve trigger

    • Perform schema validation if _schema_rev does not match (see the Schema Validation section)

Object Storage Sequence
  1. Per-property within the object:

    • Call property onValidate trigger

    • Call object onValidate trigger

  2. Per-property trigger within the object:

    • Call property onStore trigger

    • Call object onStore trigger

    • Store the object with any resulting changes to the data store

C.1.4. Managed Object Encryption

Sensitive object properties can be encrypted prior to storage, typically through the property onStore trigger. The trigger has access to configuration data, which can include arbitrary attributes that you define, such as a symmetric encryption key. Such attributes can be decrypted during retrieval from the data store through the property onRetrieve trigger.

C.1.5. Managed Object Configuration

Configuration of managed objects is provided through an array of managed object configuration objects.

{
  "objects": [ managed-object-config object, ... ]
}
objects

array of managed-object-config objects, required

Specifies the objects that the managed object service manages.

Managed-Object-Config Object Properties

Specifies the configuration of each managed object.

{
  "name"      : string,
  "schema"    : json-schema object,
  "onCreate"  : script object,
  "onRead"    : script object,
  "onUpdate"  : script object,
  "onDelete"  : script object,
  "onValidate": script object,
  "onRetrieve": script object,
  "onStore"   : script object,
  "properties": [ property-configuration object, ... ]
}
name

string, required

The name of the managed object. Used to identify the managed object in URIs and identifiers.

schema

json-schema object, optional

The schema to use to validate the structure and content of the managed object. The schema-object format is specified by the JSON Schema specification.

onCreate

script object, optional

A script object to trigger when the creation of an object is being requested. The object to be created is provided in the root scope as an object property. The script may change the object. If an exception is thrown, the create aborts with an exception.

onRead

script object, optional

A script object to trigger when the read of an object is being requested. The object being read is provided in the root scope as an object property. The script may change the object. If an exception is thrown, the read aborts with an exception.

onUpdate

script object, optional

A script object to trigger when an update to an object is requested. The old value of the object being updated is provided in the root scope as an oldObject property. The new value of the object being updated is provided in the root scope as a newObject property. The script may change the newObject. If an exception is thrown, the update aborts with an exception.

onDelete

script object, optional

A script object to trigger when the deletion of an object is being requested. The object being deleted is provided in the root scope as an object property. If an exception is thrown, the deletion aborts with an exception.

onValidate

script object, optional

A script object to trigger when the object requires validation. The object to be validated is provided in the root scope as an object property. If an exception is thrown, the validation fails.

onRetrieve

script object, optional

A script object to trigger once an object is retrieved from the repository. The object that was retrieved is provided in the root scope as an object property. The script may change the object. If an exception is thrown, then object retrieval fails.

onStore

script object, optional

A script object to trigger when an object is about to be stored in the repository. The object to be stored is provided in the root scope as an object property. The script may change the object. If an exception is thrown, then object storage fails.

properties

array of property-config objects, optional

A list of property specifications.

Script Object Properties
{
  "type"  : "text/javascript",
  "source": string
 }
type

string, required

Specifies the type of script to be executed. Currently, only "text/javascript" is supported.

source, file

string, required (only one, source or file is required)

Specifies the source code of the script to be executed (if the keyword is "source"), or a pointer to the file that contains the script (if the keyword is "file").

Property Config Properties
{
  "name"      : string,
  "onValidate": script object,
  "onRetrieve": script object,
  "onStore"   : script object,
  "encryption": property-encryption object
}
name

string, required

The name of the property being configured.

onValidate

script object, optional

A script object to trigger when the property requires validation. The property to be validated is provided in the root scope as the property property. If an exception is thrown, the validation fails.

onRetrieve

script object, optional

A script object to trigger once a property is retrieved from the repository. The property that was retrieved is provided in the root scope as the property property. The script may change the property value. If an exception is thrown, then object retrieval fails.

onStore

script object, optional

A script object to trigger when a property is about to be stored in the repository. The property to be stored is provided in the root scope as the property property. The script may change the property value. If an exception is thrown, then object storage fails.

encryption

property-encryption object, optional

Specifies the configuration for encryption of the property in the repository. If omitted or null, the property is not encrypted.

Property Encryption Object
{
  "cipher": string,
  "key"   : string
}
cipher

string, optional

The cipher transformation used to encrypt the property. If omitted or null, the default cipher of "AES/CBC/PKCS5Padding" is used.

key

string, required

The alias of the key in the OpenIDM cryptography service keystore used to encrypt the property.

C.1.6. Custom Managed Objects

Managed objects in OpenIDM are inherently fully user definable and customizable. Like all OpenIDM objects, managed objects can maintain relationships to each other in the form of links. Managed objects are intended for use as targets and sources for synchronization operations to represent domain objects, and to build up virtual identities. The name comes from the intention that OpenIDM stores and manages these objects, as opposed to system objects that are present in external systems.

OpenIDM can synchronize and map directly between external systems (system objects), without storing intermediate managed objects. Managed objects are appropriate, however, as a way to cache the data—for example, when mapping to multiple target systems, or when decoupling the availability of systems—to more fully report and audit on all object changes during reconciliation, and to build up views that are different from the original source, such transformed and combined or virtual views. Managed objects can also be allowed to act as an authoritative source if no other appropriate source is available.

Other object types exist for other settings that should be available to a script, such as configuration or look-up tables that do not need audit logging.

C.1.6.1. Setting Up a Managed Object Type

To set up a managed object, you declare the object in the conf/managed.json file where OpenIDM is installed. The following example adds a simple foobar object declaration after the user object type.

{
    "objects": [
        {
            "name": "user"
        },
        {
            "name": "foobar"
        }
    ]
}

C.1.6.2. Manipulating Managed Objects Declaratively

By mapping an object to another object, either an external system object or another internal managed object, you automatically tie the object life cycle and property settings to the other object. See the chapter on Configuring Synchronization for details.

C.1.6.3. Manipulating Managed Objects Programmatically

You can address managed objects as resources using URLs or URIs with the managed/ prefix. This works whether you address the managed object internally as a script running in OpenIDM or externally through the REST interface.

You can use all resource API functions in script objects for create, read, update, delete operations, and also for arbitrary queries on the object set, but not currently for arbitrary actions. See the Scripting Reference appendix for details.

OpenIDM supports concurrency through a multi version concurrency control (MVCC) mechanism. In other words, each time an object changes, OpenIDM assigns it a new revision.

Objects can be arbitrarily complex as long as they use supported types, such as maps, lists, numbers, strings, and booleans as defined in JSON.

C.1.6.3.1. Creating Objects

The following script example creates an object type.

openidm.create("managed/foobar/myidentifier", mymap)
C.1.6.3.2. Updating Objects

The following script example updates an object type.

var expectedRev = origMap._rev
openidm.update("managed/foobar/myidentifier", expectedRev, mymap)

The MVCC mechanism requires that expectedRev be set to the expected revision of the object to update. You obtain the revision from the object's _rev property. If something else changes the object concurrently, OpenIDM rejects the update, and you must either retry or inspect the concurrent modification.

C.1.6.3.3. Patching Objects

You can partially update a managed object using the patch method, which changes only the specified properties of the object. OpenIDM implements the JSON patch media type version 02, described at https://tools.ietf.org/html/draft-pbryan-json-patch-02.

The following script example updates an object type.

openidm.patch("managed/foobar/myidentifier", rev, value)

The patch method supports a revision of "null", which effectively disables the MVCC mechanism, that is, changes are applied, regardless of revision. In the REST interface, this matches the If-Match: "*" condition supported by patch.

The API supports patch by query, so the caller does not need to know the identifier of the object to change.

$ curl
 --header "X-OpenIDM-Username: openidm-admin"
 --header "X-OpenIDM-Password: openidm-admin"
 --request POST -d '[{"replace":"/password","value": "Passw0rd"}]' 
 "http://localhost:8080/openidm/managed/user?_action=patch&_queryId=for-userName&uid=DDOE"

For the syntax on how to formulate the query _queryId=for-userName&uid=DDOE see Section C.1.6.3.6, “Querying Object Sets”.

C.1.6.3.4. Deleting Objects

The following script example deletes an object type.

var expectedRev = origMap._rev
openidm.delete("managed/foobar/myidentifier", expectedRev)

The MVCC mechanism requires that expectedRev be set to the expected revision of the object to update. You obtain the revision from the object's _rev property. If something else changes the object concurrently, OpenIDM rejects deletion, and you must either retry or inspect the concurrent modification.

C.1.6.3.5. Reading Objects

The following script example reads an object type.

val = openidm.read("managed/foobar/myidentifier")
C.1.6.3.6. Querying Object Sets

The following script example queries object type instances.

var params = {
    "_queryId": "my-custom-query-id",
    "mycustomtoken": "samplevalue"
};
val = openidm.query("managed/foobar", params);

The example sets up a query with ID my-custom-query-id. The query definition (not shown) is found in the repository configuration. The query definition includes the parameter mycustomtoken for token substitution.

An example for a query can be found in chapter Managed Object as Correlation Query Target .

C.1.7. Accessing Managed Objects Through the REST API

OpenIDM exposes all managed object functionality through the REST API unless you configure a policy to prevent such access. In addition to the common REST functionality of create, read, update, delete, patch, and query, the REST API also supports patch by query. See the REST API Reference appendix for details.

OpenIDM requires authentication to access the REST API. Authentication configuration is shown in openidm/conf/authentication.json. The default authorization filter script is openidm/script/router-authz.js.

C.2. Configuration Objects

OpenIDM provides an extensible configuration to allow you to leverage regular configuration mechanisms.

Unlike native OpenIDM configuration, which OpenIDM interprets automatically and can start new services, OpenIDM stores custom configuration objects and makes them available to your code through the API.

See the chapter on Configuration Options for an introduction to standard configuration objects.

C.2.1. When To Use Custom Configuration Objects

Configuration objects are ideal for metadata and settings that need not be included in the data to reconcile. In other words, use configuration objects for data that does not require audit log, and does not serve directly as a target or source for mappings.

Although you can set and manipulate configuration objects both programmatically and also manually, configuration objects are expected to change slowly, perhaps through a mix of both manual file updates and also programmatic updates. To store temporary values that can change frequently and that you do not expect to be updated by configuration file changes, custom repository objects can be more appropriate.

C.2.2. Custom Configuration Object Naming Conventions

By convention custom configuration objects are added under the reserved context, config/custom.

You can choose any name under config/context. Be sure, however, to choose a value for context that does not clash with future OpenIDM configuration names.

C.2.3. Mapping Configuration Objects To Configuration Files

If you have not disabled the file based view for configuration, you can view and edit all configuration including custom configuration in openidm/conf/*.json files. The configuration maps to a file named context-config-name.json, where context for custom configuration objects is custom by convention, and config-name is the configuration object name. A configuration object named escalation thus maps to a file named conf/custom-escalation.json.

OpenIDM detects and automatically picks up changes to the file.

OpenIDM also applies changes made through APIs to the file.

By default, OpenIDM stores configuration objects in the repository. The file view is an added convenience aimed to help you in the development phase of your project.

C.2.4. Configuration Objects File & REST Payload Formats

By default, OpenIDM maps configuration objects to JSON representations.

OpenIDM represents objects internally in plain, native types like maps, lists, strings, numbers, booleans, null. OpenIDM constrains the object model to simple types so that mapping objects to external representations is trivial.

The following example shows a representation of a configuration object with a look-up map.

{
    "CODE123" : "ALERT",
    "CODE889" : "IGNORE"
}

In the JSON representation, maps are represented with braces ({ }), and lists are represented with brackets ([ ]). Objects can be arbitrarily complex, as in the following example.

{
    "CODE123" : {
        "email" : ["sample@sample.com", "john.doe@somedomain.com"],
        "sms" : ["555666777"]
    }
    "CODE889" : "IGNORE"
}

C.2.5. Accessing Configuration Objects Through the REST API

You can list all available configuration objects, including system and custom configurations, using an HTTP GET on /openidm/config.

The _id property in the configuration object provides the link to the configuration details with an HTTP GET on /openidm/config/id-value. By convention, the id-value for a custom configuration object called escalation is custom/escalation.

OpenIDM supports REST mappings for create, read, update, and delete of configuration objects. Currently OpenIDM does not support patch and custom query operations for configuration objects.

C.2.6. Accessing Configuration Objects Programmatically

You can address configuration objects as resources using the URL or URI config/ prefix both internally and also through the REST interface. The resource API provides script object functions for create, read, update, and delete operations.

OpenIDM supports concurrency through a multi version concurrency control mechanism. In other words, each time an object changes, OpenIDM assigns it a new revision.

Objects can be arbitrarily complex as long as they use supported types, such as maps, lists, numbers, strings, and booleans.

C.2.7. Creating Objects

The following script example creates an object type.

openidm.create("config/custom/myconfig", mymap)

C.2.8. Updating Objects

The following script example updates a custom configuration object type.

openidm.update("config/custom/myconfig", mymap)

C.2.9. Deleting Objects

The following script example deletes a custom configuration object type.

openidm.delete("config/custom/myconfig")

C.2.10. Reading Objects

The following script example reads an object type.

val = openidm.read("config/custom/myconfig")

C.3. System Objects

System objects are pluggable representations of objects on external systems. They follow the same RESTful resource based design principles as managed objects. There is a default implementation for the OpenICF framework, which allows any connector object to be represented as a system object.

C.4. Audit Objects

Audit objects house audit data selected for local storage in the OpenIDM repository. For details, see the chapter on Using Audit Logs.

C.5. Links

Link objects define relations between source objects and target objects, usually relations between managed objects and system objects. The link relationship is established by provisioning activity that either results in a new account on a target system, or a reconciliation or synchronization scenario that takes a LINK action.