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.
| Object Type | Intended Use | Special Functionality |
|---|---|---|
| Managed objects | Serve 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 objects | Ideal 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 objects | The equivalent of arbitrary database table access. Appropriate for managing data purely through the underlying data store or repository API. | Persistence and API access |
| System objects | Representation of target resource objects, such as accounts, but also resource objects such as groups. | |
| Audit objects | Houses audit data in the OpenIDM internal repository. | |
| Links | Defines a relation between two 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.
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.
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.
string
The unique identifier for the object. This value forms a part of the managed object's URI.
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.
string
The a reference to the schema object that the managed object is associated with.
string
The revision of the schema that was used for validation when the object was last stored.
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.
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.
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.
Triggers are user-definable functions that validate or modify object or property state.
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.
Called upon a request to create a new object. Throwing an exception causes the create to fail.
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.
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.
Called upon a request to delete an object. Throwing an exception causes the deletion to fail.
An object-scoped trigger applies to an entire object. Unless otherwise specified, the object itself is in scope for the trigger.
Validates an object prior to its storage in the data store. Throws an exception in the event of a validation failure.
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).
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).
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.
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.
Called after an object is retrieved from the data store. Typically used to transform a given property after its object's retrieval.
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.
Triggers are executed in the following order:
Retrieve the raw object from the data store
Call object onRetrieve trigger
Per-property within the object:
Call property onRetrieve trigger
Perform schema validation if _schema_rev
does not match (see the Schema
Validation section)
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.
Configuration of managed objects is provided through an array of managed object configuration objects.
{
"objects": [ managed-object-config object, ... ]
}array of managed-object-config objects, required
Specifies the objects that the managed object service manages.
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, ... ]
}string, required
The name of the managed object. Used to identify the managed object in URIs and identifiers.
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.
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.
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.
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.
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.
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.
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.
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.
array of property-config objects, optional
A list of property specifications.
{
"type" : "text/javascript",
"source": string
}string, required
Specifies the type of script to be executed. Currently, only
"text/javascript" is supported.
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").
{
"name" : string,
"onValidate": script object,
"onRetrieve": script object,
"onStore" : script object,
"encryption": property-encryption object
}string, required
The name of the property being configured.
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.
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.
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.
property-encryption object, optional
Specifies the configuration for encryption of the property in the repository. If omitted or null, the property is not encrypted.
{
"cipher": string,
"key" : string
}string, optional
The cipher transformation used to encrypt the property. If
omitted or null, the default cipher of
"AES/CBC/PKCS5Padding" is used.
string, required
The alias of the key in the OpenIDM cryptography service keystore used to encrypt the property.
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.
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"
}
]
}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.
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.
The following script example creates an object type.
openidm.create("managed/foobar/myidentifier", mymap)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.
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”.
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.
The following script example reads an object type.
val = openidm.read("managed/foobar/myidentifier")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 .
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.
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.
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.
By convention custom configuration objects are added under the
reserved context, config/custom.
You can choose any name under
config/. Be sure,
however, to choose a value for contextcontext that
does not clash with future OpenIDM configuration names.
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
,
where context-config-name.jsoncontext 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.
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"
}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/.
By convention, the id-valueid-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.
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.
The following script example creates an object type.
openidm.create("config/custom/myconfig", mymap)The following script example updates a custom configuration object type.
openidm.update("config/custom/myconfig", mymap)The following script example deletes a custom configuration object type.
openidm.delete("config/custom/myconfig")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.
Audit objects house audit data selected for local storage in the OpenIDM repository. For details, see the chapter on Using Audit Logs.
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.