Monday, September 20, 2021

After Provisioning Rule - When an entitlement is removed, disable the user through webservice

 Requirement: When an Active Directory entitlement (PMS Group) is removed, the identity has to be disabled in the target through webservice. This can be achieved by writing an After Provisioning rule.


<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule created="" id="" language="beanshell" modified="" name="AD After Provisioning Disable PMS User" type="AfterProvisioning">
  <Description>An IdentityIQ server-side rule that is executed after the connector's provisioning method is called. This gives the customer the ability to customize or react to anything in the ProvisioningPlan AFTER it has been sent out to the specific applications.
This rule will be called for any application found in a plan that also has a configured 'afterProvisioningRule' configured.</Description>
  <Signature>
    <Inputs>
      <Argument name="log">
        <Description>
          The log object associated with the SailPointContext.
        </Description>
      </Argument>
      <Argument name="context">
        <Description>
          A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
        </Description>
      </Argument>
      <Argument name="plan">
        <Description>
          The ProvisioningPlan object on its way to the Connector.
        </Description>
      </Argument>
      <Argument name="application">
        <Description>
          The application object that references this before/after script.
        </Description>
      </Argument>
      <Argument name="result">
        <Description>
          The ProvisioningResult object returned by the connectors provision method. This can be null and in many cases the connector will  not return a result and instead will annotate the plan's ProvisioningResult either at the plan or account level.        
        </Description>
      </Argument>
    </Inputs>
  </Signature>
  <Source>
import sailpoint.object.ProvisioningPlan;
import sailpoint.object.ProvisioningPlan.AccountRequest;    
import sailpoint.object.ProvisioningPlan.AttributeRequest;
import java.net.URL;
import java.net.HttpURLConnection;
import javax.net.ssl.HttpsURLConnection;
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
  

Logger log = Logger.getLogger("sailpoint.services.rule.AfterProvisioning");
log.debug("Enter Rule AD After provisioning Rule");
public void changeUserStatus(String username) {
  log.debug("username: " + username);
  String auth = "username:password";
  Base64.Encoder encoder = Base64.getEncoder();
  String encodedString = encoder.encodeToString(auth.getBytes());
 // log.debug("endocded string: " +encodedString);
 
try{
  java.net.URL url = new URL("http://example.com/ChangeUserStatus");
  log.debug("The URL to get token is "+url);
  java.net.HttpURLConnection conPost;
  conPost = (java.net.HttpURLConnection) url.openConnection();
  conPost.setRequestMethod("POST");
  conPost.setRequestProperty("Content-Type","application/json");
  conPost.setRequestProperty("Accept", "*/*");
  conPost.setRequestProperty("Content-Length", "108");
  conPost.setRequestProperty("Authorization", "Basic "+encodedString);
  //log.debug("Setting properties over");
  
  conPost.setDoOutput(true);
  
    // JSON body for POST call           
    String jsonInputString =  "{" +
   "\"users\": {   \"ActivateUser\": false, " +
       "\"Logins\":  [ \"" + username +
      "\" ] " +
    "}" +
"}";
log.debug("JSON body: " + jsonInputString);
//  log.debug("sending request");
// Send the request
  
  conPost.connect();
  
OutputStream os = conPost.getOutputStream();
    byte[] input = jsonInputString.getBytes("utf-8");
    os.write(input, 0, input.length);

//  log.debug("Reading response ");
// read the response body
 StringBuilder res = new StringBuilder();
    int responseCode = conPost.getResponseCode();
    String responseMessage = conPost.getResponseMessage();
    String geturl = conPost.getURL().toString();
 //   log.debug(geturl);
 //   log.debug(responseMessage);
    log.debug("HTTP Post Response Code :: " + responseCode);

    if (responseCode == 200) { // success
      InputStream is = conPost.getInputStream();
      int b = -1;
      do {
        b = is.read();
        char c = (char)b;
        res.append(c);
      }while(b!=-1);
      log.debug("The response is "+res.toString());
    } else {
      log.debug("Failed");
      InputStream is = conPost.getErrorStream();
      int b = -1;
      do {
        b = is.read();
        char c = (char)b;
        res.append(c);
      }while(b!=-1);
      log.debug("The failed response is "+res.toString());
    }
    
    } catch (MalformedURLException ex) {
        log.error("MalformedURLException " + ex);
    } catch (IOException ex) {
       log.error("IOException "+ ex);
    }

List &lt;AccountRequest> accountRequests = plan.getAccountRequests();
for(AccountRequest accountRequest : accountRequests){
if(accountRequest.getApplicationName().equalsIgnoreCase("Active Directory and Exchange") &amp;&amp; accountRequest.getOperation().equals(AccountRequest.Operation.Modify)){
List&lt;AttributeRequest> attributeRequests = accountRequest.getAttributeRequests();
for(AttributeRequest attributeRequest : attributeRequests){
if(attributeRequest.getName().equalsIgnoreCase("memberOf") &amp;&amp; attributeRequest.getOperation().equals(ProvisioningPlan.Operation.Remove) &amp;&amp; attributeRequest.getValue().toString().equalsIgnoreCase("CN=PMSGroup,OU=Security Groups,OU=IBM,DC=COM")){
// Invoke webservice here to Inactive user
changeUserStatus(plan.getIdentity().getName());
}
}
}
}
</Source>
</Rule> 



Thursday, September 16, 2021

Customize Approval message through Build Approval Set

 To add custom messages in Approvals, we can add it through Build Approval Set variable in Workflow.

Requirement:


Add a rule in the Build Approval Set variable.


The message that is displayed is item.setValue(). 

Below Rule is added to the Build Approval Set. 


<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule created="" id="" language="beanshell" modified="" name="Plugin Build Identity ApprovalSet" type="Workflow">
  <Description>Build Identity ApprovalSet for request coming from vendor contract extension plugin</Description>
  <Signature returnType="Object"/>
  <Source>import sailpoint.object.ProvisioningPlan;
      import sailpoint.object.ProvisioningPlan.AttributeRequest;
      import sailpoint.object.ProvisioningPlan.AccountRequest;
      import sailpoint.object.ApprovalSet;
      import sailpoint.object.ApprovalItem;
      import sailpoint.object.Attributes;
      import sailpoint.tools.Util;
  import java.util.Date;
  import java.text.SimpleDateFormat;
      
      serilog=org.apache.commons.logging.LogFactory.getLog("sailpoint.services.rules.workflow.PluginBuildIdentityApprovalSet");
  serilog.debug("--------------------------------------------------");
      serilog.debug(plan.toXml());
      ApprovalSet set = new ApprovalSet();
if ( plan != null ) {
          List accountRequests = plan.getAccountRequests();
          for ( AccountRequest request : accountRequests ) {
              ApprovalItem item = new ApprovalItem();
              item.setApplication(request.getApplication());
              item.setInstance(request.getInstance());
              item.setNativeIdentity(request.getNativeIdentity());
              item.setOperation(request.getOperation().toString());
              List attrRequestFlat = flattenAttributeRequests(request.getAttributeRequests());
           
 
            if( pluginAction.equalsIgnoreCase("vendor-contract-extension")) {
          
              String contractExtensionComments = "Request to extend the vendor contract for "+ identityDisplayName + " from "+ currentEndDate + " to " + extensionDate; 
              item.setValue(contractExtensionComments);
            
            } else if( pluginAction.equalsIgnoreCase("vendor-disable")) {
              
              SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    String date = simpleDateFormat.format(terminationDate);
              String disableComments = "Request to disable the vendor "+ identityDisplayName + " with Termination Date set to " + date; 
              item.setValue(disableComments);
            
            }else if( attrRequestFlat != null ) {
                  item.setValue(attrRequestFlat);
              } 
              Attributes attributes = getAttributeRequestArguments(request.getAttributeRequests());
              item.setAttributes(attributes);
              
              // for these requests comments come in on the plan
              String comments = plan.getComments();
              if ( Util.getString(comments) != null ) {
                  item.setRequesterComments(comments);
              }
              set.add(item);
          }
          // while we are here lets annotate the plan with previousValues
          if ( flow.equals("IdentityEditRequest") ) {
              AccountRequest iiqRequest = plan.getAccountRequest("IIQ");    
              if ( iiqRequest != null ) {
                  List attributeRequests = iiqRequest.getAttributeRequests();
                  if ( Util.size(attributeRequests) > 0 ) {
                      Identity id = context.getObject(Identity.class, identityName);
                      if ( id != null )  {
                          for ( AttributeRequest req : attributeRequests ) {
                              String name = req.getName();
                              if ( name != null ) {
                                  // We have to be carefull here, if we see manager display
                                  // the displayName
                                  Object prevValue = id.getAttribute(name);
                                  if ( prevValue != null ) {
                                      if (name.equals("manager") ) {
                                          String displayName = getIdentityProperty((String)prevValue, "displayName");
                                          if ( displayName != null ) {
                                              prevValue = displayName;
                                          }
                                      }
                                      else if (prevValue instanceof Identity) {
                                          prevValue = (String)prevValue.getDisplayableName();
                                      }
                                      else  if(prevValue instanceof List) {
                                          /* Thanks to type erasure there is no way for us to write something like
                                           * prevValue instanceof List&amp;lt;Identity> so break it into steps.  Check if
                                           * prevValue is a List.  If it has any elements get the first one. If that
                                           * is an instance of Identity then assume the rest of the elements are too
                                           * and then build a List of displayable names, because that is what we do
                                           * with Identitys. */
                                          List prevValueList = (List) prevValue;
                                          if(prevValueList.size() > 0) {
                                              if(prevValueList.get(0) instanceof Identity) {
                                                  List identityIds = new ArrayList(prevValueList.size());
                                                  for (Object value : prevValueList) {
                                                      Identity identity = (Identity) value;
                                                      identityIds.add(identity.getDisplayableName());
                                                  }
                                                  prevValue = identityIds;
                                              }
                                          }
                                      }
                                      req.put(ProvisioningPlan.ARG_PREVIOUS_VALUE, prevValue);
                                  }
                              }
                          }
                      }
                  }
              }
          }
      }
      return set;</Source>
</Rule>



SailPoint approval scheme for different events

 We can use a script in approvalScheme variable in workflow and return different values based on our requirement. 

<Variable input="true" name="approvalScheme">
    <Description>
      A String that specifies how approvals should be generated for
      this workflow there are three built-in modes
      none - disabled approvals
      manager - The user's current manager will get approvals
      newManager - The newly assigned manager will get approvals when
      manager transfers occur. Otherwise the user's manager
      current manager will be the approver.
    </Description>
    <Script>
      <Source>
        import org.apache.log4j.Logger;
        import org.apache.log4j.Level;
        private static Logger logger = Logger.getLogger("sailpoint.services.transfer");
        logger.setLevel(Level.DEBUG);
        if("Vendor Manager Transfer".equalsIgnoreCase(eventType) || "Vendor Enable".equalsIgnoreCase(eventType))
        {
if(managerStatus)
{
logger.error("managerStatus"+managerStatus);
return "newManager";
}
else {
logger.error("else block of mgrtransfer::"+managerStatus);
return "manager"+","+"newManager";
}
        }
        else if("Vendor Create".equalsIgnoreCase(eventType))
        {
logger.debug("Create Vendor::"+eventType);
return "manager";
        }
        else if("DeletePRVAccount".equalsIgnoreCase(eventType))
        {
logger.debug("Create Vendor::"+eventType);
return "manager";
        }
        else if("Create Privilaged Account".equalsIgnoreCase(eventType))
        {
logger.debug("Create Vendor::"+eventType);
return "manager";
        }
        else
        {
logger.error("else block::"+managerStatus);
return "manager"+","+"newManager";
        }
      </Source>
    </Script>
  </Variable> 



Form AllowedValues rule to filter Identities with Active Regular Active Directory accounts and identity is active and correlated

 The rule type is AllowedValues. import org.apache.log4j.Level ; import org.apache.log4j.Logger ; import sailpoint.object.Filter ; import sa...