Link Multiple Accounts to a Single Identity
This sample illustrates how IDM handles links from multiple accounts to a single identity.
The sample is based on a common use case in the insurance industry, where a company (Example.com) employs agents to sell policies to their insured customers. Most of their agents are also insured, which means that they have two distinct roles within the company - customers, and agents. With minor changes, this sample works for other use cases. For example, a hospital employs doctors who treat patients, and some of those same doctors are also patients of the hospital.
Sample Overview
You define mappings between source and target accounts in the your project's sync.json
file. As part of a mapping, you can create a link between a single source account and multiple target accounts using a link qualifier, that enables one-to-many relationships in mappings and policies. For more information about mappings and link qualifiers, see Mapping Data Between Resources and "Map a Single Source Object to Multiple Target Objects".
This sample uses two link qualifiers:
Insured
represents the accounts associated with Example.com's Insured customers, created under the LDAP containerou=Customers,dc=example,dc=com
.Agent
represents agent accounts, considered independent contractors, and created under the LDAP containerou=Contractors,dc=example,dc=com
.
Assume that agents and insured customers connect using two different portals, and that each group has access to different features, depending on the portal.
Agents might have two separate accounts; one each for professional and personal use. Although the accounts are different, the identity information for each agent should be the same for both accounts.
This sample therefore uses link qualifiers to distinguish the two categories of users. The link qualifiers are named insured
and agent
, and are defined as part of the managedUser_systemLdapAccounts
mapping in the sync.json
file:
{ "name" : "managedUser_systemLdapAccounts", "source" : "managed/user", "target" : "system/ldap/account", "linkQualifiers" : [ "insured", "agent" ], ... }
You can check this configuration in the Admin UI. Click Configure > Mappings > managedUser_systemLdapAccounts
> Properties > Link Qualifiers. You should see insured
and agent
in the list of configured link qualifiers.
In addition, the sample uses a transformation script that determines the LDAP Distinguished Name (dn
) from the user category. The following excerpt of the sync.json
file shows that script:
{ "target" : "dn", "transform" : { "type" : "text/javascript", "globals" : { }, "source" : "if (linkQualifier === 'agent') { 'uid=' + source.userName + ',ou=Contractors,dc=example,dc=com'; } else if (linkQualifier === 'insured') { 'uid=' + source.userName + ',ou=Customers,dc=example,dc=com'; }" },
Finally, the following validSource
script assesses the effective roles of a managed user to determine if that user has an Agent
or Insured
role. The script then assigns a link qualifier based on the assessed role.
"validSource" : { "type" : "text/javascript", "globals" : { }, "source" : "var res = false; var i=0; while (!res && i < source.effectiveRoles.length) { var roleId = source.effectiveRoles[i]; if (roleId != null && roleId.indexOf("/") != -1) { var roleInfo = openidm.read(roleId); logger.warn("Role Info : {}",roleInfo); res = (((roleInfo.properties.name === 'Agent') &&(linkQualifier ==='agent')) || ((roleInfo.properties.name === 'Insured') &&(linkQualifier ==='insured'))); } i++; } res" }
Prepare the Sample
Set up DS using
/path/to/openidm/samples/multi-account-linking/data/Example.ldif
.Prepare IDM, and start the server using the sample configuration:
cd /path/to/openidm/ ./startup.sh -p samples/multi-account-linking
Run the Sample
Create the managed users for John Doe and Barbara Jensen.
To set up these managed users using the Admin UI, select Manage > User > New User; otherwise, using the REST interface:
curl \ --header "Content-Type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ --data '{ "displayName" : "Barbara Jensen", "description" : "Created for OpenIDM", "givenName" : "Barbara", "mail" : "bjensen@example.com", "telephoneNumber" : "1-360-229-7105", "sn" : "Jensen", "userName" : "bjensen", "accountStatus" : "active" }' \ "http://localhost:8080/openidm/managed/user?_action=create"
{ "_id": "580f1441-ff8e-434b-9605-90e10a6fbdf6", "_rev": "00000000792afa08", "displayName": "Barbara Jensen", "description": "Created for OpenIDM", "givenName": "Barbara", "mail": "bjensen@example.com", "telephoneNumber": "1-360-229-7105", "sn": "Jensen", "userName": "bjensen", "accountStatus": "active", "effectiveRoles": [], "effectiveAssignments": [] }
curl \ --header "Content-Type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ --data '{ "displayName" : "John Doe", "description" : "Created for OpenIDM", "givenName" : "John", "mail" : "jdoe@example.com", "telephoneNumber" : "1-415-599-1100", "sn" : "Doe", "userName" : "jdoe", "accountStatus" : "active" }' \ "http://localhost:8080/openidm/managed/user?_action=create"
{ "_id": "02632173-e413-4af1-8495-f749d5880226", "_rev": "000000001298f6a6", "displayName": "John Doe", "description": "Created for OpenIDM", "givenName": "John", "mail": "jdoe@example.com", "telephoneNumber": "1-415-599-1100", "sn": "Doe", "userName": "jdoe", "accountStatus": "active", "effectiveRoles": [], "effectiveAssignments": [] }
Note
Make sure to record the unique
_id
for both managed users.Set up the managed roles Agent and Insured, to distinguish between the two user types.
To set up these roles using the Admin UI, select Manage > Role > New Role; otherwise, using the REST interface:
curl \ --header "Content-Type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ --data '{ "name" : "Agent", "description" : "Role assigned to insurance agents." }' \ "http://localhost:8080/openidm/managed/role?_action=create"
{ "_id": "1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f", "_rev": "000000005b3d5ebd", "name": "Agent", "description": "Role assigned to insurance agents." }
curl \ --header "Content-Type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ --data '{ "name" : "Insured", "description" : "Role assigned to insured customers." }' \ "http://localhost:8080/openidm/managed/role?_action=create"
{ "_id": "617368f2-fa4e-44a2-a25a-f0a86e16ef00", "_rev": "000000002b845f24", "name": "Insured", "description": "Role assigned to insured customers." }
Note
Make sure to record the unique
_id
for both managed roles.Grant the managed roles to the users. In this sample, jdoe is an agent and customer, and bjensen is only a customer.
To grant the roles, you need the
_id
s you recorded when you created the users and roles.The following command grants the Agent role to jdoe:
curl \ --header "Content-type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request PATCH \ --data '[ { "operation": "add", "field": "/roles/-", "value": { "_ref": "managed/role/1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f" } } ]' \ "http://localhost:8080/openidm/managed/user/02632173-e413-4af1-8495-f749d5880226"
{ "_id": "02632173-e413-4af1-8495-f749d5880226", "_rev": "00000000dc6160c8", "displayName": "John Doe", "description": "Created for OpenIDM", "givenName": "John", "mail": "jdoe@example.com", "telephoneNumber": "1-415-599-1100", "sn": "Doe", "userName": "jdoe", "accountStatus": "active", "effectiveAssignments": [], "effectiveRoles": [ { "_refResourceCollection": "managed/role", "_refResourceId": "1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f", "_ref": "managed/role/1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f" } ] }
The following command grants the Insured role to user bjensen:
curl \ --header "Content-type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request PATCH \ --data '[ { "operation": "add", "field": "/roles/-", "value": { "_ref": "managed/role/617368f2-fa4e-44a2-a25a-f0a86e16ef00" } } ]' \ "http://localhost:8080/openidm/managed/user/580f1441-ff8e-434b-9605-90e10a6fbdf6"
{ "_id": "580f1441-ff8e-434b-9605-90e10a6fbdf6", "_rev": "000000004cab60c8", "displayName": "Barbara Jensen", "description": "Created for OpenIDM", "givenName": "Barbara", "mail": "bjensen@example.com", "telephoneNumber": "1-360-229-7105", "sn": "Jensen", "userName": "bjensen", "accountStatus": "active", "effectiveAssignments": [], "effectiveRoles": [ { "_refResourceCollection": "managed/role", "_refResourceId": "617368f2-fa4e-44a2-a25a-f0a86e16ef00", "_ref": "managed/role/617368f2-fa4e-44a2-a25a-f0a86e16ef00" } ] }
The following command grants the Insured role to jdoe:
curl \ --header "Content-type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request PATCH \ --data '[ { "operation": "add", "field": "/roles/-", "value": { "_ref": "managed/role/617368f2-fa4e-44a2-a25a-f0a86e16ef00" } } ]' \ "http://localhost:8080/openidm/managed/user/02632173-e413-4af1-8495-f749d5880226"
{ "_id": "02632173-e413-4af1-8495-f749d5880226", "_rev": "00000000a92657c7", "displayName": "John Doe", "description": "Created for OpenIDM", "givenName": "John", "mail": "jdoe@example.com", "telephoneNumber": "1-415-599-1100", "sn": "Doe", "userName": "jdoe", "accountStatus": "active", "effectiveAssignments": [] "effectiveRoles": [ { "_refResourceCollection": "managed/role", "_refResourceId": "1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f", "_ref": "managed/role/1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f" }, { "_refResourceCollection": "managed/role", "_refResourceId": "617368f2-fa4e-44a2-a25a-f0a86e16ef00", "_ref": "managed/role/617368f2-fa4e-44a2-a25a-f0a86e16ef00" } ] }
Notice jdoe now has two managed roles, as shown by the multiple
effectiveRoles
.
Create the managed assignments.
Assignments specify what a role actually does on a target system. A single account frequently has different functions on a system. For example, while agents might be members of the Contractor group, insured customers might be part of a Chat Users group (possibly for access to customer service). The following commands create two managed assignments that will be attached to the agent and insured roles. Note the
_id
of each assignment because you will need these when you attach the assignment to its corresponding role.The following command creates an
ldapAgent
assignment. Users who have this assignment will have theirldapGroups
property in DS set tocn=Contractors,ou=Groups,dc=example,dc=com
. The assignment is associated with theagent
link qualifier:curl \ --header "Content-Type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ --data '{ "name": "ldapAgent", "description": "LDAP Agent Assignment", "mapping": "managedUser_systemLdapAccounts", "attributes": [ { "name": "ldapGroups", "value": [ "cn=Contractors,ou=Groups,dc=example,dc=com" ], "assignmentOperation": "mergeWithTarget", "unassignmentOperation": "removeFromTarget" } ], "linkQualifiers": ["agent"] }' \ "http://localhost:8080/openidm/managed/assignment?_action=create"
{ "_id": "cc0dbcdc-64a4-4f5b-aade-648fc012e2b5", "_rev": "00000000c7554e13", "name": "ldapAgent", "description": "LDAP Agent Assignment", "mapping": "managedUser_systemLdapAccounts", "attributes": [ { "name": "ldapGroups", "value": [ "cn=Contractors,ou=Groups,dc=example,dc=com" ], "assignmentOperation": "mergeWithTarget", "unassignmentOperation": "removeFromTarget" } ], "linkQualifiers": [ "agent" ] }
The following command creates an
ldapCustomer
assignment. Users who have this assignment will have theirldapGroups
property in DS set tocn=Chat Users,ou=Groups,dc=example,dc=com
. The assignment is associated with theinsured
link qualifier:curl \ --header "Content-Type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ --data '{ "name": "ldapCustomer", "description": "LDAP Customer Assignment", "mapping": "managedUser_systemLdapAccounts", "attributes": [ { "name": "ldapGroups", "value": [ "cn=Chat Users,ou=Groups,dc=example,dc=com" ], "assignmentOperation": "mergeWithTarget", "unassignmentOperation": "removeFromTarget" } ], "linkQualifiers": ["insured"] }' \ "http://localhost:8080/openidm/managed/assignment?_action=create"
{ "_id": "56b1f300-7156-4110-9b23-2052c16dd2aa", "_rev": "000000000cde398e", "name": "ldapCustomer", "description": "LDAP Customer Assignment", "mapping": "managedUser_systemLdapAccounts", "attributes": [ { "name": "ldapGroups", "value": [ "cn=Chat Users,ou=Groups,dc=example,dc=com" ], "assignmentOperation": "mergeWithTarget", "unassignmentOperation": "removeFromTarget" } ], "linkQualifiers": [ "insured" ] }
Add the assignments to their respective roles.
Add the
ldapCustomer
assignment to the Insured customer role:curl \ --header "Content-type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request PATCH \ --data '[ { "operation": "add", "field": "/assignments/-", "value": { "_ref": "managed/assignment/56b1f300-7156-4110-9b23-2052c16dd2aa" } } ]' \ "http://localhost:8080/openidm/managed/role/617368f2-fa4e-44a2-a25a-f0a86e16ef00"
{ "_id": "617368f2-fa4e-44a2-a25a-f0a86e16ef00", "_rev": "0000000050c62938", "name": "Insured", "description": "Role assigned to insured customers." }
Add the
ldapAgent
assignment to the Agent role:curl \ --header "Content-type: application/json" \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request PATCH \ --data '[ { "operation": "add", "field": "/assignments/-", "value" : { "_ref": "managed/assignment/cc0dbcdc-64a4-4f5b-aade-648fc012e2b5" } } ]' \ "http://localhost:8080/openidm/managed/role/1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f"
{ "_id": "1b58ec8d-fae2-4b28-a5cf-b63567e4cf3f", "_rev": "0000000013e50a6b", "name": "Agent", "description": "Role assigned to insurance agents." }
With the managed roles and assignments set up, reconcile the managed user repository with the DS data store:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request POST \ "http://localhost:8080/openidm/recon?_action=recon&mapping=managedUser_systemLdapAccounts"
{ "_id": "a6b46fc6-0731-47d8-83b5-89cca8963512-11550", "state": "ACTIVE" }
This reconciliation creates three new accounts in DS:
Two accounts under
ou=Customers,dc=example,dc=com
(one for each user who has the insured customers role),bjensen
andjdoe
.One account under
ou=Contractors,dc=example,dc=com
(for the use who has the agents role),jdoe
.
Note that both of these users already existed in DS (from the
Example.ldif
file that you imported during the setup).Query the list of users in DS to see the multiple accounts created for jdoe and bjensen as a result of the reconciliation:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept-API-Version: resource=1.0" \ --request GET \ "http://localhost:8080/openidm/system/ldap/account?_queryId=query-all-ids"
{ "result": [ { "_id": "3bbf1f43-e120-4d34-a4c9-05bd02be23bd" }, { "_id": "d6c73ea1-fd05-4b80-8625-c50303755c91" }, { "_id" : "0acc77a5-0f38-473b-b533-e37ca1d4fd4c" }, { "_id" : "3310b29a-0d7f-4ed5-aa0d-795d2780e002" }, { "_id" : "3c8e3c3d-f748-44c1-8cfc-172f5b0a9b5e" } ], ... }