Scripts in mappings
You can use a number of script hooks to manipulate objects and attributes during synchronization. Scripts can be triggered during various stages of the synchronization process, and are defined as part of the mapping.
You can trigger a script when a managed or system object is created (onCreate
), updated (onUpdate
), or deleted (onDelete
). You can also trigger a script when a link is created (onLink
) or removed (onUnlink
).
In the default synchronization mapping, changes are always written to target objects, not to source objects. However, you can explicitly include a call to an action that should be taken on the source object within the script.
Construct and manipulate attributes
The most common use of synchronization scripts is when a target object is created or updated.
The onUpdate
script is always called for an UPDATE situation, even if the synchronization process determines that there is no difference between the source and target objects, and that the target object will not be updated.
If the onUpdate
script has run and the synchronization process then determines that the target value to set is the same as its existing value, the change is prevented from synchronizing to the target.
The following excerpt of a sample mapping derives a DN for an LDAP entry when the corresponding managed entry is created:
{
"onCreate": {
"type": "text/javascript",
"source":
"target.dn = 'uid=' + source.uid + ',ou=people,dc=example,dc=com'"
}
}
Perform other actions
Construct and Manipulate Attributes With Scripts shows how to manipulate attributes with scripts when objects are created and updated. You can also trigger scripts in response to other synchronization actions. For example, you might not want to delete a managed user directly when an external account is deleted, but instead unlink the objects and deactivate the user in another resource. Alternatively, you might delete the object in IDM and run a script to perform some subsequent action.
The following example shows a more advanced mapping configuration that exposes the script hooks available during synchronization:
{
"mappings": [
{
"name": "systemLdapAccount_managedUser",
"source": "system/ldap/account",
"target": "managed/user",
"validSource": {
"type": "text/javascript",
"file": "script/isValid.js"
},
"correlationQuery" : {
"type" : "text/javascript",
"source" : "var map = {'_queryFilter': 'uid eq \"' +
source.userName + '\"'}; map;"
},
"properties": [
{
"source": "uid",
"transform": {
"type": "text/javascript",
"source": "source.toLowerCase()"
},
"target": "userName"
},
{
"source": "",
"transform": {
"type": "text/javascript",
"source": "if (source.myGivenName)
{source.myGivenName;} else {source.givenName;}"
},
"target": "givenName"
},
{
"source": "",
"transform": {
"type": "text/javascript",
"source": "if (source.mySn)
{source.mySn;} else {source.sn;}"
},
"target": "familyName"
},
{
"source": "cn",
"target": "fullname"
},
{
"condition": {
"type": "text/javascript",
"source": "var clearObj = openidm.decrypt(object);
((clearObj.password != null) &&
(clearObj.ldapPassword != clearObj.password))"
},
"transform": {
"type": "text/javascript",
"source": "source.password"
},
"target": "__PASSWORD__"
}
],
"onCreate": {
"type": "text/javascript",
"source": "target.ldapPassword = null;
target.adPassword = null;
target.password = null;
target.ldapStatus = 'New Account'"
},
"onUpdate": {
"type": "text/javascript",
"source": "target.ldapStatus = 'OLD'"
},
"onUnlink": {
"type": "text/javascript",
"file": "script/triggerAdDisable.js"
},
"policies": [
{
"situation": "CONFIRMED",
"action": "UPDATE"
},
{
"situation": "FOUND",
"action": "UPDATE"
},
{
"situation": "ABSENT",
"action": "CREATE"
},
{
"situation": "AMBIGUOUS",
"action": "EXCEPTION"
},
{
"situation": "MISSING",
"action": "EXCEPTION"
},
{
"situation": "UNQUALIFIED",
"action": "UNLINK"
},
{
"situation": "UNASSIGNED",
"action": "EXCEPTION"
}
]
}
]
}
The following list shows the properties that you can use as hooks in mapping configurations to call scripts:
- Triggered by Situation
-
onCreate, onUpdate, onDelete, onLink, onUnlink
- Object Filter
-
validSource, validTarget
- Correlating Objects
-
correlationQuery
- Triggered on Reconciliation
-
result
- Scripts Inside Properties
-
condition, transform
Scripts can obtain data from any connected system by using the openidm.read(id)
function, where id
is the identifier of the object to read.
The following example reads a managed user object from the repository:
repoUser = openidm.read("managed/user/9dce06d4-2fc1-4830-a92b-bd35c2f6bcbb");
The following example reads an account from an external LDAP resource:
externalAccount = openidm.read("system/ldap/account/uid=bjensen,ou=People,dc=example,dc=com");
For illustration purposes, this query targets a DN rather than a UID as it did in the previous example. The attribute that is used for the |
Generate log messages
IDM provides a logger
object that you can use from scripts defined in your mapping. These scripts can log messages to the OSGi console and to log files. The logger
object includes the following functions:
-
debug()
-
error()
-
info()
-
trace()
-
warn()
Consider the following mapping excerpt:
{
"mappings" : [
{
"name" : "systemCsvfileAccounts_managedUser",
"source" : "system/csvfile/account",
"target" : "managed/user",
"correlationQuery" : {
"type" : "text/javascript",
"source" : "var query = {'_queryId' : 'for-userName', 'uid' : source.name};query;"
},
"onCreate" : {
"type" : "text/javascript",
"source" : "logger.warn('Case onCreate: the source object contains: = {} ', source); source;"
},
"onUpdate" : {
"type" : "text/javascript",
"source" : "logger.warn('Case onUpdate: the source object contains: = {} ', source); source;"
},
"result" : {
"type" : "text/javascript",
"source" : "logger.warn('Case result: the source object contains: = {} ', source); source;"
},
"properties" : [
{
"transform" : {
"type" : "text/javascript",
"source" : "logger.warn('Case no Source: the source object contains: = {} ', source); source;"
},
"target" : "sourceTest1Nosource"
},
{
"source" : "",
"transform" : {
"type" : "text/javascript",
"source" : "logger.warn('Case emptySource: the source object contains: = {} ', source); source;"
},
"target" : "sourceTestEmptySource"
},
{
"source" : "description",
"transform" : {
"type" : "text/javascript",
"source" : "logger.warn('Case sourceDescription: the source object contains: = {} ', source); source"
},
"target" : "sourceTestDescription"
},
...
]
}
]
}
The scripts that are defined for onCreate
, onUpdate
, and result
log a warning message to the console whenever an object is created or updated, or when a result is returned. The script result includes the full source object.
The scripts that are defined in the properties
section of the mapping log a warning message if the property in the source object is missing or empty. The last script logs a warning message that includes the description of the source object.
During a reconciliation operation, these scripts would generate output in the OSGi console, similar to the following:
2017-02... WARN Case no Source: the source object contains: = null [9A00348661C6790E7881A7170F747F...] 2017-02... WARN Case emptySource: the source object contains: = {roles=openidm-..., lastname=Jensen...] 2017-02... WARN Case no Source: the source object contains: = null [9A00348661C6790E7881A7170F747F...] 2017-02... WARN Case emptySource: the source object contains: = {roles=openidm..., lastname=Carter,...] 2017-02... WARN Case sourceDescription: the source object contains: = null [EEE2FF4BCE9748927A1832...] 2017-02... WARN Case sourceDescription: the source object contains: = null [EEE2FF4BCE9748927A1832...] 2017-02... WARN Case onCreate: the source object contains: = {roles=openidm-..., lastname=Carter, ...] 2017-02... WARN Case onCreate: the source object contains: = {roles=openidm-..., lastname=Jensen, ...] 2017-02... WARN Case result: the source object contains: = {SOURCE_IGNORED={count=0, ids=[]}, FOUND_ALL...]
You can use similar scripts to inject logging into any aspect of a mapping. You can also call the logger
functions from any configuration file that has scripts hooks. For more information about the logger
functions, see Log Functions.