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 container ou=Customers,dc=example,dc=com.

  • Agent represents agent accounts, considered independent contractors, and created under the LDAP container ou=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]._ref;
      if (roleId != null && roleId.indexOf("/") != -1) {
        var roleInfo = openidm.read(roleId);
        res = (((roleInfo.name === 'Agent') &&(linkQualifier ==='agent'))
        || ((roleInfo.name === 'Insured') &&(linkQualifier ==='insured')));
      }
      i++;
    }
    res"
}

Prepare the Sample

  1. Set up DS using /path/to/openidm/samples/multi-account-linking/data/Example.ldif.

  2. 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 Users, Roles, and Assignments
  1. 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.

  2. 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.

  3. 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 _ids you recorded when you created the users and roles.

    1. 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"
          }
        ]
      }
    2. 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"
          }
        ]
      }
    3. 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.

  4. 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 their ldapGroups property in DS set to cn=Contractors,ou=Groups,dc=example,dc=com. The assignment is associated with the agent 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 their ldapGroups property in DS set to cn=Chat Users,ou=Groups,dc=example,dc=com. The assignment is associated with the insured 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"
      ]
    }
  5. 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."
    }
  6. 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."
    }
Reconcile Managed Users to the LDAP Server
  1. 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 and jdoe.

    • 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).

  2. 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"
        }
      ],
      ...
    }
    
Read a different version of :