Transform logic

Hi All,I’m working on a transform that checks the expiry dates from multiple sources and compares them with the current date minus 90 days, to identify which accounts are nearing expiry. I’ve built a transform for this, but I’m facing an issue: if an identity doesn’t have an account in one of the sources, the transform fails and stops execution. I tried using FirstValid, but it hasn’t resolved the issue. Could someone please help me troubleshoot this?

{
“id”: “xxxx”,
“name”: “testexstat”,
“type”: “firstValid”,
“attributes”: {
“requiresPeriodicRefresh”: “true”,
“values”: [
{
“type”: “static”,
“attributes”: {
“account1”: {
“type”: “dateCompare”,
“attributes”: {
“firstDate”: {
“type”: “dateFormat”,
“attributes”: {
“inputFormat”: “EPOCH_TIME_WIN32”,
“outputFormat”: “ISO8601”,
“input”: {
“type”: “firstValid”,
“attributes”: {
“values”: [
{
“type”: “accountAttribute”,
“attributes”: {

“accountPropertyFilter”:“!(accountFlags.contains(\“Disabled\”))”,
“attributeName”: “msDS-XX”,
“sourceName”: “XXXX1”
}
},
{
“attributes”: {
“value”: “None”
},
“type”: “static”
}
]
}
}
}
},
“secondDate”: {
“type”: “dateMath”,
“attributes”: {
“expression”: “now-90d”,
“roundUp”: false
}
},
“operator”: “lt”,
“positiveCondition”: “true”,
“negativeCondition”: “false”
}
},
“account2”: {
“type”: “dateCompare”,
“attributes”: {
“firstDate”: {
“type”: “dateFormat”,
“attributes”: {
“inputFormat”: “EPOCH_TIME_WIN32”,
“outputFormat”: “ISO8601”,
“input”: {
“type”: “firstValid”,
“attributes”: {
“values”: [
{
“type”: “accountAttribute”,
“attributes”: {

“accountPropertyFilter”:“!(accountFlags.contains(\“Disabled\”))”,
“attributeName”: “msDS-xyz”,
“sourceName”: “XXXX2”
}
},
{
“attributes”: {
“value”: “None”
},
“type”: “static”
}
]
}
}
}
},
“secondDate”: {
“type”: “dateMath”,
“attributes”: {
“expression”: “now-90d”,
“roundUp”: false
}
},
“operator”: “lt”,
“positiveCondition”: “true”,
“negativeCondition”: “false”
}
},
“value”: “#if($account1 == ‘true’)account1#elseif($account2 == ‘true’)account2#{else}noexpireaccount#end”
}
}
],
“ignoreErrors”: false
},
“internal”: false
}

Hi @nidhipriya,

I see you are working on a very interesting use case.

You’re checking if the expiry date is less than now-90dwhich finds accounts that expired more than 90 days ago. You probably want accounts expiring in the next 90 days, if so use now+90d.

Also, using “None” as a fallback doesn’t play well with epoch time conversions, use a date far in the future in case there is no account for identity, like 9999999999. Perhaps you would find it easy if you update value of ignoreErrors to true in your transform to avoid the NPE.

Below is a sample account1 body for you to model: -

    "account1": {
      "type": "firstValid",
      "attributes": {
        "values": [
          {
            "type": "dateCompare",
            "attributes": {
              "firstDate": {
                "type": "dateFormat", 
                "attributes": {
                  "inputFormat": "EPOCH_TIME_WIN32",
                  "outputFormat": "ISO8601",
                  "input": {
                    "type": "firstValid",
                    "attributes": {
                      "values": [
                        {
                          "type": "accountAttribute",
                          "attributes": {
                            "accountPropertyFilter": "!(accountFlags.contains(\"Disabled\"))",
                            "attributeName": "msDS-UserPasswordExpiryTimeComputed",
                            "sourceName": "Source 1"
                          }
                        },
                        {
                          "type": "static", 
                          "attributes": {
                            "value": "9999999999"
                          }
                        }
                      ],
                      "ignoreErrors": true
                    }
                  }
                }
              },
              "secondDate": {
                "type": "dateMath",
                "attributes": {
                  "expression": "now+90d",
                  "roundUp": false
                }
              },
              "operator": "lt",
              "positiveCondition": "true", 
              "negativeCondition": "false"
            }
          },
          {
            "type": "static",
            "attributes": {
              "value": "false"
            }
          }
        ],
        "ignoreErrors": true
      }

Good luck!

Hi @TheOneAMSheriff - Thank you for the response.

This works partially for our case. however i am trying to retrieve UPN name if account get expired.is there any way in the transform i can fetch it.
I am trying with conditional , but unsure if it works.
Any suggestion/recommendation is greatly appreciated.

1 Like

Hi @nidhipriya,

I am glad my recommendation worked for you. I believe it’s possible to get UPN of the account on a conditional transform. You would have to calculate based on the expression perhaps like below: -

{
  "account1": {
    "type": "firstValid",
    "attributes": {
      "values": [
        {
          "type": "conditional",
          "attributes": {
            "expression": "$isExpiring eq true",
            "positiveCondition": "$upnValue",
            "negativeCondition": "$noExpiryValue",
            "isExpiring": {
              "type": "dateCompare",
              "attributes": {
                "firstDate": {
                  "type": "dateFormat",
                  "attributes": {
                    "inputFormat": "EPOCH_TIME_WIN32",
                    "outputFormat": "ISO8601",
                    "input": {
                      "type": "firstValid",
                      "attributes": {
                        "values": [
                          {
                            "type": "accountAttribute",
                            "attributes": {
                              "accountPropertyFilter": "!(accountFlags.contains(\"Disabled\"))",
                              "attributeName": "msDS-UserPasswordExpiryTimeComputed",
                              "sourceName": "Source 1"
                            }
                          },
                          {
                            "type": "static",
                            "attributes": {
                              "value": "9999999999"
                            }
                          }
                        ],
                        "ignoreErrors": true
                      }
                    }
                  }
                },
                "secondDate": {
                  "type": "dateMath",
                  "attributes": {
                    "expression": "now+90d",
                    "roundUp": false
                  }
                },
                "operator": "lt",
                "positiveCondition": "true",
                "negativeCondition": "false"
              }
            },
            "upnValue": {
              "type": "accountAttribute",
              "attributes": {
                "accountPropertyFilter": "!(accountFlags.contains(\"Disabled\"))",
                "attributeName": "userPrincipalName",
                "sourceName": "Source 1"
              }
            },
            "noExpiryValue": {
              "type": "static",
              "attributes": {
                "value": null
              }
            }
          }
        },
        {
          "type": "static",
          "attributes": {
            "value": null
          }
        }
      ],
      "ignoreErrors": true
    }
  }
}

Good luck!

@TheOneAMSheriff- Thankyou !!
It worked for me, except for the case if account doesn’t exists.

1 Like

Hi ,
I have written below transform which should return UPN value if password expired date is greater than 90 days.
this is working for some users and few users its not displaying UPN value although password expired is greater than 90days.
condition must also include if account doesn’t exists
can someone pls suggest, what changes has to be done?

"id": "bf4fbb19-9cee-4fa5-a9e5-3958f5bd6d4f",
"name": "testexstat",
"type": "firstValid",
"attributes": {
    "requiresPeriodicRefresh": "true",
    "values": [
        {
            "type": "static",
            "attributes": {
                "date1": {
                    "type": "dateCompare",
                    "attributes": {
                        "firstDate": {
                            "type": "dateFormat",
                            "attributes": {
                                "inputFormat": "EPOCH_TIME_WIN32",
                                "outputFormat": "ISO8601",
                                "input": {
                                    "type": "firstValid",
                                    "attributes": {
                                        "values": [
                                            {
                                                "type": "accountAttribute",
                                                "attributes": {
                                                    "accountPropertyFilter": "!(accountFlags.contains(\"Disabled\"))",
                                                    "attributeName": "msDS-",
                                                    "sourceName": "source1"
                                                }
                                            }
                                        ]
                                    }
                                }
                            }
                        },
                        "secondDate": {
                            "type": "dateMath",
                            "attributes": {
                                "expression": "now-90d",
                                "roundUp": false
                            }
                        },
                        "operator": "lt",
                        "positiveCondition": "expired",
                        "negativeCondition": "notexpired"
                    }
                },
                "date2": {
                    "type": "dateCompare",
                    "attributes": {
                        "firstDate": {
                            "type": "dateFormat",
                            "attributes": {
                                "inputFormat": "EPOCH_TIME_WIN32",
                                "outputFormat": "ISO8601",
                                "input": {
                                    "type": "firstValid",
                                    "attributes": {
                                        "values": [
                                            {
                                                "type": "accountAttribute",
                                                "attributes": {
                                                    "attributeName": "msDS-",
                                                    "sourceName": "source2"
                                                }
                                            }
                                        ]
                                    }
                                }
                            }
                        },
                        "secondDate": {
                            "type": "dateMath",
                            "attributes": {
                                "expression": "now-90d",
                                "roundUp": false
                            }
                        },
                        "operator": "lt",
                        "positiveCondition": "expired",
                        "negativeCondition": "notexpired"
                    }
                },
                "upnValue": {
                    "type": "accountAttribute",
                    "attributes": {
                        "accountPropertyFilter": "!(accountFlags.contains(\"Disabled\"))",
                        "attributeName": "userPrincipalName",
                        "sourceName": "source1"
                    }
                },
                "upnValue1": {
                    "type": "accountAttribute",
                    "attributes": {
                        "accountPropertyFilter": "!(accountFlags.contains(\"Disabled\"))",
                        "attributeName": "userPrincipalName",
                        "sourceName": "source2"
                    }
                },
                "value": "#if($date1 == 'expired')$upnValue#elseif($date1 == 'notexpired' || !$date1)#if($date2 == 'expired')$upnValue1#elseif($date2 == 'notexpired')date2notexpired#{else}date2accountnotfound#end#{else}accountnotfound#end"
            }
        }
    ],
    "ignoreErrors": true
},
"internal": false

}

Transform is not the right approach to build this usecase considering a lot of sources.

Traditional approach:

Create an Identity attribute, for AD it is UAC, for other sources status or something like that.

Calculate status attribute based on last logon and enable attribute sync or fire workflow to disable account using this attribute.

Transform might be a viable approach if it is limited sources (up to 10), more than that it will be complex to build Transform logic.

Alternative Approach:

  1. Use Accounts API call, filter with source(s)
  2. Get lastLogin
  3. Disable if user didn’t login for X days

You can build this as a custom script and schedule it in IQ Service server.

Transform:

Static Transform with Velocity Script

  1. Get Identity Links
  2. Iterate and check some condition like starts with or contains
  3. Get lastLogin and do the math (I tried once to play with EPOC timestamps using velocity, it didn’t work. SailPoint experts informed me that velocity math is not supported).
  4. Add accountID to an array

Fire a workflow based on this attribute, use loop to disable all those IDs

You can’t use workflow directly without relying on an Identity attribute as loop has limitation on iterations.

I would go with Custom script, because Transform calculation will be complex and time consuming, you need a lot of expertise to build this kind of Transform as error free irrespective of polluted data. Chances of Identities getting into error state and more time for Refresh and Aggregations.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.