<?xml version='1.0' encoding='UTF-8'?>
A generic account correlation rule to be used for all applications. It uses the application's correlation config to determine which attribute contains the logon id. A first attempt will be made using the primaryLanID Identity Attribute, then if that fails it will look for a match amongst any authoratative links associated with an identity using the
ATTR_NativeID Link Attribute. Existing links to uncorrelated identitities will be re-evaluated and re-linked if a better match is found Matches to multiple identities will be ignored
import java.util.LinkedHashSet;
import java.util.HashSet;
import java.util.regex.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import sailpoint.object.*;
import sailpoint.tools.Util;
private Identity getUniqueIdentityFromLinks(List links)
{
HashSet identities = new HashSet();
Identity identity = null;
for (Link link : links)
{
pLog.debug("Matched Link: " + link.getNativeIdentity() + " from: " + link.getApplicationName());
identities.add(link.getIdentity());
}
pLog.debug("Found: " + identities.size() + " from matching links");
if (identities.size() == 1)
{
identity = identities.iterator().next();
}
return(identity);
}
public QueryOptions setIgnoreWorkgroupIndexes (QueryOptions qo) {
ArrayList trueAndFalse = new ArrayList();
trueAndFalse.add(new java.lang.Boolean(false));
qo.addFilter(Filter.in("workgroup", trueAndFalse));
qo.setCloneResults(true);
return qo;
}
Log pLog = LogFactory.getLog("rule.Office365_Account_Correlation1");
String appName = application.getName();
pLog.debug("Starting Office365 Account Correlation Rule for application: " + appName + ", account:" + account.getIdentity());
CorrelationConfig correlationConfig = application.getAccountCorrelationConfig();
HashMap result = new HashMap();
Identity identity = null;
String identityName = null;
//Service Account Check
pLog.debug(appName+":Checking for Service Account");
boolean isServiceAccount = false;
if (link == null) {
Rule checkServiceAccount = context.getObjectByName(Rule.class, "Is Service Account");
Map map = new HashMap();
map.put("attributes", account.getAttributes());
map.put("application", application);
isServiceAccount = context.runRule(checkServiceAccount, map);
} else {
isServiceAccount = link.getAttribute("service") != null ? link.getAttribute("service") : false;
}
pLog.debug(appName+":Service Account Status is " + isServiceAccount);
//Generic Account Check
pLog.debug(appName+":Checking for Generic Account");
boolean isGenericAccount = false;
if (link == null) {
Rule checkGenericAccount = context.getObjectByName(Rule.class, "Is Generic Account");
Map map = new HashMap();
map.put("attributes", account.getAttributes());
map.put("application", application);
isGenericAccount = context.runRule(checkGenericAccount, map);
} else {
isGenericAccount = link.getAttribute("generic") != null ? link.getAttribute("generic") : false;
}
pLog.debug(appName+":Generic Account Status is " + isGenericAccount);
if ((isServiceAccount || isGenericAccount) && !(isServiceAccount && isGenericAccount)) {
String accountType = isServiceAccount ? "Service" : "Generic";
Identity managerIdentity = null;
pLog.debug(appName+":Processing " + account.getDisplayName() + " as " + accountType);
String manager = account.getAttribute("manager");
if(manager != null){
QueryOptions qo = new QueryOptions();
qo.addFilter(Filter.eq("distinguishedName", manager));
List managerLink = context.getObjects(Link.class, qo);
if(!managerLink.isEmpty()){
managerIdentity = managerLink.get(0).getIdentity();
if (null != managerIdentity) {
pLog.debug(appName+":Generic-account--Processing managerStatus-" +managerIdentity.getManagerStatus());
List activeReporties = context.getObjects(Identity.class, new QueryOptions().addFilter(Filter.and(Filter.eq("manager.name", managerIdentity.getName()),Filter.eq("inactive", false), Filter.or(Filter.eq("links.application.name", "HR"),Filter.eq("links.application.name", "TLC HCM"),Filter.eq("links.application.name", "Oracle HCM")))));
pLog.debug(appName+":Generic-account--Processing activeReporties-" +activeReporties.size());
while(activeReporties.isEmpty()){
pLog.debug(appName+":Generic-account--Processing managerIdentity-1-" +managerIdentity);
managerIdentity = managerIdentity.getManager();
pLog.debug(appName+":Generic-account--Processing managerIdentity-2-" +managerIdentity);
activeReporties = context.getObjects(Identity.class, new QueryOptions().addFilter(Filter.and(Filter.eq("manager.name", managerIdentity.getName()),Filter.eq("inactive", false), Filter.or(Filter.eq("links.application.name", "HR"),Filter.eq("links.application.name", "TLC HCM"),Filter.eq("links.application.name", "Oracle HCM")))));
}
identityName = accountType+"-Identity-"+managerIdentity.getName();
pLog.debug(appName+":Generic-account--Processing identity name:" +identityName);
}
}
}
if(link != null && link.getIdentity() != null && link.getIdentity().isCorrelated()){
String linkManager = link.getAttribute("manager");
pLog.debug(appName+":Generic-account--Processing linkManager-" +linkManager);
//if(linkManager != null && manager.equalsIgnoreCase(linkManager)){
identity = link.getIdentity();
pLog.debug(appName+":Generic-account--Processing link identity -"+identity);
if(identityName == null && !appName.equalsIgnoreCase("CORPAD") && !appName.equalsIgnoreCase("tattsgroup.com")){
if (identity != null) {
identityName =identity.getName();
}
}
else if(identity != null && !identity.getName().equalsIgnoreCase(identityName)){
identity = context.getObjectByName(Identity.class, identityName);
pLog.debug(appName+":Generic-account--Processing identity updated based on IdentityName -"+identity);
}
pLog.debug(appName+":Generic-account--Processing link identity-" +identity);
//}
}
if(identity == null){
Rule processServiceGenericAccount = context.getObjectByName(Rule.class, "Process Service or Generic Account");
Map map = new HashMap();
map.put("account", account);
map.put("type", accountType);
map.put("application", application);
map.put("identityName", identityName);
map.put("owner", managerIdentity);
pLog.debug(appName+":Generic-account--creating identity Map-" +map);
identity = context.runRule(processServiceGenericAccount, map);
pLog.debug(appName+":Generic-account--Processing identity -" +identity);
}
pLog.debug("Processed " + accountType + "account and correlation identity is " + identity);
}
else {
// Look for an existing link. If it is to a correlated identity, then keep it
if (link != null && link.getIdentity() != null && link.getIdentity().isCorrelated()) {
pLog.debug("Link already correlated to authoratative identity");
identity = link.getIdentity();
// Unless we're forcing re-correlation...
if (application.getBooleanAttributeValue("forceRecorrelation")) {
boolean recorrelate = true;
/*
* Forced re-correlation. If we're doing this for an authoratative application
* then it only makes sense if we're not already correlated elsewhere
*/
if (application.isAuthoritative())
{
List links = link.getIdentity().getLinks();
for (Link l : links)
{
Application app = l.getApplication();
if (!application.equals(app) && app.isAuthoritative())
{
recorrelate = false;
}
}
}
if (recorrelate)
{
pLog.warn("Forcing recorrelation of: " + link.getNativeIdentity());
identity = null;
}
}
} else {
// See if there is already an uncorrelated Identity for this application ProfileClass
if (identity == null) {
String correlateTo = application.getProfileClass();
pLog.debug("Checking existing links for ProfileClass :" + correlateTo);
if (!Util.isNullOrEmpty(correlateTo))
{
String nativeIdentity = account.getIdentity();
pLog.debug("Searching Identities in: " + correlateTo + " using: " + nativeIdentity);
QueryOptions qo = new QueryOptions();
qo.addFilter(Filter.and(
Filter.eq("application.profileClass", correlateTo),
Filter.ignoreCase(Filter.eq("nativeIdentity",nativeIdentity))));
qo.setCloneResults(true);
List links = context.getObjects(Link.class, qo);
if (links.size() == 1)
{
identity = links.get(0).getIdentity();
pLog.debug("id: " + identity.getId());
} else if (links.size() > 1) {
identity = getUniqueIdentityFromLinks(links);
if (identity != null) {
pLog.debug("id: " + identity.getId());
}
}
}
}
// Since a Rule fires before a config, run the config first and if we don't have a match then perform special handling
// We use the application's correlationConfig to tell us what to match against
if (identity == null || !identity.isCorrelated()) {
if (correlationConfig != null) {
List filters = correlationConfig.getAttributeAssignments();
if (filters != null ) {
for (Filter filter : filters)
{
String identityAttributeName = filter.getProperty();
String linkAttributeName = filter.getValue();
if (!Util.isNullOrEmpty(identityAttributeName) && !Util.isNullOrEmpty(linkAttributeName)) {
String linkAttributeValue = account.getStringAttribute(linkAttributeName);
if (!Util.isNullOrEmpty(linkAttributeValue)) {
pLog.debug("Running correlationConfig: " + identityAttributeName + " -> " + linkAttributeName);
pLog.debug("Looking for " + identityAttributeName + "=" + linkAttributeValue);
QueryOptions qo = new QueryOptions();
setIgnoreWorkgroupIndexes(qo);
qo.addFilter(Filter.ignoreCase(Filter.eq(identityAttributeName, linkAttributeValue)));
List identities = context.getObjects(Identity.class, qo);
pLog.debug("Found: " + identities.size() + " identities");
if (identities.size() == 1) {
identity = identities.get(0);
pLog.debug("id: " + identity.getId());
break;
} else if (identities.size() > 1) {
pLog.debug(">1 Identities found, not correlating");
}
} else {
// Don't really expect the correlation attribute to be null/empty
pLog.debug("Correlation Attribute: " + linkAttributeName + " has value: " + linkAttributeValue + " - can't correlate");
}
}
}
} else {
pLog.warn("CorrelationConfig is empty" );
}
} else {
pLog.warn("Missing CorrelationConfig, defaulting to FirstName/LastName" );
}
}
// Try and locate using the FullName but split up into firstname/lastname pair.
if (identity == null || !identity.isCorrelated()) {
String accountUserName = "";
if (appName.equals("WagerAD")) {
String wagerFName = account.getAttribute("givenName") != null ? account.getAttribute("givenName"):"";
String wagerLName = account.getAttribute("sn") != null ? account.getAttribute("sn"):"";
accountUserName = accountUserName + wagerFName + " "+ wagerLName;
} else if (appName.startsWith("KENO-APPLICATION-QLD") || appName.startsWith("NEO-APPLICATION")) {
// FullName is Last, First
accountUserName = account.getAttribute("FullName");
if (accountUserName != null) {
accountUserName = accountUserName.replaceFirst("(.*), (.*)", "$2 $1");
}
} else {
accountUserName = account.getAttribute("FullName");
if (accountUserName == null) {
accountUserName = account.getAttribute("FULLNAME");
}
}
if (accountUserName != null) {
String [] nameparts = accountUserName.split(" ");
String first = "";
String last = "";
for (int i=0; i < nameparts.length ; i++){
if (i==0) {
first = first + nameparts[i];
} else {
last = last + nameparts[i] + " ";
}
}
last = last.trim();
if (!Util.isNullOrEmpty(first) && !Util.isNullOrEmpty(last)) {
pLog.debug("Looking for firstname=" + first + (last != null ? " and lastname=" + last : ""));
QueryOptions qo = new QueryOptions();
setIgnoreWorkgroupIndexes(qo);
qo.addFilter(Filter.ignoreCase(Filter.eq("firstname", first)));
if (!Util.isNullOrEmpty(last)) {
qo.addFilter(Filter.ignoreCase(Filter.eq("lastname", last)));
}
List identities = context.getObjects(Identity.class, qo);
pLog.debug("Found: " + identities.size() + " identities");
if (identities.size() == 1) {
identity = identities.get(0);
}
}
}
}
}
}
// Did we find anything?
if (identity != null) {
if (link != null) {
if (identity.equals(link.getIdentity())) {
pLog.debug("Link correlation unchanged");
} else {
if (account !=null && link.getIdentity() != null && identity != null) {
pLog.info("Moved: " + account.getIdentity() + " from: " + link.getIdentity().getName() + " to: " + identity.getName());
}
}
} else {
if (account != null && identity != null) {
pLog.info("Correlated: " + account.getIdentity() + " to: " + identity.getName());
}
}
}
// If we had an existing link, and the correlator didn't find a better match, then keep it
if (identity == null && link != null) {
if(link.getApplication().getType().equals("Active Directory - Direct")){
String acctName = link.getAttribute("sAMAccountName");
if(acctName != null && acctName.startsWith("pa_")){
acctName = acctName.substring(3,acctName.length());
}else if(acctName != null && acctName.endsWith("_admin")){
acctName = acctName.substring(0,acctName.length()-6);
}
QueryOptions qo = new QueryOptions();
setIgnoreWorkgroupIndexes(qo);
qo.addFilter(Filter.ignoreCase(Filter.eq("tc_username", acctName)));
List identities = context.getObjects(Identity.class, qo);
if (identities.size() == 1) {
identity = identities.get(0);
}else{
identity = link.getIdentity();
}
}else{
identity = link.getIdentity();
}
pLog.info("Retaining existing link: " + link.getNativeIdentity());
}
//Defaulting to existing uncorrelated identity if found
appName = application.getProfileClass();
if (Util.isNullOrEmpty(appName)) {
appName = application.getName();
}
appName = appName.replace(" ", “”);
String acctName;
if (!Util.isNullOrEmpty(appName) && appName.equals(“Office365”)) {
acctName = account.getAttribute(“userPrincipalName”);
}else{
acctName = account.getIdentity();
}
String delim = “_”;
String identityStr = “u” + delim + appName + delim + acctName;
identity=context.getObjectByName(Identity.class,identityStr);
if (identity != null && !identity.isWorkgroup()) {
result.put("identity",identity);
}
return(result);</Source>