Saturday, August 28, 2021

Sailpoint IdentityIQ Web Service Connector Configuration

 Sailpoint IdentityIQ Web Service Connector

Group Data
  
<?xml version='1.0' encoding='UTF-8'?>
<results preview='0'>
    <meta>
        <fieldOrder>
            <field>ID</field>
            <field>ATTR</field>
            <field>ATVAL</field>
        </fieldOrder>
    </meta>
    <messages>
        <msg type="DEBUG">Data informtaion</msg>
        <msg type="INFO">Your timerange was substituted based on your search string</msg>
    </messages>
    <result offset='0'>
        <field k='ID'>
            <value h='1'>
                <text>3-Role1</text>
            </value>
        </field>
        <field k='ATTR'>
            <value h='1'>
                <text>PROFILE</text>
            </value>
        </field>
        <field k='ATVAL'>
            <value>
                <text>Role one</text>
            </value>
        </field>
    </result>
    <result offset='1'>
        <field k='ID'>
            <value h='1'>
                <text>3-Role2</text>
            </value>
        </field>
        <field k='ATTR'>
            <value h='1'>
                <text>PROFILE</text>
            </value>
        </field>
        <field k='ATVAL'>
            <value>
                <text>Role two</text>
            </value>
        </field>
    </result>
</results>

Account Data

<?xml version='1.0' encoding='UTF-8'?>
<results preview='0'>
    <meta>
        <fieldOrder>
            <field>ID</field>
            <field>USERLIST</field>
            <field>UserNameInProfile</field>
            <field>EmployeeNumberProfile</field>
        </fieldOrder>
    </meta>
    <messages>
        <msg type="DEBUG">Data informtaion</msg>
        <msg type="INFO">Your timerange was substituted based on your search string</msg>
    </messages>
    <result offset='0'>
        <field k='ID'>
            <value h='1'>
                <text>3-Role1,3-Role2,3-Role3,3-Role4</text>
            </value>
        </field>
        <field k='USERLIST'>
            <value>
                <text>ABC123</text>
            </value>
        </field>
        <field k='UserNameInProfile'>
            <value>
                <text>VISHAL KEJRIWAL</text>
            </value>
        </field>
        <field k='EmployeeNumberProfile'>
            <value h='1'>
                <text>ABC123</text>
            </value>
        </field>
    </result>
    <result offset='1'>
        <field k='ID'>
            <value h='1'>
                <text>3-Role1,3-ROLE3</text>
            </value>
        </field>
        <field k='USERLIST'>
            <value>
                <text>XYZ123</text>
            </value>
        </field>
        <field k='UserNameInProfile'>
            <value>
                <text>VIS KEJ</text>
            </value>
        </field>
        <field k='EmployeeNumberProfile'>
            <value h='1'>
                <text>XYZ123</text>
            </value>
        </field>
    </result>
</results>

Schema Mapping 






















Adding Group and Account Aggregation Operation







Context URL : URL to fetch data , this need to be same as URL use to fetch data from any API client

Header 
Content-Type : text/XML

Response
Response Attribute Mapping 
PROFILE :field[1]/value/text
Attribute : field[2]/value/text
ProfileName : field[3]/value/text

Root Path
//results/result

Sucessful Response Code 
2**


Similar Step need to be followed for Account Aggregation 

Sample WebServiceBeforeOperationRule  if Endpoint URL need to be modified

  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import java.io.IOException;
  import java.net.URI;
  import java.net.URISyntaxException;
  import org.apache.http.HttpHeaders;
  import org.apache.http.HttpResponse;
  import org.apache.http.client.ClientProtocolException;
  import org.apache.http.client.HttpClient;
  import org.apache.http.client.methods.HttpPost;
  import org.apache.http.client.utils.URIBuilder;
  import org.apache.http.entity.StringEntity;
  import org.apache.http.impl.client.HttpClients;
  import org.apache.http.client.entity.UrlEncodedFormEntity;
  import org.apache.http.message.BasicNameValuePair;
  import org.apache.http.util.EntityUtils;

  String SEARCH_QUERY ="search index=cleanup RECTYPE=NME ID=3-* earliest=@w0  ATTR=PROFILE | table  ID ATTR ATVAL";

  try {
    List visUrlEncoded = new ArrayList();
     visUrlEncoded.add(new BasicNameValuePair("search", SEARCH_QUERY));	
     UrlEncodedFormEntity visUrlEncodedEntity = new UrlEncodedFormEntity(visUrlEncoded);

    String visFinalURL = requestEndPoint.getFullUrl()+EntityUtils.toString(visUrlEncodedEntity);
    requestEndPoint.setFullUrl(visFinalURL);
  }
  catch (Exception exception) {
    log.error("Exception Occured: " + exception);
  }
  return requestEndPoint;

Sunday, August 1, 2021

Listing Objects in Namespace at Runtime in Sailpoint IdentityIQ

 Listing Objects in Namespace at Runtime in Sailpoint IdentityIQ

import org.apache.log4j.Logger;
import org.apache.log4j.Level;

Logger log = Logger.getLogger("sailpoint.services.bshdemo");
log.setLevel(Level.DEBUG);
log.debug("Listing Variables passed to Beanshell namespace:");

// BeanShell has a "this.variables" array that we can access.

for (int i = 0 ; i < this.variables.length ; i++) {
   String varName = this.variables[i];

   Object varValue = null;
   try {
      if ("transient".equals(varName)) {
         varValue = "[reserved word]";
      } else {
         varValue = eval(varName);
      } 
   } catch (Exception ex) {
      varValue = "[eval exception]";
   }

   String varClass = "void";
   if ((void != varValue) && (null != varValue)) {
      varClass = varValue.getClass().getSimpleName();
   }

   if (void == varValue) {
       log.debug(varName + " = void");
   } else if (null == varValue) {
       log.debug(varName + " = null");
   } else {
       log.debug(varName + ": " + varClass + " = " + varValue);
   }
}
return;

Sailpoint IdentityIQ PolicyViolation WorkFlow

 PolicyViolation WorkFlow , This WF is used to modify the violation object , This will remove the violation object and will remove if anything is added through LCM .

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Workflow PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Workflow explicitTransitions="true" handler="sailpoint.api.StandardWorkflowHandler" name="VIS Detective SOD Policy Violation Workflow" type="PolicyViolation">
  <Variable input="true" name="approvalObject">
    <Description>PolicyViolation to process.  Note that we use approvalObject for
      consistency with other workflows, but the violation has already
      been persisted.  Calling the commit or rollback actions will 
      have no effect.</Description>
  </Variable>
  <Variable input="true" name="approver">
    <Description>The user to receive the work item, normally the owner of the policy.</Description>
    <Script>
      <Source>
	  import sailpoint.object.Identity;
      
	  Identity newOwner= approvalObject.getOwner();
	  return newOwner.getName();
      </Source>
    </Script>
  </Variable>
  <Variable input="true" name="violator">
    <Description>The identity that has the violation.</Description>
  </Variable>
  <Variable name="approved">
    <Description>Internal variable automatically set logically true an Approval
      process completes with no rejects.
	</Description>
  </Variable>
  <Variable name="action">
    <Description>Variable that may be set in the approval page to determine 
      the action to take on this violation.  We handle violation approvals
      differently than most work items.  There is no &amp;quot;reject&amp;quot; there
      is a selection of an action (mitigate, remediate, delete, ignroe) 
      followed by buttons that always post approval.</Description>
  </Variable>
  <Variable name="expiration">
    <Description>Variable that must be set to a Date (or the String representation
      of a Date) in order to use the &amp;quot;mitigate&amp;quot; action.  This will
      be tested in the call:mitigate handler and logged if it is invalid.
      You may wish to have the worklfow do it&amp;#39;s own validation.</Description>
  </Variable>
  <Variable name="comments">
    <Description>Variable that may be set to comments to be included with
      a mitigation or remediation.</Description>
  </Variable>
  <Variable name="remediatables">
    <Description>Variable that may be set to a list of things that can
      be selected for remediation.  Currently this will only
      be set for Role SOD violations.</Description>
  </Variable>
  <Variable name="remediations">
    <Description>Variable holding the remediatables selected in the work item.</Description>
  </Variable>
  <RuleLibraries>
    <Reference class="sailpoint.object.Rule" name="Rule Library"/>
  </RuleLibraries>
  <Step icon="Default" name="Logs" posX="98" posY="126">
    <Arg value="ref:remediatables"/>
    <Script>
      <Source>
		import java.util.Map;
		import java.util.Date;
		import java.util.List;
		import java.util.HashMap;
		import java.util.ArrayList;
		import sailpoint.tools.Util;
		import sailpoint.object.Filter;	
		import sailpoint.api.ObjectUtil;		
		import java.text.ParseException;
		import java.text.SimpleDateFormat;
		import sailpoint.object.Identity;
		import sailpoint.object.QueryOptions;
		import sailpoint.api.SailPointContext;
		import sailpoint.object.EmailOptions;
		import sailpoint.object.EmailTemplate;
		import sailpoint.object.PolicyViolation;
		import sailpoint.object.ManagedAttribute;	
		import org.apache.commons.logging.Log;
		import sailpoint.tools.GeneralException;
		import sailpoint.object.IdentityEntitlement;
		import org.apache.commons.logging.LogFactory;
		import sailpoint.object.IdentitySelector.MatchTerm;

		Log logger = LogFactory.getLog("vis.workflow.visDetectiveSODPolicyViolationWorkflow");
        
		public boolean checkIfThroughLCM(String applicationName, String identityName, String entitlementName) {
			boolean wasThroughLCM = false;
		 
			StringBuilder result = new StringBuilder();
			String sDate1 = "06/05/2021";
			   
			Date date = new SimpleDateFormat("MM/dd/yyyy").parse(sDate1);
			result.append("date [").append(date).append("]\n");
			Filter dateCheckFilter = Filter.gt("created", date);

			logger.debug(" new Date dt : "+ sDate1 + " new date : " + result);
			QueryOptions  qo = new QueryOptions();

			qo.addFilter(Filter.and(Filter.eq("source","Aggregation"),Filter.eq("application.name",applicationName), Filter.eq("identity.name",identityName),Filter.eq("value",entitlementName),dateCheckFilter));
			List identityEntitlements = context.getObjects(IdentityEntitlement.class, qo);
			logger.debug("identityEntitlements :: " + identityEntitlements);
			if(identityEntitlements.size() > 0) {
				return true;
			}else {
				return false;
			}
		}
		public Map getEntitlementDetails(String entitlementValue, String applicationName) {
			QueryOptions qo = new QueryOptions();
			qo.addFilter(Filter.and(Filter.eq("value", entitlementValue)  ,   Filter.eq("application.name", applicationName)));
			Map entDetailsMap = new HashMap();
			List managedAttributes = context.getObjects(ManagedAttribute.class, qo);
			if(managedAttributes != null &amp;&amp; managedAttributes.size() > 0) {
				ManagedAttribute managedAttribute = managedAttributes.get(0);
				entDetailsMap.put("LogiplexName", managedAttribute.getAttribute("logiplexAppName"));
				entDetailsMap.put("EntitlementDescription", managedAttribute.getDescriptions().get("en_US") );
			}
			return entDetailsMap;
		}	


		//Main code starts here
		
		logger.debug("Startes Main code here");

		String piiMarkerGroup = "<<Left Group>>";
		String notificationTemplateForPolicyViolation = "VIS Policy Violation Notification Template";
		Identity violationOnwer   = approvalObject.getOwner();
		EmailTemplate violationTemplate = context.getObjectByName(EmailTemplate.class,notificationTemplateForPolicyViolation );
		Map emailVariables = new HashMap();
		String ownerEmails=   Util.listToCsv(ObjectUtil.getEffectiveEmails(context,violationOnwer));
		List entitlementsTobeAddedToViolation = new ArrayList();
		List PIIEntitlementsToBeAddedToViolation = new ArrayList();
        
		if (approvalObject != null &amp;&amp; approvalObject.getArgument("ViolatingEntitlements") != null) { 
			
			Identity identityWithViolation = approvalObject.getIdentity();
			
			String firstName = identityWithViolation.getFirstname();
			String lastName = identityWithViolation.getLastname();
			String lanId = identityWithViolation.getAttribute("lanId");
			String identityName = identityWithViolation.getAttribute("displayName");

			emailVariables.put("firstName", firstName);
			emailVariables.put("lastName", lastName);
			emailVariables.put("lanId", lanId);
			emailVariables.put("identityName", identityName);

			for (int i = 0; i &lt; approvalObject.getArgument("ViolatingEntitlements").size(); i++) {
				sailpoint.object.IdentitySelector.MatchTerm entitlementViolatingAtTop = approvalObject.getArgument("ViolatingEntitlements").get(i);
				if (entitlementViolatingAtTop != null) {       
					String applicationNameForViolatingEntitlement = "";
					String entitlementValueForViolatingEntitlement = "";
					String accountNameForViolatingEntitlement="";

					if(entitlementViolatingAtTop.getApplication() != null ){
						applicationNameForViolatingEntitlement = entitlementViolatingAtTop.getApplication().getName();
						accountNameForViolatingEntitlement= getAccountNmae(identityWithViolation, entitlementViolatingAtTop.getApplication());                                   
					}
					if(entitlementViolatingAtTop.getValue() != null) {
						entitlementValueForViolatingEntitlement = entitlementViolatingAtTop.getValue();
					}

					if(entitlementValueForViolatingEntitlement.equalsIgnoreCase(piiMarkerGroup)) {
						PIIEntitlementsToBeAddedToViolation.add(entitlementViolatingAtTop);
					}else {      
						boolean checkThruLCMmethodResult = checkIfThroughLCM(applicationNameForViolatingEntitlement, identityWithViolation.getName(), entitlementValueForViolatingEntitlement) ;      
						logger.debug("CheckThruLCMmethodResult::  " + checkThruLCMmethodResult );      
						if( checkThruLCMmethodResult == true ) {
							entitlementsTobeAddedToViolation.add(entitlementViolatingAtTop);     
							Map entDetails = getEntitlementDetails(entitlementValueForViolatingEntitlement, applicationNameForViolatingEntitlement);
				
							auditDetectiveSOD( "Violation Detected","Aggregation",lanId,entDetails.get("LogiplexName"),entitlementValueForViolatingEntitlement,accountNameForViolatingEntitlement,approvalObject,"Aggregation",lanId );  
				
							emailVariables.put("entitltmentName",entitlementValueForViolatingEntitlement);
							emailVariables.put("entitltmentDesc",entDetails.get("EntitlementDescription"));
			   
							if(violationTemplate!= null){
								logger.debug("Violation temp loop");
								Identity policyViolationApproverObject   = approvalObject.getOwner();							
								if(null!=policyViolationApproverObject &amp;&amp; ( Util.listToCsv(ObjectUtil.getEffectiveEmails(context,policyViolationApproverObject)) != null)){
									approverEmails =  Util.listToCsv(ObjectUtil.getEffectiveEmails(context,policyViolationApproverObject));		
									EmailOptions ops = new EmailOptions(approverEmails, emailVariables);            
									try {
										context.sendEmailNotification(violationTemplate, ops);
									}catch(Exception e){ 
										log.error("Could not send email to GS team as : " + e);
									}
									logger.debug("Email Sent ");
								}
							}
						}
					}
				}
			}  
		}		
		if(entitlementsTobeAddedToViolation != null &amp;&amp; entitlementsTobeAddedToViolation.size() >0){         
			entitlementsTobeAddedToViolation.addAll(PIIEntitlementsToBeAddedToViolation) ;
			approvalObject.setArgument("ViolatingEntitlements",entitlementsTobeAddedToViolation );
			context.saveObject(approvalObject);
			context.commitTransaction();
			logger.debug("OBJECT persisted");
        }else{
			context.removeObject(approvalObject);
			context.commitTransaction();
			logger.debug("OBJECT DELETED");
        }
		
		logger.debug("End of workflow Step");
      </Source>
    </Script>
    <Transition to="End"/>
  </Step>
  <Step icon="Stop" name="End" posX="160" posY="126"/>
  <Step icon="Start" name="Start" posX="28" posY="10">
    <Transition to="Logs"/>
  </Step>
</Workflow>