Track Your Movers

Special Thank to @rohit_prabhu & @mostafa_helmy for the valuable inputs and support.

Problem Overview

In many organizations, there’s a growing need for better visibility into Identities movements aka “movers”. These movements could involve role changes, departmental shifts, or location reassignments.

Organizations leaders are interested in informations such as:

  • How often has a user moved within the organization?

  • How many movers were there in the past quarter?

  • When was a specific user’s last move?

Yet currently, no out-of-the-box (OOTB) feature is available in ISC to directly answer these questions.

Solution

In this blog, I’ll walk you through a smart and lightweight solution to track movers in your identity program by introducing three custom identity attributes in your Identity profile attached to three transforms.

1. What defines a “Mover“?

A mover is any identity that has undergone a change in one or more of the following attributes:

  • Job Title

  • Department

  • Location

You can customize these criteria to suit your organization’s definition of a mover and update the Mover Calculation Transform.

2. Create a Mover Calculation Attribute

This attribute holds the current state of mover-related fields. i.e Detects changes in job title, department, or location, and log the movement with a timestamp and reset the attribute after a timestamp

Transform Logic Highlights:

  • Compares current and old values of the mover criteria.

  • Records timestamped movements when changes occur.

  • Handles data expiry using dateMath expressions.

{
    "name": "Mover Calculations",
    "type": "firstValid",
    "attributes": {
        "requiresPeriodicRefresh": true,
        "values": [
            {
                "type": "static",
                "attributes": {
                    "moverCriteria": {
                                      // Where you add your Mover criteria //
                        "type": "concat",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "values": [
                                {
                                    "type": "identityAttribute",
                                    "attributes": {
                                        "name": "jobTitle"
                                    }
                                },
                                " || ",
                                {
                                    "type": "identityAttribute",
                                    "attributes": {
                                        "name": "department"
                                    }
                                },
                                " || ",
                                {
                                    "type": "identityAttribute",
                                    "attributes": {
                                        "name": "location"
                                    }
                                }
                            ]
                        }
                    },
                    "oldValue": {
                        "type": "firstValid",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "values": [
                                {
                                    "type": "static",
                                    "attributes": {
                                        "value": "$oldValue"
                                    }
                                },
                                "N/A"
                            ],
                            "ignoreErrors": true
                        }
                    },
                    "currentTimeStamp": {
                        "type": "dateMath",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "expression": "now/m"
                        }
                    },
                    "newExpiryDate": {
                        "type": "dateMath",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "expression": "now+7d/d" //Define the duration to keep the mover history//
                        }
                    },
                    "currentExpiryDate": {
                        "type": "firstValid",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "values": [
                                {
                                    "type": "split",
                                    "attributes": {
                                        "delimiter": "<-->",
                                        "index": 2,
                                        "throw": false,
                                        "input": {
                                            "type": "static",
                                            "attributes": {
                                                "value": "$oldValue"
                                            }
                                        }
                                    }
                                },
                                "N/A"
                            ],
                            "ignoreErrors": true
                        }
                    },
                    "value": "#if($moverCriteria == $oldValue && $oldValue == \"N/A\" && !$oldValue.contains('<-->'))$moverCriteria#elseif(!$oldValue.contains('<-->') && $moverCriteria != $oldValue)$oldValue <-->$currentTimeStamp<-->$newExpiryDate#elseif($currentExpiryDate.compareTo($currentTimeStamp) <= 0 || $currentExpiryDate == \"N/A\")$moverCriteria#{else}$moverCriteria#end"
            },
            ""
        ]
    },
    "internal": false
}

3. Create a Mover Flag Attribute

This attribute reflects whether the user is a mover and holds a history of move dates. i.e Turns “True” when a movement is detected and capture all movement timestamps in the identity record.

Transform Logic Highlights:

  • Checks if current and previous criteria differ.

  • Appends timestamp if movement is detected.

  • Retains previous history for auditability.

{
    "name": "Mover Flag",
    "type": "firstValid",
    "attributes": {
        "requiresPeriodicRefresh": true,
        "values": [
            {
                "type": "static",
                "attributes": {
                    "moverCriteria": {
                        "type": "concat",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "values": [
                                {
                                    "type": "identityAttribute",
                                    "attributes": {
                                        "name": "jobTitle"
                                    }
                                },
                                " || ",
                                {
                                    "type": "identityAttribute",
                                    "attributes": {
                                        "name": "department"
                                    }
                                },
                                " || ",
                                {
                                    "type": "identityAttribute",
                                    "attributes": {
                                        "name": "location"
                                    }
                                }
                            ]
                        }
                    },
                    "oldValue": {
                        "type": "firstValid",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "values": [
                                {
                                    "type": "static",
                                    "attributes": {
                                        "value": "$oldValue"
                                    }
                                },
                                "N/A"
                            ],
                            "ignoreErrors": true
                        }
                    },
                    "currentTimeStamp": {
                        "type": "dateMath",
                        "attributes": {
                            "requiresPeriodicRefresh": true,
                            "expression": "now/m"
                        }
                    },
                    "moveCalculation": {
                        "type": "identityAttribute",
                        "attributes": {
                            "name": "moverCalculations"
                        }
                    },
                    "value": "#if($moverCriteria == $moveCalculation && $oldValue == \"N/A\")False#elseif($moverCriteria != $moveCalculation && !$oldValue.contains(\"True\")) True - $currentTimeStamp#elseif($oldValue.contains(\"True\") && $moverCriteria != $moveCalculation) $oldValue - $currentTimeStamp#{else}$oldValue#end"
                }
            },
            ""
        ]
    },
    "internal": false
}

4.Create a Last Move DateType Attribute

This attribute extracts the latest move timestamp from the mover calculation. i.e Easily filter users based on their last movement date.

Transform Logic Highlights:

  • Parses the second part of the stored string using a delimiter.

  • Falls back to $oldValue if parsing fails.

{
    "name": "LastMoveDateType",
    "type": "firstValid",
    "attributes": {
        "requiresPeriodicRefresh": true,
        "values": [
            {
                "type": "split",
                "attributes": {
                    "delimiter": "<-->",
                    "index": 1,
                    "throw": false,
                    "input": {
                        "type": "identityAttribute",
                        "attributes": {
                            "name": "moverCalculations"
                        }
                    }
                }
            },
            "$oldValue",
            ""
        ],
        "ignoreErrors": true
    },
    "internal": false
}

Track your Movers

Once these attributes are configured and transforms applied, you can gain insights using simple search queries:

  • List all movers in the organization:

attributes.moverFlag:True*

  • Find movers in the last 30 days:

attributes.lastMoveDateType:[now-30d TO now]

These queries help leadership, HR, and access governance teams stay informed and tracks the movers by running reports.

With these attributes and transforms, you empower your org with visibility, auditability, and control over internal movement, crucial for compliance, security, and operational insights.

2 Likes