fionali
(Fiona Li)
January 16, 2025, 8:24am
1
Which IIQ version are you inquiring about?
8.4
Please share any images or screenshots, if relevant.
We are developing custom rule to check for policy violation for preventive and detective access requests. We observed that when raising access request, it will randomly throw this error for some identities, but some identities will not and runs through the custom rule successfully. Anyone face this error before?
Arpitha1
(Arpitha Halaguru Kunne Gowda)
January 16, 2025, 8:48am
2
Can you share your rule xml ?
fionali
(Fiona Li)
January 16, 2025, 8:55am
3
<Source>import sailpoint.object.Identity;
import sailpoint.object.ManagedAttribute;
import sailpoint.object.IdentityEntitlement;
import sailpoint.object.Filter;
import sailpoint.object.QueryOptions;
import sailpoint.object.PolicyViolation;
import sailpoint.object.Custom;
import sailpoint.tools.Util;
import sailpoint.object.Bundle;
import sailpoint.object.Application;
import sailpoint.object.Link;
import sailpoint.object.Entitlement;
import sailpoint.object.ManagedAttribute;
import sailpoint.object.IdentitySelector;
import sailpoint.object.IdentitySelector.MatchExpression;
import sailpoint.object.IdentitySelector.MatchTerm;
import sailpoint.object.Policy;
import sailpoint.object.GenericConstraint;
import sailpoint.object.WorkItem;
import sailpoint.object.WorkItemArchive;
import sailpoint.object.Attributes;
import sailpoint.object.ApprovalSet;
import sailpoint.persistence.Sequencer;
import sailpoint.object.ApprovalItem;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
import java.util.Calendar;
import java.util.Date;
import sailpoint.api.SailPointContext;
WorkItem w = null;
PolicyViolation violation = null;
boolean isPreventive = false;
boolean isDetective = false;
String violationDescription = "";
Locale locale = new Locale("en", "US");
//End state of the identity if the identity request is approved
Identity optIdentity = identity;
//Get current state of identity
Identity dbIdentity = context.getObjectByName(Identity.class, identity.getName());
String attrValue = optIdentity.getAttribute("worker_id");
List relativeEmpID = optIdentity.getAttribute("relative");
List optidenEntList = new ArrayList();
List optidenEntListToComp = new ArrayList();
List dbidenEntList = new ArrayList();
List dbtidenEntListToComp = new ArrayList();
//Get list of relatives
HashSet relatedIdentitySet = new HashSet();
HashSet relativeEntitlementSet = new HashSet();
HashSet relativeEntitlementSetToComp = new HashSet();
//Get list of accounts to prepare for getting entitlements
List optappLinks = optIdentity.getLinks();
List dbappLinks = dbIdentity.getLinks();
List<String> optentitlementToCompare = new ArrayList();
List<String> dbentitlementToCompare = new ArrayList();
List<String> optentitlementInConflict = new ArrayList();
List<String> dbentitlementInConflict = new ArrayList();
List getIdentityEntitlements(Identity identity)
{
//creating the entitlement list
List identityEntList = new ArrayList();
List appLinks = identity.getLinks();
if(appLinks!=null && appLinks.size()>0)
{
for(Link applink : appLinks)
{
String appName = applink.getApplicationName();
Application application = context.getObjectByName(Application.class, appName);
List appAccLinks = identity.getLinks(application);
//check for the entitlements in the same app accounts
if(appAccLinks!=null && appAccLinks.size()>0)
{
for(Link appAccLink : appAccLinks)
{
List entitlementList = appAccLink.getEntitlements(locale, null);
if(entitlementList!=null && entitlementList.size()>0)
{
for(Entitlement entitlement: entitlementList)
{
//check if entitlement contains Lvl-
if(entitlement.getAttributeValue().startsWith("cn=Lvl-")){
//log.error("Entitlement exists in account: " + entitlement.getAttributeValue());
//add the identity name, app name and entitlement into the entitlement list
identityEntList.add(identity.getName() + "|" +appName+"|"+entitlement.getAttributeValue());
}
}
}
}
}
}
}
return identityEntList;
}
List getIdentityEntitlementsToComp(Identity identity)
{
//creating the entitlement list
List identityEntList = new ArrayList();
List appLinks = identity.getLinks();
if(appLinks!=null && appLinks.size()>0)
{
for(Link applink : appLinks)
{
String appName = applink.getApplicationName();
Application application = context.getObjectByName(Application.class, appName);
List appAccLinks = identity.getLinks(application);
//check for the entitlements in the same app accounts
if(appAccLinks!=null && appAccLinks.size()>0)
{
for(Link appAccLink : appAccLinks)
{
List entitlementList = appAccLink.getEntitlements(locale, null);
if(entitlementList!=null && entitlementList.size()>0)
{
for(Entitlement entitlement: entitlementList)
{
//check if entitlement contains Lvl-
if(entitlement.getAttributeValue().startsWith("cn=Lvl-")){
//log.error("Entitlement exists in account: " + entitlement.getAttributeValue());
//add the identity name, app name and entitlement into the entitlement list
identityEntList.add(appName+"|"+entitlement.getAttributeValue());
}
}
}
}
}
}
}
return identityEntList;
}
List checkAppAccEnt(List list1, List list2) {
//Iterator<String> iterator = list1.iterator();
List<String> result = new ArrayList();
for (String item1 : list1) {
String[] parts1 = item1.split("\\|");
if (parts1.length < 3) continue;
String secondEntry = parts1[1];
boolean found = false;
boolean hasLvl = false;
for (String item2 : list2) {
if (item2.contains("|" + secondEntry + "|")) {
found = true;
if (item2.contains("cn=Lvl-")) {
hasLvl = true;
break;
}
}
}
if (found && hasLvl) {
result.add(item1);
}
}
return result;
}
void getRelativeDetails()
{
if(relativeEmpID!=null && relativeEmpID.size()>0)
{
for(String empId : relativeEmpID)
{
Filter empFilter = Filter.eq("worker_id",empId);
QueryOptions empQO = new QueryOptions();
empQO.add(empFilter);
//get relative identity
List relativeIdentityList = context.getObjects(Identity.class,empQO);
//add relative into Hashset
if(relativeIdentityList!=null && relativeIdentityList.size()>0)
{
Identity relativeIdentity = relativeIdentityList.get(0);
relatedIdentitySet.add(relativeIdentity.getName());
}
}
}
//log.error(relatedIdentitySet);
}
void getRelativeEntitlements()
{
if(relatedIdentitySet !=null && relatedIdentitySet.size()>0)
{
for(String relativeIdentityName : relatedIdentitySet)
{
Identity relativeIdentity = context.getObjectByName(Identity.class,relativeIdentityName);
if(relativeIdentity!=null)
{
List relativeIdenEntList = getIdentityEntitlements(relativeIdentity);
List relativeIdenEntListToComp = getIdentityEntitlementsToComp(relativeIdentity);
if(relativeIdenEntList!=null && relativeIdenEntList.size()>0)
{
//add the relative entitlement list into hashset
relativeEntitlementSet.addAll(relativeIdenEntList);
relativeEntitlementSetToComp.addAll(relativeIdenEntListToComp);
}
}
}
}
//log.error("Relative entry: " + relativeEntitlementSet);
//log.error("Relative entry to compare: " + relativeEntitlementSetToComp);
}
void createViolation()
{
violation = new PolicyViolation();
violation.setActive(true);
violation.setIdentity(identity);
violation.setPolicy(policy);
violation.setConstraint(constraint);
violation.setStatus(sailpoint.object.PolicyViolation.Status.Open);
violation.setOwner(policy.getViolationOwner());
violation.setDescription(violationDescription);
context.startTransaction();
context.saveObject(v);
context.commitTransaction();
}
void createWorkItem()
{
log.error("Create work item for Lvl combination");
Calendar expiration = Calendar.getInstance();
w = new WorkItem();
w.setType(WorkItem.Type.ManualAction);
w.setOwner(identity.getManager());
w.setRequester("spadmin");
Sequencer sequencer = new Sequencer();
w.setName(sequencer.generateId(context, w));
w.setRenderer("lcmManualActionsRenderer.xhtml");
w.setLevel(WorkItem.Level.Normal);
w.setTarget(identity);
w.setTargetClass(Identity.class.getName());
w.setDescription("Policy Violation WorkItem - Policy for "+optIdentity.getDisplayName());
w.setHandler("sailpoint.api.Workflower");
Attributes attributes = new Attributes();
w.setAttributes(attributes);
int index = 0;
ApprovalSet approvalSet = new ApprovalSet();
for(String value : dbentitlementInConflict) {
// Split the string by the pipe character '|'
String[] parts = value.split("\\|");
// The second part (index 1) contains the desired information
String result = parts[1];
ApprovalItem approvalItem = new ApprovalItem();
approvalItem.setApplication(result);
approvalItem.setNativeIdentity(identity.getName());
approvalItem.setOperation("Remove");
approvalItem.setValue(value);
//String relatedIdentityString = relatedIdentitySet.isEmpty() ? "" : relatedIdentitySet.iterator().next();
//Identity relatedIdentity = context.getObjectByName(Identity.class,relatedIdentityString);
//String managerName = relatedIdentity.getManager().getName();
approvalItem.setRequesterComments("Please liaise with " + identity.getName() + " to evaluate on the conflicting roles and remove accordingly.");
approvalSet.add(approvalItem);
}
attributes.put("approvalSet", approvalSet);
attributes.put("identityDisplayName", identity.getDisplayName());
attributes.put("identityName", identity.getName());
w.setExpiration(expiration.getTime());
context.startTransaction();
context.saveObject(w);
context.commitTransaction();
}
if (dbIdentity == null) {
log.error("dbIdentity not found for name: " + identity.getName());
}
if(optIdentity!=null){
//getRelativeDetails();
//getRelativeEntitlements();
//Check 1st condition. Check if user has Lvl roles, if have create violation
if(optappLinks != null && !optappLinks.isEmpty() && dbappLinks != null && !dbappLinks.isEmpty()) {
//get raised entitlement
//log.error(optIdentity.getName());
optidenEntList = getIdentityEntitlements(optIdentity);
optidenEntListToComp = getIdentityEntitlementsToComp(optIdentity);
//get initial entitlements
//log.error(dbIdentity.getName());
dbidenEntList = getIdentityEntitlements(dbIdentity);
dbidenEntListToComp = getIdentityEntitlementsToComp(dbIdentity);
}
//comparing raised and initial entitlements, if the initial list is not empty
if (optidenEntList!=null && !optidenEntList.isEmpty() && dbidenEntList!=null && !dbidenEntList.isEmpty()){
optentitlementToCompare.addAll(optidenEntListToComp);
dbentitlementToCompare.addAll(dbidenEntListToComp);
optentitlementInConflict.addAll(optidenEntList);
optentitlementInConflict.removeAll(dbidenEntList);
log.error("Get final entitlement list: " + optidenEntList);
log.error("Get original entitlement list: " + dbidenEntList);
log.error("Get added entitlement list after comparing: " + optentitlementInConflict);
optentitlementInConflict = checkAppAccEnt (optentitlementInConflict, dbidenEntList);
}
//Preventive Check 1 if self conflicting, user raising for more than 1 Lvl roles
if (!isDetective){
if (optentitlementInConflict.size() > 0){
log.error("Is self conflicting");
log.error(optentitlementInConflict.size());
isPreventive = true;
violationDescription = "User not allowed to have more than 1 Lvl roles listed.";
}
}
if (!isPreventive){
//Detective Check 1 if self conflicting, user has more than 1 Lvl roles
for(Link appLink : dbappLinks) {
String appName = appLink.getApplicationName();
Application application = context.getObjectByName(Application.class, appName);
List dbAccs = dbIdentity.getLinks(application);
for(Link dbAcc : dbAccs) {
List<String> dbEntitlementList = dbAcc.getEntitlements(locale, null);
int detectiveCount = 0;
for(dbEntitlement: dbEntitlementList){
if(dbEntitlement.getAttributeValue().startsWith("cn=Lvl-")){
dbentitlementInConflict.add(appName+"|"+appLink.getDisplayName()+"|"+dbEntitlement.getAttributeValue());
detectiveCount++;
//log.error("Increasing Counter" + detectiveCount);
}
//check if that account have more than 1 conflicting entitlements
if(detectiveCount >= 2){
log.error("Account have more than one Lvl role, count: " +detectiveCount);
isDetective = true;
violationDescription = "User has conflicting Lvl roles.";
break;
}
}
if (isDetective){
//log.error("Is self detective violation");
break;
}
}
if (isDetective){
//log.error("Is self detective violation");
break;
}
}
}
}
if(isDetective){
log.error("Created detective policy violation");
Filter empFilter = Filter.eq("identity",identity);
Filter empFilter1 = Filter.eq("policyName","Combo 1 Policy Advanced");
Filter empFilter2 = Filter.eq("active",true);
QueryOptions empQO = new QueryOptions();
empQO.add(empFilter);
empQO.add(empFilter1);
empQO.add(empFilter2);
List<PolicyViolation> existingPolicyViolation = context.getObjects(PolicyViolation.class,empQO);
//return existingPolicyViolation;
if(existingPolicyViolation==null || existingPolicyViolation.isEmpty()){
log.error("Creating policy work item");
createWorkItem();
violationDescription = "Full Name:" + identity.getAttribute("full_name")
+ "||Email:" + identity.getAttribute("email")
+ "||Policy Violated:Combo 1 Policy Advanced"
+ "||Rule Name: Lvl rule"
+ "||Entitlement Affected:" + dbentitlementInConflict
+ "||Relative Full Name:" + "NA"
+ "||Relative Email:" + "NA"
+ "||WorkItem ID:" + w.getName()
+ "||Relative Entitlement Affected:" +"NA"
+ "||Date Created:"
+ "||Violation Owner:" + identity.getManager().getName();
createViolation();
}
else{
log.error("Existing policy violation");
PolicyViolation v = existingPolicyViolation.get(0);
String violationDescription = v.getDescription();
String workitemName = "";
String[] info = violationDescription.split("\\|\\|");
for (String i : info) {
if (i.startsWith("WorkItem ID")) {
String result = i.substring("WorkItem ID:".length());
log.error("workitem id "+result);
workitemName=result;
}
}
//log.error("Workitem Name is "+workitemName);
WorkItemArchive wiArchive = context.getObjectByName(WorkItemArchive.class,workitemName);
if(wiArchive!=null){
List comments = wiArchive.getComments();
log.error("comments "+comments);
Date date = wiArchive.getArchived();
log.error("date "+date);
violationDescription = violationDescription + "||Date Completed:" + date + "||Status:" + comments;
}
v.setDescription(violationDescription);//set workitem description
context.startTransaction();
context.saveObject(v);
context.commitTransaction();
return v;
}
}
if (isPreventive){
log.error("is preventive");
createViolation();
log.error("Created preventive policy violation");
}
//context.decache(identity);
return violation;
</Source>
Arpitha1
(Arpitha Halaguru Kunne Gowda)
January 16, 2025, 9:06am
4
Can you replace Filter empFilter = Filter.eq("identity",identity);
with Filter empFilter = Filter.eq("identity.name",identity.getName());
On another note, you can use identity
directly instead of iniatializing with optIdentity
. Try this, just in case the problem is not resolved even after changing the Filter.
fionali
(Fiona Li)
January 16, 2025, 9:25am
5
Have tried the filter and also used identity instead of optIdentity but still having same error…
Arpitha1
(Arpitha Halaguru Kunne Gowda)
January 16, 2025, 9:28am
6
Have you replaced the empFilter and tried ?
fionali
(Fiona Li)
January 16, 2025, 9:34am
7
Yes have replaced the empFilter, but still having same error
Arpitha1
(Arpitha Halaguru Kunne Gowda)
January 16, 2025, 9:44am
8
Can you get logs and share to us.
@fionali some obervation:-
Use workflower class to close workitem or expiry workitem
w.setExpiration(expiration.getTime());
context.startTransaction();
context.saveObject(w);
context.commitTransaction();
No need to do start and stop transition
context.startTransaction();
You can save all then commit at once also.
fionali
(Fiona Li)
January 17, 2025, 3:56am
10
Hi Kumar, Noted on the suggestion. But the error is throwing when raising access request, so it does not go into creating the workitem.
Have added additional logging in between, noticed error is thrown before context.commitTransaction(). Why is it not able to commit?
Arpitha1
(Arpitha Halaguru Kunne Gowda)
January 17, 2025, 4:28am
11
Hi @fionali
Policy Violation would execute twice. To troubleshoot, you can add loggers before and after saving objects. This will help us identify the specific block where the error is occurring by examining the logs
fionali
(Fiona Li)
January 17, 2025, 5:44am
12
Would you advise if is because of the logic wrote for preventive and detective is incorrect approach?
The expected is that the identity is not allowed to raise for more than one group starting with Lvl-, and during the Check Active Policies should detect if there are any existing violations for identities having more than one group of Lvl-.
hi @fionali your code need to be more simple then i dont think u need this much code. I belive you are saving policy violation and commiting that also wrong. So you can simply remove the context.save and commit for policy violation as well
if(validateIdentityEnt(identity)){
PolicyViolation pv = new PolicyViolation();
pv.setActive(true);
pv.setIdentity(identity);
pv.setPolicy(policy);
//pv.setConstraint (constraint);
pv.setDescription(“your desciprtion”);
pv.setStatus(sailpoint.object.PolicyViolation.Status.Open);
return pv;
}else{
return false;
}
system
(system)
Closed
March 18, 2025, 7:54am
14
This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.