Connect to DS With ScriptedREST

This sample uses the scripted REST connector to interact with the ForgeRock Directory Services (DS) REST API, using Groovy scripts. The sample demonstrates reconciliation, implicit sync, and liveSync between the IDM repository and a DS instance.

The scripted REST connector is bundled with IDM in the JAR openidm/connectors/scriptedrest-connector-1.5.20.0.jar.

The Groovy scripts required for the sample are located in the samples/scripted-rest-with-dj/tools directory. You must customize these scripts to address the requirements of your specific deployment, however, the sample scripts are a good starting point on which to base your customization.

Important

The Rest2ldap HTTP endpoint provided with DS is an evolving interface. As such, compatibility between versions is not guaranteed. This sample was tested with DS 7.

Set Up DS

  1. Set up DS, but remove the line --set ds-user-data/ldifFile:Example.ldif.

  2. Optionally, you can enable an HTTP access logger on the DS server.

  3. Import the data required for the sample:

    /path/to/opendj/bin/ldapmodify \
    --port 1636 \
    --useSSL \
    --usePkcs12TrustStore /path/to/opendj/config/keystore \
    --trustStorePasswordFile /path/to/opendj/config/keystore.pin \
    --hostname localhost \
    --bindDN uid=admin \
    --bindPassword password \
    --filename /path/to/openidm/samples/scripted-rest-with-dj/data/ldap.ldif
    # ADD operation successful for DN dc=example,dc=com
    
    # ADD operation successful for DN ou=Administrators,dc=example,dc=com
    
    # ADD operation successful for DN uid=idm,ou=Administrators,dc=example,dc=com
    
    # ADD operation successful for DN ou=People,dc=example,dc=com
    
    # ADD operation successful for DN ou=Groups,dc=example,dc=com
  4. Set up the access control instructions (ACIs) that enable the IDM administrator user to read the DS external change log:

    /path/to/opendj/bin/dsconfig set-access-control-handler-prop \
    --port 4444 \
    --usePkcs12TrustStore /path/to/opendj/config/keystore \
    --trustStorePasswordFile /path/to/opendj/config/keystore.pin \
    --hostname localhost \
    --bindDN uid=admin \
    --bindPassword password \
    --add global-aci:"(target=\"ldap:///cn=changelog\")(targetattr=\"*||+\") \
    (version 3.0; acl \"IDM can access cn=changelog\"; \
    allow (read,search,compare) \
    userdn=\"ldap:///uid=idm,ou=Administrators,dc=example,dc=com\";)" \
    --no-prompt
    /path/to/opendj/bin/dsconfig set-access-control-handler-prop \
    --port 4444 \
    --usePkcs12TrustStore /path/to/opendj/config/keystore \
    --trustStorePasswordFile /path/to/opendj/config/keystore.pin \
    --hostname localhost \
    --bindDN uid=admin \
    --bindPassword password \
    --add global-aci:"(targetcontrol=\"1.3.6.1.4.1.26027.1.5.4\") \
    (version 3.0; acl \"IDM changelog control access\"; \
    allow (read) \
    userdn=\"ldap:///uid=idm,ou=Administrators,dc=example,dc=com\";)" \
    --no-prompt
  5. Enable the default Rest2ldap HTTP endpoint:

    /path/to/opendj/bin/dsconfig set-http-endpoint-prop \
    --port 4444 \
    --usePkcs12TrustStore /path/to/opendj/config/keystore \
    --trustStorePasswordFile /path/to/opendj/config/keystore.pin \
    --hostname localhost \
    --bindDN uid=admin \
    --bindPassword password \
    --endpoint-name /api \
    --set authorization-mechanism:"HTTP Basic" \
    --set config-directory:config/rest2ldap/endpoints/api \
    --set enabled:true \
    --no-prompt

    For more information, see HTTP User APIs in the DS Configuration Guide.

  6. Replace the default DS REST to LDAP configuration with the configuration for this sample:

    cp /path/to/openidm/samples/scripted-rest-with-dj/data/example-v1.json /path/to/opendj/config/rest2ldap/endpoints/api/
  7. Restart DS for the configuration change to take effect.

    /path/to/opendj/bin/stop-ds --restart
    Stopping Server...
    ...
    The Directory Server has started successfully

Run the Sample

This section illustrates the basic CRUD operations on users and groups using the ScriptedREST connector and the DS REST API. Note that the power of the Groovy connector is in the associated Groovy scripts, and their application in your particular deployment. The scripts provided with this sample are specific to the sample and customization of the scripts is required.

  1. Start IDM with the configuration for the ScriptedREST sample:

    cd /path/to/openidm/
    ./startup.sh -p samples/scripted-rest-with-dj
  2. Check that the scripted REST connector can reach the DS instance by obtaining the connector status over REST:

    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/system/scriptedrest?_action=test"
    {
      "name": "scriptedrest",
      "enabled": true,
      "config": "config/provisioner.openicf/scriptedrest",
      "connectorRef": {
        "bundleVersion": "[1.5.0.0,1.6.0.0)",
        "bundleName": "org.forgerock.openicf.connectors.scriptedrest-connector",
        "connectorName": "org.forgerock.openicf.connectors.scriptedrest.ScriptedRESTConnector"
      },
      "displayName": "Scripted REST Connector",
      "objectTypes": [
        "__ALL__",
        "account",
        "group"
      ],
      "ok": true
    }
  3. Create a group entry on the DS server:

    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 '{
      "cn": "group1"
    }' \
    "http://localhost:8080/openidm/system/scriptedrest/group?_action=create"
    {
      "_id": "group1",
      "members": null,
      "created": "2020-07-21T23:04:25Z",
      "cn": "group1",
      "displayName": "group1"
    }
  4. Create a user entry on the DS server. This command creates a user with uid scarter:

    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 '{
      "givenName": "Steven",
      "familyName": "Carter",
      "emailAddress": "scarter@example.com",
      "telephoneNumber": "444-444-4444",
      "password": "5up35tr0ng",
      "displayName": "Steven.Carter",
      "uid": "scarter"
    }' \
    "http://localhost:8080/openidm/system/scriptedrest/account?_action=create"
    {
      "_id": "scarter",
      "givenName": "Steven",
      "groups": null,
      "displayName": "Steven.Carter",
      "emailAddress": "scarter@example.com",
      "uid": "scarter",
      "created": "2020-07-21T23:07:13Z",
      "familyName": "Carter",
      "telephoneNumber": "444-444-4444"
    }

    Notice that the user is not a member of any group.

  5. Reconcile the DS server with the managed user repository:

    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 \
    "http://localhost:8080/openidm/recon?_action=recon&mapping=systemRestLdapUser_managedUser&waitForCompletion=true"
    {
      "_id": "ee7534bd-ccfd-4f6a-bdc3-49caa6d2043c-547",
      "state": "SUCCESS"
    }
  6. The reconciliation creates a managed user with a server-assigned ID. To retrieve the ID, run the following query:

    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 GET \
    "http://localhost:8080/openidm/managed/user?_queryFilter=true&_fields=_id"
    {
      "result": [
        {
          "_id": "4657a420-6608-410e-baa7-f64668cc500c",
          "_rev": "000000007995f006"
        }
      ],
      ...
    }
  7. To initialize liveSync set the sync token by running one liveSync operation over REST:

    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/system/scriptedrest/account?_action=liveSync"
    {
      "connectorData": {
        "nativeType": "string",
        "syncToken": "8"
      }
    }
  8. Update Steven Carter's managed user entry, by modifying his telephone number. Specify the user ID that you retrieved previously:

    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": "telephoneNumber",
        "value": "555-555-5555"
      }
    ]' \
    "http://localhost:8080/openidm/managed/user/4657a420-6608-410e-baa7-f64668cc500c"
    {
      "_id": "4657a420-6608-410e-baa7-f64668cc500c",
      "_rev": "0000000096edf021",
      "userName": "scarter",
      "mail": "scarter@example.com",
      "displayName": "Steven.Carter",
      "telephoneNumber": "555-555-5555",
      "givenName": "Steven",
      "sn": "Carter",
      "accountStatus": "active",
      "effectiveRoles": [],
      "effectiveAssignments": []
    }
  9. The implicit synchronization mechanism between the managed user repository and DS propagates the change to DS. You can check this change by reading scarter's user entry in DS and noting the changed telephoneNumber:

    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/scriptedrest/account/scarter"
    {
      "_id": "scarter",
      "familyName": "Carter",
      "givenName": "Steven",
      "created": "2018-02-07T10:14:31Z",
      "uid": "scarter",
      "groups": null,
      "emailAddress": "scarter@example.com",
      "displayName": "Steven.Carter",
      "telephoneNumber": "555-555-5555"
    }
  10. Now, update Steven Carter's entry on the DS server, by modifying his givenName:

    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": "givenName",
        "value": "Steve"
      }
    ]' \
    "http://localhost:8080/openidm/system/scriptedrest/account/scarter"
    {
      "_id": "scarter",
      "givenName": "Steve",
      "groups": null,
      "displayName": "Steven.Carter",
      "emailAddress": "scarter@example.com",
      "uid": "scarter",
      "created": "2020-07-21T23:07:13Z",
      "familyName": "Carter",
      "telephoneNumber": "555-555-5555"
    }
  11. To propagate the change made on DS back to the managed user entry, launch a liveSync operation, either by defining a schedule, or directly over REST. The following command launches liveSync over REST:

    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/system/scriptedrest/account?_action=liveSync"
    {
      "connectorData": {
        "nativeType": "string",
        "syncToken": "9"
      },
      "_rev": "000000000a585336",
      "_id": "SYSTEMSCRIPTEDRESTACCOUNT"
    }
  12. Verify that the changes were propagated by reading scarter's managed user entry and noting the changed givenName:

    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/4657a420-6608-410e-baa7-f64668cc500c"
    {
      "_id": "4657a420-6608-410e-baa7-f64668cc500c",
      "_rev": "000000007937efb7",
      "userName": "scarter",
      "mail": "scarter@example.com",
      "displayName": "Steven.Carter",
      "telephoneNumber": "555-555-5555",
      "givenName": "Steve",
      "sn": "Carter",
      "accountStatus": "active",
      "effectiveRoles": [],
      "effectiveAssignments": []
    }
  13. Add user scarter to the group you created previously, by updating the group entry:

    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" \
    --header "If-Match: *" \
    --request PUT \
    --data '{
      "_id": "group1",
      "members": [{"_id": "scarter"}]
    }' \
    "http://localhost:8080/openidm/system/scriptedrest/group/group1"
    {
      "_id": "group1",
      "displayName": "group1",
      "created": "2018-02-07T10:14:12Z",
      "members": [
        {
          "_id": "scarter",
          "displayName": "Steven.Carter"
        }
      ],
      "cn": "group1",
      "lastModified": "2018-02-07T10:20:22Z"
    }
  14. Read Steven Carter's user entry in DS, to verify that he is now a member of group1:

    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/scriptedrest/account/scarter"
    {
      "_id": "scarter",
      "givenName": "Steve",
      "groups": [
        {
          "_id": "group1"
        }
      ],
      "displayName": "Steven.Carter",
      "emailAddress": "scarter@example.com",
      "uid": "scarter",
      "created": "2020-07-21T23:07:13Z",
      "familyName": "Carter",
      "telephoneNumber": "555-555-5555"
    }
  15. Read the group entry to verify its members:

    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/scriptedrest/group/group1"
    {
      "_id": "group1",
      "lastModified": "2020-07-21T23:17:09Z",
      "members": [
        {
          "_id": "scarter",
          "displayName": "Steven.Carter"
        }
      ],
      "created": "2020-07-21T23:04:25Z",
      "cn": "group1",
      "displayName": "group1"
    }
  16. Reconcile the DS groups with the managed group repository:

    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=systemRestLdapGroup_managedGroup&waitForCompletion=true"
    {
      "_id": "ee7534bd-ccfd-4f6a-bdc3-49caa6d2043c-1477",
      "state": "SUCCESS"
    }
  17. The reconciliation creates a managed group with a server-assigned ID. To retrieve the group ID, run the following query:

    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 GET \
    "http://localhost:8080/openidm/managed/group?_queryId=query-all-ids"
    {
      "result": [
        {
          "_id": "67b5ec50-d5a6-4bfa-bb19-17965447ad00",
          "_rev": "00000000b0e95e9b"
        }
      ],
      ...
    }
  18. Read the managed group to verify that the DS group has been added, and that its members have been reconciled to the managed group repository. Specify the ID that you retrieved in the previous step:

    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/group/67b5ec50-d5a6-4bfa-bb19-17965447ad00"
    {
      "_id": "67b5ec50-d5a6-4bfa-bb19-17965447ad00",
      "_rev": "00000000b0e95e9b",
      "members": [
        {
          "_id": "scarter",
          "displayName": "Steven.Carter"
        }
      ],
      "displayName": "group1"
    }
  19. Delete the DS user and group entries, returning the DS server to its initial state.

    curl \
    --header "X-OpenIDM-Username: openidm-admin" \
    --header "X-OpenIDM-Password: openidm-admin" \
    --header "Accept-API-Version: resource=1.0" \
    --request DELETE \
    "http://localhost:8080/openidm/system/scriptedrest/account/scarter"
    {
      "_id": "scarter",
      "givenName": "Steve",
      "groups": [
        {
          "_id": "group1"
        }
      ],
      "displayName": "Steven.Carter",
      "emailAddress": "scarter@example.com",
      "uid": "scarter",
      "created": "2020-07-21T23:07:13Z",
      "familyName": "Carter",
      "telephoneNumber": "555-555-5555"
    }
    curl \
    --header "X-OpenIDM-Username: openidm-admin" \
    --header "X-OpenIDM-Password: openidm-admin" \
    --header "Accept-API-Version: resource=1.0" \
    --request DELETE \
    "http://localhost:8080/openidm/system/scriptedrest/group/group1"
    {
      "_id": "group1",
      "lastModified": "2020-07-21T23:17:09Z",
      "members": null,
      "created": "2020-07-21T23:04:25Z",
      "cn": "group1",
      "displayName": "group1"
    }
Read a different version of :