I am using IdentityIQ version 8.4 and working on the expiration of work items after a defined period of time as part of the access request approval process.
When the Check Workitem Expired task runs (return null), provisioning does not occur, but the workitem status shows completed and success (green), even though the status=“expired”.
I’ve worked on this use-case recently, configured the escalation rule in the Provisioning Approval Subprocess workflow like below:
<Variable initializer="Test-Rule-Escalation" input="true" name="workItemEscalationRule">
<Description>The rule used to assign a new ownder during escalation.</Description>
</Variable>
The rule used to assign a new ownder during escalation.
Below is my escalation rule:
import java.util.List;
If in understand your requirement correctly, you should explicitly update the IdentityRequest status inside the Expiring WorkItem step so the request is marked as Rejected or Expired .
just add few line of the code to mark it rejected or expired.
In our configuration, we have set up two reminder notifications to be sent every three days. This means the first reminder is issued on the 3rd day (72 hours) after the work item is created, and the second reminder is sent on the 6th day (144 hours). Then, on the 9th day, our escalation rule is triggered, which expires the work item. We are not reassigning ownership at any point, as reflected in the code sample I shared earlier.
If your requirement is different, please share the exact requirement details
Hi @helanprates1 you have to add this transition in approval step
<Transition to="end" when="script:("Expired".equals(workflow.get("lastApprovalState")))"/>
or
<Transition to="end" when="script:lastApprovalState.equals("Expired")"/>
and in finalize step, you have to update the IR with state Expired when lastApprovalState = Expired. lastApprovalState you will get from wfcontext. let me know if you have any issue.
Exactly that! The work item is expiring as scheduled, but in the interface it appears as completed and successful (green). The user who requested the item might think that access was granted. Therefore, I would like the work item to expire and appear in the interface as rejected or canceled - Expired after 10 days without approval (red).
Can you help me with this code within the Expiring WorkItem step?
if ("Expired".equalsIgnoreCase(lastApprovalState)) {
IdentityRequest ir = context.getObjectById(IdentityRequest.class, irId);
if (ir == null) {
log.error("Finalize: IR not found for id=" + irId); return;
}
// Set the custom state
ir.setState("end - Expired");
context.saveObject(ir);
context.commitTransaction();
}
Looking like your use case requires one more approval. Instead of writing the access request status explicitly, add one more approval for the manual work item team queue, since they are not taking any action, or they can accept or reject at the approval level. Once they approve it, it will generate the manual work item, and they can close the ticket as soon as it is approved. If rejected or expired approvals , it will show at the access request level.
@helanprates1 You can add above snippet in Identity Request Finalize. This is last second step in LCM and by this time, LCM already processed the identity request or other audits. Adding it in subprocess, may get overridden in subsequent steps.
Hello everyone, I was involved in other tasks and was away for a few days. Nothing has been changed in the proposed code. Please check if I did the right thing.
</Approval>
<Transition to="Expiring WorkItem" when="script:("Expired".equals(lastApprovalState))"/>
<Transition to="Process Approval Decisions" when="script:(!"Expired".equals(workflow.get("lastApprovalState")) && step.getApproval() != null && step.getApproval().containsApprovalItems())"/>
<Transition to="end"/>
</Step>
<Step name="Expiring WorkItem" posX="240" posY="171">
<Script>
<Source>
import sailpoint.object.ApprovalSet;
import sailpoint.object.ApprovalItem;
import sailpoint.object.WorkItem;
import org.apache.log4j.Logger;
Logger log = Logger.getLogger("sailpoint.workflow.expiry");
log.error("EXPIRY CHECK: Marking all approval items as Rejected due to expiration");
if (approvalSet != null) {
List items = approvalSet.getItems();
if (items != null) {
for (ApprovalItem item : items) {
item.setState(WorkItem.State.Rejected);
if (item.getApproverComments() == null) {
item.setApproverComments("Auto-rejected: Work item expired");
}
log.error("EXPIRY CHECK: Rejected item - " + item.getValue());
}
}
}
if ("Expired".equalsIgnoreCase(lastApprovalState)) {
IdentityRequest ir = context.getObjectById(IdentityRequest.class, irId);
if (ir == null) {
log.error("Finalize: IR not found for id=" + irId); return;
}
// Set the custom state
ir.setState("end - Expired");
context.saveObject(ir);
context.commitTransaction();
}
// Also clear the project/plan to prevent provisioning
project = null;
plan = null;
</Source>
</Script>
<Transition to="end"/>
</Step>
IdentityRequest ir = context.getObjectById(IdentityRequest.class, irId);
List items = ir.getItems();
for(IdentityRequestItem item : items) {
item.setApprovalState(WorkItem.state.Expired);
item.setProvisioningState(ApprovalItem.ProvisioningState.Failed);
}
ir.setItems(items);
}
ir.setExecutionStatus(IdentityRequest.ExecutionStatus.Terminated);
ir.setCompletionStatus(IdentityRequest.CompletionStattus.Failure);
ir.setState("End - Expired");
ir.setDate(date); // Date date - defined before use
context.saveObject(ir);
context.commitTransation();
Hi @helanprates1 Check the transition to see if the work item is expired. if it is expried It ends with the error message in the access request, which is why you don’t need to set the access request status programmatically. Similar implementation. Here is the link: please follow it and let me know if you have any questions. Manual Task Work Item - Closed Inccomplete/Rejected - #5 by Peddapolu
Good afternoon! I noticed that I deleted the Expiring step and the behavior was the same, so the flow is probably not entering the expiring step, staying only in the afterScript.
<Step icon="Approval" name="Approval" posX="158" posY="22">
<Approval mode="ref:approvalMode" owner="call:buildCommonApprovals" renderer="lcmWorkItemRenderer.xhtml" send="identityDisplayName,identityName,approvalSet,flow,policyViolations,identityRequestId">
<AfterScript>
<Source>
import sailpoint.workflow.IdentityRequestLibrary;
import sailpoint.object.WorkItem;
import sailpoint.object.ApprovalSet;
import sailpoint.object.ApprovalItem;
if (item == null) return;
if (WorkItem.State.Expired.equals(item.getState())) {
if (approvalSet != null) {
approvalSet.reject();
List items = approvalSet.getItems();
if (items != null) {
for (ApprovalItem aItem : items) {
aItem.setState(WorkItem.State.Rejected);
}
}
item.setCompletionComments("Expirado automaticamente após timeout sem resposta.");
}
workflow.put("lastApprovalState", "Expired");
}
assimilateWorkItemApprovalSet(wfcontext, item, approvalSet);
auditDecisions(item);
IdentityRequestLibrary.assimilateWorkItemApprovalSetToIdentityRequest(wfcontext, approvalSet);
</Source>
</AfterScript>