Mover process shall trigger an access review for mover's manager, but shall exclude specific access profiles

Hello,

I created a mover process which shall only create a certification campaign if the mover has access profiles or roles. Entitlements shall not be certified as these might be AD or AAD groups where the business requirements are not clarified yet.

That was working fine, but now we need to exclude futher access profiles from this campaign as the business requirement is that this access right shall be never removed. I’m using an HTTP Request to create a certification campaign as the regular create certification item is so restricted that it doesn’t help. So I’m using this API Call in this HTTP Request create-campaign | SailPoint Developer Community, but the accessConstraints function doesn’t work here as expected.

The expected format is:

[
  "0fd680deb851471dae2d2019a70ad7e8",
  "a8239f3ade134915afa07fbfb93f26d1",
  "c2f37c43ee6d42ae9f06205497efb517",
  "cf4426563eed4d3f88cac36665b9f9c3"
]

And this can actually be reached with a JSONPath e. g. $[?(@.name != ‘NameofAC’)].id was checked with JSONPath Online Evaluator, but instead converting it like above it is converted as below which leads to a failure:

"["0fd680deb851471dae2d2019a70ad7e8" "a8239f3ade134915afa07fbfb93f26d1" "c2f37c43ee6d42ae9f06205497efb517" "cf4426563eed4d3f88cac36665b9f9c3"]"

It returns the correct values, but the formatting is wrong. My process has much more paths, but to simply it I removed the other paths so that it is easier here to discuss it.

So this is the simplified workflow. How can I reach to exclude specific access profiles from here?

{
	"name": "Copy of Mover_department_squad_country_company_Change",
	"description": "The mover process is triggered once an identity has a change of department, squad, cost center,  supervisoryOrgName, companyName and/or country. The new manager will get an email and a certification if the identity has any access profiles or roles assigned.",
	"definition": {
		"start": "Get Identity",
		"steps": {
			"Activate Certification Campaign 2": {
				"actionId": "sp:activate-campaign",
				"attributes": {
					"id.$": "$.hTTPRequest6.body.id"
				},
				"description": "Activate campaign",
				"displayName": "",
				"nextStep": "Get Access 3",
				"type": "action",
				"versionNumber": 1
			},
			"Activate Certification Campaign 3": {
				"actionId": "sp:activate-campaign",
				"attributes": {
					"id.$": "$.hTTPRequest3.body.id"
				},
				"description": "Activate campaign",
				"displayName": "",
				"nextStep": "End Step - Success 5",
				"type": "action",
				"versionNumber": 1
			},
			"Compare Numbers": {
				"choiceList": [
					{
						"comparator": "NumericGreaterThanEquals",
						"nextStep": "Send Email 1",
						"variableA.$": "$.getAccess.accessItems.length()",
						"variableB": 1
					}
				],
				"defaultStep": "End Step - Success 8",
				"description": "Here we will check if the identity has any access profiles or not. If he/she has access profiles we want to do a certification.",
				"displayName": "Check if Mover has Access Profiles",
				"type": "choice"
			},
			"Compare Numbers 3": {
				"choiceList": [
					{
						"comparator": "NumericGreaterThanEquals",
						"nextStep": "HTTP Request 3",
						"variableA.$": "$.getAccess3.accessItems.length()",
						"variableB": 1
					}
				],
				"defaultStep": "End Step - Success 4",
				"description": "Here we will check if the identity has any roles or not. If he/she has roles we want to do a certification.",
				"displayName": "Check if Mover has Roles (2)",
				"type": "choice"
			},
			"Compare Strings": {
				"choiceList": [
					{
						"comparator": "StringEquals",
						"nextStep": "Define Variable",
						"variableA.$": "$.getIdentity.attributes.cloudLifecycleState",
						"variableB": "active"
					}
				],
				"defaultStep": "End Step - Success 1",
				"description": "Here we want to exclude all identies from the process that have not joined yet teh company.",
				"displayName": "Exclude joiners from process",
				"type": "choice"
			},
			"Define Variable": {
				"attributes": {
					"id": "sp:define-variable",
					"variables": [
						{
							"description": "This Deadline shall be used for the creation of the Mover campaign which shall be the last modification date or date of today plus 30 days. We need this later for the HTTP calls to set the correct deadline for the certification.",
							"name": "DeadlineMover",
							"transforms": [
								{
									"id": "sp:transform:addTime:time",
									"input": {
										"length": 30,
										"unit": "days"
									}
								}
							],
							"variableA.$": "$.getIdentity.lastRefresh"
						}
					]
				},
				"displayName": "Define Deadline of Mover Campaign",
				"nextStep": "Get Access",
				"type": "Mutation"
			},
			"End Step - Success 1": {
				"description": "No mover actions shall happen if they are not active yet.",
				"displayName": "Joiners are excluded",
				"type": "success"
			},
			"End Step - Success 4": {
				"description": "No roles assigned, therefore no role certification.",
				"displayName": "Mover has no roles, but access profiles (old manager)",
				"type": "success"
			},
			"End Step - Success 5": {
				"displayName": "Mover has roles & access profiles (old manager)",
				"type": "success"
			},
			"End Step - Success 8": {
				"description": "Simplified process, usually the path would be longer here to check if the user has roles etc.",
				"displayName": "",
				"type": "success"
			},
			"Get Access": {
				"actionId": "sp:access:get",
				"attributes": {
					"accessprofiles": true,
					"entitlements": false,
					"getAccessBy": "specificIdentity",
					"identityToReturn.$": "$.trigger.identity.id",
					"roles": false
				},
				"description": "Here we want to fetch all current access profiles. In the next step we will check if this value is 0 (no access profiles) or if the identity is holding acces profiles. In last case we want to do a certification.",
				"displayName": "Get Mover's Access Profiles",
				"nextStep": "Compare Numbers",
				"type": "action",
				"versionNumber": 1
			},
			"Get Access 3": {
				"actionId": "sp:access:get",
				"attributes": {
					"accessprofiles": false,
					"entitlements": false,
					"getAccessBy": "specificIdentity",
					"identityToReturn.$": "$.trigger.identity.id",
					"roles": true
				},
				"description": "Here we want to fetch all current roles. In the next step we will check if this value is 0 (no roles) or if the identity is holding roles. In last case we want to do a certification.",
				"displayName": "Get Mover's Roles (2)",
				"nextStep": "Compare Numbers 3",
				"type": "action",
				"versionNumber": 1
			},
			"Get Identity": {
				"actionId": "sp:get-identity",
				"attributes": {
					"id.$": "$.trigger.identity.id"
				},
				"description": "Here we want to fetch the moving identity",
				"displayName": "Get moving identity",
				"nextStep": "Get Identity 1",
				"type": "action",
				"versionNumber": 2
			},
			"Get Identity 1": {
				"actionId": "sp:get-identity",
				"attributes": {
					"id.$": "$.getIdentity.managerRef.id"
				},
				"description": "Here we want to fetch the EXISTING manager of the moving identity for a later process. In some cases there is no manager change. Therefore we need this attribute for such cases.",
				"displayName": "Get existing Manager of Mover",
				"nextStep": "Compare Strings",
				"type": "action",
				"versionNumber": 2
			},
			"HTTP Request 3": {
				"actionId": "sp:http",
				"attributes": {
					"authenticationType": "OAuth",
					"basicAuthUserName": null,
					"jsonPatchRequestBody": {
						"autoRevokeAllowed": false,
						"correlatedStatus": "CORRELATED",
						"deadline": "2024-08-15T10:00:01.456Z",
						"description": "Mover Campaign",
						"emailNotificationEnabled": true,
						"mandatoryCommentRequirement": "REVOKE_ONLY_DECISIONS",
						"name": "Mover Campaign v7",
						"recommendationsEnabled": false,
						"searchCampaignInfo": {
							"accessConstraints": [
								{
									"operator": "ALL",
									"type": "ACCESS_PROFILE"
								}
							],
							"description": "Search Campaign description",
							"identityIds": [
								"{{$.trigger.identity.id}}"
							],
							"reviewer": {
								"id": "{{$.getIdentity.managerRef.id}}",
								"type": "IDENTITY"
							},
							"type": "IDENTITY"
						},
						"sunsetCommentsRequired": true,
						"type": "SEARCH"
					},
					"jsonRequestBody": {
						"autoRevokeAllowed": false,
						"correlatedStatus": "CORRELATED",
						"deadline": "{{$.defineVariable.deadlineMover}}",
						"description": "Mover Campaign for Roles",
						"emailNotificationEnabled": true,
						"mandatoryCommentRequirement": "REVOKE_ONLY_DECISIONS",
						"name": "Mover Campaign for Roles",
						"recommendationsEnabled": false,
						"searchCampaignInfo": {
							"accessConstraints": [
								{
									"operator": "ALL",
									"type": "ROLE"
								}
							],
							"description": "Search Campaign description",
							"identityIds": [
								"{{$.trigger.identity.id}}"
							],
							"reviewer": {
								"id": "{{$.getIdentity.managerRef.id}}",
								"type": "IDENTITY"
							},
							"type": "IDENTITY"
						},
						"sunsetCommentsRequired": true,
						"type": "SEARCH"
					},
					"method": "post",
					"oAuthClientId": "xxxxx",
					"oAuthCredentialLocation": "oAuthInHeader",
					"oAuthScope": "",
					"oAuthTokenUrl": "https://xxx.api.identitynow.com/oauth/token",
					"requestContentType": "json",
					"requestHeaders": null,
					"url": "https://xxx.api.identitynow.com/v3/campaigns",
					"urlParams": null
				},
				"description": "Generate certification campaign for new manager as certifier to verify roles.",
				"displayName": "Create role certification-old manager (2)",
				"nextStep": "Wait 3",
				"type": "action",
				"versionNumber": 2
			},
			"HTTP Request 6": {
				"actionId": "sp:http",
				"attributes": {
					"authenticationType": "OAuth",
					"basicAuthUserName": null,
					"jsonPatchRequestBody": {
						"autoRevokeAllowed": false,
						"correlatedStatus": "CORRELATED",
						"deadline": "2024-08-15T10:00:01.456Z",
						"description": "Mover Campaign",
						"emailNotificationEnabled": true,
						"mandatoryCommentRequirement": "REVOKE_ONLY_DECISIONS",
						"name": "Mover Campaign v7",
						"recommendationsEnabled": false,
						"searchCampaignInfo": {
							"accessConstraints": [
								{
									"operator": "ALL",
									"type": "ACCESS_PROFILE"
								}
							],
							"description": "Search Campaign description",
							"identityIds": [
								"{{$.trigger.identity.id}}"
							],
							"reviewer": {
								"id": "{{$.getIdentity.managerRef.id}}",
								"type": "IDENTITY"
							},
							"type": "IDENTITY"
						},
						"sunsetCommentsRequired": true,
						"type": "SEARCH"
					},
					"jsonRequestBody": {
						"autoRevokeAllowed": false,
						"correlatedStatus": "CORRELATED",
						"deadline": "{{$.defineVariable.deadlineMover}}",
						"description": "Mover Campaign for Access Profiles",
						"emailNotificationEnabled": true,
						"mandatoryCommentRequirement": "REVOKE_ONLY_DECISIONS",
						"name": "Mover Campaign for Access Profiles",
						"recommendationsEnabled": false,
						"searchCampaignInfo": {
							"accessConstraints": [
								{
									"ids": "{{$.getAccess.accessItems[?(@.name != 'NameofAC')].id}}",
									"operator": "SELECTED",
									"type": "ACCESS_PROFILE"
								}
							],
							"description": "Search Campaign description",
							"identityIds": [
								"{{$.trigger.identity.id}}"
							],
							"reviewer": {
								"id": "{{$.getIdentity1.id}}",
								"type": "IDENTITY"
							},
							"type": "IDENTITY"
						},
						"sunsetCommentsRequired": true,
						"type": "SEARCH"
					},
					"method": "post",
					"oAuthClientId": "xxx",
					"oAuthCredentialLocation": "oAuthInHeader",
					"oAuthScope": "",
					"oAuthTokenUrl": "https://xxx.api.identitynow.com/oauth/token",
					"requestContentType": "json",
					"requestHeaders": null,
					"url": "https://xxx.api.identitynow.com/v3/campaigns",
					"urlParams": null
				},
				"description": "Generate certification campaign for new manager as certifier to verify access profiles.\n\nADJUST NEW MANAGER later in body.",
				"displayName": "",
				"nextStep": "Wait 2",
				"type": "action",
				"versionNumber": 2
			},
			"Send Email 1": {
				"actionId": "sp:send-email",
				"attributes": {
					"body": "<p>Dear {{$.getIdentity1.attributes.firstname}} text</p>",
					"context": null,
					"from.$": "",
					"recipientEmailList.$": "$.getIdentity1.attributes.email",
					"replyTo.$": "",
					"subject": "Access Review required for {{$.getIdentity.attributes.firstname}} {{$.getIdentity.attributes.lastname}} after attribute change"
				},
				"description": "If the identity doesn't have a new manager we will send an email to the existing manager.",
				"displayName": "Send Email to existing Manager (2)",
				"nextStep": "HTTP Request 6",
				"type": "action",
				"versionNumber": 2
			},
			"Wait 2": {
				"actionId": "sp:sleep",
				"attributes": {
					"duration": "1m",
					"type": "waitFor"
				},
				"description": "Wait for campaign generation.",
				"displayName": "Wait 1 min. (3)",
				"nextStep": "Activate Certification Campaign 2",
				"type": "action",
				"versionNumber": 1
			},
			"Wait 3": {
				"actionId": "sp:sleep",
				"attributes": {
					"duration": "1m",
					"type": "waitFor"
				},
				"description": "Wait for campaign generation.",
				"displayName": "Wait 1 min. (4)",
				"nextStep": "Activate Certification Campaign 3",
				"type": "action",
				"versionNumber": 1
			}
		}
	},
	"creator": {
		"type": "IDENTITY",
		"id": "0000000000000000000000000",
		"name": "ff.admin"
	},
	"trigger": {
		"type": "EVENT",
		"attributes": {
			"description": "This process is triggered if the department, squad, tribe, country, cost center and/or supervisoryOrgName has changed. It triggers the mover process where the new manager gets emails and recertifications.",
			"filter.$": "$.changes[?(@.attribute == \"department\" || @.attribute == \"costCenter\" || @.attribute == \"squadId1\" || @.attribute == \"squadId2\" || @.attribute ==  \"tribeId1\"  ||  @.attribute ==  \"tribeId2\" || @.attribute == \"supervisoryOrgName\" || @.attribute == \"country\" || @.attribute == \"companyName\")]",
			"id": "idn:identity-attributes-changed"
		}
	}
}

Have you considered setting up a campaign filter and including that in the campaign creation call?

The problem is that the “Create Certification Call” is very limited because you cannot apply all the criteria. E. g. you can say the reviewer type is individual and select the mover’s manager as the specific reviewer as in the screenshot below, but then you need to select “Identity Certification”, because if you select "Access Certification you cannot select that only this one mover identity shall be certified.



Or if you select “Manager” as reviewer Type, it would affect all the managers. There is no option to specify the manager then nor the person that shall be certified.

Therefore I did it with an HTTP request as described above. And in this API (create-campaign | SailPoint Developer Community) I chose the searchCampaignInfo, because here I can specify it all, but somehow the accessconstraints is not working as it should, eventhough it is correct with the evaluator. The same issue appears when I try to define a variable with the content $.getAccess.accessItems[?(@.name != ‘NameofAC’)].id It evaluates this in the input correctly, but then it fails with the failure message as seen below. I think this is because an array cannot be saved in a variable.(Workflow: Define Variable json: cannot unmarshal string into Go struct field MutativeOperatorInput.variables of type definition.Variables - #3 by mbo11)


There is also a campaign filter option in this API call, but it cannot be combined with the searchCampaignInfo I have also tried that, but I need to use the searchCampaignInfo, otherwise I cannot specify that only this mover user shall be certified by this specific manager.

With kind regards

Fabienne

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