filtering idm transactions with variable values
From time to time we run across requirements where there is some attribute that is used to hold a value that can vary greatly across the enterprise from one object to another, usually users. Most commonly it is for things like job codes, departments, locations or various entities under a corporate umbrella. Typically in those situations we find that the requirements call for some values to be permitted through the system while others are not or that various values will need to have additional logic applied to them compared to others.
Now this may not sound like a difficult requirement to implement but usually when we run across these issues it deals with more than one or two values but rather several values and the expectation that the values will change over time. Even with that information it would possible to hardcode all of these codes and scenarios into driver policies; even if those policies spread across multiple drivers. However, if you hardcode policies for specific values then there is an automatic, built-in maintenance cost that goes along with that implementation because if a value is removed or added then it requires lengthy code changes to every policy/rule impacted by that change. In addition to that maintenance cost there is also an increased risk built-in because if a required policy/rule change is missed or not updated correctly it could result in provisioning and/or authorization errors within the target system. That is definitely not something anybody wants to have happen.
So far we have talked a little bit about the issue but what about the solution?
One of the best solutions for a scenario like the one mentioned above that I have found is to use a Global Configuration Variable (GCV) to hold a delimited string of values that can be checked very easy using a regular expression inside of any required rules to determine if the current value meets the criteria needed for processing.
But Gary, why not just use a multi-valued GCV? Why use a delimited string?
Honestly, I have found this approach easier to implement and maintain compared to using multi-valued GCVs that require a more complex iteration approach in the code. It is easier to write code that checks for a value’s inclusion in a delimited string versus code that polls for a collection of values in an array that is then required to iterate through each value doing a direct comparison looping until a match is found or all values in the index are eliminated.
In standard programming terms it is the difference between:
if (;123;234;345;456;567;’ contains ‘234’)
//do this action here
(foreach value in x GCV)
if (x.value[i] == current value)
//do some action and exit loop
Both approaches return the same result but one requires far less code and when dealing with a large collection of values is more efficient.
Ok, that makes sense but how is your solution implemented?
Well, obviously it all starts with a GCV that will hold your list of values that need to be compared. For each collection of values create a single-valued string GCV either on the driver set or the target driver. In most cases I have found it is necessary to create the GCV on the driver set so that the one collection of values is available to multiple drivers.
Once the GCV is created, populate it with a delimited list of values. I prefer to use semi-colons (;) as my delimiter value and I use that character to start and end the string so my final list looks something along the lines of : “;abc;def;ijk;lmm;qrs;”. Of course you can use other values as your delimiter but I have found semi-colons ( ; ) and pipes ( | ) are generally the easiest to use. I have had some issues when trying to use other characters like commas ( , ), tildes ( ~ ), dollar signs ( $ ). These characters are reserved by the drivers and are interpreted as representing some other type of value that results in errors or failures to compare properly. And as a general point you want to steer clear of characters that may be included in any GCV values like dashes ( – ), underscores ( _ ) or ampersands ( & ).
Side note: If your environment contains more than one eDirectory server and you put the GCV on the driver set you will want to create the GCV on all servers hosting that driver set.
Do you want explain why you put the semi-colon at the beginning and the end of the values too?
Because we will be implementing code that checks to see if a value is contained within our new GCV string the extra semi-colons act as a fail-safe to make sure we do not have any false-positives in our rule(s). Once we get into the discussion of how the rule is constructed this will make more sense.
And on that note, let’s take a look at how we can use that GCV in our rules.
Now within a driver rule in NetIQ IDM you are given the ability to create XPath expressions that will evaluate to the typical TRUE/FALSE output as part of your rule conditions or even as an if condition within the rule actions should you choose. Typically with most driver rules there are conditions for things like “if object class equals User” or “if operation equals Add” or “if source attribute Surname equals ‘Richardson'” and these types of conditions are very easy and straightforward to create and understand.
And honestly the XPath expressions really are not that different to regular rules but they do require you to know some basic XPath programming terms and syntax. While the NetIQ development UI allows you to create/user XPath expressions in your rules it does not provide you XPath commands or syntax references; but that’s where Google comes in. XPath expressions are nothing more than a slight twist on the standard “if” statement used in driver rules. Normally rules use an “if” statement to do essentially a direct comparison where as with XPath expressions it is more of an “if” statement within an “if” statement. To help make sense of this take a look at the comparison below:
Normal condition: if class name equal to “User”
XPath condition: if XPath expression not true “contains(‘~My_GCV_Values~’, ‘;abc;’)”
So how does that XPath expression work?
As I mentioned before it is akin to an “if” statement within an “if” statement. The XPath expression could be represented in a more common expression as “True or False, does My_GCV_Values contain the text string ‘;abc;’?” and then that is encapsulated inside another “if” statement that compares its result to see if it returned a true or false value.
So stripped down to the minimal standards the XPath condition basically reads “If my GCV contains this value” (XPath expression is true) or “If my GCV does not contain this value” (XPath expression not true) but as you can see there are two checks involved instead of the typical one for those conditions.
To use this approach invoke the XPath contains() method and pass two values to be compared. The first value is the string to be searched (your GCV value) and the second value is the value to be searched for (the value to be checked for inclusion). And like with pretty much all programming languages the two variables being passed are separated by a comma ( , ).
Ok. That seems simple enough but what about the semi-colons? Why does the GCV value have the delimiter character at the beginning and the end and not just between the values like normal?
If you look back at the example XPath condition you will notice that the second value (the value being looked for) is “;abc;” and not just “abc”. The value being searched for is surrounded by the semi-colons so that we are doing an exact match in the GCV string value and doing so ensures that we will only match on exact matches between the delimiter values.
To better illustrate my point let’s assume we have a GCV value using the standard delimiter practice of “batch;match;catch”. Notice we only separate the values and that there are no preceding or trailing delimiters. The issue now comes if we create a rule that says if our “action” equals one of these values then we want to provision a set of permissions to that user but there are other values that could exist in that user’s attribute like “tch”. What would happen in this scenario would be the string “batch;match;catch” would be checked to see if it contained “tch” which would return a TRUE statement because batch, match and catch all contain the letters “tch” and that is the value being checked for within our GCV. This would result in a false positive that would trigger the driver to give permissions to a user who should not be authorized to receive them creating a potentially costly security issue within the environment.
Now, consider the approach of using the delimiter as suggested above and the search criteria in our earlier example. The GCV value now becomes “;batch;match;catch;” and our search criteria becomes does contain “;tch;”. Does the GCV value here contain a match for “;tch;”? No, it does not and thus the XPath expression would return proper result that would allow better control over the provisioning of resources, accounts, permissions, etc. to the target object.
In short this approach gives you an easy method of comparing several values in a GCV to determine if the value being evaluated is valid or not for that rule. And in a system where there may be dozens of job codes or locations that have to be checked this is much more efficient than iterating through a lengthy array. Not to mention that by using a GCV instead of trying to hardcode multiple rules around these values that if a value needs to be added or removed from that list it only takes a few quick button clicks to update the GCV and restart the driver compared to reviewing every rule in every driver, making the physical rule changes to meet the new requirements, deploying changes from Designer (preferably), and then restarting the drivers.
We all know the saying, “Time is money”. Well this approach cuts down on development time and maintenance time saving your company money from the word “go”. Not to mention the time and money that could be saved by reducing the risk of provisioning or de-provisioning accounts, authorizations, etc. to accounts erroneously.