Systems - Groups synchronization (script / workflow)

The current stable version of this synchronization is maintained in the extras module. Using the version from extras - the script from IdM 16 or the workflow up to IdM 15 - is highly recommended over the core version.

This tutorial describes the synchronization of groups (roles) from Active Directory / LDAP into IdM and how to customize it. From IdM 16 the logic lives in a Groovy synchronization script; up to IdM 15 it was a BPMN workflow. Both editions behave the same and are driven by the same application properties. After customizing it, the synchronization of groups can:

  • create automatic roles by:
    • organization structure
    • attributes
  • create a role catalogue
  • assign roles to the catalogue
  • provision membership of identities to another system
  • resolve membership - identities already assigned to groups in another system
For the management of membership there are currently a few special characters which are unsupported. The name of a role cannot contain: " ' \

From IdM 16 the synchronization logic is no longer a BPMN workflow but a Groovy synchronization action script. Activiti was removed in IdM 16, so the former syncRoleLdap workflow was rewritten as the script syncRoleLdap (name Synchronization - Roles from LDAP, category SYNCHRONIZATION). The script ships in the acc module and can be edited directly in the Scripts agenda - no Eclipse or Activiti tooling is needed anymore.

To use it, set the script as the action script of the synchronization for the same three situations the old workflow handled:

  • Linked / update entity
  • Missing entity / create entity
  • Unlinked / create link and update entity

The script is executed instead of the standard situation action - it calls the standard action itself through defaultSynchronizationService and then adds the extra behaviour (catalogue, role mapping, membership, automatic roles). A string returned by the script is appended to the synchronization item log.

The four workflow Data Objects are now hardcoded constants at the top of the main flow of the script. Change them directly in the script body when you need different values:

  • STRUCTURE_FORM_ATTRIBUTE (default `null`) - code of the tree node EAV used to look up an organization node by the role name (automatic role by organization structure). When it is `null`, the organization structure step is skipped.
  • CODE_OF_TYPE_STRUCTURE (default `ORGANIZATIONS`) - code of the tree type whose organization structure is searched for the automatic role.
  • AUTO_ROLE_ORG_STRUCTURE_ENABLED (default `false`) - enables creating automatic roles by organization structure.
  • AUTO_ROLE_ATTRIBUTES_ENABLED (default `false`) - enables creating automatic roles by attributes.
STRUCTURE_FORM_ATTRIBUTE = null;
CODE_OF_TYPE_STRUCTURE = "ORGANIZATIONS";
AUTO_ROLE_ORG_STRUCTURE_ENABLED = false;
AUTO_ROLE_ATTRIBUTES_ENABLED = false;

Everything else is externalized to idm.pub.acc.syncRole.* application properties, which the script reads once in taskGetAttributesFromProperties() (see Set application properties below).

The main flow of the script mirrors the flow of the original workflow. For a normal element it runs, in this order:

  1. taskGetAttributesFromProperties() - reads all idm.pub.acc.syncRole.* properties once into script variables.
  2. taskSetAttributes() - reads the role name from the IC attribute `name` and the distinguishedName from the IC attribute named by attributeNameOfRoleIdentificator. It also builds transformationScript as the distinguished name wrapped in quotes - the successor of the former TRANSFORMATION_SCRIPT workflow variable.
  3. taskSetAutomaticRoleByOrgStructure() - resolves organizationTreeNode via treeTypeService.getByCode(CODE_OF_TYPE_STRUCTURE) and formService.findOwners(IdmTreeNodeDto.class, STRUCTURE_FORM_ATTRIBUTE, name, null). It is skipped when STRUCTURE_FORM_ATTRIBUTE is `null`.
  4. taskSetAutomaticRoleByAttributes() - builds the automaticAttributes array. The shipped body is only an example meant to be customized for your data.
  5. resolveCatalogue(distinguishedName) - sets catalogueId. It is skipped when the distinguished name is `null` or isResolveCatalogEnabled is `false`. When createAllRolesToOneCatalogue is `null`, a folder tree is built from the OUs of the distinguished name; otherwise all roles go into a single folder named by that property.
  6. The situation branch - see below.
  7. taskResolveMembership() - assigns the role to the member identities.

The MISSING_ACCOUNT situation is handled first and returns early - it only calls defaultSynchronizationService.resolveMissingAccountSituation(…) and none of the steps above run.

The other three situations delegate to the standard action and then run the auto-roles-and-catalogue task:

  • MISSING_ENTITY - defaultSynchronizationService.resolveMissingEntitySituation(…), then taskCreateAutoRolesAndCatalog(), but only for actionType CREATE_ENTITY.
  • LINKED - defaultSynchronizationService.resolveLinkedSituation(…), then taskUpdateAutoRolesAndCatalog(), but only for actionType UPDATE_ENTITY or LINK_AND_UPDATE_ENTITY.
  • UNLINKED - defaultSynchronizationService.resolveUnlinkedSituation(…), then taskUpdateAutoRolesAndCatalog(), but only for actionType UPDATE_ENTITY or LINK_AND_UPDATE_ENTITY.

Both auto-roles-and-catalogue tasks set the canBeRequested flag on the role, add the role to the catalogue (addCatalogueForCreate / addCatalogueForUpdate), create the automatic roles (only if the constants above enable them) and call addResource(…). addResource(…) creates the memberOf mapping attribute (with the built transformationScript as the transformation) on the identity provisioning system, but only when systemCodeForRoleMapping (property idm.pub.acc.syncRole.provisioningOfIdentities.system.code) is set; otherwise it does nothing.

Finally, taskResolveMembership() assigns the role to the identities listed in the member attribute (the attribute named by idm.pub.acc.syncRole.roles.attributeNameOfMembership). Members are matched to identities by the EAV configured in idm.pub.acc.syncRole.identity.eav.externalIdentifier.code, and the role is assigned through a role request that is executed immediately. This runs for actionType CREATE_ENTITY, or in any situation when idm.pub.acc.syncRole.update.resolveMembership is `true`.

Two things are worth knowing when reading or customizing the script:

  • removeLastItemFromCatalogue() is now an empty stub. The old workflow logic that removed the previous catalogue folder when a role was moved to a different catalogue is gone; the method only resets the catalogue variable to `null`.
  • The scriptEvaluator binding variable (provided to every synchronization action script) is not used by this script.

Both the script (IdM 16 and newer) and the workflow (up to IdM 15) are configured purely by application properties, so you can just add the properties below without changing the script or workflow file itself. Application properties are set in the Settings agenda, Configuration tab (like you can see on the picture below).

With the Add button you can add any of the properties described below and configure the synchronization.

Following properties are used, when the workflow is used for creating roles that manage group membership of accounts in a connected system:

  • idm.pub.acc.syncRole.provisioningOfIdentities.system.code - (default: null, _mandatory_) - it is code (name) of the system, which is used for provisioning the identities to the system. E.g. "AD users". It is mandatory attribute, otherwise workflow will not be working.
  • idm.pub.acc.syncRole.system.mapping.objectClassName - (default: \_\_ACCOUNT\_\_) - this is important to provisioning member attribute of identity. It is an object class name of identity schema. It should stay "\_\_ACCOUNT\_\_"
  • idm.pub.acc.syncRole.system.mapping.attributeMemberOf - (default: ldapGroups) - it is the name of an attribute in a mapping of identity provisioning. It is usually ldapGroups (recommended) or memberOf. This attribute will be added to role's mapping with transformation script (which will be set later).
  • idm.pub.acc.syncRole.system.mapping.attributeRoleIdentificator - (default: distinguishedName) - the name of an attribute in the connector, which holds the distinguished name of a role object.

Managing group membership of account - more special options for the roles:

  • idm.pub.acc.syncRole.roleSystem.forwardManagement.value - (default: false) - every role, which manages group membership on the connected system, has the option forward account management. This property can set this option.
  • idm.pub.acc.syncRole.roleSystem.update.manageforwardManagement - (default: false) - this property will manage forward account management option even when updating existing roles by the synchronization.
  • idm.pub.acc.syncRole.roles.nameOfRoles.doNotSentValueOnExclusion - (default: null) - every role, which manages group membership on the connected system, has the option to skip the value if it's assigned on an excluded contract (see the tutorial about this). Add to this property names of new roles separated with comma, which should have this option set (i.e., they should be skipped when the contract is excluded). (Does not work with roles, which have comma in name.)
  • idm.pub.acc.syncRole.roles.update.nameOfRoles.manageSentValueOnExclusion - (default: false) - this property will set the option skip the value if it's assigned on an excluded contract even when updating existing roles by the synchronization. The option will be set to all roles in the property idm.pub.acc.syncRole.roles.nameOfRoles.doNotSentValueOnExclusion and unset to all other AD roles.

The workflow enables loading group membership from the system. That means, if the group in AD have some members and you want to assign roles to identities IdM based on that, you can use this workflow to do it. Typically, you would do it only as an initial loading. Necessary properties:

  • idm.pub.acc.syncRole.identity.eav.externalIdentifier.code - (default: null, _mandatory for resolving group membership_) - code of EAV with a distinguished name of identities. It is used when creating a new role for a new group, or when loading group membership for existing roles. All identities managed by IdM in AD have to have the EAV containing their current distinguishedName, otherwise resolving membership will not work. Load the value to the EAV (recommended name: distinguishedName) when you run reconciliation of identities. FIXME create a tutorial. Then set the value "distinguishedName" to this property. Once you load the group membership, remove this property, so the membership won't be loaded from AD for new roles (IdM should be the authority for group membership in the standard production use).
  • idm.pub.acc.syncRole.update.resolveMembership - (true/false, default: false) - with this property you can turn on resolving memberships of roles even in other situations than creating role. Recommended way: Turn it on for initial loading of group membership, turn it off afterwards. Note that resolving membership of newly created roles is done independently of this property, see the note in the property idm.pub.acc.syncRole.identity.eav.externalIdentifier.code above.
  • idm.pub.acc.syncRole.roles.attributeNameOfMembership - (default: member) - it is name of attribute of role in source system, which holds identificators of identities. The default value is typical for AD.

Settings of the created role - properties connected to the requesting of roles and the role approval:

  • idm.pub.acc.syncRole.role.canBeRequested - (true/false, default: false) - sets to all roles, if the role can be requested by common users (not superadmin)
  • idm.pub.acc.syncRole.role.update.manageCanBeRequested - (true/false, default: false) - enable/disable setting can-be-requested role attribute
  • idm.pub.acc.syncRole.roles.create.priorityOfRoles - (default: null, values: 1,2,3,4) - this property will set criticality (priority) of roles, which affects the approval process. Only on create.
  • idm.pub.acc.syncRole.roles.create.garanteeOfRoles - (default: null) - fill in name of role, which will become the Role authorizer of all created roles. Only on create.

The workflow can create the folders in the role catalogue. It can be either one folder, or the tree structure of folders based on the DNs of the roles:

  • idm.pub.acc.syncRole.roleCatalog.ResolveCatalog - (true/false, default: true) - this property enables creating of new folders in the role catalogue. Set it to false if you don't want to create and add roles to the role catalogue at all.
  • idm.pub.acc.syncRole.roles.allToOneCatalog - (default: null) - use this property, if you want to add all roles in one folder. Set the name of the folder to this property. If a folder with the same code already exists, the workflow will create a new one (it won't reuse already existing folder).
  • idm.pub.acc.syncRole.roleCatalog.catalogueTreeInOneCatalog - (default: null) - use this property, if you want to create and add roles in a tree structure of folders. Set the name of the root folder to this property. The workflow will create a tree of folders under this root folder. If this property will be changed, new catalog folder will be created. Name of folders in the role catalogue can be changed in IdM.

Since Extras version 1.8.0 you can use two new options which will help with following use case: I have more then 1 AD system connected as group source. Now the workflow has "global" configuration via application properties so I am not able to run scheduled synchronization and put group from one AD to catalog "one" and from second AD to catalog "two" and similar issue is with mapped systems. This changes are backward compatible because if you don't set these new properties the WF behavior is same as in previous version. If you set this property then the new behavior will be turned on.

  • idm.pub.acc.syncRole.roles.catalogByCodeList - UUID of code list for catalogs for each system. Item in code list has UUID of source system and as value they have code of role catalog
  • idm.pub.acc.syncRole.provisioningOfIdentities.codeList - UUID of code list for mapped sysmtes for each system. Item in code list has UUID value of AD group system which is used for synchronization and as value UUID of AD system which is used for user provisioning
This part applies to IdM 15 and older, where the synchronization of groups was implemented as a BPMN workflow running on Activiti. From IdM 16 use the synchronization script described above instead - Activiti and this workflow were removed in IdM 16.

In this tutorial we will be using Eclipse and the Activiti framework.

For synchronization of groups from AD, we have prepared the workflow syncRoleLdap.bpmn20.xml.

The workflow has these actions modified:

  • Linked / update entity
  • Missing entity / create entity
  • Unlinked / create link and update entity

The workflow is divided into 9 activities, but only the first four activities are mainly to be modified.

First of all it is crucial to set the data objects in the Data Objects tab.

  • STRUCTURE_FORM_ATTRIBUTE - code of the EAV of an organization tree node. It is used to add an automatic role by organization structure. Every organization tree node should have an EAV with some value that determines which role gets an automatic role on which tree node.
  • CODE_OF_TYPE_STRUCTURE - code of the structure; it defines which organization tree is used for searching/creating automatic roles by organization structure. The default value means the default organization tree.
  • AUTO_ROLE_ORG_STRUCTURE_ENABLED - if false, automatic roles by organization structure are skipped.
  • AUTO_ROLE_ATTRIBUTES_ENABLED - if false, automatic roles by attributes are skipped.

This activity gets some attributes from icAttributes, such as name and distinguished name. You can get others if they are needed in the following activities. This variable is also set:

execution.setVariable("TRANSFORMATION_SCRIPT", "\""+distinguishedName+"\"");

The value of this variable is used as the transformation script (it is used for provisioning the member attribute of identities).

In this script it is crucial to find, for a role, the tree node (organization) used to create the automatic role by organization structure, and to set it to a variable like:

execution.setVariable("organizationTreeNode", pomList.get(0));

This script can be slightly changed to work fine. In the default state it searches for a tree node that has the name of the role in an EAV. In a previous activity we can get another attribute and, using a substring, it should be enough.

This part creates the attributes for an automatic role. There can be more attributes, but only for identity/contract attributes or identity/contract EAVs. You should create the attributes (by the default algorithm), put them into the field and lastly into the "automaticAttributes" variable.

This part is about the role catalogue. There are two methods. The first method creates the catalogue based on the distinguished name of the role: the rightmost OU value is the root of the catalogue, the other OUs from the right become folders, and roles are assigned in the leftmost OU/catalogue.

The other method is for removing folders of a catalogue: if a role is transferred to another catalogue, it finds the old one and sets it in the "catalogue" variable, and it is erased.

This should be all, but if you made bigger changes in the methods you should probably test your new workflow. After modifying the workflow, don't forget to update this workflow in IdM.
  • by koulaj