Email Notification after Entitlement Removal via Workflow

Hi all,

I require a workflow for one application that is managing its access rights via Azure AD groups where an email notification shall be sent to a specific email address if one of the application’s Azure AD groups are removed (e. g. by a regular certification). Of course, I could consider this during the mover and leaver workflow, but I would like to have a separate workflow so that revocations of regular certification can also be considered.

So, I created a workflow in our SB and the workflow test before enablement was working fine, but when I activated it and I removed one of the Azure AD groups there is no email that is triggered.

I believe that the trigger filter is not working correctly. I’m using the “provisioning completed” trigger with the following filter where I want to filter for specific Azure AD groups that were removed, so I specified them with the attribute “attributeValue” and specified the operation “Remove”.

$…accountRequests[?(@.provisioningResult == “SUCCESS” && @.provisioningTarget == “Azure testinfra tennant”)].attributeRequests[?(@.operation == “Remove” && (@.attributeValue in [“a3f48ba1-7114-4b96-ba77-102def475630”, “900653c7-2d4b-4af7-849d-944544b6479b”, “9023471e-324b-46aa-9277-f1e78ae5f473”, “633b3fbd-d20c-4191-8d88-35a645ba2657”, “c8a11341-3130-4266-bafa-f0fc9cf10144”, “dda55e6c-5520-4274-b812-f1beff94b954”, “5ea1a315-1759-4c7c-aa79-7c0d784c0c84”, “90726444-fc90-47d5-bdd3-ac1134d747b8”, “df4e5b78-da32-41a9-8bc6-ee83e3beab64”, “1b74a09e-6549-4e76-9d98-bbd79532f32b”, “ffb1e4c0-5354-4cb3-ae8e-45dece96eb99”]))]

Further I want to mention this Azure AD groups in an email, but I can only fetch the attribute “attributeValue” and not the display name. Does anyone have an idea how I could fetch the display name with this trigger? I’m using the following in an email body:

Dear recipient,

this email shall inform you that The AAD group with value
{{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}} was removed from {{$.getIdentity.attributes.firstname}} {{$.getIdentity.attributes.lastname}} by {{$.getIdentity1.attributes.firstname}} {{$.getIdentity1.attributes.lastname}}.

Your IAM team

Thanks a lot in advance.

Fabienne

You can use the following API to get the details of the entitlement using it’s ID

Then use the name from the response json body in your email

Hello @fabienne_florian,

Not all JSONPath libraries supports the ‘in’ array syntax. I’m not certain whether ISC does or not, but please validate this by changing that part to == and || and retry.

$..accountRequests[?(@.provisioningResult == "SUCCESS" && @.provisioningTarget == "Azure testinfra tennant")].attributeRequests[?(@.operation == "Remove" && (@.attributeValue == "a3f48ba1-7114-4b96-ba77-102def475630" || @.attributeValue == "900653c7-2d4b-4af7-849d-944544b6479b" || @.attributeValue == "9023471e-324b-46aa-9277-f1e78ae5f473" || @.attributeValue == "633b3fbd-d20c-4191-8d88-35a645ba2657" || @.attributeValue == "c8a11341-3130-4266-bafa-f0fc9cf10144" || @.attributeValue == "dda55e6c-5520-4274-b812-f1beff94b954" || @.attributeValue == "5ea1a315-1759-4c7c-aa79-7c0d784c0c84" || @.attributeValue == "90726444-fc90-47d5-bdd3-ac1134d747b8" || @.attributeValue == "df4e5b78-da32-41a9-8bc6-ee83e3beab64" || @.attributeValue == "1b74a09e-6549-4e76-9d98-bbd79532f32b" || @.attributeValue == "ffb1e4c0-5354-4cb3-ae8e-45dece96eb99"))]

For the name of the entitlement, use a HTTP Request Action (Using Workflow’s HTTP Request Action to Work With IdentityNow APIs) and call GET /beta/entitlement/{entitlement-id} endpoint (Get an entitlement) and extract the name from the response.

I also noticed on the workflow docs-page for Provisioning Completed that the sample JSON had "provisioningResult" : "committed". I’m not sure whether it is committed or SUCCESS that is expected. To force an invocation of the workflow you could loosen the trigger filter a bit, and instead use a Verify Data Type to examine the input - or even more extreme: You could run the “Provision Complete” into a “Send Email” to examine the results of your JSONPath.

For further assistance, please attach your JSON of the workflow.

1 Like

Great thank you! It worked after I removed the part @.provisioningResult == “SUCCESS”, I have not tried yet with “comitted”, but this seems to be the reason why it was not triggered. I have one other concern regarding the email that is triggered. Here I used the following JSONPath in the body:

New Test Dear recipient,

this email shall inform you that The AAD group with value
{{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}} was removed from {{$.getIdentity.attributes.firstname}} {{$.getIdentity.attributes.lastname}} by {{$.getIdentity1.attributes.firstname}} {{$.getIdentity1.attributes.lastname}}.

Your IAM team

This is working fine, but instead of the attributeValue I would rather like to mention the displayname of the Azure AD group in this email, but it looks like I cannot fetch it as there is no attribute for this in the JSON structure for the “Provisioning Completed” trigger. Do you have any other idea how I could get the displayname in my workflow for the action “Send email”?

This is my full Workflow:

{
“name”: “Version 3.1: Notification - Access Right Removal”,
“description”: “Notification - Access Right Removal”,
“modified”: “2024-08-07T10:43:16.334345532Z”,
“modifiedBy”: {
“type”: “IDENTITY”,
“id”: “58c6809d9095485494ceb146901e661b”,
“name”: “fabienne.test”
},
“definition”: {
“start”: “Get Identity”,
“steps”: {
“End Step - Success”: {
“displayName”: “”,
“type”: “success”
},
“Get Identity”: {
“actionId”: “sp:get-identity”,
“attributes”: {
“id.$”: “$.trigger.recipient.id”
},
“description”: “The previous step filters for successful completed provisioning towards Azure AD with the operation "Remove" and the specific CRM values. Here we fetch the identity from whom the access right was removed.\n\nGet id of recipient”,
“displayName”: “”,
“nextStep”: “Get Identity 1”,
“type”: “action”,
“versionNumber”: 2
},
“Get Identity 1”: {
“actionId”: “sp:get-identity”,
“attributes”: {
“id.$”: “$.trigger.requester.id”
},
“description”: “Get id of requester”,
“displayName”: “”,
“nextStep”: “Send Email”,
“type”: “action”,
“versionNumber”: 2
},
“Send Email”: {
“actionId”: “sp:send-email”,
“attributes”: {
“body”: “New Test Dear recipient,

this email shall inform you that The AAD group with value \n{{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}} was removed from {{$.getIdentity.attributes.firstname}} {{$.getIdentity.attributes.lastname}} by {{$.getIdentity1.attributes.firstname}} {{$.getIdentity1.attributes.lastname}}.

Your IAM team”,
“context”: {},
“from”: null,
“recipientEmailList.$”: “$.getIdentity.attributes.displayName”,
“subject”: “Test”
},
“displayName”: “”,
“nextStep”: “End Step - Success”,
“type”: “action”,
“versionNumber”: 2
}
}
},
“creator”: {
“type”: “IDENTITY”,
“id”: “58c6809d9095485494ceb146901e661b”,
“name”: “fabienne.test”
},
“trigger”: {
“type”: “EVENT”,
“attributes”: {
“filter.$”: “$…accountRequests[?(@.provisioningTarget == "Azure testinfra tennant")].attributeRequests[?(@.operation == "Remove" && (@.attributeValue == "dae97df6-630f-466d-93fb-13a8d533e766" || @.attributeValue == "900653c7-2d4b-4af7-849d-944544b6479b" ))]”,
“id”: “idn:post-provisioning”
}
}
}

image

Thank you a lot in advance.

Best regards,

Fabienne

Hello again @fabienne_florian

Yes, this is simple. As previously mentioned, you need to use the action HTTP Reqeust to contact the Sailpoint BETA API get-entitlement and modify your Workflow to look like this.

You then use the API to search for the entitlement with ID {{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}} and extract its name from the response body, and change the email accordingly.

See this show and tell for full reference on how to perform this HTTP Request.

Using Workflow’s HTTP Request Action to Work With IdentityNow APIs - Identity Security Cloud (ISC) / ISC Show and Tell - SailPoint Developer Community

Okay, thanks, I didn’t see the response from Nithesh Rao before. I just tried it. This is how the path of the JSON looks like:

And it seems that the id is delivered correctly, but still the request fails without a concret message what went wrong. This is how it looks like:

The full input that is given during the test is:

With kind regards

Fabienne

It looks to be an authorization error.
Make sure your PAT (Personal Access Token) has proper access, preferably sp:scopes:all - but at the very least: scopes: idn:entitlement:read,idn:entitlement:manage

If it has - please try to run the same request using postman or curl and get back to me with the results.

I think the token is fine, because my token is sp:scopes:all, but I was wondering if the Request URL cannot work like this, because what we deliver here is the “value” of the entitlement that we deliver with {{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}}, but on get-entitlement | SailPoint Developer Community it requires the “id” instead in the Request URL, but the JSON trigger structure doesn’t deliver the id. On Triggers - SailPoint Identity Services the structure is shown like below, so I wonder if it cannot work like this. Is there any other way how I can fetch the id beforehand to get the displayname in the end?

{
“trackingNumber”:“4b4d982dddff4267ab12f0f1e72b5a6d”,
“action”:“IdentityRefresh”,
“requester”:{
“id”:“2c91808b6ef1d43e016efba0ce470906”,
“name”:“Adam Admin”,
“type”:“IDENTITY”
},
“recipient”:{
“id”:“2c91808b6ef1d43e016efba0ce470909”,
“name”:“Ed Engineer”,
“type”:“IDENTITY”
},
“errors”:[
“General Error”,
“Connector AD Failed”
],
“warnings”:[
“Notification Skipped due to invalid email”
],
“sources”:“Corp AD, Corp LDAP, Corp Salesforce”,
“accountRequests”:[
{
“source”:{
“id”:“4e4d982dddff4267ab12f0f1e72b5a6d”,
“name”:“Corporate Active Directory”,
“type”:“SOURCE”
},
“accountId”:“CN=example,ou=sample,ou=test,dc=ex,dc=com”,
“accountOperation”:“Modify”,
“provisioningResult”:“committed”,
“provisioningTarget”:“Corp AD”,
“ticketId”:“72619262”,
“attributeRequests”:[
{
“operation”:“Add”,
“attributeName”:“memberOf”,
“attributeValue”:“CN=admin,DC=training,DC=com”
}
]
}
]
}

I also tried it with the value via Postman where it failed as well. It only works if I take the id.

But I think it should work with this API list-entitlements | SailPoint Developer Community. In Postman I can filter here for the value.

But I don’t know how I can apply this in the HTTP Request action. I tried to add it in query parameters, but it doesn’t work as it will still fetches the whole list of entitlements afterwards. On the page Using Workflow’s HTTP Request Action to Work With IdentityNow APIs - Identity Security Cloud (ISC) / ISC Show and Tell - SailPoint Developer Community it is described to put it in a format like "filters:identityId eq “{{$.trigger.identity.id}}” ", but the worklow query parameter only has 2 fields where I first need to provide the attribute and then the respective content. So, I’m not sure how to set this filter on the action item via Workflows.

image

With kind regards

Fabienne

Hello again @fabienne_florian

I understand. Since your value looked very much like an id i just assumed it was the id, my bad.

It is still solvable, but instead of querying one specific entitlement, query all of your entitlements and find the one you are looking for.

I.e. change the HTTP Request URL to /beta/entitlements/ (without the ID).
Then change the JSONPath to look for the element where value == {{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}} and extract the name using:

$.hTTPRequest.body[?(@.value == "{{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}}")].name

You could probably also do it using your method using with the filters query parameter. But since you need to GET all entitlements anyway, might just use the JSONPath immediately.
But to answer your question, for setting this up in UI, you would do it like this:
image

1 Like

Thank you so much for your great support :slight_smile: it works now. I adjusted a few things.

I put the following as request URL: https://TENANT.api.identitynow.com/beta/entitlements/

And the below Query Parameters. The full text of the value field behind the key for filters is: value eq “{{$.trigger.accountRequests[0].attributeRequests[0].attributeValue}}”

image

In my email I’m using {{$.hTTPRequest.body[0].name}} to fetch now the name of the Azure AD group.

With kind regards

Fabienne

Glad to hear that it worked out, Fabienne! :slight_smile:

Actually I have one more question. I did some tests and I figured that this process only works if there is only one AAD group in one request, but if there are more than one AAD groups that are removed by one request (e. g. if there are 2 AAD groups in one access profile or if 2 different AAD groups are revoked within one access review) it doesn’t work as intended as we will not have an output of the HTTP request with the different entitlements.

The reason behind that is that the data structure is slidly different as the attributeValue is given in quotation marks and then in square brackets like this:

“attributeValue”: “[2e012c83-a7fc-42c9-a0b2-fefd859340ae, dae97df6-630f-466d-93fb-13a8d533e766]”

Therefore the JASONPath $.trigger.accountRequests[0].attributeRequests[0].attributeValue will output: “[2e012c83-a7fc-42c9-a0b2-fefd859340ae, dae97df6-630f-466d-93fb-13a8d533e766]” and then the output for the HTTP request will not work as intended.

I couldn’t find any way yet how to filter for the seperate values.

With kind regards

Fabienne

Hi @fabienne_florian , Please use Loop operator to get each attribute value.

1 Like

So, in this case you probably mean that I could use a loop with the input $.trigger.accountRequests[0].attributeRequests[0].attributeValue where I could then fetch the different values in order to have one HTTP request for each of the values, right? And after the loop I could fetch the DisplayName for each in the email.

But as the input looks like below from the trigger, I would think that this is not a list or an array as it is in quotation marks. So, IdentityNOW would read it as a String and as far as I understood Loops only work on lists/arrays. I think it would work if it would not be in quotation marks or how could I adress each of these values?

“attributeValue”: “[2e012c83-a7fc-42c9-a0b2-fefd859340ae, dae97df6-630f-466d-93fb-13a8d533e766]”

Thank you in advance.

Could you please share the trigger input here if possible?

Yes sure, I actually enabled the Workflow and saw that the format is as followed if more than 1 entitlements are removed:

“attributeValue”: “[2e012c83-a7fc-42c9-a0b2-fefd859340ae, dae97df6-630f-466d-93fb-13a8d533e766]”

There is also just one trackingNumber is two AAD were removed together.

So, the trigger input from my enabled workflow was as followed:

{
"input":{
	"_meta":{
		"invocationId":"4d2e5017-1b90-4e39-9d8f-c0a4837bdf42",
		"subscriptionId":"b05ec1ba-3d9f-4ea8-b7b8-7bd37e72168e",
		"triggerType":"FIRE_AND_FORGET"
		},
	"accountRequests":[{
		"accountId":"8c0b0adc-b5bb-41a7-8383-617c961548b5",
		"accountOperation":"Modify",
		"attributeRequests":[{
			"attributeName":"groups",
			"attributeValue":"[2e012c83-a7fc-42c9-a0b2-fefd859340ae, dae97df6-630f-466d-93fb-13a8d533e766]",
			"operation":"Remove"
			}],
		"provisioningResult":"committed",
		"provisioningTarget":"Azure testinfra tennant",
		"source":{
			"id":"2366a1d3dea24c6d9cf0b6e501c2528e",
			"name":"Azure testinfra tennant",
			"type":"SOURCE"
			},
		"ticketId":null}],
	"action":"Certification",
	"errors":[],
	"recipient":{
		"id":"c4e99466de564c3c83da364d6b7a6aa9",
		"name":"Fabienne Test",
		"type":"IDENTITY"},
	"requester":{
		"id":"58c6809d9095485494ceb146901e661b",
		"name":"fabienne.test.admin",
		"type":"IDENTITY"},
	"sources":"Azure testinfra tennant",
	"trackingNumber":"088f47b4061145fba2c2d294c231640e",
	"warnings":[]
}}

So I took over this structure to test my workflow as followed where I adjusted the attributeValue and the recipients requesters id and name:

The full trigger input would be as followed:

{
  "trackingNumber": "4b4d982dddff4267ab12f0f1e72b5a6d",
  "action": "IdentityRefresh",
  "requester": {
    "id": "58c6809d9095485494ceb146901e661b",
    "name": "fabienne.test",
    "type": "IDENTITY"
  },
  "recipient": {
    "id": "09668e92017240f4931178871e07f37a",
    "name": "shivam.test",
    "type": "IDENTITY"
  },
  "errors": null,
  "warnings": null,
  "sources": "Azure testinfra tennant",
  "accountRequests": [
    {
      "source": {
        "id": "2366a1d3dea24c6d9cf0b6e501c2528e",
        "name": "Azure testinfra tennant",
        "type": "SOURCE"
      },
      "accountId": "CN=Rob.Robertson,ou=csm,ou=sales,dc=helpco,dc=com",
      "accountOperation": "Modify",
      "provisioningResult": "SUCCESS",
      "provisioningTarget": "Azure testinfra tennant",
      "ticketId": "72619262",
      "attributeRequests": [
        {
          "operation": "Remove",
          "attributeName": "groups",
          "attributeValue": "[2e012c83-a7fc-42c9-a0b2-fefd859340ae, dae97df6-630f-466d-93fb-13a8d533e766]"
        }
      ]
    }
  ]
}

I think the problem is the format that the value is in quatation marks and then in square brackets and this way it is read as a String and with loops we need an array.

With kind regards

Fabienne

Is there any other suggestion? Because actually I think there can always be the case that more than 1 entitlement is removed. I tested it e. g. for a certification and then it even lists everything in this format that was removed, even if it is not part of the trigger.

We have tried it with loops as well, but it didn’t work as it is not in the correct format.

So it doesn’t work in this format:
“attributeValue”:“[2e012c83-a7fc-42c9-a0b2-fefd859340ae, dae97df6-630f-466d-93fb-13a8d533e766]”,

I guess it would only work if it would be possible somehow to transfer this dataformat.

With kind regards

Fabienne

Hi @fabienne_florian , can you share your latest workflow JSON if possible. Pls mask the necessary.

What error are you receiving when using loops?

Thanks,
Shailee