Scripting
Guide to scripting for ForgeRock® Identity Cloud.
Scripting lets you extend Identity Cloud functionality. For example, you can provide custom logic between source and target mappings, define correlation rules, filters, triggers, and so on. This guide shows you how to use scripts in Identity Cloud and provides reference information on the script engine.
Identity Cloud supports scripts written in JavaScript, and uses the following libraries:
-
Rhino version 1.7.13 to run JavaScript.
Rhino has limited support for ES6 / ES2015 (JavaScript version 1.7). For more information, see Rhino ES2015 Support. -
Lodash 3.10.1 and Handlebars 4.7.6 for Rhino scripting.
Using Handlebars JS in server-side JS scripts requires synchronization; for example:
var Handlebars = require("lib/handlebars"); var result = new Packages.org.mozilla.javascript.Synchronizer(function() { var template = Handlebars.compile("Handlebars {{doesWhat}}"); return template({ doesWhat: "rocks!" }); }, Handlebars)(); console.log(result);
-
BouncyCastle 1.67 for signing JWTs.
The BouncyCastle .JAR file that is bundled with Identity Cloud includes the org.bouncycastle.asn1.util.Dump
command-line utility. Although this utility is not used directly by Identity Cloud, it is possible to reference the utility in your scripts. Due to a security vulnerability in this utility, you should not reference it in your scripts. For more information, see the corresponding BouncyCastle issue.
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.
The ForgeRock Common REST API works across the platform to provide common ways to access web resources and collections of resources.
Call a script from the Identity Cloud configuration
To call a script from the Identity Cloud configuration, edit the configuration object. For example:
{
"type" : "text/javascript",
"source": "scriptSource"
}
Script variables are not necessarily simple key:value
pairs, and can be any arbitrarily complex JSON object.
- type
-
string, required
The script type.
Identity Cloud supports
"text/javascript"
. - source
-
string, required
Specifies the source code of the script to be executed.
In general, you should namespace variables passed into scripts with the
|
Examples
The following example script (in the mapping configuration) determines whether to include or ignore a target object in the reconciliation process based on an employeeType
of true
:
"validTarget" : {
"type" : "text/javascript",
"source" : "target.employeeType == 'external'"
}
The following example script (in the mapping configuration) sets the __PASSWORD__
attribute to defaultpwd
when Identity Cloud creates a target object:
"onCreate" : {
"type" : "text/javascript",
"source" : "target.__PASSWORD__ = 'defaultpwd'"
}
You can pass variables to your scripts to provide contextual details at runtime. You pass variables to the scripts that are referenced in configuration by declaring the variable name in the script reference.
The following scheduled task configuration calls a script that triggers an email notification, but 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",
"source" : "scriptSource",
"fromSender" : "admin@example.com",
"toEmail" : "user@example.com"
}
}
}
Validate scripts over REST
Identity Cloud exposes a script
endpoint over which scripts can be validated, by specifying the script parameters as part of the JSON payload. This functionality lets you test how a script will operate in your deployment, with complete control over the inputs and outputs. Testing scripts in this way can be useful in debugging.
The script
endpoint supports two actions - eval
and compile
.
The eval
action evaluates a script, by taking any actions referenced in the script, such as router calls to affect the state of an object. For JavaScript scripts, the last statement that is executed is the value produced by the script, and the expected result of the REST call.
The following REST call returns the value of an ESV (Environment Secret and Variable):
curl \ --header "Authorization: Bearer *token*" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "type": "text/javascript", "source": "identityServer.getProperty(\"esv-myvariable_1\")" }' \ "https://<tenant-env-fqdn>/openidm/script?_action=eval"
The variables passed into this script are namespaced with the |
The compile
action compiles a script, but does not execute it. A successful compilation returns true
. An unsuccessful compilation returns the reason for the failure.
The following REST call tests whether a transformation script will compile:
curl \ --header "Authorization: Bearer *token*" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "type":"text/javascript", "source":"source.mail ? source.mail.toLowerCase() : null" }' \ "http://<tenant-env-fqdn>/openidm/script?_action=compile" True
If the script is not valid, the action returns an indication of the error, for example:
curl \ --header "Authorization: Bearer *token*" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "type":"text/javascript", "source":"source.mail ? source.mail.toLowerCase()" }' \ "http://<tenant-env-fqdn>/openidm/script?_action=compile" { "code": 400, "reason": "Bad Request", "message": "missing : in conditional expression (386...BF2#1)in 386...BF2 at line number 1 at column number 39" }
Create custom endpoints to launch scripts
Custom endpoints let you run arbitrary scripts through the REST API.
A custom endpoint configuration includes an inline script that provides the endpoint functionality.
Custom endpoint scripts
The following custom endpoint script demonstrates all the HTTP operations that can be called by a script. Each HTTP operation is associated with a method
(create
, read
, update
, delete
, patch
, action
, or query
). Requests sent to the custom endpoint return a list of the variables available to each method.
All scripts are invoked with a global request
variable in their scope. This request structure carries all the information about the request.
Read requests on custom endpoints must not modify the state of the resource, either on the client or the server, as this can make them susceptible to CSRF exploits. The standard READ endpoints are safe from Cross Site Request Forgery (CSRF) exploits because they are inherently read-only. That is consistent with the Guidelines for Implementation of REST, from the US National Security Agency, as "… CSRF protections need only be applied to endpoints that will modify information in some way." |
Custom endpoint scripts must return a JSON object. The structure of the return object depends on the method
in the request.
Depending on the method, the variables available to the script can include the following:
resourceName
-
The name of the resource, without the
endpoint/
prefix, such asecho
. newResourceId
-
The identifier of the new object, available as the results of a
create
request. revision
-
The revision of the object.
parameters
-
Any additional parameters provided in the request. The sample code returns request parameters from an HTTP GET with
?param=x
, as"parameters":{"param":"x"}
. content
-
Content based on the latest revision of the object, using
getObject
. context
-
The context of the request, including headers and security. For more information, see Request context chain.
- Paging parameters
-
The
pagedResultsCookie
,pagedResultsOffset
, andpageSize
parameters are specific toquery
methods. For more information see Page Query Results. - Query parameters
-
The
queryId
andqueryFilter
parameters are specific toquery
methods. For more information see Construct Queries.
Sample custom endpoint script
(function(){
if (request.method === "create") {
return {
method: "create",
resourceName: request.resourcePath,
newResourceId: request.newResourceId,
parameters: request.additionalParameters,
content: request.content,
context: context.current
};
} else if (request.method === "read") {
return {
method: "read",
resourceName: request.resourcePath,
parameters: request.additionalParameters,
context: context.current
};
} else if (request.method === "update") {
return {
method: "update",
resourceName: request.resourcePath,
revision: request.revision,
parameters: request.additionalParameters,
content: request.content,
context: context.current
};
} else if (request.method === "patch") {
return {
method: "patch",
resourceName: request.resourcePath,
revision: request.revision,
parameters: request.additionalParameters,
patch: request.patchOperations,
context: context.current
};
} else if (request.method === "query") {
// query results must be returned as a list of maps
return [ {
method: "query",
resourceName: request.resourcePath,
pagedResultsCookie: request.pagedResultsCookie,
pagedResultsOffset: request.pagedResultsOffset,
pageSize: request.pageSize,
queryId: request.queryId,
queryFilter: request.queryFilter.toString(),
parameters: request.additionalParameters,
content: request.content,
context: context.current
} ];
} else if (request.method === "delete") {
return {
method: "delete",
resourceName: request.resourcePath,
revision: request.revision,
parameters: request.additionalParameters,
context: context.current
};
} else if (request.method === "action") {
return {
method: "action",
action: request.action,
content: request.content,
parameters: request.additionalParameters,
context: context.current
};
} else {
throw { code : 500, message : "Unknown request type " + request.method };
}
})();
Custom endpoint configuration
A custom endpoint configuration has the following structure:
{
"context" : "context path",
"type" : "script language",
"source" : "script source"
}
context
-
string, optional
The root URL path for the endpoint, in other words, the route to the endpoint. An endpoint with the context
endpoint/test
is addressable over REST at the URLhttp://<tenant-env-fqdn>/openidm/endpoint/test
or by using a script such asopenidm.read("endpoint/test")
.Endpoint contexts support wild cards, as shown in the preceding example. The
endpoint/linkedview/*
route matches the following patterns:endpoint/linkedView/managed/realm-name_user/bjensen endpoint/linkedView/system/ldap/account/bjensen endpoint/linkedView/ endpoint/linkedView
type
-
string, required
The script type.
Identity Cloud supports
"text/javascript"
. source
-
The inline script source.
For example:
"source" : "require('linkedView').fetch(request.resourcePath);"
Script exceptions
Some custom endpoint scripts require exception-handling logic. To return meaningful messages in REST responses and in logs, you must comply with the language-specific method of throwing errors.
A script written in JavaScript should comply with the following exception format:
throw {
"code": 400, // any valid HTTP error code
"message": "custom error message",
"detail" : {
"var": parameter1,
"complexDetailObject" : [
"detail1",
"detail2"
]
}
}
Any exceptions will include the specified HTTP error code, the corresponding HTTP error message, such as Bad Request
, a custom error message that can help you diagnose the error, and any additional detail that you think might be helpful.
Register custom scripted actions
You can register custom scripts that initiate some arbitrary action on a managed object endpoint. You can declare any number of actions in your managed object schema and associate those actions with a script.
The return value of a custom scripted action is ignored. The managed object is returned as the response of the scripted action, whether that object has been updated by the script or not.
Custom scripted actions have access to the following variables:
-
context
-
request
-
resourcePath
-
object
Example scenario
In this scenario, you want your managed users to have the option to receive update notifications. You can define an action that toggles the value of a specific property on the user object.
-
Add an
updates
property to the managed object configuration:"properties": { ... "updates": { "title": "Automatic Updates", "viewable": true, "type": "boolean", "searchable": true, "userEditable": true }, ... }
-
Add a
toggleUpdates
action to the managed user object definition:{ "objects" : [ { "name" : "user", "onCreate" : { ... }, ... "actions" : { "toggleUpdates" : { "type" : "text/javascript", "source" : "openidm.patch(resourcePath, null, [{ 'operation' : 'replace', 'field' : '/updates', 'value' : !object.updates }])" } }, ... } ] }
The toggleUpdates
action calls a script that changes the value of the user’supdates
property. -
To call the script, specify the ID of the action in a POST request on the user object:
curl \ --header "Authorization: Bearer *token*" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ "http://<tenant-env-fqdn>/openidm/managed/realm-name_user/ID?_action=toggleUpdates"
You can now test the functionality.
-
Create a managed user,
bjensen
, with anupdates
property set totrue
:curl \ --header "Authorization: Bearer *token*" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "userName":"bjensen", "sn":"Jensen", "givenName":"Barbara", "mail":"bjensen@example.com", "telephoneNumber":"5556787", "description":"Created by OpenIDM REST.", "updates": true, "password":"Passw0rd" }' \ "http://<tenant-env-fqdn>/openidm/managed/realm-name_user?_action=create" { "_id": "9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb", "_rev": "0000000050c62938", "userName": "bjensen", "sn": "Jensen", "givenName": "Barbara", "mail": "bjensen@example.com", "telephoneNumber": "5556787", "description": "Created by OpenIDM REST.", "updates": true, "accountStatus": "active", "effectiveRoles": [], "effectiveAssignments": [] }
-
Run the
toggleUpdates
action onbjensen
:curl \ --header "Authorization: Bearer *token*" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ "http://<tenant-env-fqdn>/openidm/managed/realm-name_user/9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb?_action=toggleUpdates" { "_id": "9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb", "_rev": "00000000a92657c7", "userName": "bjensen", "sn": "Jensen", "givenName": "Barbara", "mail": "bjensen@example.com", "telephoneNumber": "5556787", "description": "Created by OpenIDM REST.", "updates": false, "accountStatus": "active", "effectiveRoles": [], "effectiveAssignments": [] }
Note in the command output that this action has set bjensen’s updates
property tofalse
.
Request context chain
The context chain of any request is established as follows:
-
The request starts with a root context, associated with a specific context ID.
-
The root context is wrapped in the security context that includes the authentication and authorization detail for the request.
-
The security context is further wrapped by the HTTP context, with the target URI. The HTTP context is associated with the normal parameters of the request, including a user agent, authorization token, and method.
-
The HTTP context is wrapped by one or more server/router context(s), with an endpoint URI. The request can have several layers of server and router contexts.
Script triggers
Scripts can be triggered in different places, and by different events. The following list indicates the configuration files in which scripts can be referenced, the events upon which the scripts can be triggered, and the actual scripts that can be triggered on each of these files.
- Scripts called in mappings
-
- Triggered by situation
-
onCreate, onUpdate, onDelete, onLink, onUnlink
- Object filter
-
validSource, validTarget
- Triggered when correlating objects
-
correlationQuery, correlationScript
- Triggered on any reconciliation
-
result
- Scripts inside properties
-
condition, transform
sync.json
supports only one script per hook. If multiple scripts are defined for the same hook, only the last one is kept. - Scripts inside policies
-
condition
Within a synchronization policy, you can use a
condition
script to apply different policies based on the link type, for example:"condition" : { "type" : "text/javascript", "source" : "linkQualifier == \"user\"" }
- Scripts called in the managed object configuration
-
onCreate, onRead, onUpdate, onDelete, onValidate, onRetrieve, onStore, onSync, postCreate, postUpdate, and postDelete
The managed object configuration supports only one script per hook. If multiple scripts are defined for the same hook, only the last one is kept.
- Scripts called in the router configuration
-
onRequest, onResponse, onFailure
The router configuration supports multiple scripts per hook.
Script triggers defined in the managed object configuration
For information about how managed objects are handled, and the available script triggers, see Managed objects.
Managed object configuration object
Trigger | Variable |
---|---|
|
|
Returns JSON object |
|
Returns JSON object. |
|
Returns JSON object. |
|
Returns JSON object |
|
Returns JSON object |
|
Property object
Trigger | Variable |
---|---|
Returns JSON object |
|
Returns JSON object |
|
Script triggers defined in mappings
For information about how managed objects in mappings are handled, and the script triggers available, see Object-Mapping Objects.
Object-mapping object
Trigger | Variable |
---|---|
Returns JSON object |
|
Returns JSON object |
|
Returns JSON object |
|
Returns JSON object |
|
Returns JSON object |
|
Returns JSON object |
|
Returns JSON object of reconciliation results |
|
Returns boolean |
|
Returns boolean |
|
Property object
Trigger | Variable |
---|---|
Returns boolean |
|
Returns JSON object |
|
Policy object
Trigger | Variable |
---|---|
Returns string OR JSON object |
|
Returns JSON object |
|
Script triggers defined in the router configuration
Trigger | Variable |
---|---|
|
exception |
|
request |
|
response |
The augmentSecurityContext
trigger
The augmentSecurityContext
trigger, defined in the authentication configuration, can reference a script that is executed after successful authentication. Such scripts can populate the security context of the authenticated user. If the authenticated user is not found in the resource specified by queryOnResource
, the augmentSecurityContext
can provide the required authorization map.
Such scripts have access to the following bindings:
-
security
- includes theauthenticationId
and theauthorization
key, which includes themoduleId
.The main purpose of an
augmentSecurityContext
script is to modify theauthorization
map that is part of thissecurity
binding. The authentication module determines the value of theauthenticationId
, and Identity Cloud attempts to populate theauthorization
map with the details that it finds, related to thatauthenticationId
value. These details include the following:-
security.authorization.component
- the resource that contains the account (this will always will be the same as the value ofqueryOnResource
by default). -
security.authorization.id
- the internal_id
value that is associated with the account. -
security.authorization.roles
- any roles that were determined, either from reading theuserRoles
property of the account or from calculation. -
security.authorization.moduleId
- the authentication module responsible for performing the original authentication.
You can use the
augmentSecurityContext
script to change any of theseauthorization
values. The script can also add new values to theauthorization
map, which will be available for the lifetime of the session. -
-
properties
- corresponds to theproperties
map of the related authentication module. -
httpRequest
- a reference to theRequest
object that was responsible for handling the incoming HTTP request.This binding is useful to the augment script because it has access to all of the raw details from the HTTP request, such as the headers. The following code snippet shows how you can access a header using the
httpRequest
binding. This example accesses theauthToken
request header:httpRequest.getHeaders().getFirst('authToken').toString()
Script variables
The variables available to a script depend on several factors:
-
The trigger that launches the script.
-
The configuration file in which that trigger is defined.
-
The object type:
-
For objects defined in the managed object configuration, the object type is either a managed object, or a managed object property.
-
For objects defined in the mapping configuration, the object can be an object-mapping object, a property object, or a policy object. For more information, see Policy Objects).
-
The following subtopics list the variables available to scripts, based on the configuration file in which the trigger is defined.
Variables available to scripts in custom endpoints
All custom endpoint scripts have a request
variable in their scope, which is a JSON object containing all information about the request. The parameters found in this object vary depending on the request method. The request may include headers, credentials, and the desired action. The request normally also includes the endpoint as well as the payload to be processed.
For more details about writing custom endpoint scripts, see Custom Endpoint Scripts.
Variable | Variable Parameters |
---|---|
|
|
Variables available to role assignment scripts
The optional onAssignment
and onUnassignment
event scripts specify what should happen to attributes that are affected by role assignments when those assignments are applied to a user, or removed from a user.
These scripts have access to the following variables:
-
sourceObject
-
targetObject
-
existingTargetObject
-
linkQualifier
The standard assignment scripts, replaceTarget.js
, mergeWithTarget.js
, removeFromTarget.js
, and noOp.js
have access to all the variables in the previous list, as well as the following:
-
attributeName
-
attributeValue
-
attributesInfo
Role assignment scripts must always return |
The identityServer
variable
Identity Cloud provides an additional variable, named identityServer
, to scripts. You can use this variable in several ways. The ScriptRegistryService
, described in Validate scripts over REST, binds this variable to:
-
getProperty
Retrieves property information from system configuration files. Takes up to three parameters:
-
The name of the property you are requesting.
-
(Optional) The default result to return if the property wasn’t set.
-
(Optional) Boolean to determine whether to use property substitution when getting the property.
For example, you can retrieve the value of the
openidm.config.crypto.alias
property with the following code:alias = identityServer.getProperty("openidm.config.crypto.alias", "true", true);
The following REST call returns the value of an ESV (Environment Secret and Variable):
curl \ --header "Authorization: Bearer *token*" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "type": "text/javascript", "source": "identityServer.getProperty(\"esv-myvariable_1\")" }' \ "https://<tenant-env-fqdn>/openidm/script?_action=eval"
-
-
getInstallLocation
Retrieves the Identity Cloud installation path, such as
/path/to/openidm
. May be superseded by an absolute path.
Router configuration
The router service provides the uniform interface to all Identity Cloud objects: managed objects, system objects, configuration objects, and so on.
The router configuration contains an array of Filter objects:
{
"filters": [ filter object, ... ]
}
Filter objects
The required filters array defines a list of filters to be processed on each router request. Filters are processed in the order in which they are specified in this array, and have the following configuration:
{
"pattern": string,
"methods": [ string, ... ],
"condition": script object,
"onRequest": script object,
"onResponse": script object,
"onFailure": script object
}
- pattern
-
string, optional
Specifies a regular expression pattern matching the JSON pointer of the object to trigger scripts. If not specified, all identifiers (including
null
) match. Pattern matching is done on the resource name, rather than on individual objects. - methods
-
array of strings, optional
One or more methods for which the script(s) should be triggered. Supported methods are:
"create"
,"read"
,"update"
,"delete"
,"patch"
,"query"
,"action"
. If not specified, all methods are matched. - condition
-
script object, optional
Specifies a script that is called first to determine if the script should be triggered. If the condition yields
"true"
, the other script(s) are executed. If no condition is specified, the script(s) are called unconditionally. - onRequest
-
script object, optional
Specifies a script to execute before the request is dispatched to the resource. If the script throws an exception, the method is not performed, and a client error response is provided.
- onResponse
-
script object, optional
Specifies a script to execute after the request is successfully dispatched to the resource and a response is returned. Throwing an exception from this script does not undo the method already performed.
- onFailure
-
script object, optional
Specifies a script to execute if the request resulted in an exception being thrown. Throwing an exception from this script does not undo the method already performed.
Pattern matching in the router configuration
Pattern matching can minimize overhead in the router service. The default router configuration includes instances of the pattern
filter object, that limit script requests to specified methods and endpoints.
Based on the following code snippet, the router service would trigger the policyFilter.js
script for CREATE
and UPDATE
calls to managed and internal objects:
{
"pattern" : "^(managed|internal)($|(/.+))",
"onRequest" : {
"type" : "text/javascript",
"source" : "require('policyFilter').runFilter()"
},
"methods" : [
"create",
"update"
]
}
Without this pattern
, Identity Cloud would apply the policy filter to additional objects, such as the audit service, which could affect performance.
Script execution sequence
All onRequest
and onResponse
scripts are executed in sequence. First, the onRequest
scripts are executed from the top down, then the onResponse
scripts are executed from the bottom up.
client -> filter 1 onRequest -> filter 2 onRequest -> resource client <- filter 1 onResponse <- filter 2 onResponse <- resource
The following sample router configuration shows the order in which the scripts would be executed:
{
"filters" : [
{
"onRequest" : {
"type" : "text/javascript",
"source" : "require('router-authz').testAccess()"
}
},
{
"pattern" : "^managed/realm-name_user",
"methods" : [
"read"
],
"onRequest" : {
"type" : "text/javascript",
"source" : "console.log('requestFilter 1');"
}
},
{
"pattern" : "^managed/realm-name_user",
"methods" : [
"read"
],
"onResponse" : {
"type" : "text/javascript",
"source" : "console.log('responseFilter 1');"
}
},
{
"pattern" : "^managed/realm-name_user",
"methods" : [
"read"
],
"onRequest" : {
"type" : "text/javascript",
"source" : "console.log('requestFilter 2');"
}
},
{
"pattern" : "^managed/realm-name_user",
"methods" : [
"read"
],
"onResponse" : {
"type" : "text/javascript",
"source" : "console.log('responseFilter 2');"
}
}
]
}
This configuration would produce a log as follows:
requestFilter 1
requestFilter 2
responseFilter 2
responseFilter 1
Example Filter Configuration
This example executes a script after a managed user object is created or updated:
{
"filters": [
{
"pattern": "^managed/realm-name_user",
"methods": [
"create",
"update"
],
"onResponse": {
"type": "text/javascript",
"file": "scripts/afterUpdateUser.js"
}
}
]
}
Script scope
Scripts are provided with the following scope:
{
"openidm": openidm-functions object,
"request": resource-request object,
"response": resource-response object,
"exception": exception object
}
- openidm
-
Provides access to Identity Cloud resources.
- request
-
resource-request object
The resource-request context, which has one or more parent contexts. Provided in the scope of all scripts. For more information about the request context, see Request context chain.
- response
-
resource-response object
The response to the resource-request. Only provided in the scope of the
"onResponse"
script. - exception
-
exception object
The exception value that was thrown as a result of processing the request. Only provided in the scope of the
"onFailure"
script. An exception object is defined as:{ "code": integer, "reason": string, "message": string, "detail": string }
- code
-
integer
The numeric HTTP code of the exception.
- reason
-
string
The short reason phrase of the exception.
- message
-
string
A brief message describing the exception.
- detail
-
(optional), string
A detailed description of the exception, in structured JSON format, suitable for programmatic evaluation.
1. Scripting function reference
If you need to request specific resource versions, see REST API versioning. |
Functions (access to managed objects, system objects, and configuration objects) within Identity Cloud are accessible to scripts via the openidm
object, which is included in the top-level scope provided to each script.
The script engine supports the following functions:
openidm.create(resourceName, newResourceId, content, params, fields)
This function creates a new resource object.
- Parameters
-
- resourceName
-
string
The container in which the object will be created, for example,
managed/realm-name_user
. - newResourceId
-
string
The identifier of the object to be created, if the client is supplying the ID. If the server should generate the ID, pass null here.
- content
-
JSON object
The content of the object to be created.
- params
-
JSON object (optional)
Additional parameters that are passed to the create request.
- fields
-
JSON array (optional)
An array of the fields that should be returned in the result. The list of fields can include wild cards, such as
*
or*_ref
. If no fields are specified, the entire new object is returned.
- Returns
-
The created resource object.
- Throws
-
An exception is thrown if the object could not be created.
- Example
-
openidm.create("managed/realm-name_user", ID, JSON object);
openidm.patch(resourceName, rev, value, params, fields)
This function performs a partial modification of a managed or system object. Unlike the update
function, only the modified attributes are provided, not the entire object.
- Parameters
-
- resourceName
-
string
The full path to the object being updated, including the ID.
- rev
-
string
The revision of the object to be updated. Use
null
if the object is not subject to revision control, or if you want to skip the revision check and update the object, regardless of the revision. - value
-
An array of one or more JSON objects
The value of the modifications to be applied to the object. The patch set includes the operation type, the field to be changed, and the new values. A PATCH request can
add
,remove
,replace
, orincrement
an attribute value.A
remove
operation removes a property if the value of that property equals the specified value, or if no value is specified in the request. The following examplevalue
removes themarital_status
property from the object, if the value of that property issingle
:[ { "operation": "remove", "field": "marital_status", "value": "single" } ]
For fields whose value is an array, it’s not necessary to know the position of the value in the array, as long as you specify the full object. If the full object is found in the array, that value is removed. The following example removes user adonnelly from bjensen’s
reports
:{ "operation": "remove", "field": "/manager", "value": { "_ref": "managed/realm-name_user/adonnelly", "_refResourceCollection": "managed/realm-name_user", "_refResourceId": "adonnelly", "_refProperties": { "_id": "ed6620e4-98ba-410c-abc0-e06dc1be7aa7", "_rev": "000000008815942b" } } }
If an invalid value is specified (that is a value that does not exist for that property in the current object) the patch request is silently ignored.
A
replace
operation replaces an existing value, or adds a value if no value exists.
- params
-
JSON object (optional)
Additional parameters that are passed to the patch request.
- fields
-
JSON array (optional)
An array of the fields that should be returned in the result. The list of fields can include wild cards, such as
*
or*_ref
. If no fields are specified, the entire new object is returned. - Returns
-
The modified resource object.
- Throws
-
An exception is thrown if the object could not be updated.
- Examples
-
Patching an object to add a value to an array:
openidm.patch("managed/realm-name_role/" + role._id, null, [{"operation":"add", "field":"/members/-", "value": {"_ref":"managed/realm-name_user/" + user._id}}]);
Patching an object to remove an existing property:
openidm.patch("managed/realm-name_user/" + user._id, null, [{"operation":"remove", "field":"marital_status", "value":"single"}]);
Patching an object to replace a field value:
openidm.patch("managed/realm-name_user/" + user._id, null, [{"operation":"replace", "field":"/password", "value":"Passw0rd"}]);
Patching an object to increment an integer value:
openidm.patch("managed/realm-name_user/" + user._id, null, [{"operation":"increment","field":"/age","value":1}]);
openidm.read(resourceName, params, fields)
This function reads and returns a resource object.
- Parameters
-
- resourceName
-
string
The full path to the object to be read, including the ID.
- params
-
JSON object (optional)
The parameters that are passed to the read request. Generally, no additional parameters are passed to a read request, but this might differ, depending on the request. If you need to specify a list of
fields
as a third parameter, and you have no additionalparams
to pass, you must passnull
here. Otherwise, you simply omit both parameters. - fields
-
JSON array (optional)
An array of the fields that should be returned in the result. The list of fields can include wild cards, such as
*
or*_ref
. If no fields are specified, the entire object is returned.
- Returns
-
The resource object, or
null
if not found. - Example
-
openidm.read("managed/realm-name_user/"+userId, null, ["*", "manager"]);
openidm.update(resourceName, rev, value, params, fields)
This function updates an entire resource object.
- Parameters
-
- id
-
string
The complete path to the object to be updated, including its ID.
- rev
-
string
The revision of the object to be updated. Use
null
if the object is not subject to revision control, or if you want to skip the revision check and update the object, regardless of the revision. - value
-
object
The complete replacement object.
- params
-
JSON object (optional)
The parameters that are passed to the update request.
- fields
-
JSON array (optional)
An array of the fields that should be returned in the result. The list of fields can include wild cards, such as
*
or*_ref
. If no fields are specified, the entire object is returned.
- Returns
-
The modified resource object.
- Throws
-
An exception is thrown if the object could not be updated.
- Example
-
In this example, the managed user entry is read (with an
openidm.read
, the user entry that has been read is updated with a new description, and the entire updated object is replaced with the new value.var user_read = openidm.read('managed/realm-name_user/' + source._id); user_read['description'] = 'The entry has been updated'; openidm.update('managed/realm-name_user/' + source._id, null, user_read);
openidm.delete(resourceName, rev, params, fields)
This function deletes a resource object.
- Parameters
-
- resourceName
-
string
The complete path to the to be deleted, including its ID.
- rev
-
string
The revision of the object to be deleted. Use
null
if the object is not subject to revision control, or if you want to skip the revision check and delete the object, regardless of the revision. - params
-
JSON object (optional)
The parameters that are passed to the delete request.
- fields
-
JSON array (optional)
An array of the fields that should be returned in the result. The list of fields can include wild cards, such as
*
or*_ref
. If no fields are specified, the entire object is returned.
- Returns
-
Returns the deleted object if successful.
- Throws
-
An exception is thrown if the object could not be deleted.
- Example
-
openidm.delete('managed/realm-name_user/'+ user._id, user._rev);
openidm.query(resourceName, params, fields)
This function performs a query on the specified resource object. For more information, see Construct Queries.
- Parameters
-
- resourceName
-
string
The resource object on which the query should be performed, for example,
"managed/realm-name_user"
, or"system/ldap/account"
. - params
-
JSON object
The parameters that are passed to the query (
_queryFilter
, or_queryId
). Additional parameters passed to the query will differ, depending on the query.Certain common parameters can be passed to the query to restrict the query results. The following sample query passes paging parameters and sort keys to the query.
reconAudit = openidm.query("audit/recon", { "_queryFilter": queryFilter, "_pageSize": limit, "_pagedResultsOffset": offset, "_pagedResultsCookie": string, "_sortKeys": "-timestamp" });
For more information about
_queryFilter
syntax, see Common Filter Expressions. For more information about paging, see Page Query Results. - fields
-
list
A list of the fields that should be returned in the result. The list of fields can include wild cards, such as
*
or*_ref
. The following example returns only theuserName
and_id
fields:openidm.query("managed/realm-name_user", { "_queryFilter": "/userName sw \"user.1\""}, ["userName", "_id"]);
This parameter is particularly useful in enabling you to return the response from a query without including intermediary code to massage it into the right format.
Fields are specified as JSON pointers.
- Returns
-
The result of the query. A query result includes the following parameters:
- query-time-ms
-
(For JDBC repositories only) the time, in milliseconds, that Identity Cloud took to process the query.
- result
-
The list of entries retrieved by the query. The result includes the properties that were requested in the query.
The following example shows the result of a custom query that requests the ID, user name, and email address of all managed users in the repository.
{ "result": [ { "_id": "9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb", "_rev": "00000000a059dc9f", "userName": "bjensen", "mail": "bjensen@example.com" }, { "_id": "42f8a60e-2019-4110-a10d-7231c3578e2b", "_rev": "00000000d84ade1c", "userName": "scarter", "mail": "scarter@example.com" } ], "resultCount": 2, "pagedResultsCookie": null, "totalPagedResultsPolicy": "NONE", "totalPagedResults": -1, "remainingPagedResults": -1 }
- Throws
-
An exception is thrown if the given query could not be processed.
- Examples
-
The following sample query uses a
_queryFilter
to query the managed user repository:openidm.query("managed/realm-name_user", {'_queryFilter': userIdPropertyName + ' eq "' + security.authenticationId + '"'});
The following sample query references the
for-userName
query, defined in the repository configuration, to query the managed user repository:openidm.query("managed/realm-name_user", {"_queryId": "for-userName", "uid": request.additionalParameters.uid });
openidm.action(resource, actionName, content, params, fields)
This function performs an action on the specified resource object. The resource
and actionName
are required. All other parameters are optional.
- Parameters
-
- resource
-
string
The resource that the function acts upon, for example,
managed/realm-name_user
. - actionName
-
string
The action to execute. Actions are used to represent functionality that is not covered by the standard methods for a resource (create, read, update, delete, patch, or query). In general, you should not use the
openidm.action
function for create, read, update, patch, delete or query operations. Instead, use the corresponding function specific to the operation (for example,openidm.create
).Using the operation-specific functions lets you benefit from the well-defined REST API, which follows the same pattern as all other standard resources in the system. Using the REST API enhances usability for your own API, and enforces the established patterns.
Identity Cloud-defined resources support a fixed set of actions. For user-defined resources (scriptable endpoints) you can implement whatever actions you require.
- Supported Actions Per Resource
-
The following list outlines the supported actions for each resource or endpoint. The actions listed here are also supported over the REST interface.
- Actions supported on the
authentication
endpoint (authentication/*
) -
reauthenticate
- Actions supported on the configuration resource (
config/
) -
No action parameter applies.
- Actions supported on custom endpoints
-
Custom endpoints enable you to run arbitrary scripts through the REST URI, and are routed at
endpoint/name
, where name generally describes the purpose of the endpoint. For more information on custom endpoints, see Create custom endpoints to launch scripts. You can implement whatever actions you require on a custom endpoint. Identity Cloud uses custom endpoints in its workflow implementation. Those endpoints, and their actions are as follows:endpoint/getprocessforuser
-create, complete
endpoint/gettasksview
-create, complete
- Actions supported on the
external
endpoint -
-
external/email
-send
, for example:{ emailParams = { "from" : 'admin@example.com', "to" : user.mail, "subject" : 'Password expiry notification', "type" : 'text/plain', "body" : 'Your password will expire soon. Please change it!' } openidm.action("external/email", "send", emailParams); }
-
external/email
-sendTemplate
, for example:{ emailParams = { "templateName" : "welcome", "to" : user.mail, "cc" : "ccUser1@example.com,ccUser2@example.com", "bcc" : "bigBoss@example.com" } openidm.action("external/email", "sendTemplate", emailParams); }
-
external/rest
-call
, for example:openidm.action("external/rest", "call", params);
-
- Actions supported on the
info
endpoint (info/*
) -
No action parameter applies.
- Actions supported on managed resources (
managed/*
) -
patch, triggerSyncCheck
- Actions supported on the policy resource (
policy
) -
validateObject, validateProperty
For example:
openidm.action("policy/" + fullResourcePath, "validateObject", request.content, { "external" : "true" });
- Actions supported on the reconciliation resource (
recon
) -
recon, reconById, cancel
For example:
openidm.action("recon", "cancel", content, params);
- Actions supported on the repository (
repo
) -
command
For example:
var r, command = { "commandId": "purge-by-recon-number-of", "numberOf": numOfRecons, "includeMapping": includeMapping, "excludeMapping": excludeMapping }; r = openidm.action("repo/audit/recon", "command", {}, command);
- Actions supported on the script resource (
script
) -
eval
For example:
openidm.action("script", "eval", getConfig(scriptConfig), {});
- Actions supported on the synchronization resource (
sync
) -
getLinkedResources, notifyCreate, notifyDelete, notifyUpdate, performAction
For example:
openidm.action('sync', 'performAction', content, params);
- Actions supported on system resources (
system/*
) -
availableConnectors, createCoreConfig, createFullConfig, test, testConfig, liveSync, authenticate, script
For example:
openidm.action("system/ldap/account", "authenticate", {"username" : "bjensen", "password" : "Passw0rd"});
- Actions supported on the task scanner resource (
taskscanner
) -
execute, cancel
- Actions supported on the workflow resource (
workflow/*
) -
On
workflow/processdefinition
create, completeOn
workflow/processinstance
create, completeFor example:
var params = { "_key":"contractorOnboarding" }; openidm.action('workflow/processinstance', 'create', params);
On
workflow/taskinstance
claim, create, completeFor example:
var params = { "userId":"manager1" }; openidm.action('workflow/taskinstance/15', 'claim', params);
- Actions supported on the
- content
-
object
Content given to the action for processing.
- params
-
object (optional)
Additional parameters passed to the script. The
params
object must be a set of simple key:value pairs, and cannot include complex values. The parameters must map directly to URL variables, which take the formname1=val1&name2=val2&…
. - fields
-
JSON array (optional)
An array of the fields that should be returned in the result. The list of fields can include wild cards, such as
*
or*_ref
. If no fields are specified, the entire object is returned.- Returns
-
The result of the action may be
null
. - Throws
-
If the action cannot be executed, an exception is thrown.
openidm.encrypt(value, cipher, alias)
This function encrypts a value.
- Parameters
-
- value
-
any
The value to be encrypted.
- cipher
-
string
The cipher with which to encrypt the value, using the form "algorithm/mode/padding" or just "algorithm". Example:
AES/CBC/PKCS5Padding
. - alias
-
string
The key alias in the keystore, such as
openidm-sym-default
(deprecated) or a purpose defined in thesecrets.json
file, such asidm.password.encryption
.
- Returns
-
The value, encrypted with the specified cipher and key.
- Throws
-
An exception is thrown if the object could not be encrypted.
openidm.decrypt(value)
This function decrypts a value.
- Parameters
-
- value
-
object
The value to be decrypted.
- Returns
-
A deep copy of the value, with any encrypted value decrypted.
- Throws
-
An exception is thrown if the object could not be decrypted for any reason. An error is thrown if the value is passed in as a string - it must be passed in an object.
openidm.isEncrypted(object)
This function determines if a value is encrypted.
- Parameters
-
- object to check
-
any
The object whose value should be checked to determine if it is encrypted.
- Returns
-
Boolean,
true
if the value is encrypted, andfalse
if it is not encrypted. - Throws
-
An exception is thrown if the server is unable to detect whether the value is encrypted, for any reason.
openidm.hash(value, algorithm, options)
This function calculates a value using a salted hash algorithm.
Algorithm | Config Property and Description | ||
---|---|---|---|
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
- Parameters
-
- value
-
any
The value to be hashed.
- algorithm
-
string (optional)
The hashing algorithm. Example:
SHA-512
.If no algorithm is provided, a
null
value must be passed, and the algorithm defaults to SHA-256. - options
-
For JavaScript, JSON object (optional)
Configuration properties for the selected algorithm.
- Returns
-
The value, calculated with the specified hash algorithm.
- Throws
-
An exception is thrown if the object could not be hashed for any reason.
- Examples
-
- JavaScript
-
openidm.hash(\"dummy\", \"BCRYPT\", {\"cost\": 10})
openidm.isHashed(value)
This function detects whether a value has been calculated with a salted hash algorithm.
- Parameters
-
- value
-
any
The value to be reviewed.
- Returns
-
Boolean,
true
if the value is hashed, andfalse
otherwise. - Throws
-
An exception is thrown if the server is unable to detect whether the value is hashed, for any reason.
openidm.matches(string, value)
This function detects whether a string, when hashed, matches an existing hashed value.
- Parameters
-
- string
-
any
A string to be hashed.
- value
-
any
A hashed value to compare to the string.
- Returns
-
Boolean,
true
if the hash of the string matches the hashed value, andfalse
otherwise. - Throws
-
An exception is thrown if the string could not be hashed.
1.1. Log functions
Identity Cloud also provides a logger
object to access the Simple Logging Facade for Java (SLF4J) facilities. The following code shows an example of the logger
object.
logger.info("Parameters passed in: {} {} {}", param1, param2, param3);
In addition, JavaScript has a useful logging function named console.log()
. This function provides an easy way to dump data to the Identity Cloud standard output (usually the same output as the OSGi console). The function works well with the JavaScript built-in function JSON.stringify
and provides fine-grained details about any given object. For example, the following line will print a formatted JSON structure that represents the HTTP request details to STDOUT.
console.log(JSON.stringify(context.http, null, 4));
The script engine supports the following log functions:
logger.debug(string message, object… params)
Logs a message at DEBUG level.
- Parameters
-
- message
-
string
The message format to log. Params replace
{}
in your message. - params
-
object
Arguments to include in the message.
- Returns
-
A
null
value if successful. - Throws
-
An exception is thrown if the message could not be logged.
logger.error(string message, object… params)
Logs a message at ERROR level.
- Parameters
-
- message
-
string
The message format to log. Params replace
{}
in your message. - params
-
object
Arguments to include in the message.
- Returns
-
A
null
value if successful. - Throws
-
An exception is thrown if the message could not be logged.
logger.info(string message, object… params)
Logs a message at INFO level.
- Parameters
-
- message
-
string
The message format to log. Params replace
{}
in your message. - params
-
object
Arguments to include in the message.
- Returns
-
A
null
value if successful. - Throws
-
An exception is thrown if the message could not be logged.
logger.trace(string message, object… params)
Logs a message at TRACE level.
- Parameters
-
- message
-
string
The message format to log. Params replace
{}
in your message. - params
-
object
Arguments to include in the message.
- Returns
-
A
null
value if successful. - Throws
-
An exception is thrown if the message could not be logged.
logger.warn(string message, object… params)
Logs a message at WARN level.
- Parameters
-
- message
-
string
The message format to log. Params replace
{}
in your message. - params
-
object
Arguments to include in the message.
- Returns
-
A
null
value if successful. - Throws
-
An exception is thrown if the message could not be logged.