Sunday, July 2, 2023

Developer Best Practices

 Use independent libraries and workflows:

• Write code consistent with best practices

Use independent libraries and workflows:

The best way to avoid issues introduced into common code changes up to the extent possible, instead of introducing your changes directly into a common code source (such as BPK workflow library, BPK Rule library) try to create independent code libraries and sub-process and reference them in common code

Write code consistent with best practices

• Code quality is particularly important because there is a good chance to someone in the future will need to understand it without prior context. Here are some high-level guidelines:

• Follow standard Java conventions and standards

• Use proper indentation

• Comment your code thoroughly

A good rule of thumb is to give high-level comments on what each code block is doing and then comment on anything unusual that you do.

• Write code that is clear and easy to understand

Write your code in a way that is easy to follow logically and consistent with the way you are writing it.

• Keep code performance efficient

• Create or update existing documentation where appropriate

• The code should be reviewed by the team and keep the proper logs statements.


Developer Best Practices:

1. Use proper naming conversation for all variable declarations.

eg: 'Identity idnRequester' or 'int intIdentityCount'.

2. Any connection objects (e.g., database, File, server) must be closed in the final block.

try{

conn= DriverManager.getConnection("");

}

catch(SQLException ex){

handle the exception or throw as a general exception

}

finally{

try{

if(conn !=null){

conn.close();

}

}catch(){

}

}

3. while throwing the exception, wrap with GeneralException along with information causing an exception.

ex: catch(){

throw new GeneralException("occurred while loading the entitlement data",e);

}

4. Don't log for throwing the exception in the catch block, it results in duplicate logs in the log file for the same exception.

ex: catch(illegalArgumentException e){

//log.error(e); do not do this

throw new GeneralException("occurred while loading the entitlement data",e);

}

5. Always check for the Null object while accessing any object.

ex: Identity id= context.getObjectByName(Identity.class,"test");

if( null ==id){

log.error("no identity found);

return ;

}

6. Check for void if you are accessing out of boxes variables in any rules, workflows forms, etc.

7. Check for object instances if you need more clarification on the run time object.( instanceof List or instanceof String).

8. Try to avoid logic in workflow steps, call as a method from a rule.

9. Try to avoid saving complete objects in workflow parameters until it is really required.

10. Make sure while deploying the code in production the trace parameter is set to false.

11. Do not print complete objects as info or error. do it in debug.

12. Be a practice of using separate logger objects for each rule.

eg: Logger log= Logger.getLogger("");

13. Always use context.search with specific columns while loading data.

14. Avoid using IIQ objects as variable names.

15. Flush the iterator once it is done with the logic. This will release the cursor object related to the database.

ex: Util.flushIterator(itername);


16. Decache the loaded objects once done with the operation.

context.decache(obj name);

17. Default imports for bean shells. Do not add imports explicitly.

java.net.*;

java.lang.*;

java.util.*;


18. Do not print passwords in logs, put password generation in before the provisioning rule and try to implement encrypt mechanism.

19.Do not log any "sailpoint object data "(Ex.log.debug(plan.toXml()), log.debug(project.toXml()).

20. Do not log any authentication token at any level.

21. If you are referring to any rule in your new rule, refer to all the rules references of the parent rule as well.

Saturday, May 27, 2023

Saturday, April 1, 2023

Identity Blog URL:-

https://community.sailpoint.com/t5/IdentityIQ-Blog/bg-p/IIQ_blog

EFix URL:-

#

https://community.sailpoint.com/t5/IdentityIQ-Blog/IdentityIQ-log4j-Remote-Code-Execution-Vulnerability/ba-p/206681?elq=46e7bafd65ca4860965690f2a5d3da35&elqCampaignId=4118&elqTrackId=757e1b94243c4dbc97f78764f0daecff&elqaid=5155&elqat=1&utm_medium=email&utm_source=Eloqua

#

https://community.sailpoint.com/t5/IdentityIQ-Blog/Identity-Forwarding-Vulnerability/ba-p/226246

#

https://community.sailpoint.com/t5/IdentityIQ-Blog/IdentityIQ-JavaServer-Faces-File-Path-Traversal-Vulnerability/ba-p/227148


Thursday, February 9, 2023

Report for tasks and scheduled or not including those tasks present in sequential tasks.

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE TaskDefinition PUBLIC "sailpoint.dtd" "sailpoint.dtd">

<TaskDefinition executor="sailpoint.reporting.LiveReportExecutor" name="TaskDefSch-Report" progressMode="Percentage" resultAction="Rename" subType="Role Management Reports" template="true" type="LiveReport">

<Attributes>

<Map>

<entry key="TaskDefinition.runLengthAverage" value="422"/>

<entry key="TaskDefinition.runLengthTotal" value="422"/>

<entry key="TaskDefinition.runs" value="1"/>

<entry key="report">

<value>

<LiveReport title="Task Result Report">

<DataSource objectType="TaskDefinition" type="Filter">

<QueryParameters>

<Parameter argument="type" property="type">

<QueryScript>

<Source>

import sailpoint.object.Filter;

import sailpoint.tools.Util;


List allowedTypes = new ArrayList();

allowedTypes.add("AccountAggregation");

allowedTypes.add("AccountGroupAggregation");


queryOptions.addFilter(Filter.in("type", allowedTypes));

queryOptions.addFilter(Filter.notnull("parent"));

return queryOptions;

</Source>

</QueryScript>

</Parameter>

</QueryParameters>

</DataSource>

<Columns>

<ReportColumnConfig field="taskName" header="Task Name" property="name" sortable="true" width="110"/>

<ReportColumnConfig field="taskType" header="Task Type" property="type" sortable="true" width="110"/>

<ReportColumnConfig field="appName" header="Application Name" property="name" sortable="true" width="110">

<RenderScript>

<Source>

import sailpoint.object.TaskDefinition;


TaskDefinition taskDef = context.getObjectByName(TaskDefinition.class, value);

if(taskDef != null &amp;&amp; null != taskDef.getArguments() &amp;&amp; null!= taskDef.getArguments().get("applications")){

return taskDef.getArguments().get("applications");

}

else

return "";

</Source>

</RenderScript>

</ReportColumnConfig>

<ReportColumnConfig field="isSchedule" header="Is Sheduled" property="name" sortable="true" width="110">

<RenderScript>

<Source>

import sailpoint.object.TaskDefinition;

import sailpoint.object.TaskDefinition;

import sailpoint.object.TaskSchedule;

import sailpoint.object.QueryOptions;

import sailpoint.object.Attributes;

import sailpoint.object.Filter;

import sailpoint.api.IncrementalObjectIterator;

import java.util.List;

import java.util.ArayList;

import java.util.Set;


public static String isPresentInSchlTasks(String taskIdParam)

{

//log.error("Entered into the method isPresentInSchlTasks() ");

try{

QueryOptions qo = new QueryOptions();


IncrementalObjectIterator taskSchedule = new IncrementalObjectIterator(context, TaskSchedule.class, qo);

String returnStmt = "notscheduled";

while (taskSchedule.hasNext()) {

TaskSchedule taskScheduleObject = (TaskSchedule) taskSchedule.next();

if(taskScheduleObject.getArguments().get("executor").contains(taskIdParam))

{

returnStmt = "scheduled";

break;

}

}

return returnStmt;

}

catch (Exception e)

{

return e.getMessage();

}

}


public static String checkInSeqSchExe(String taskNameParam)

{

try{

Filter f = Filter.like("formPath","sequentialTask");

QueryOptions qo = new QueryOptions();

qo.add(f);


IncrementalObjectIterator taskDefSeq = new IncrementalObjectIterator(context, TaskDefinition.class, qo);

String returnValue = "No";

while (taskDefSeq.hasNext()) {

TaskDefinition taskDefSeqObject = (TaskDefinition) taskDefSeq.next();

String taskName = taskDefSeqObject.getName();

String taskId = taskDefSeqObject.getId();

if(taskDefSeqObject.getArgument("taskList")!=null &amp;&amp; taskDefSeqObject.getArgument("taskList").contains(taskNameParam))

{

returnValue = isPresentInSchlTasks(taskId);

break;

}

}

return returnValue;

}

catch (Exception e)

{

return e.getMessage();

}

}


try{


//log.error("value task: "+value);


TaskDefinition taskDef = context.getObjectByName(TaskDefinition.class, value);

String taskId = taskDef.getId();

String taskName = taskDef.getName();

if(taskDef != null &amp;&amp; null != taskId)

{

String isPresented = isPresentInSchlTasks(taskId);

if("scheduled".equalsIgnoreCase(isPresented))

{

return "Yes";

}

else if("notscheduled".equalsIgnoreCase(isPresented))

{

String result = checkInSeqSchExe(taskName);

if("scheduled".equalsIgnoreCase(result))

{

return "Yes";

}

else

{

return "No";

}

}

}

else

return null;

}

catch(Exception e){

return e.getMessage();

}

</Source>

</RenderScript>

</ReportColumnConfig>

<ReportColumnConfig field="executeTime" header="Execution Time" property="name" sortable="true" width="110">

<RenderScript>

<Source>

import sailpoint.object.QueryOptions;

import sailpoint.object.Filter;

import sailpoint.object.TaskDefinition;

import sailpoint.object.TaskSchedule;

import sailpoint.object.Attributes;

import sailpoint.api.IncrementalObjectIterator;

import java.util.List;

import java.util.ArayList;



public static String isPresentInSchlTasks(String taskIdParam)

{

try{

QueryOptions qo = new QueryOptions();

IncrementalObjectIterator taskSchedule = new IncrementalObjectIterator(context, TaskSchedule.class, qo);

String returnStmt = "NA";


while (taskSchedule.hasNext()) {

TaskSchedule taskScheduleObject = (TaskSchedule) taskSchedule.next();

//log.error("Inside the while loop ");

if(taskScheduleObject.getArguments().get("executor").equalsIgnoreCase(taskIdParam) &amp;&amp; null != taskScheduleObject.getNextExecution())

{

returnStmt = taskScheduleObject.getNextExecution().toString();

break;

}

}

return returnStmt;

}

catch (Exception e)

{

return e.getMessage();

}

}


public static String checkInSeqSchExe(String taskNameParam)

{

try{

Filter f = Filter.like("formPath","sequentialTask");

QueryOptions qo = new QueryOptions();

qo.add(f);


IncrementalObjectIterator taskDefSeq = new IncrementalObjectIterator(context, TaskDefinition.class, qo);

String returnValue = "NA";

while (taskDefSeq.hasNext()) {

TaskDefinition taskDefSeqObject = (TaskDefinition) taskDefSeq.next();

String taskName = taskDefSeqObject.getName();

String taskId = taskDefSeqObject.getId();

if(taskDefSeqObject.getArgument("taskList")!=null &amp;&amp; taskDefSeqObject.getArgument("taskList").contains(taskNameParam))

{

returnValue = isPresentInSchlTasks(taskId);

break;

}

}

return returnValue;

}

catch (Exception e)

{

return e.getMessage();

}

}


try{


TaskDefinition taskDef = context.getObjectByName(TaskDefinition.class, value);

String taskId = taskDef.getId();

String taskName = taskDef.getName();

if(taskDef != null &amp;&amp; null != taskId)

{

String exeTime = isPresentInSchlTasks(taskId);

if(exeTime!=null &amp;&amp; !"NA".equalsIgnoreCase(exeTime))

{

return exeTime;

}

else

{

String exeTime2 = checkInSeqSchExe(taskName);

if(exeTime2!=null &amp;&amp; !"NA".equalsIgnoreCase(exeTime2))

{

return exeTime2;

}

else

{

return "NA";

}

}

}

else

return null;

}

catch(Exception e){

return e.getMessage();

}

</Source>

</RenderScript>

</ReportColumnConfig>

<ReportColumnConfig field="executeFrequency" header="Execution Frequency" property="name" sortable="true" width="110">

<RenderScript>

<Source>

import sailpoint.object.QueryOptions;

import sailpoint.object.Filter;

import sailpoint.object.TaskDefinition;

import sailpoint.object.TaskSchedule;

import sailpoint.object.Attributes;

import sailpoint.api.IncrementalObjectIterator;

import java.util.List;

import java.util.ArayList;



public static long isPresentInSchlTasks(String taskIdParam)

{

try{

QueryOptions qo = new QueryOptions();

IncrementalObjectIterator taskSchedule = new IncrementalObjectIterator(context, TaskSchedule.class, qo);

long returnStmt = 0L;


while (taskSchedule.hasNext()) {

TaskSchedule taskScheduleObject = (TaskSchedule) taskSchedule.next();

if(taskScheduleObject.getArguments().get("executor").equalsIgnoreCase(taskIdParam) &amp;&amp; null != taskScheduleObject.getNextExecution() &amp;&amp; null != taskScheduleObject.getLastExecution())

{

returnStmt = (taskScheduleObject.getNextExecution().getTime())-(taskScheduleObject.getLastExecution().getTime());

break;

}

}

return returnStmt;

}

catch (Exception e)

{

return e.getMessage();

}

}


public static long checkInSeqSchExe(String taskNameParam)

{

try{

Filter f = Filter.like("formPath","sequentialTask");

QueryOptions qo = new QueryOptions();

qo.add(f);


IncrementalObjectIterator taskDefSeq = new IncrementalObjectIterator(context, TaskDefinition.class, qo);

long returnValue = 0L;

while (taskDefSeq.hasNext()) {

TaskDefinition taskDefSeqObject = (TaskDefinition) taskDefSeq.next();

String taskName = taskDefSeqObject.getName();

String taskId = taskDefSeqObject.getId();

if(taskDefSeqObject.getArgument("taskList")!=null &amp;&amp; taskDefSeqObject.getArgument("taskList").contains(taskNameParam))

{

returnValue = isPresentInSchlTasks(taskId);

break;

}

}

return returnValue;

}

catch (Exception e)

{

return e.getMessage();

}

}


try{


TaskDefinition taskDef = context.getObjectByName(TaskDefinition.class, value);

String taskId = taskDef.getId();

String taskName = taskDef.getName();

if(taskDef != null &amp;&amp; null != taskId)

{

long exeTime = isPresentInSchlTasks(taskId);

if(exeTime!=null &amp;&amp; exeTime!=0)

{

if((exeTime / (1000*60*60)) % 24==1)

{

return "Once in a hour";

}

else if((exeTime / (1000*60*60*24)) % 365==1)

{

return "Once in a day";

}

else if((exeTime / (1000*60*60*24)) % 365==7)

{

return "Once in a week";

}

else if((exeTime / (1000*60*60*24)) % 365==31)

{

return "Once in a month";

}

else if ((exeTime / (1000*60*60*24)) % 365==89)

{

return "Once in a quarter";

}

else if ((exeTime / (1000*60*60*24)) % 365==0)

{

return "Once in a year";

}

else

return "Once in a "+exeTime+" milliseconds";



}

else

{

long exeTime2 = checkInSeqSchExe(taskName);

if(exeTime2!=null &amp;&amp; exeTime2!=0)

{

if((exeTime2 / (1000*60*60)) % 24==1)

{

return "Once in a hour";

}

else if((exeTime2 / (1000*60*60*24)) % 365==1)

{

return "Once in a day";

}

else if((exeTime2 / (1000*60*60*24)) % 365==7)

{

return "Once in a week";

}

else if((exeTime2 / (1000*60*60*24)) % 365==31)

{

return "Once in a month";

}

else if ((exeTime2 / (1000*60*60*24)) % 365==89)

{

return "Once in a quarter";

}

else if ((exeTime2 / (1000*60*60*24)) % 365==0)

{

return "Once in a year";

}

else

return "Once in a "+exeTime2+" milliseconds";

}

else

{

return "NA";

}

}

}

else

return null;

}

catch(Exception e){

return e.getMessage();

}

</Source>

</RenderScript>

</ReportColumnConfig>

</Columns>

</LiveReport>

</value>

</entry>

</Map>

</Attributes>

<Description>Displays the tasks and schedules.</Description>

<RequiredRights>

<Reference class="sailpoint.object.SPRight" name="FullAccessIdentityRoleReport"/>

</RequiredRights>

</TaskDefinition>


Rule for Deleting AccessRequests before 365 days.

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">

<Rule language="beanshell" name="Rule-Purging-AccessRequests">

<Source>


import sailpoint.object.QueryOptions;

import sailpoint.object.IdentityRequest;

import sailpoint.object.Filter;

import sailpoint.object.TaskResult;

import sailpoint.object.WorkflowCase;

import sailpoint.api.Workflower;

import sailpoint.api.Terminator;

import sailpoint.tools.Util;

import sailpoint.tools.Message;


try {

Terminator terminator = new Terminator(context);

Workflower workflower = new Workflower(context);

int daysToDelete = 365;

int daysToDeleteNegative = (~(daysToDelete - 1));

Calendar cal = Calendar.getInstance();

cal.add(Calendar.DAY_OF_MONTH, daysToDeleteNegative);

Date beforeDate= cal.getTime();

QueryOptions qo = new QueryOptions();

qo.addFilter(Filter.lt("created",beforeDate));

qo.addFilter(Filter.or(Filter.eq("completionStatus", "Pending"),Filter.eq("executionStatus", "Executing")));


Iterator iterator = context.search(IdentityRequest.class,qo);

if( null!= iterator){

while(iterator.hasNext()){

IdentityRequest identityRequest = (IdentityRequest) iterator.next();

if(null != identityRequest &amp;&amp; null != identityRequest.getAttribute("taskResultId"))

{

TaskResult taskResult = context.getObjectById(TaskResult.class,identityRequest.getAttribute("taskResultId"));

if(null != taskResult &amp;&amp; null != taskResult.getAttribute("workflowCaseId"))

{

WorkflowCase workflowCase = context.getObjectById(WorkflowCase.class, taskResult.getAttribute("workflowCaseId"));

if(null != workflowCase)

{

workflower.terminate(workflowCase);

}

//terminator.deleteObject(taskResult);

}

Calendar cal2 = Calendar.getInstance();

Date verificationDate = cal2.getTime();

List msgList = new ArrayList();

Message msg = new Message();

msg.setType(Message.Type.Warn);

msg.setKey("This request has been made to terminated through a rule explicitly, since it has been there in pending queue from long back.");

msgList.add(msg);

identityRequest.setMessages(msgList);

identityRequest.setVerified(verificationDate);

identityRequest.setExecutionStatus(IdentityRequest.ExecutionStatus.Terminated);

identityRequest.setCompletionStatus(IdentityRequest.CompletionStatus.Failure);

context.saveObject(identityRequest);

context.commitTransaction();

}

}

Util.flushIterator(iterator);

}

}

catch(Exception e) {

log.error("Exception "+e.getMessage);

}

</Source>

</Rule>

Saturday, January 7, 2023

Pagination

 Web Service:

WebService connector supports pagination for Account Aggregation and Group Aggregation.

There are two ways to implement pagination for WebService connector:

1. Paging Tab

2. Before Rule (OR) After Rule


Ex 1: fullUrl = https://mightypedia.com/xyz/api/employee?pageIndex=1

Json Response:

{

"totalcount": 666,

"pageSize": 100,

"pageIndex":1,

"startAt":1,

"records":[

{

.......

.......

.......

}

]

}

Paging Tab:

TERMINATE_IF $response.startAt == 0

$offset$ = $response.pageIndex$ + 1

$endpoint.fullUrl$ = $application.baseUrl$ + $endpoint.relativeUrl$ + ?pageIndex=+ $offset$

Sunday, November 6, 2022

Exclusion Rule

import sailpoint.object. Certifiable;

import sailpoint.object.EntitlementGroup ;

import java.util.List;

import java.util.ArrayList;


String description = "";

List certificationObjectList = new ArrayList();

Iterator itr = items.iterator();

while(itr.hasNext()){

Certifiable certificationObject = itr.next();

if(certificationObject instanceOf EntitlementGroup){

EntitlementGroup entitlementGroup = (EntitlementGroup) certificationObject ;

String applicationName = entitlementGroup .getApplicationName();

String entitlementName = entitlementGroup.getAttributeName().get(0);

String entitlementValue = entitlementGroup.getAttributes().get(entitlementName );

if(entitlementValue.contains("SailPoint") || entitlementValue.contains("OIM") || entitlementValue.contains("Java")){

certificationObjectList.add(certificationObject );

} else{

itemsToExclude.add(certificationObject);

itr.remove();

description = "Entitlements matches the exclusion criteria";

}

}

}

return description ;

IAM, IGA & Identity Security

IAM sets up the employee's account so they can log in and access the application with their credentials. IGA makes sure that access requ...

Featured Articles