---
title: Link historical accounts
description: This sample demonstrates the retention of inactive (historical) LDAP accounts that have been linked to a corresponding managed user account. The sample builds on Two-way synchronization between LDAP and IDM and uses the LDAP connector to connect to a PingDS (DS) instance. You can use any LDAP-v3 compliant directory server.
component: pingidm
version: 8.1
page_id: pingidm:samples-guide:historical-account-linking
canonical_url: https://docs.pingidentity.com/pingidm/8.1/samples-guide/historical-account-linking.html
keywords: ["Samples", "Link", "Historical Accounts"]
section_ids:
  historical-accounts-overview: Sample overview
  run-sample-historical-accounts: Run the sample
---

# Link historical accounts

This sample demonstrates the retention of inactive (historical) LDAP accounts that have been linked to a corresponding managed user account. The sample builds on [Two-way synchronization between LDAP and IDM](sync-with-ldap-bidirectional.html) and uses the LDAP connector to connect to a PingDS (DS) instance. You can use any LDAP-v3 compliant directory server.

## Sample overview

In this sample, IDM is the source resource. Managed users in the IDM repository maintain a list of the accounts to which they have been linked on the local LDAP server. This list is stored in the `historicalAccounts` field of the managed user entry. The list contains a reference to all past and current LDAP accounts. Each LDAP account in the list is represented as a [relationship](../objects-guide/relationships.html) and includes information about the date the accounts were linked or unlinked, and whether the account is currently active.

This sample includes the following custom scripts, in its `script` directory:

* `onLink-managedUser_systemLdapAccounts.js`

  When a managed user object is linked to a target LDAP object, this script creates the relationship entry in the managed user's `historicalAccounts` property. The script adds two relationship properties:

  * `linkDate`: Specifies the date that the link was created.

  * `active`: Boolean true/false. When set to true, this property indicates that the target object is *currently* linked to the managed user account.

* `onUnlink-managedUser_systemLdapAccounts.js`

  When a managed user object is unlinked from a target LDAP object, this script updates that relationship entry's properties with an `unlinkDate` that specifies when the target was unlinked, and sets the `active` property to false, indicating that the target object is no longer linked.

* `check_account_state_change.js`

  During liveSync or reconciliation, this script checks if the LDAP account state has changed. If the state has changed, the script updates the historical account properties to indicate the new state (enabled or disabled), and the date that the state was changed. This date can only be approximated and is set to the time that the change was detected by the script.

* `ldapBackCorrelationQuery.js`

  This script correlates entries in the LDAP directory with managed user identities in IDM.

## Run the sample

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|   | Starting with IDM 8.1, the [legacy admin UI is deprecated](../release-notes/deprecated-functionality.html#legacy-admin-ui-deprecated) and is no longer bundled with IDM. New deployments should use the [Platform admin UI](../setup-guide/platform-admin-ui.html), which is the replacement for the legacy admin UI.Both UIs are available as separate downloads from the [Backstage download site](https://backstage.forgerock.com/downloads):- To install the Platform admin UI, follow the steps in [Install the Platform admin UI for standalone IDM](../setup-guide/platform-admin-ui.html).

- To continue using the legacy admin UI, follow the steps in [Install the legacy admin UI](../setup-guide/legacy-admin-ui.html). |

This section walks you through each step of the sample to demonstrate how historical accounts are stored.

1. [Set up DS](start-here.html#ldap-server-config) using `/path/to/openidm/samples/historical-account-linking/data/Example.ldif`.

2. In the `/path/to/opendj/bin/dsconfig` directory, use the `set-replication-server-prop` command to set `changelog-enabled` to `enabled` in DS:

   ```
   /path/to/opendj/bin/dsconfig set-replication-server-prop \
   --provider-name Multimaster\ Synchronization \
   --set changelog-enabled:enabled \
   --hostname localhost \
   --port 4444 \
   --bindDn uid=admin \
   --bindPassword password \
   --trustAll \
   --no-prompt
   ```

3. Use the `get-replication-server-prop` command to verify the server properties:

   ```
   /path/to/opendj/bin/dsconfig get-replication-server-prop \
   --provider-name Multimaster\ Synchronization \
   --hostname localhost \
   --port 4444 \
   --bindDn uid=admin \
   --bindPassword password \
   --trustAll \
   --no-prompt
   ```

   | `Property`                           | `Values`                                                                                                                                                  |
   | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | `advertised-listen-address`          | `localhost`                                                                                                                                               |
   | `changelog-enabled`                  | `enabled`                                                                                                                                                 |
   | `changelog-enabled-excluded-domains` | `When changelog is enabled, searches using "change numbers" are available for all domains (in other words, change number indexing includes all domains).` |
   | `confidentiality-enabled`            | `false`                                                                                                                                                   |
   | `listen-address`                     | `0.0.0.0`                                                                                                                                                 |
   | `replication-db-directory`           | `changelogDb`                                                                                                                                             |
   | `replication-port`                   | `8989`                                                                                                                                                    |
   | `weight`                             | `1`                                                                                                                                                       |

4. [Prepare IDM](start-here.html#preparing-openidm), and start the server using the sample configuration:

   ```
   cd /path/to/openidm/
   ./startup.sh -p samples/historical-account-linking
   ```

5. Create a user, Joe Smith, in IDM:

   ```
   curl \
   --header "X-OpenIDM-Username: openidm-admin" \
   --header "X-OpenIDM-Password: openidm-admin" \
   --header "Accept-API-Version: resource=1.0" \
   --header "Content-Type: application/json" \
   --request POST \
   --data '{
     "userName": "joe.smith",
     "givenName": "Joe",
     "sn" : "Smith",
     "password" : "Passw0rd",
     "displayName" : "Joe Smith",
     "mail" : "joe.smith@example.com"
   }' \
   "http://localhost:8080/openidm/managed/user?_action=create"
   {
     "_id": "24356bf0-f026-4dc1-9f68-2a571b0a236f",
     "_rev": "00000000c8dc2137",
     "userName": "joe.smith",
     "givenName": "Joe",
     "sn": "Smith",
     "displayName": "Joe Smith",
     "mail": "joe.smith@example.com",
     "accountStatus": "active",
     "effectiveRoles": [],
     "effectiveAssignments": []
   }
   ```

   Record Joe Smith's system-generated `_id`.

6. Verify that the user Joe Smith was created in DS.

   Because implicit synchronization is enabled by default, any change to the managed/user repository should be propagated to DS. Learn more about implicit synchronization in [Synchronization types](../synchronization-guide/sync-types.html).

   The following command returns all users in DS and shows that user joesmith was created successfully:

   ```
   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?_queryFilter=true&_fields=_id,dn"
   {
     "result": [
       {
         "_id": "0da50512-79bb-3461-bd04-241ee4c785bf",
         "dn": "uid=jdoe,ou=People,dc=example,dc=com"
       },
       {
         "_id": "887732e8-3db2-31bb-b329-20cd6fcecc05",
         "dn": "uid=bjensen,ou=People,dc=example,dc=com"
       },
       {
         "_id": "da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
         "dn": "uid=joe.smith0,ou=People,dc=example,dc=com"
       }
     ],
     ...
   }
   ```

   |   |                                                                                                                                                                                                       |
   | - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   |   | Joe Smith's `uid` in DS is appended with a `0`. The `onCreate` script, defined in the mapping (`sync.json`), increments the `uid` each time a new DS entry is linked to the same managed user object. |

7. Verify that the historical account *relationship object* that corresponds to this linked LDAP account was created in the IDM repository.

   The following command queries Joe Smith's managed user entry and returns all of the `historicalAccounts` for that entry:

   ```
   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/managed/user/24356bf0-f026-4dc1-9f68-2a571b0a236f/historicalAccounts?_queryFilter=true"
   {
     "result": [
       {
         "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
         "_rev": "00000000c2beced4",
         "_ref": "system/ldap/account/da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
         "_refResourceCollection": "system/ldap/account",
         "_refResourceId": "da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
         "_refProperties": {
           "active": true,
           "stateLastChanged": "Mon May 18 2020 13:47:18 GMT+0200 (SAST)",
           "state": "enabled",
           "linkDate": "Mon May 18 2020 13:47:18 GMT+0200 (SAST)",
           "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
           "_rev": "00000000c2beced4"
         }
       }
     ],
     ...
   }
   ```

   At this stage, Joe Smith has only one historical account link—the link to `system/ldap/account/da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa`, which corresponds to the DN `"dn": "uid=joe.smith0,ou=People,dc=example,dc=com"`. Note that the relationship properties (`_refProperties`) show the following information about the linked accounts:

   * The date the accounts were linked.

   * This link is currently active.

   * The account state in DS (`enabled`).

8. Enable the liveSync schedule to propagate changes made in DS to the managed user repository.

   To start liveSync, set `enabled` to `true` in the `conf/schedule-liveSync.json` file:

   ```
   more /path/to/openidm/samples/historical-account-linking/conf/schedule-liveSync.json
   {
       "enabled" : true,
       "type" : "simple",
       "repeatInterval" : 15000,
   ...
   ```

9. Use the `manage-account` command in the `opendj/bin` directory to disable Joe Smith's account in DS:

   ```
   /path/to/opendj/bin/manage-account set-account-is-disabled \
   --port 4444 \
   --usePkcs12TrustStore /path/to/opendj/config/keystore \
   --trustStorePassword:file /path/to/opendj/config/keystore.pin \
   --hostname localhost \
   --bindDN uid=admin \
   --bindPassword password \
   --operationValue true \
   --targetDN uid=joe.smith0,ou=people,dc=example,dc=com
   Account Is Disabled:  true
   ```

   Within 15 seconds, according to the configured schedule, liveSync should pick up the change. IDM should then adjust the `state` property in Joe Smith's managed user account.

10. To make sure that the linked account state has changed, request Joe Smith's historical accounts:

    ```
    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/managed/user/24356bf0-f026-4dc1-9f68-2a571b0a236f/historicalAccounts?_queryFilter=true"
    {
      "result": [
        {
          "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
          "_rev": "00000000d430e15a",
          "_ref": "system/ldap/account/da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
          "_refResourceCollection": "system/ldap/account",
          "_refResourceId": "da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
          "_refProperties": {
            "active": true,
            "stateLastChanged": "Mon May 18 2020 13:51:06 GMT+0200 (SAST)",
            "state": "disabled",
            "linkDate": "Mon May 18 2020 13:47:18 GMT+0200 (SAST)",
            "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
            "_rev": "00000000d430e15a"
          }
        }
      ],
      ...
    }
    ```

11. Now, deactivate Joe Smith's managed user account by setting his `accountStatus` property to `inactive`.

    To do this using the admin UI, select Manage > User, select Joe Smith's account, and change the Status to *inactive* on the Details tab.

    This command deactivates Joe Smith's account over REST:

    ```
    curl \
    --header "X-OpenIDM-Username: openidm-admin" \
    --header "X-OpenIDM-Password: openidm-admin" \
    --header "Accept-API-Version: resource=1.0" \
    --header "Content-Type: application/json" \
    --request PATCH \
    --data '[
      { "operation" : "replace",
        "field" : "accountStatus",
        "value" : "inactive" }
    ]' \
    "http://localhost:8080/openidm/managed/user/24356bf0-f026-4dc1-9f68-2a571b0a236f"
    {
      "_id": "24356bf0-f026-4dc1-9f68-2a571b0a236f",
      "_rev": "000000004cc82207",
      "userName": "joe.smith",
      "givenName": "Joe",
      "sn": "Smith",
      "displayName": "Joe Smith",
      "mail": "joe.smith@example.com",
      "accountStatus": "inactive",
      "effectiveRoles": [],
      "effectiveAssignments": []
    }
    ```

12. Request Joe Smith's historical accounts:

    ```
    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/managed/user/24356bf0-f026-4dc1-9f68-2a571b0a236f/historicalAccounts?_queryFilter=true"
    {
      "result": [
        {
          "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
          "_rev": "0000000037beefe7",
          "_ref": "system/ldap/account/da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
          "_refResourceCollection": "system/ldap/account",
          "_refResourceId": "da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
          "_refProperties": {
            "active": false,
            "stateLastChanged": "Mon May 18 2020 13:51:06 GMT+0200 (SAST)",
            "state": "disabled",
            "linkDate": "Mon May 18 2020 13:47:18 GMT+0200 (SAST)",
            "unlinkDate": "Mon May 18 2020 13:52:33 GMT+0200 (SAST)",
            "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
            "_rev": "0000000037beefe7"
          }
        }
      ]
      ...
    }
    ```

13. Activate Joe Smith's managed user account by setting his `accountStatus` property to active. This action should create a new entry in DS (with `uid=joe.smith1`) and a new link from Joe Smith's managed user object to that DS entry.

    You can activate the account over the REST interface or by using the admin UI, as described previously.

    This command activates Joe Smith's account over REST:

    ```
    curl \
    --header "X-OpenIDM-Username: openidm-admin" \
    --header "X-OpenIDM-Password: openidm-admin" \
    --header "Accept-API-Version: resource=1.0" \
    --header "Content-Type: application/json" \
    --request PATCH \
    --data '[
      { "operation" : "replace",
        "field" : "accountStatus",
        "value" : "active" }
    ]' \
    "http://localhost:8080/openidm/managed/user/24356bf0-f026-4dc1-9f68-2a571b0a236f"
    {
      "_id": "24356bf0-f026-4dc1-9f68-2a571b0a236f",
      "_rev": "00000000c8d52133",
      "userName": "joe.smith",
      "givenName": "Joe",
      "sn": "Smith",
      "displayName": "Joe Smith",
      "mail": "joe.smith@example.com",
      "accountStatus": "active",
      "effectiveRoles": [],
      "effectiveAssignments": []
    }
    ```

14. Verify that a new LDAP entry for user Joe Smith was created in DS.

    This command returns all IDs in DS and shows that two entries now exist for Joe Smith: `uid=joe.smith0` and `uid=joe.smith1`:

    ```
    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?_queryFilter=true&_fields=_id,dn"
    {
      "result": [
        {
          "_id": "0da50512-79bb-3461-bd04-241ee4c785bf",
          "dn": "uid=jdoe,ou=People,dc=example,dc=com"
        },
        {
          "_id": "887732e8-3db2-31bb-b329-20cd6fcecc05",
          "dn": "uid=bjensen,ou=People,dc=example,dc=com"
        },
        {
          "_id": "da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
          "dn": "uid=joe.smith0,ou=People,dc=example,dc=com"
        },
        {
          "_id": "52821eec-e00d-4321-8857-f46a870afc45",
          "dn": "uid=joe.smith1,ou=People,dc=example,dc=com"
        }
      ],
      ...
    }
    ```

15. Request Joe Smith's historical accounts:

    ```
    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/managed/user/24356bf0-f026-4dc1-9f68-2a571b0a236f/historicalAccounts?_queryFilter=true"
    {
      "result": [
        {
          "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
          "_rev": "0000000037beefe7",
          "_ref": "system/ldap/account/da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
          "_refResourceCollection": "system/ldap/account",
          "_refResourceId": "da7c8fe9-4959-4dc9-9cd5-60c0ead9b0aa",
          "_refProperties": {
            "active": false,
            "stateLastChanged": "Mon May 18 2020 13:51:06 GMT+0200 (SAST)",
            "state": "disabled",
            "linkDate": "Mon May 18 2020 13:47:18 GMT+0200 (SAST)",
            "unlinkDate": "Mon May 18 2020 13:52:33 GMT+0200 (SAST)",
            "_id": "3f193422-156b-4b66-adcf-447db1b7d770",
            "_rev": "0000000037beefe7"
          }
        },
        {
          "_id": "8850640c-2233-4ddc-9725-6b4b2d59605f",
          "_rev": "000000000843ce68",
          "_ref": "system/ldap/account/52821eec-e00d-4321-8857-f46a870afc45",
          "_refResourceCollection": "system/ldap/account",
          "_refResourceId": "52821eec-e00d-4321-8857-f46a870afc45",
          "_refProperties": {
            "active": true,
            "stateLastChanged": "Mon May 18 2020 13:54:52 GMT+0200 (SAST)",
            "state": "enabled",
            "linkDate": "Mon May 18 2020 13:54:52 GMT+0200 (SAST)",
            "_id": "8850640c-2233-4ddc-9725-6b4b2d59605f",
            "_rev": "000000000843ce68"
          }
        }
      ],
      ...
    }
    ```

    Joe Smith's entry now shows two DS accounts, but only the link to `uid=joe.smith1` (`"_ref": "system/ldap/account/52821eec-e00d-4321-8857-f46a870afc45",`) is `enabled` and `active`.
