Migrating IDM objects to ForgeRock Identity Cloud

Summary: Leveraging the IDM remote proxy for migrating IDM roles and assignments from a self-managed ForgeRock deployment to ForgeRock Identity Cloud

Introduction

Many existing self-managed IDM deployments leverage IDM provisioning roles and assignment features. These features enable customers to define automatic updates to specific user attributes when roles are provisioned or de-provisioned from a user. These attributes are eventually used as OpenID Connect (OIDC) claims to allow applications to make runtime authorization decisions.

Problem Statement

Identity Cloud offers connectors that allow migrating user profile attributes to Identity Cloud. Currently, there is no connector to migrate IDM-managed objects. However, there is an RFE for creating an out-of-the-box IDM connector to facilitate such migrations: OPENICF-1710.

Solution

This approach leverages the IDM remote proxy feature which is used in the traditional IDM migration service. The IDM proxy leverages the latest IDM 7.x version deployed in a self-managed infrastructure.

Steps

Identity Cloud OAuth client: OnPremIDM

  1. Log into your Identity Cloud Admin UI.

  2. Register a new OAuth 2 “service machine-to-machine” client that uses client credentials; for example, client_id: OnPremIDM. Provide a Client Secret value and add the fr:idm:* scope.

  3. Update your tenant IDM authentication configuration (rsFilter) to allow this new client (OnPremIDM) to make REST calls to Identity Cloud.

    This JS can be executed within the context of the IDM Admin UI by using Chrome’s Developer Tools console.

    NOTE: The code below has been tested in a Chrome browser only. Also, adding authentication rsFilter configuration for OnPremIDM twice can cause issues in IDM configurations so please be sure to use the “if” clause if (indexAuthN === -1) before executing the following statements:

    var authN = await $.get('/openidm/config/authentication')
    var indexAuthN = authN.rsFilter.staticUserMapping.findIndex((o) => (o.subject ==='OnPremIDM')) 
    
    if (indexAuthN === -1) {
    authN.rsFilter.staticUserMapping.push({subject: "OnPremIDM", localUser: "internal/user/idm- 
    provisioning", roles: ["internal/role/platform-provisioning"]});
    
    await $.ajax({method: 'PUT', url: '/openidm/config/authentication', data: JSON.stringify(authN), 
    headers : { 'If-Match': '*', 'Content-type': 'application/json'}});
    }
    
    
  4. Update your tenant IDM authorization configuration (access) to allow more permissions for the idm-provisioning role. This JS can be executed within the context of the IDM Admin UI by using Chrome’s Developer Tools console:

    var authZ = await $.get('/openidm/config/access')
    
    var indexAuthZ = authZ.configs.findIndex((o) => (o.pattern === 'managed/*' && o.roles === 
    'internal/role/platform-provisioning')) 
    
    authZ["configs"][indexAuthZ].methods = "create,read,query,patch,delete,update"
    
    await $.ajax({method: 'PUT', url: '/openidm/config/access', data: JSON.stringify(authZ), headers : { 
    'If-Match': '*', 'Content-type': 'application/json'}}
    
    

Self-managed IDM proxy configurations

Connectors

  1. Install IDM 7.x within the same environment as the resources that you would like to sync to the tenant. This IDM can be deployed with an embedded DS repository.

  2. Create two “Remote IDM Proxy Service” connectors.

    NOTE: As these are not traditional connectors, they can’t be created via the IDM Admin UI. These configurations need to be manually created by adding the below IDM configurations in the /conf directory:

    a. Connecting to the existing self-managed IDM, external.idm-65.json:

     {
      "enabled" : true,
      "authType" : "basic",
      "instanceUrl" : "http://idm65.example.com:7272/openidm/",
      "userName" : "openidm-admin",
      "password" : "openidm-admin"
     }
    

    b. Connecting to Identity Cloud, external.idm-fidc.json:

    {
      "enabled" : true,
      "authType" : "bearer",
      "instanceUrl" : "https://<tenant-name>.forgeblocks.com/openidm/",
      "clientId" : "OnPremIDM",
      "clientSecret" : "xxxxxxxx",
      "scope" : [
       "fr:idm:*"
      ],
     "tokenEndpoint" : "https://<tenant-name>.forgeblocks.com/am/oauth2/realms/root/realms/alpha/access_token"
       }
    

Mappings

Five mappings are required for this migration:


IDM proxy mappings

NOTE: As these external connectors are not traditional connectors, these mappings can’t be created via the IDM Admin UI.

Refer to this sample sync.json when creating these connectors and the following mappings:

1. Users migration mapping

Create a mapping (onprem_user_to_fidc_alpha_user) for migrating users.

NOTE: Users are usually migrated using out-of-the-box IDM connectors; this step is required for creating links for Identity Cloud<->self-managed identities only. These links are used to retrieve the user’s _id field in Identity Cloud for creating user<->roles relationships.

The properties below are required for this mapping:

Source

external/idm/65/managed/user

Target

external/idm/fidc/managed/alpha_user

userName userName
Correlation Query
"linkQualifier" : "default", \
                    "expressionTree" : { \
                        "any" : [ \
                            "userName" \
                        ] \
                    },

As the mapping above is only for creating lDM links, update the “onprem_user_to_fidc_alpha_user” behavior actions:

  • Absent situation to IGNORE
  • Missing situation to UNLINK

2. Assignments migration mapping

Create a mapping (onprem_asgn_to_fidc_alpha_asgn) for migrating assignments.

The properties below are required for this mapping:

Source

external/idm/65/managed/assignment

Target

external/idm/fidc/managed/alpha_assignment

name name
description description
mapping (Default: managedAlpha_user_managedAlpha_user)
Correlation Query
"linkQualifier" : "default", \
                    "expressionTree" : { \
                        "any" : [ \
                            "name" \
                        ] \
                    },

3. Roles migration mapping

Three role migration mappings are required for migrating roles:

  • Migrating roles
  • Migrating assignments<->roles relationships
  • Migrating users<->roles relationships

3a. Create a mapping (onprem_role_to_fidc_alpha_role) for migrating roles. The properties below are required for this mapping:

Source

external/idm/65/managed/role

Target

external/idm/fidc/managed/alpha_role

name name
description description
Correlation Query
"linkQualifier" : "default", \
                    "expressionTree" : { \
                        "any" : [ \
                            "name" \
                        ] \
                    },

3b. Create a mapping (onprem_role_to_fidc_alpha_role_assignments) for migrating assignments<->roles relationships.

The properties below are required for this mapping:

Source

external/idm/65/managed/role

Target

external/idm/fidc/managed/alpha_role

name name
Correlation Query
"linkQualifier" : "default", \
                    "expressionTree" : { \
                        "any" : [ \
                            "name" \
                        ] \
                    },
  • The transformation script for “assignments” allows you to sync assignments references to establish assignments<->roles relationships. This script refers to links created by “onprem_user_to_fidc_alpha_user” mapping to retrieve the corresponding Identity Cloud assignment’s _id value.

  • Add sourceQuery in this mapping. This allows the IDM proxy to retrieve referenced assignments and members. This is not yet available in the IDM Admin UI, so update the sync.json directly:

    "name" : "onprem_role_to_fidc_alpha_role_assignments",
    "target" : ....
    "sourceQuery" : {
              "_queryFilter" : true,
              "_fields" : "*,*_ref"
    },
    "properties" :  ...
    
    
  • Update this mapping’s behavior actions by specifying the scripts below. These scripts need to be present under the <IDM-Project>/script folder:

    • Confirmed: script/assignment-role-confirmed.js
    • Found: script/assignment-role-found.js

3c. Create a mapping (onprem_user_to_fidc_alpha_user_roles) for migrating users<->roles relationships.

The properties below are required for this mapping:

Source

external/idm/65/managed/user

Target

external/idm/fidc/managed/alpha_user

userName userName
Correlation Query
"linkQualifier" : "default", \
                    "expressionTree" : { \
                        "all" : [ \
                            "userName" \
                        ] \
                    },
  • Add sourceQuery in this mapping. This allows the IDM proxy to retrieve referenced assignments and members. This is not yet available in the IDM Admin UI, so update the sync.json directly:

       "name" : "onprem_role_to_fidc_alpha_role",
       "target" : ....
       "sourceQuery" : {
                 "_queryFilter" : true,
                 "_fields" : "*,*_ref"
      },
       "properties" :  ...
    
    
  • Configure taskThreads as 2.

  • Update this mapping’s behavior actions:
    1. Absent situation to IGNORE.
    2. Specify the scripts below. These scripts must be present under the <IDM-Project>/script folder:

    • Confirmed: script/user-role-confirmed.js
    • Found: script/user-role-found.js

Retrieving roles and assignments in OIDC claims

The following changes are required in Identity Cloud configurations:

IDM mapping

  1. Navigate to the Identity Cloud IDM Admin UI.

  2. Create a “managedAlpha_user_managedAlpha_user” with no properties:

Source Target
managed/alpha_user managed/alpha_user
N/A N/A
  1. Change this “mapping behavior" policy to Read-only.

Alpha_user managed object

User attributes can be updated using the Relationship-derived virtual properties (RDVP) feature. This feature helps in mapping Roles and Assignment names in user attributes and they are dynamically updated.

  1. Retrieve managed.json from Identity Cloud:

    curl --location --request GET 'https://<tenant-name>forgeblocks.com/openidm/config/managed' \
    --header 'Accept-API-Version: resource=1.0' \
    --header 'Authorization: Bearer <Admin Access token>'
    
  2. Update alpha_user’s properties (frIndexedMultivalued1, frIndexedMultivalued2) in managed.json. NOTE: This change needs to be done only in alpha_user (not bravo_user). Refer to the sample managed.json

    "frIndexedMultivalued1": {
       "deleteQueryConfig": false,
       "description": "Role Names",
       "isPersonal": false,
       "isVirtual": true,
       "items": {
           "type": "string"
       },
       "queryConfig": {
           "flattenProperties": true,
           "referencedObjectFields": [
               "name"
           ],
           "referencedRelationshipFields": [
               "roles"
           ]
       },
       "returnByDefault": true,
       "searchable": false,
       "title": "Role Names",
       "type": "array",
       "usageDescription": null,
       "userEditable": false,
       "viewable": true
    },
    "frIndexedMultivalued2": {
       "deleteQueryConfig": false,
       "description": "Assignment Names",
       "isPersonal": false,
       "isVirtual": true,
       "items": {
           "type": "string"
       },
       "queryConfig": {
           "flattenProperties": true,
           "referencedObjectFields": [
               "name"
           ],
           "referencedRelationshipFields": [
               "roles",
               "assignments"
           ]
       },
       "returnByDefault": true,
       "searchable": false,
       "title": "Assignment Names",
       "type": "array",
       "usageDescription": null,
       "userEditable": false,
       "viewable": true
    }
    
    
  3. Push the updated managed.json to Identity Cloud:

    curl --location --request PUT 'https://<tenant-name>.forgeblocks.com/openidm/config/managed' \
    --header 'Accept-API-Version: resource=1.0' \
    --header 'Authorization: Bearer <Admin Access token>' \
    --data-raw '{
        "_id": "managed",
        "objects": [
            {
                "name": "alpha_user",
              …. 
         }'
    

OIDC claims

  1. Create an OIDC application client scopes: openid, profile, assignments, roles.

  2. Update the OIDC claims script to add multivalued attributes corresponding to roles (from frIndexedMultivalued1), and assignments (from frIndexedMultivalued2) in OIDC claims:

    claimAttributes = [
         "email": userProfileClaimResolver.curry("mail"),
         "address": { claim, identity -> [ "address" :    userAddressClaimResolver(claim, identity) ] },
         "given_name": userProfileClaimResolver.curry("givenname"),
         "zoneinfo": userProfileClaimResolver.curry("preferredtimezone"),
         "family_name": userProfileClaimResolver.curry("sn"),
         "locale": userProfileClaimResolver.curry("preferredlocale"),
         "name": userProfileClaimResolver.curry("cn"),
         "roles": userProfileClaimResolver.curry("fr-attr-imulti1"),
         "assignments": userProfileClaimResolver.curry("fr-attr-imulti2")     
    ]
    /*
     * Map of scopes to claim objects.
    */
    // {scope}: [ {claim}, ... ]
    scopeClaimsMap = [
         "email": [ "email" ],
         "address": [ "address" ],
         "profile": [ "given_name", "zoneinfo", "family_name", "locale", "name" ],
         "roles": ["roles"],
         "assignments": ["assignments"]
    ]
    

Testing the Use Cases

Syncing self-managed roles and entitlements

  1. Sync user links by executing the “onprem_user_to_fidc_alpha_user” recon.

  2. Sync assignments by executing the “onprem_asgn_to_fidc_alpha_asgn” recon.

  3. Sync roles and relationships by executing the remaining 3 mappings.

  4. Validate that the roles and assignments (including assignments<->roles and user<->roles relationships) are synced to Identity Cloud.

  5. Validate that the frIndexedMultivalued1 attribute for a user has been updated with the required roles.

  6. Validate that the frIndexedMultivalued2 attribute for a user has been updated with the required assignments.

Issue ID token

  1. Invoke required OAuth grant such as ROPC to get an OIDC token:

    curl --location --request POST 'https://<tenant-name>.forgeblocks.com/am/oauth2/realms/root/realms/alpha/access_token' \
     --header 'Content-Type: application/x-www-form-urlencoded' \
     --data-urlencode 'grant_type=password' \
     --data-urlencode 'username=bjensen' \
     --data-urlencode 'password=password' \
     --data-urlencode 'scope=openid profile assignments roles' \
     --data-urlencode 'client_id=postmanConfidentialClient' \
     --data-urlencode 'client_secret=password'
    
    
  2. Validate that the issued OIDC token contains the required claims:

    {
     "at_hash": "wyKAqM_GdFbP-b-pR_eVcQ",
     "sub": "0c4c7d6e-2721-48f4-bd80-beceb447c514",
     "assignments": [
       "Asgn2",
       "Asgn1",
       "Asgn4",
       "Asgn3"
     ],
      "auditTrackingId": "b5116fba-1e65-4d5f-88e8-54bb12f16a2d-784961",
      "roles": [
       "Role5",
       "Role3",
      "Role2"
      ],
      "subname": "0c4c7d6e-2721-48f4-bd80-beceb447c514",
      "iss": "https://<tenant-name>.forgeblocks.com:443/am/oauth2/realms/root/realms/alpha",
      "tokenName": "id_token",
      "description": "Created By CSV 65",
      "given_name": "Barbara",
      "aud": "postmanConfidentialClient",
      "azp": "postmanConfidentialClient",
      "auth_time": 1645129612,
      "name": "Barbara Jensen",
      "realm": "/alpha",
      "exp": 1645129672,
      "tokenType": "JWTToken",
      "iat": 1645129612,
      "family_name": "Jensen"
    }
    

Limitations

Some limitations of this approach are as follows:

  1. LiveSync is not supported for this migration. IDM schedules can be leveraged for various mappings.

  2. Changes in self-managed assignments<->roles<->user members should be performed in self-managed IDM only until self-managed IDM is completely deprovisioned. If changes to these existing assignments<->roles<->user members are performed in Identity Cloud then they will get overridden by subsequent recons. NOTE: New roles, assignments and their corresponding relationships can be performed in Identity Cloud.

  3. Multiple IDM proxies for High Availability are not supported.

  4. Bidirectional synchronization from Identity Cloud to self-managed IDM is not currently implemented in this blog.

  5. As user attributes are updated using RDVP, assignments<->roles<->user relationships need to be updated at least once for triggering this feature. This means that existing users need to be assigned/unassigned at-least one role and existing roles need to be assigned/unassigned at least one assignment. New users are not impacted by this limitation.

References

1 Like