@vijaylca Here’s the code from version 1.7.1 (available in the attached ZIP file in this article https://community.sailpoint.com/t5/Working-With-Services-Knowledge/IdentityNow-Mock-Project/ta-p/208216
import sailpoint.object.Application;
import sailpoint.object.Attributes;
import sailpoint.object.Filter;
import sailpoint.object.Identity;
import sailpoint.object.ManagedAttribute.Type;
import sailpoint.object.ProvisioningPlan;
import sailpoint.object.ProvisioningPlan.AccountRequest;
import sailpoint.object.ProvisioningPlan.AttributeRequest;
import sailpoint.tools.GeneralException;
import java.text.SimpleDateFormat;
import sailpoint.rule.Account;
import sailpoint.rule.ManagedAttributeDetails;
/*
* Version 1.7.1
* Last Updated: 07/18/2022
*/
/*
* Main Application Method. This will go through the passed in event configurations.
* If any event trigger/operation matches, it will apply the action for that configuration
*
* The Before Provisioning Rule configurations allows for the generic BeforeProvisioningRule to process common events based on standard best practices.
* The configuration itself is a list of JSON Maps that include 2 basic concepts
* Trigger: This configuration determines if this event should be applied based on
* Operation of the account request
* Identity Attribute values for the user being modified
* Attribute updates in the account request
* Entitlement updates in the account request
* Entitlement Name updates in the account request
* Entitlement Cardinality Update Triggers: This checks if the account request contains
* updates on the entitlement to either add when previously empty or remove the last entitlement
* Current Account Status Trigger: This checks the current status of the account
* Action: This configuration determines what to do if this event should be applied. Available options are
* Move AD Account: Adds AC_NewParent to the specified OU
* Change Operation: changes the AccountRequest Operation to the specified operation
* Remove Entitlements: removes all entitlements based on the account in IdentityNow
* Remove AD Entitlements: sets the memberOf attribute to a list containing the one group
* Scramble Password: sets the specified attribute to a string of characters
* Update Attribute: Adds the specified attribute with the specified value
* Add Argument: Adds the specified argument with the specified value
* Add Argument If Not Null: Adds the specified argument with the specified value. If the value is null, it ignores.
* Throw Error: Throws an error specified in the value attribute or "Unspecified Exception"
* Stop Processing: Stops processing the BeforeProvisioningRule and proceeds to provisioning.
*/
public void applyEventConfigurations(ProvisioningPlan plan, List events) throws GeneralException{
if(events == null) {
log.info("Events are null");
return;
}
if(plan == null) {
log.error("Plan is null");
return;
}
List accountRequests = plan.getAccountRequests();
Identity identity = plan.getIdentity();
for(AccountRequest accountRequest: accountRequests) {
for(Map event: events) {
// Check if this request matches the event configuration
log.debug("Check AccountRequest " + accountRequest + " matches event configuration: " + event);
if(!isAccountRequestMatch(identity, accountRequest, event)) {
log.info("Match NOT Found");
continue;
}
// Found a match. need to apply the configurations associated
log.info("Match Found ... apply configurations");
List actionConfigs = (List) event.get("eventActions");
if(actionConfigs == null || actionConfigs.isEmpty()) {
log.error("No actions for event");
continue;
}
for(Map actionConfig: actionConfigs) {
/*
* Each action should have
* Action: What to do
* Attribute: Specific to the action
* Value: Specific to the action
*/
String action = (String) actionConfig.get("Action");
if(action == null) {
log.error("Action Config does not have Action set");
continue;
}
String attribute = (String) actionConfig.get("Attribute");
Object value = (String) actionConfig.get("Value");
switch(action) {
case "ADMoveAccount":moveADAccount(identity, accountRequest, value);break;
case "ChangeOperation":changeOperation(accountRequest, value);break;
case "RemoveEntitlements":removeEntitlements(identity, accountRequest, attribute);break;
case "RemoveADEntitlements":removeADEntitlements(identity, accountRequest, value);break;
case "ScramblePassword":scramblePassword(accountRequest, attribute, value);break;
case "UpdateAttribute":updateAttribute(identity, accountRequest, attribute, value);break;
case "AddArgument":addArgument(identity, accountRequest, attribute, value);break;
case "AddArgumentIfNotNull":addArgument(identity, accountRequest, attribute, value, true);break;
case "ThrowError":throwError(identity, accountRequest, attribute, value);break;
case "StopProcessing":return;
default: log.error("Invalid Action: " + action);
}
}
}
}
}
/*
* Helper Action Methods
*/
public void moveADAccount(Identity identity, AccountRequest accountRequest, Object value) {
log.debug("Enter MoveADAccount: " + value);
if(accountRequest == null) {
log.error("MoveADAccount: Invalid Arguments: accountRequest is null");
return;
}
if(value instanceof String) {
log.debug("MoveADAccount: value is a string, send through replace");
String newOU = replaceIdentityValue(identity, accountRequest, (String) value);
log.info("MoveADAccount: replaced new value: " + newOU);
String currentNativeIdentity = accountRequest.getNativeIdentity();
if(currentNativeIdentity == null) {
log.error("moveADAccount: Invalid State: Current Native Identity is null");
return;
}
if(newOU == null || "".equals(newOU)) {
log.error("moveADAccount: Invalid Arguments: newOU is null");
return;
}
int indexOfCurrentOU = currentNativeIdentity.indexOf(newOU);
if(indexOfCurrentOU > 0 && !currentNativeIdentity.substring(0, indexOfCurrentOU).contains("OU=")) {
log.info("moveADAccount: Account already lives in OU");
return;
}
//TODO: Uniqueness checks and serialization
accountRequest.add(new AttributeRequest("AC_NewParent", ProvisioningPlan.Operation.Set, newOU));
}
else{
log.error("MoveADAccount: value is not a string or is null: " + value);
}
log.debug("Exit MoveADAccount");
}
public void changeOperation(AccountRequest accountRequest, Object value) {
log.debug("Enter changeOperation: " + value);
AccountRequest.Operation newOp = null;
try {
newOp = AccountRequest.Operation.valueOf((String) value);
}
catch(IllegalArgumentException e) {
log.error("ChangeOperation: Invalid Operation: " + value);
}
if(newOp != null) {
log.info("ChangeOperation: update Operation: " + newOp);
accountRequest.setOperation(newOp);
}
log.debug("Exit changeOperation");
}
public void removeEntitlements(Identity identity, AccountRequest accountRequest, String attribute) {
log.debug("Enter RemoveEntitlements: " + attribute);
if(accountRequest == null) {
log.error("RemoveEntitlements: Invalid Arguments: accountRequest is null");
return;
}
if(attribute == null) {
log.error("RemoveEntitlements: Invalid Arguments: attribute is null");
return;
}
if(identity == null) {
log.error("RemoveEntitlements: Invalid Arguments: Identity is null");
return;
}
Account account = getAccount(identity, accountRequest);
if(null != idn.getRawAccountAttribute(account, attribute)) {
List ents = asList(idn.getRawAccountAttribute(account, attribute));
if(ents != null) {
accountRequest.add(new AttributeRequest(attribute, ProvisioningPlan.Operation.Remove, ents));
}
}
log.debug("Exit RemoveEntitlements");
}
public void removeADEntitlements(Identity identity, AccountRequest accountRequest, Object value) {
log.debug("Enter removeADEntitlements: " + value);
if(accountRequest == null) {
log.error("removeADEntitlements: Invalid Arguments: accountRequest is null");
return;
}
String adDomainUsers = null;
if(value == null) {
log.error("removeADEntitlements: Invalid Arguments: value is null");
return;
}
else if(value instanceof String) {
if(((String) value).contains("DC")) {
adDomainUsers = (String)value;
}
}
if(adDomainUsers == null) {
log.error("removeADEntitlements: Invalid Arguments: value is not valid");
return;
}
if(identity == null) {
log.error("removeADEntitlements: Invalid Arguments: Identity is null");
return;
}
List groupList = new ArrayList();
groupList.add(adDomainUsers);
accountRequest.add(new AttributeRequest("memberOf", ProvisioningPlan.Operation.Set, groupList));
log.debug("Exit RemoveEntitlements");
}
public void scramblePassword(AccountRequest accountRequest, String attribute, Object value) {
log.debug("Enter ScramblePassword");
if(accountRequest == null) {
log.error("UpdateAttribute: Invalid Arguments: accountRequest is null");
return;
}
if(attribute == null) {
log.error("UpdateAttribute: Invalid Arguments: attribute is null");
return;
}
String newPassword = "";
String charset = "ABNCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+-={}[]:;<>?,./";
int count;
int index;
int len;
Random rnd = new Random();
len = charset.length();
for (count = 0; count < 18; count++) {
index = rnd.nextInt(len);
newPassword += charset.charAt(index);
}
accountRequest.add(new AttributeRequest(attribute, ProvisioningPlan.Operation.Set, newPassword));
//TODO: Update to use PasswordGenerator
log.debug("Exit ScramblePassword");
}
public void updateAttribute(Identity identity, AccountRequest accountRequest, String attribute, Object value) {
log.debug("Enter UpdateAttribute: " + value);
if(accountRequest == null) {
log.error("UpdateAttribute: Invalid Arguments: accountRequest is null");
return;
}
if(attribute == null) {
log.error("UpdateAttribute: Invalid Arguments: attribute is null");
return;
}
Object newValue = null;
if(value instanceof String) {
log.debug("UpdateAttribute: value is a string, send through replace");
newValue = replaceIdentityValue(identity, accountRequest, (String) value);
log.info("UpdateAttribute: replaced new value: " + newValue );
}
else{
log.debug("UpdateAttribute: value is not a string or is null: " + value);
newValue = value;
}
accountRequest.add(new AttributeRequest(attribute, ProvisioningPlan.Operation.Set, newValue));
log.debug("Exit UpdateAttribute");
}
public void addArgument(Identity identity, AccountRequest accountRequest, String attribute, Object value) {
log.debug("Enter AddArgument without ignoreIfNotNull ... calling other method with a false");
addArgument(identity, accountRequest, attribute, value, false);
}
public void addArgument(Identity identity, AccountRequest accountRequest, String attribute, Object value, boolean ignoreIfNotNull) {
log.debug("Enter AddArgument: " + value);
log.debug("Ignore If Not Null: " + ignoreIfNotNull);
if(accountRequest == null) {
log.error("AddArgument: Invalid Arguments: accountRequest is null");
return;
}
if(attribute == null) {
log.error("AddArgument: Invalid Arguments: attribute is null");
return;
}
Object newValue = null;
if(value instanceof String) {
log.debug("AddArgument: value is a string, send through replace");
newValue = replaceIdentityValue(identity, accountRequest, (String) value);
log.info("AddArgument: replaced new value: " + newValue );
}
else{
log.debug("AddArgument: value is not a string or is null: " + value);
newValue = value;
}
Attributes args = accountRequest.getArguments();
if(args == null) {
args = new Attributes();
accountRequest.setArguments(args);
}
if((newValue == null || newValue.toString().isEmpty()) && ignoreIfNotNull) {
log.debug("AddArgument: value is null and ignoreIfNotNull is true ... ignoring");
}
else {
args.put(attribute, newValue);
log.debug("AddArgument: setting value");
}
log.debug("Exit AddArgument");
}
public void throwError(Identity identity, AccountRequest accountRequest, String attribute, Object value) throws GeneralException {
log.debug("Enter throwError: " + value);
if(value instanceof String)
throw new GeneralException((String) value);
else {
throw new GeneralException("Unspecified Exception");
}
}
/*
* Helper Matching Methods
*/
/*
* This is the main matching method. It will check the operation of the account request first.
* Operation is the only required check. If there are not triggers, then every request of that operation matches.
* if the operation matches, it will then check to see if everything of the following matches. These are all AND matches
* Identity Attribute Triggers: Validating against the identity
* Account Attribute Update Triggers: Validating against updates in the account request
* Entitlement Update Triggers: Similar to Account Attribute Update Triggers, but checking multivalued attributes Add or Remove
* Entitlement Name Update Triggers: Similar to Entitlement Update Triggers, but the entitlement's name is checked instead of value.
*
*/
public boolean isAccountRequestMatch(Identity identity, AccountRequest accountRequest, Map event) {
log.debug("Enter isAccountRequestMatch: " + accountRequest + " on event " + event);
String opCheck = (String) event.get("Operation");
if(accountRequest.getOperation().toString().equals(opCheck)) {
log.debug("Account Request matches op of event: " + opCheck);
List idAttrTriggers = (List) event.get("Identity Attribute Triggers");
if(idAttrTriggers != null && !idAttrTriggers.isEmpty()) {
for(Map trigger: idAttrTriggers) {
if(isIdentityAttributeConfigMatch(identity, trigger)) {
log.debug("Identity " + identity + " matches " + trigger);
}
else {
log.debug("Identity " + identity + " doesn't match " + trigger);
return false;
}
}
}
List acctAttrUpdateTriggers = (List) event.get("Account Attribute Update Triggers");
if(acctAttrUpdateTriggers != null && !acctAttrUpdateTriggers.isEmpty()) {
for(Map trigger: acctAttrUpdateTriggers) {
if(isAccountAttributeUpdateConfigMatch(accountRequest, trigger)) {
log.debug("Request matches " + trigger);
}
else {
log.debug("Request doesn't match " + trigger);
return false;
}
}
}
List entUpdateTriggers = (List) event.get("Entitlement Update Triggers");
if(entUpdateTriggers != null && !entUpdateTriggers.isEmpty()) {
for(Map trigger: entUpdateTriggers) {
if(isEntitlementUpdateConfigMatch(accountRequest, trigger)) {
log.debug("Request matches " + trigger);
}
else {
log.debug("Request doesn't match " + trigger);
return false;
}
}
}
List entNameUpdateTriggers = (List) event.get("Entitlement Name Update Triggers");
if(entNameUpdateTriggers != null && !entNameUpdateTriggers.isEmpty()) {
for(Map trigger: entNameUpdateTriggers) {
if(isEntitlementNameUpdateConfigMatch(accountRequest, trigger)) {
log.debug("Request matches " + trigger);
}
else {
log.debug("Request doesn't match " + trigger);
return false;
}
}
}
List cardinalityChangeTriggers = (List) event.get("Entitlement Cardinality Update Triggers");
if(cardinalityChangeTriggers != null && !cardinalityChangeTriggers.isEmpty()) {
for(Map trigger: cardinalityChangeTriggers) {
if(isCardinalityMatch(accountRequest, trigger)) {
log.debug("Request matches " + trigger);
}
else {
log.debug("Request doesn't match " + trigger);
return false;
}
}
}
String accountStatusCheck = (String) event.get("Current Account Status Trigger");
if(accountStatusCheck != null && !accountStatusCheck.equals("")) {
if(isAccountStatusMatch(accountRequest, accountStatusCheck)) {
log.debug("Request existing account status matches " + accountStatusCheck);
}
else {
log.debug("Request existing account status doesn't match " + accountStatusCheck);
return false;
}
}
}
else {
log.debug("AccountRequest " + accountRequest + " doesn't match operation check: " + opCheck);
return false;
}
return true;
}
public boolean isAccountAttributeUpdateConfigMatch(AccountRequest accountRequest, Map trigger) {
if(trigger == null) {
log.error("Error isIdentityAttributeConfigMatch Configuration: trigger is null");
return false;
}
String attr = (String) trigger.get("Attribute");
String op = (String) trigger.get("Operation");
String val = (String) trigger.get("Value");
if(attr == null) {
log.error("Error Configuration: attribute is null");
return false;
}
if(!"eq".equals(op) && !"ne".equals(op)) {
log.error("Error Configuration: operation is invalid: " + op);
return false;
}
List attrReqs = accountRequest.getAttributeRequests();
if(attrReqs != null) {
for(AttributeRequest attrReq: attrReqs) {
if(attr.equals(attrReq.getName())) {
Object attrVal = attrReq.getValue();
boolean valsMatch = isValueMatch(attrVal, val);
if("eq".equals(op) && !valsMatch) {
log.debug("Check for eq did not match: " + attrVal + " vs " + val);
return false;
}
if("ne".equals(op) && valsMatch) {
log.debug("Check for ne matched: " + attrVal + " vs " + val);
return false;
}
log.debug("Found match for attribute change " + op + " " + val);
return true;
}
}
}
return false;
}
public boolean isIdentityAttributeConfigMatch(Identity identity, Map trigger) {
log.debug("Enter isIdentityAttributeConfigMatch: " + identity + " " + trigger);
if(trigger == null) {
log.error("Error isIdentityAttributeConfigMatch Configuration: trigger is null");
return false;
}
String attr = (String) trigger.get("Attribute");
String op = (String) trigger.get("Operation");
String val = (String) trigger.get("Value");
if(attr == null) {
log.error("Error Configuration: attribute is null");
return false;
}
if(!"eq".equals(op) && !"ne".equals(op)) {
log.error("Error Configuration: operation is invalid: " + op);
return false;
}
log.debug("Replace value: " + val);
Object idVal = identity.getAttribute(attr);
boolean valsMatch = isValueMatch(idVal, val);
if("eq".equals(op) && !valsMatch) {
log.debug("Check for eq did not match: " + idVal + " vs " + val);
return false;
}
if("ne".equals(op) && valsMatch) {
log.debug("Check for ne matched: " + idVal + " vs " + val);
return false;
}
return true;
}
public boolean isEntitlementUpdateConfigMatch(AccountRequest accountRequest, Map trigger) {
log.debug("Enter isEntitlementUpdateConfigMatch: " + identity + " " + trigger);
if(trigger == null) {
log.error("Error isEntitlementUpdateConfigMatch Configuration: trigger is null");
return false;
}
String attr = (String) trigger.get("Attribute");
String op = (String) trigger.get("Operation");
String val = (String) trigger.get("Value");
if(attr == null) {
log.error("Error Configuration: attribute is null");
return false;
}
if(!"Add".equals(op) && !"Remove".equals(op) && !"Set".equals(op)) {
log.error("Error Configuration: operation is invalid: " + op);
return false;
}
log.debug("Check change in group: " + val);
boolean foundMatch = false;
List entAttrReqs = accountRequest.getAttributeRequests(attr);
if(entAttrReqs != null) {
for(AttributeRequest entAttrReq: entAttrReqs) {
boolean doCompare = false;
if("Add".equals(op) && entAttrReq.getOperation() == ProvisioningPlan.Operation.Add) {
log.debug("Looking at an Add and operation in trigger is Add");
doCompare = true;
}
else if("Remove".equals(op) && entAttrReq.getOperation() == ProvisioningPlan.Operation.Remove) {
log.debug("Looking at an Remove and operation in trigger is Remove");
doCompare = true;
}
else if("Set".equals(op) && entAttrReq.getOperation() == ProvisioningPlan.Operation.Set) {
log.debug("Looking at an Set and operation in trigger is Set");
doCompare = true;
}
if(doCompare) {
List valuesUpdated = asList(entAttrReq.getValue());
if(valuesUpdated != null) {
for(String update: valuesUpdated){
if(isValueMatch(update, val)) {
foundMatch = true;
}
}
}
}
}
}
return foundMatch;
}
public boolean isCardinalityMatch(AccountRequest accountRequest, Map trigger) {
log.debug("Enter isCardinalityMatch: " + accountRequest + " " + trigger);
if(trigger == null) {
log.error("Error isCardinalityMatch Configuration: trigger is null");
return false;
}
String attr = (String) trigger.get("Attribute");
String op = (String) trigger.get("Operation");
if(attr == null) {
log.error("Error Configuration: attribute is null");
return false;
}
if(op == null) {
log.error("Error Configuration: operation is null");
return false;
}
Identity identity = plan.getIdentity();
log.debug("Have Identity: " + identity);
Account acct = getAccount(identity, accountRequest);
log.debug("Have acct: " + acct);
if(acct == null) {
log.error("Error Configuration: account doesn't exist");
return false;
}
String scenario = "";
if (op.toUpperCase().equals("LASTREMOVED")) {
scenario = "LASTREMOVED";
}
else if (op.toUpperCase().equals("FIRSTADDED")) {
scenario = "FIRSTADDED";
}
else {
//Currently, we only care if we are adding the first or removing the last.
//Therefore, only the configuration combinations above are valid.
//Theorertically we can expand this to look at arbitrary
//cardinalities and comparators
log.error("Error Configuration: operation is invalid: " + op);
return false;
}
log.debug("Check change in group cardinality for attribute " + attr);
boolean foundMatch = false;
Map pendingChangeMap = new HashMap();
List entAttrReqs = accountRequest.getAttributeRequests(attr);
log.debug("Have entAttrReqs: " + entAttrReqs);
if(entAttrReqs != null && !entAttrReqs.isEmpty()) {
for(Object entAttrReqObj: entAttrReqs) {
AttributeRequest entAttrReq = (AttributeRequest) entAttrReqObj;
boolean collectForAnalysis = false;
if(entAttrReq.getOperation() == ProvisioningPlan.Operation.Add) {
log.debug("Looking at an Add and operation in trigger has cardinality 1");
collectForAnalysis = true;
}
else if(entAttrReq.getOperation() == ProvisioningPlan.Operation.Remove) {
log.debug("Looking at a Remove and operation in trigger has cardinality 0");
collectForAnalysis = true;
}
else {
//Currently, we are ignoring set commands because
//in most instances this should not result in a
//change in cardinality. However, we may want to
//add this feature one day to support potential
//corner cases or plans that have not been compiled
//against an accurate account model.
log.debug("Not an add or remove. Ignoring attribute request");
collectForAnalysis = false;
}
if(collectForAnalysis) {
List valuesUpdated = asList(entAttrReq.getValue());
List changesForOperation = (List) pendingChangeMap.get(entAttrReq.getOperation());
if (changesForOperation != null) {
changesForOperation.addAll(valuesUpdated);
}
else {
changesForOperation = new ArrayList();
changesForOperation.addAll(valuesUpdated);
}
pendingChangeMap.put(entAttrReq.getOperation(), changesForOperation);
log.debug("Updated map after request: " + pendingChangeMap);
}
}
List currentValues = asList(idn.getRawAccountAttribute(acct, attr));
log.debug("currentValues: " + currentValues);
int initialValuesSize = 0;
if (currentValues != null && currentValues.size() > 0) {
initialValuesSize = currentValues.size();
}
else {
currentValues = new ArrayList();
}
log.debug("initialValuesSize: " + initialValuesSize);
List valuesToAdd = (List) pendingChangeMap.get(ProvisioningPlan.Operation.Add);
if (valuesToAdd != null) {
currentValues.addAll(valuesToAdd);
}
List valuesToRemove = (List) pendingChangeMap.get(ProvisioningPlan.Operation.Remove);
if (valuesToRemove != null) {
currentValues.removeAll(valuesToRemove);
}
int targetValuesSize = currentValues.size();
log.debug("targetValuesSize: " + targetValuesSize);
if ("FIRSTADDED".equals(scenario) && initialValuesSize == 0 && targetValuesSize > 0) {
foundMatch = true;
}
else if ("LASTREMOVED".equals(scenario) && initialValuesSize > 0 && targetValuesSize == 0) {
foundMatch = true;
}
}
return foundMatch;
}
public boolean isAccountStatusMatch(AccountRequest accountRequest, String status) {
log.debug("Enter isAccountStatusMatch: " + accountRequest + " " + status);
if(status == null) {
log.error("Error Configuration: Status is null");
return false;
}
Identity identity = plan.getIdentity();
Account acct = getAccount(identity, accountRequest);
if (acct == null) {
//This is likely a create operation, so we can't match
log.debug("Exit isAccountStatusMatch: no account");
return false;
}
if (status.toUpperCase().equals("ACTIVE")) {
log.debug("Exit isAccountStatusMatch: " + !acct.isDisabled());
return !acct.isDisabled();
}
else if (status.toUpperCase().equals("DISABLED")) {
log.debug("Exit isAccountStatusMatch: " + acct.isDisabled());
return acct.isDisabled();
}
else {
//Invalid Configuration
log.error("Error Configuration: Status is invalid: " + status);
return false;
}
}
public boolean isEntitlementNameUpdateConfigMatch(AccountRequest accountRequest, Map trigger) {
log.debug("Enter isEntitlementNameUpdateConfigMatch: " + identity + " " + trigger);
if(trigger == null) {
log.error("Error isEntitlementNameUpdateConfigMatch Configuration: trigger is null");
return false;
}
String attr = (String) trigger.get("Attribute");
String op = (String) trigger.get("Operation");
String val = (String) trigger.get("Value");
if(attr == null) {
log.error("Error Configuration: attribute is null");
return false;
}
if(!"Add".equals(op) && !"Remove".equals(op) && !"Set".equals(op)) {
log.error("Error Configuration: operation is invalid: " + op);
return false;
}
log.debug("Check change in group: " + val);
boolean foundMatch = false;
List entAttrReqs = accountRequest.getAttributeRequests(attr);
if(entAttrReqs != null) {
for(AttributeRequest entAttrReq: entAttrReqs) {
boolean doCompare = false;
if("Add".equals(op) && entAttrReq.getOperation() == ProvisioningPlan.Operation.Add) {
log.debug("Looking at an Add and operation in trigger is Add");
doCompare = true;
}
else if("Remove".equals(op) && entAttrReq.getOperation() == ProvisioningPlan.Operation.Remove) {
log.debug("Looking at an Remove and operation in trigger is Remove");
doCompare = true;
}
else if("Set".equals(op) && entAttrReq.getOperation() == ProvisioningPlan.Operation.Set) {
log.debug("Looking at an Set and operation in trigger is Set");
doCompare = true;
}
if(doCompare) {
List valuesUpdated = asList(entAttrReq.getValue());
if(valuesUpdated != null) {
for(String update: valuesUpdated){
String entitlementDisplayName = getEntitlementDisplayName(application.getId(), attr, update);
if(entitlementDisplayName != null && isValueMatch(entitlementDisplayName, val)) {
foundMatch = true;
}
}
}
}
}
}
return foundMatch;
}
/*
* Helper Utility Methods
*/
/*
* Is Value Match is used when determining a specific val1 (identity attribute, account attribute, request attribute) matches val2
* If val2 contains wild cards "*" or "?", then we need to check the wild card match method
*/
public boolean isValueMatch(Object val1, String val2) {
log.debug("Enter isValueMatch: " + val1 + " " + val2);
if(val1 instanceof String) {
val1 = replaceNullValuesWithNull((String) val1);
}
if(val2 instanceof String) {
val2 = replaceNullValuesWithNull(val2);
}
if(val1 == null && val2 == null) {
log.debug("Exit isValueMatch: Both null");
return true;
}
if(val1 == null && val2 != null) {
log.debug("Exit isValueMatch: obj1 null, val2 not");
return false;
}
if(val1 != null && val2 == null) {
log.debug("Exit isValueMatch: obj1 not null, val2 null");
return false;
}
if(val1 instanceof String) {
log.debug("val1 is string, comparing against val2");
if(val2.contains("?") || val2.contains("*")) {
log.debug("val2 contains wild cards. checking wild card match");
return wildCardMatch((String) val1, val2);
}
if(((String) val1).equals(val2)) {
log.debug("val1 matches val2");
return true;
}
}
return false;
}
// The function that checks if
// two given strings match. The first string
// may contain wild card characters "?" and "*"
public boolean wildCardMatch(String value, String pattern)
{
log.debug("Enter wildCardMatch: " + value + " against " + pattern);
// If we reach at the end of both strings,
// we are done
if (pattern.length() == 0 && value.length() == 0) {
log.debug("Exit wildCardMatch: each value is empty now");
return true;
}
// Make sure that the characters after '*'
// are present in second string.
// This function assumes that the first
// string will not contain two consecutive '*'
if (pattern.length() > 1 && pattern.charAt(0) == '*' &&
value.length() == 0) {
log.debug("Exit wildCardMatch: pattern contains additional characters but value is empty");
return false;
}
// If the first string contains '?',
// or current characters of both strings match
if ((pattern.length() > 1 && pattern.charAt(0) == '?') ||
(pattern.length() != 0 && value.length() != 0 &&
pattern.charAt(0) == value.charAt(0))) {
log.debug("Recurse wildCardMatch: first character of " + value + " matches first character of " + pattern);
return wildCardMatch(value.substring(1),
pattern.substring(1));
}
// If there is *, then there are two possibilities
// a - We consider current character of second string
// b - We ignore current character of second string.
if (pattern.length() > 0 && pattern.charAt(0) == '*') {
log.debug("Recurse wildCardMatch: first character of " + pattern + " is a wild card need to check rest of pattern AND rest of string against " + value);
return wildCardMatch(value, pattern.substring(1)) ||
wildCardMatch(value.substring(1), pattern);
}
log.debug("Exit wildCardMatch: value " + value + " does not match pattern " + pattern);
return false;
}
public String replaceNullValuesWithNull(String val) {
if("#{null}".equals(val) || "".equals(val)){
return null;
}
return val;
}
public String replaceIdentityValue(Identity identity, AccountRequest accountRequest, String val) {
log.debug("Enter replaceIdentityValue: " + identity + ": " + val);
if("#{null}".equals(val) || val == null){
return null;
}
log.debug("Start with val: " + val);
if(val.contains("#{now}")) {
val = val.replace("#{now}", (new Date()).toString());
}
log.debug("Val after now replacement: " + val);
int nextReplaceCount = val.split("#\\{now\\.").length - 1; // Adding '}' to allow for validator to ignore mismatched counts of braces
for (int i = 1; i <= nextReplaceCount && val.contains("#{now"); i++) { // Adding '}' to allow for validator to ignore mismatched counts of braces
log.debug("Val still has now ... has a format change: " + val);
String dateRegex = "(.*)(#\\{now\\.)([^\\}]*)(\\})(.*)"; // Adding '{' to allow for validator to ignore mismatched counts of braces
String dateFormat = val.replaceAll(dateRegex, "$3");
log.debug("Date Format: " + dateFormat);
if(dateFormat == null) {
dateFormat = "yyyy-MM-dd";
}
String formattedDate = "";
switch(dateFormat){
case "EPOCH_TIME_WIN32":
Long win32TimeStamp = ((new Date()).getTime()+ 11644473600000L) * 10000L ;
formattedDate = "" + win32TimeStamp;
break;
case "EPOCH_TIME_JAVA":
formattedDate = "" + (new Date()).getTime();
break;
case "EPOCH_TIME":
formattedDate = "" + ((new Date()).getTime() / 1000);
break;
default:
SimpleDateFormat sdf = null;
log.debug("Use SimpleDateFormat for " + dateFormat);
if("ISO8601".equals(dateFormat)) {
sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
}
else {
sdf = new SimpleDateFormat(dateFormat);
}
formattedDate = sdf.format(new Date());
}
log.debug("replace #{now." + dateFormat+ "} with " + formattedDate);
val = val.replace("#{now." + dateFormat+ "}", formattedDate);
log.debug("Val replaced with date formated change: " + val);
}
nextReplaceCount = val.split("#\\{identity\\.").length - 1; // Adding '}' to allow for validator to ignore mismatched counts of braces
for (int i = 1; i <= nextReplaceCount && val.contains("#{identity"); i++) { // Adding '}' to allow for validator to ignore mismatched counts of braces
String attributeRegex = "(.*)(#\\{identity\\.)([^\\}]*)(\\})(.*)"; // Adding '{' to allow for validator to ignore mismatched counts of braces
String attributeName = val.replaceAll(attributeRegex, "$3");
log.debug("Identity attribute to grab: " + attributeName);
String identityVal = null;
if(identity == null) {
log.warn("No Identity");
}
else {
identityVal = (String) identity.getAttribute(attributeName);
}
if(identityVal == null) {
identityVal = "";
}
val = val.replace("#{identity." + attributeName + "}", identityVal);
log.debug("Val replaced with attribute: " + val);
}
nextReplaceCount = val.split("#\\{manager\\.").length - 1; // Adding '}' to allow for validator to ignore mismatched counts of braces
for (int i = 1; i <= nextReplaceCount && val.contains("#{manager"); i++) { // Adding '}' to allow for validator to ignore mismatched counts of braces
String attributeRegex = "(.*)(#\\{manager\\.)([^\\}]*)(\\})(.*)"; // Adding '{' to allow for validator to ignore mismatched counts of braces
String attributeName = val.replaceAll(attributeRegex, "$3");
log.debug("Manager attribute to grab: " + attributeName);
String identityVal = null;
if(identity == null || identity.getManager() == null) {
log.warn("No Manager");
}
else {
identityVal = (String) identity.getManager().getAttribute(attributeName);
}
if(identityVal == null) {
identityVal = "";
}
val = val.replace("#{manager." + attributeName + "}", identityVal);
log.debug("Val replaced with attribute: " + val);
}
nextReplaceCount = val.split("#\\{account\\.").length - 1; // Adding '}' to allow for validator to ignore mismatched counts of braces
for (int i = 1; i <= nextReplaceCount && val.contains("#{account"); i++) { // Adding '}' to allow for validator to ignore mismatched counts of braces
String attributeRegex = "(.*)(#\\{account\\.)([^\\}]*)(\\})(.*)"; // Adding '{' to allow for validator to ignore mismatched counts of braces
String attributeName = val.replaceAll(attributeRegex, "$3");
log.debug("Account attribute to grab: " + attributeName);
Account account = getAccount(identity, accountRequest);
log.debug("Got account");
String accountVal = "";
if(account != null) {
accountVal = idn.getAccountAttribute(account, attributeName);
log.debug("Got account attribute value: " + accountVal);
}
if(accountVal == null) {
accountVal = "";
}
val = val.replace("#{account." + attributeName + "}", accountVal);
log.debug("Val replaced with attribute: " + val);
}
log.debug("Exit replaceIdentityValue: " + val);
return val;
}
/*
* Method takes an object and returns a list. If the object is already a list, it returns the object
* Otherwise it'll return a list containing the object if not null
*/
public List asList(Object val){
if(val == null) {
return null;
}
List retList = null;
if(val instanceof List) {
retList = (List) val;
}
else if(val instanceof String) {
retList = new ArrayList();
retList.add((String) val);
}
return retList;
}
public Account getAccount(Identity identity, AccountRequest accountRequest) {
String appName = accountRequest.getApplicationName();
String nativeId = accountRequest.getNativeIdentity();
Account account = idn.getAccountByNativeIdentity(appName,nativeId);
return account;
}
public String getEntitlementDisplayName(String id, String attr, String value) {
ManagedAttributeDetails entDetails = idn.getManagedAttributeDetails(id, attr, value, Type.Entitlement);
Map entAttrs = entDetails != null ? entDetails.getAttributes() : null;
return (entAttrs != null && entAttrs.containsKey("displayName")) ? (String) entAttrs.get("displayName") : null;
}
/*
Main Running Code
*/
Attributes appAtts = application.getAttributes();
if(appAtts != null && appAtts.get("cloudServicesIDNSetup") != null) {
Map idnSetup = (Map) appAtts.get("cloudServicesIDNSetup");
log.debug("In Before Provisioning Rule :::: idnSetup: " + idnSetup);
List eventConfigs = (List) idnSetup.get("eventConfigurations");
log.debug("In Before Provisioning Rule :::: eventConfigs: " + eventConfigs);
applyEventConfigurations(plan, eventConfigs);
}
```