In this series I have been walking through all the policies in the ServiceNow driver for NetIQ Identity Manager. You can see a collection of my various driver walk throughs that I have done over the past few years at this Wiki page. If you have done anything similar on your own, please update the Wiki to include links.
I do these so that I can learn how a driver works, at a reasonably low level. I get these walk throughs can be incredibly boring, because after all, who actually cares about this stuff, other than me? But I will say, I get a much better understanding of how a driver works, without ever seeing it in action from this approach than I might otherwise.
My hope is that should you be using a driver such as this one, encounter something funny happening in a policy, you will be able to find this type of article, get an explanation for how the specific policy is supposed to work, to help you understand if the trace you are seeing makes sense, or is the sign of a problem. In order to diagnose that question, you need to understand what is supposed to be happening. Alas, the vendor will never write this kind of documentation, and I am not even sure I blame them for it to be honest. It is a ton of work, and not as valuable as other things. Thus I do the dirty work no one else seems to want to do. (Yes, I like Mike Rowe, but the stuff he does is gross, this is just time consuming).
Previously I looked at the settings, GCVs, filter, and schema maps. I looked at the Subscriber channel which only has a Mathc and Creation policy sets so far. There is no Event Transform, nor a Placement policy.
The absence of the Event Transform implies that delete and renames are directly mapped. A move probably should be blocked, since it does not make a lot of sense in a flat placement system.
The absence of Placement makes sense since ServiceNow stores everyone in a flat database table exposed over SOAP or REST.
Let's start this by looking at the Command Transform, which has seven policies.
This has a single rule, "Veto move operation event". Oh look, there you go, as I just noted, a move should be blocked and here it is being blocked. By doing this in the Command Transform, the <r;move>r; comes in and if the user exists and is associated, stays a <r;move>r; into the Command Transform. If the user is not associated or does not exist, then it becomes an <r;add>r; in the new location. So blocking it here lets a move create a user and stops a raw move from progressing and does not require an earlier rule.
There are eight rules in this policy.
Login Disabled attribute change in IDVault Remove Group Membership changes if using Group Entitlement Veto if event not relevant User Account entitlement change (Disable Option) User Account entitlement change (Delete Option) Group entitlement change Role entitlement change Department entitlement change
Login Disabled attribute change in IDVault
This rule implements something useful. Usually we map the IDV Login Disabled attribute direct to the connected systems active/inactive attribute. Sometimes with a flip since some systems have an Enabled boolean, so our Login Disabled = True attribute value means Enabled = False. However, if you want to use Entitlements, usually you want let Entitlements handle the account active status in the target system. In fact as we will see below, soon enough, a revoke of a UserAccount Entitlement can map to either a disable in ServiceNow, or an account delete, a pretty common model implemented in many drivers.
But if that is the case, should we unmap Login Disabled? Well you might still want the Helpdesk to be able to disable a user fast and have it flow everywhere, since locking out a rogue user is more important than anything else in some cases. When security comes and escorts the employee away in handcuffs it is often important to go disable their accounts post haste! I have to admit, while I have certainly been the IT guy doing the disabling when this happens, I have never actually seen Security come in and kick someone out of the office, though I sure as heck have worked with people who should have been!
You might be asking, if this can be so important, why is this not the default all the time? Well it does mean that your IDV and application fall out of sync, at least in terms of Entitlements and since with Identity Governance we want to make sure our view of the systems are consistent you probably want to minimize these disconnects. The Micro Focus Identity Governance application (the internally written one, not the Aveksa licensed one (AGS 6.x), nor the Sailpoint licensed one (AGS 7.x) tries to rely at least to some degree on the Role and Resource model to abstract away some of the details of permission granting. I.e. If you call this Role a specific permission that requires Governance, it would be good if it was a reliable indicator of the current state of that permission. Thus there is a cost, potentially to falling out of sync.
Thus we have a GCV, drv.sync.disabled that controls whether to sync Login Disabled or not when it changes. This is prety common as a pattern in most drivers, since the logic behind it is true in most drivers.
In this rule, our conditions are first, are we using Entitlements via a GCV. Then are we syncing Login Disabled, (testing to see if we are NOT). Finally a test for the evnt type being a modify with the operation attribute Login Disabled available.
If all that is true, then they strip the operation attribute Login Disabled so it does not sync. By doing this in the Command Transform it also handles the merge case of a <r;sync>r; or migrate. The initial modify of Login Disabled on an unassociated
Remove Group Membership changes if using Group Entitlement
Here the synchronization of the member attribute is stripped, if you are using the Group Entitlement (GCV is checked) and it is a Group object with the Member attribute in the flow. Note they check for operation of add|modify for a Regular Expression compare, which allows you to imply an OR operation even though it is in the midst of an AND group. Very useful approach, if you were not aware of it.
Thus, if you have enabled Group Entitlements, and a Group is changing and the Member attribute is being changed do not sync it, rather we expect the Entitlement to change which will cause the Entitlement Implementation policy (a few policies down I think) to send the change directly.
Veto if event not relevant
Thus has three OR'ed condition groups as the test. First class is not user. Then if three GCVs are set specifically. That UserAccount, Group, and Role entitlements are not being used. Finally if the DirXML-EntitlementRef attribute is not changing. In all those cases, the following rules which implement the three entitlement types, do not apply.
Contrary to the name of this rule, the action is actually Break, not Veto. That is, why run through implementing the Group entitlement if it is not in use, and so on, for all the defined cases.
The carrier of entitlement information is the attribute DirXML-EntitlementRef so if it is not changing then there is no entitlement event happening. (A sync would have generated a merge which would have included the DirXML-EntitlementRef values if present).
User Account entitlement change (Disable Option)
When you use the UserAccount entitlement, you have to decide what happens when you remove it. Should the destination user be deleted or disabled? In this case, this rule implements the disable case.
Thus we check for the GCV to say that the UserAccount entitlement is in use. Then the GCV that the action to take upon removal is disable, then is it a User, a modify event, and finally, is the UserAccount entitlement actually changing.
When you implement entitlements, you should always use a for-each loop over the Entitlement values (Be that the Entitlement noun token, the Removed Entitlement, or Added Entitlement). This is good practice, since some entitlements can be multiply applied (Like the Group entitlement which can have many groups assigned to one user, and thus many Group Entitlements assigned). If you only ever have one, as is usually the case for UserAccount then the loop only goes over one instance. If you have more then it does as many as are available.
In fact, before the embedded IF tokens in IDM (pre-3.6 and maybe 3.5) you could synthesize the affect of an IF-THEN block by using a for-each of an XPATH expression that implemented your conditions. If the XPATH was true, it executed the code inside the for-each. If not, it skipped it. THus an effective IF block. Not perfect, but back in those days, mostly what we had at hand.
Thus first we loop over the Removed Entitlement, and for each value we do two things. First we send in a set destination attribute of true to disable the user, and then back in the Identity Vault we remove the Association, after this current event. It is a Source Attribute event, so it always runs as a separate event, so we want this to happen after the Destination Attribute write is complete.
The other benefit of using a for-each loop over entitlement values is that the current-node variable will be the payload of the DirXML-EntitlementRef value, which has a Path component that is XML, and inside the XML there is a <r;param>r; node, and that is what current-value will hold. You can extract that from the raw attribute but it is a few steps to do so, and the for-each loop does all the work for you. This is needed in the case of group entitlements since you need the name and info of the group in the target system to manipulate since it is not just the current object. We will see this in action, in 2 rules from now.
Then we loop over the Added Entitlement token, for UserAccount which then looks at the current operation to see if Login Disabled is already present. If not, it gets added to the current event as false, to try and reactivate the account in the target system.
Now one issue I have seen is that there are a couple of events in the same document, where you get a <r;add>r;, then a <r;modify>r;, and possibly another <r;modify>r;, thus this rule is trying to avoid the case of sending multiple instances of a modify of Login Disabled. This test would catch if it is in the current modify in my example of three events, but not the following or preceding one. However earlier they did a break, if this is not the case of a modify that contains an entitlement change, so it should not be an issue.
User Account entitlement change (Delete Option)
This rule handles the case where removing the entitlement means delete the user in the target system.
The conditions are similar to the previous rule, the GCV for using UserAccount entitlement is true, the remove entitlement mode is delete, it is a user, a modify and the UserAccount entitlement is in the current document and changing.
The actions send a delete into the target system, then does something I have not seen yet in this driver, it sets an XML attribute, sn:original-event to a value of 'modify'. Finally it removes the association back in the Identity Vault. I looked ahead and do not see any obvious policy that would use the sn:original-event attribute in the document. This leads me to think that the shim itself has some code that uses this value. Interesting, since I do not recall anything like this in the parts of the Service Now API that I looked at, primarily the SOAP interface. If anyone has any thoughts on this, please post a comment since this is interesting and has me wondering.
That wraps up this article, stay tuned for more as I work my way through this driver, policy by painful policy.