Wikis - Page

Managing multiple Active Directory domains in one IDM system - Part 4

0 Likes
The Active Directory driver in all versions of Identity Manager from 2.0 and up, when we started using DirXML Script instead of XSLT for policies have had a pair of attributes in common. DirXML-ADContext and DirXML-ADAliasName.

These are used to handle the strange circumstance of a rename or move event in Active Directory. The shim cannot tell the difference between a rename or move event. Both cases are actually a modify of the distinguishedName (DN) attribute.

For example: cn=geoffc, ou=Users, dc=acme, dc=com

If this were to change, it would depend where the change occurred to know if this was a move or rename event. If the cn=geoffc part changed, then that is a rename event. If any of the ou=Users, dc=acme, dc=com part changed, then this was a move event, since the parent container for the object is now different, in other words a move event.

You can find the policies that manage this in the Publisher Event Transformation rule set. There have been a number of different shipping default configurations for Identity Manager, so the name of the rule and its exact workings have changed over time. With the advent of IDM 4 and Packages, we should see this stabilize and become more manageable.

The problem with using single valued, simple string attributes for this task is how do you handle a second AD driver in a different domain? Well if the user is only ever in a single domain, that is fine, but if you have worked with IDM then you know that one of the cool things about IDM is how easy it would be to manage users in multiple AD domains, eDirectory, and many other connected services.

If you add a second Active Directory domain to your IDM world, then the values of DirXML-ADAliasName and DirXML-ADContext will be incompatible between drivers and domains.

In the first article in this series Managing multiple Active Directory domains in one IDM system - Part 1 I discussed an approach in general of a plural version of the attributes, using Path syntax.

In the second article in this series Managing multiple Active Directory domains in one IDM system - Part 2 I discussed more of the specific implementation details of making this work. I provided some sample code for making sure you update the attributes correctly.

In the third article in this series Managing multiple Active Directory domains in one IDM system - Part 3 I worked through a good chunk of the Publisher channel rules that need to changed for the DirXML-ADContexts attribute. Still need to do the same for the DirXML-ADAliasNames attribute.

In this article I will work through the rest of the Publisher channel.

As a quick recap, we will use DirXML-ADContexts and DirXML-ADAliasNames (note the plural) as multi valued, path syntax attributes instead of the single valued string equivalents that IDM ships with. In the previous article I showed some sample code on how you might update that attribute. The key is to remember to find the current value associated with this driver, remove it, then add a new value in.

Next up, is to decide WHERE do we need to make these changes? Well the easy way to manage this is to export the driver configuration as an iManager configuration file, open it in a text editor and then search for the various attribute names.

I wanted to use the latest configuration, since the IDM 3.6.1 has several possible configurations. (V4, V5, V6, and with one of the patches V7). However I happen to know that there are a number of bugs fixed in the IDM 4 Package version of the driver. I was starting a new project that needed an Active Directory driver but could not yet use IDM 4 for this project, instead had to use IDM 3.6.1. So I decided to try something funny.

I started a scratchpad Designer project, set up an IDM 4 Identity vault, added the Active Directory packaged driver, with all the options, and then I configured it for the most part.

Next I exported the driver to an iManager configuration file, and edited that, making it work with IDM 3.6.1. I have to find the time to write up that exercise as that was quite interesting to see how Packages have changed some things in the config files.

Then I searched through to find all the locations these attributes are in use. Here are my results, shown for the two different attributes, in case you want to identify them independently.


DirXML-ADContexts plural:




Input Transform:

     NOVLADDCFG-itp-SubscriberUserAdd 1 rule



Publisher Channel:

     Event Transformation:

          NOVLADDCFG-pub-etp-HandleMovesAndRenames 3 rules


     Create Policy Set:

          NOVLADDCFG-pub-cp 1 rule


     Command Transform:

          NOVLADDCFG-pub-ctp 2 rules



Subscriber Channel:

     Command Transform:

          NOVLADENTEX-sub-ctp-EntitlementsImpl 2 rules (more?)





DirXML-ADAliasNames:



Filter (done)

Schema Map (done)

Subscriber Channel:

     Create Policy Set:

          NOVLADDCFG-sub-cp-Users, 1 rule

          NOVLADDCFG-sub-cp-Groups 1 rule


     Command Transform:

          NOVLADENTEX-sub-ctp-EntitlementsImpl 2 or more rules)



Publisher Channel:

     Command Transform:

          NOVLADDCFG-pub-ctp 2 rules

          NOVLADDCFG-pub-ctp-UserNameMap 5 rules





New rules needed:

     Input Transform

          itp-Convert Plural Attribute


     Output Transform

          otp-Convert Plural Attribute




We are working through the changes needed for the DirXML-ADContexts attribute and in the Publisher channel, up to the Command Transform.

In the Policy object pub-ctp (part of the NOVLADDCFG package) there is one more rule that needs updating.

set cached context value on merge


Now this rule puzzles me. It looks like there is a bug in the configuration, or else I do not understand what is going on. From the rule name, since there is no Comment to explain, one would assume on a merge event, then this rule should update the cached context value. The cached context value as you will have noted from the previous article is the DirXML-ADContext attribute.

This makes sense. When you either migrate an object, or else make a change on it once the driver is running and the object is not associated, then it will take that event (<sync> or <modify>) and convert it to a synthetic add event. The first thing that happens on a synthetic add is an attempt to match. If it matches, then the two objects are merged together. You also get an XML attribute from-merge with a value of true in the <add from-merge='true'> event node.

Now the condition test for this rule is if XPATH is NOT true @from-merge='true' then it would fire, which seems backwards to me. I have switched it to true, so I am not sure what the story here is really. I think I am correct, but not sure if there are unintended consequences to this rule.

Anyway, inside the rule, there was an add destination attribute DirXML-ADContext action. Well we just need to replace that with the structured attribute add destination attribute that the last few articles have been talking about. Again I think it worthwhile to do a loop and read back the current DirXML-ADContexts, compare for any for this driver, and if found remove them. This is important as there are easy error cases to get into where you might have more than one value, if you did not have this loop present. The simplest example is if you decided to redo a test with a user and remembered to remove the DirXML-Associations value for the driver, but forgot to clean up the DirXML-ADContexts attribute. By doing the check here, that gets cleaned up nicely.

That completes the Publisher channel, now on to the Subscriber channel. There is only one Policy object of interest and it is in the Command Transform named sub-ctp-EntitlementsImpl (part of the NOVLADENTEX package) and it has a couple of rules that need updates.

User Account Entitlement change (Delete Option)
User Account Entitlement change (Disable Option)

These rules are used when you have enabled (via a Global Configuration Value (GCV) setting) the use of entitlements. You should be using entitlements for IDM now a days, mostly because the Roles Based Provisioning Module (RBPM) needs them to really be useful. Basically an entitlement is something granted to an object, that entitles them to use something. (as the name would suggest). For a variety of reasons, in RBPM, there is an abstraction called Resources, that mostly map one to one to Entitlements, mostly for naming and prettiness issues. A friend summarized it nicely (Hey Mike W!) that entitlements are for computers, resources are for people. (I think he is a computer chauvinist, but what else is new in technology jobs?). Anyway, a Role is composed of a bunch of other Roles and/or Resources. But if you do not have Entitlements, there is not a lot you can do with RBPM. So you should be using them.

Anyway, when you add or remove an entitlement, then the driver uses that as the trigger to know to add, delete, or disable the User. In the Active Directory driver, when the Entitlement is removed, the driver configuration offers two choices, delete or disable the AD user. This makes sense as you might not want to delete them, since getting their SID back in AD is hard, and thus any rights they might have had, or rights granted across trusts, so it is better to disable until you are sure you really want to delete them.

Thus the two rules handle these two cases. Now these rules are somewhat different than the previous rules, since they use the Clear Source attribute token, which removes all values in the source (Identity Vault, since we are now on the Subscriber channel).

Obviously with a multi valued plural set of attributes, this will not be acceptable. Well easy fix, we already have the code to do it. We just loop through the DirXML-ADContexts values, test to see if each such value is for our current driver, and if so remove it.

The only major change is that we need to change the channel, since the code samples we have were for the Publisher channel, where we were using destination tokens, and now we need to use source tokens. Easy enough to change in the XML Source view, and a bit of a pain in the Policy Builder view. Here is what the code should look like:

<do-for-each>
<arg-node-set>
<token-removed-entitlement name="UserAccount"/>
</arg-node-set>
<arg-actions>
<do-delete-dest-object/>
<do-remove-association when="after">
<arg-association>
<token-association/>
</arg-association>
</do-remove-association>
<do-for-each>
<arg-node-set>
<token-src-attr name="DirXML-ADAliasNames"/>
</arg-node-set>
<arg-actions>
<do-if>
<arg-conditions>
<and>
<if-xpath op="true">$current-node/component[@name='volume']="~dirxml.auto.driverdn~"</if-xpath>
</and>
</arg-conditions>
<arg-actions>
<do-remove-src-attr-value name="DirXML-ADAliasNames">
<arg-value type="structured">
<arg-component name="nameSpace">
<token-xpath expression='$current-node/component[@name="nameSpace"]'/>
</arg-component>
<arg-component name="volume">
<token-xpath expression='$current-node/component[@name="volume"]'/>
</arg-component>
<arg-component name="path">
<token-xpath expression='$current-node/component[@name="path"]'/>
</arg-component>
</arg-value>
</do-remove-src-attr-value>
</arg-actions>
<arg-actions/>
</do-if>
</arg-actions>
</do-for-each>
<do-for-each>
<arg-node-set>
<token-src-attr name="DirXML-ADContexts"/>
</arg-node-set>
<arg-actions>
<do-if>
<arg-conditions>
<and>
<if-xpath op="true">$current-node/component[@name='volume']="~dirxml.auto.driverdn~"</if-xpath>
</and>
</arg-conditions>
<arg-actions>
<do-remove-src-attr-value name="DirXML-ADContexts">
<arg-value type="structured">
<arg-component name="nameSpace">
<token-xpath expression='$current-node/component[@name="nameSpace"]'/>
</arg-component>
<arg-component name="volume">
<token-xpath expression='$current-node/component[@name="volume"]'/>
</arg-component>
<arg-component name="path">
<token-xpath expression='$current-node/component[@name="path"]'/>
</arg-component>
</arg-value>
</do-remove-src-attr-value>
</arg-actions>
<arg-actions/>
</do-if>
</arg-actions>
</do-for-each>
</arg-actions>
</do-for-each>



Initially the rule looped through the Removed Entitlements token results, since it is a little awkward to select them out the raw XML, so a token was added to make it easier, and then did a clear source attribute for DirXML-ADAliasName and DirXML-ADContext and then in the Delete rule, deleted the object in Active Directory, and removed the association value.

This replaces the clear source attribute tokens with a for each loop over the attribute of interest. (Both of our new plural attribute cases are present in both of these rules).

You can see from the XML how easy it is to change the channel in XML, just edit the nodes <token-dest-attr name="DirXML-ADContexts"/> and <do-remove-dest-attr-value> to be <token-src-attr name="DirXML-ADContexts"/> and <do-remove-src-attr-value>. The dest to src switch is really easy, just remember to do the close nodes as well, or else you invalidate the XML and Designer will not let you switch back to the Policy Builder view, nor save it. (Which is really handy since I often forget or make a typo!). Personally I want a button in the user interface to change channels, but then I want a lot of things.

With that rule finished, we have all the known instances of DirXML-ADContext replaced in a compatible fashion with DirXML-ADContexts, the plural version. Now on to the slightly harder example of DirXML-ADAliasNames.

It turns out that while DirXML-ADContext is used for rename and move support, the use for DirXML-ADAliasName has actually changed over time. That is, in earlier driver configurations, DirXML-ADAliasName was mapped to Active Directory's sAMAccountName attribute. This was actually helpful, as CN was multivalued and mapping a multivalued to a single valued attribute can be quite awkward. Additionally, this allows a user to have a different common name in eDirectory than they have in Active Directory which can be helpful at times.

However, with Identity Manager 3.6.1 and the V5 default driver configuration, this mapping changed, from sAMAccountName to DirXML-ADAliasName to instead hold the userPrincipleName value. userPrincipleName (UPN) in Active Directory is a somewhat odd attribute. Usually it holds a name in the format of sAMAccountName@domain.com that kind of looks like an email address, but almost never is a valid email address unless your email domain exactly coincides with the Active Directory domain root. It turns out that Active Directory does not actually validate this value. That means you can actually put any string in there and it will let you, so take care. I know this because we had a client who had a typo and set a couple of thousand users with an incorrect domain value, and no one really noticed. We corrected it with a toolkit rule, like the kind discussed in this series of articles:








Anyway, the change of the mapping was more in depth than just the mapping itself. There are a number of rules that generate the attribute value, and manage it that needed to be modified to support it. I have actually gone through the process of trying to convert the new mapping to be like the old mapping, and it is about as much work as this exercise is, to change how DirXML-ADAliasName and DirXML-ADContext are used.

From the listing of rules affected at the top of the article, we see we have a number of changes needed. We need to update the schema map, since now we are mapping DirXML-ADAliasNames (plural) to userPrincipleName instead of the singular version. Thus we also need to update the Filter, or else the events won't come through.

There are five policy objects that have rules to be changed, and we will work through those, but we also need to add two new policy objects, one in each of the Input and Output transform policy sets. This is because instead of being a simple single valued attribute mapping, we now have a multivalued structured attribute being synchronized with a single valued string attribute, and that just won't work well without some hand holding.

Lets start with the Input and Output transform rules, since these are actually quite simple, with tricky consequences. In fact the Output Transform is a nice simple one liner, that uses the reformat operational attribute token to accomplish everything we need.

You can either take the approach of actually testing for something in the condition block, or not. I prefer to test for if operational attribute is available personally, but when you look at the default policies from Novell you will see they generally do not do any testing, only if they are using the reformat operational attribute token, since of course it does nothing if the attribute is not present in the current document.

Regardless, here is the token as I first used it:

<do-reformat-op-attr name="userPrincipalName">
<arg-value type="string">
<token-xpath expression='$current-value/component[@name="path"]/text()'/>
</arg-value>
</do-reformat-op-attr>



Simple, since we are taking a structured attribute, and flattening it. This takes advantage of the very handy reformat operational attribute token, which is great as it knows how to handle all the different cases where this attribute might come through the driver. That is because a <modify>, <add>, and <instance> event have slightly different XML, so doing this by hand is actually a fair bit harder than it looks. You can read more about the power of this token in this article: Reformat Operation Attribute


Now you will notice there is no testing to be sure this is our instance of the attribute, since we need to make sure that we only send through one attribute change. As I think about it now, I wonder if this will be an issue. For example, once you have two such drivers operating, associating a user to the second driver would probably trigger a change in this driver to the DirXML-ADAliasNames, so I guess we should strip out irrelevant values. Good news is we have the code to do that already in our previous drivers, we just need to change the focus a bit. We could do this by looping through the operational attribute, but after further reflection it seems like a strip by XPATH would be much easier. However, because this could be an <add> or a <modify> event, there are actually at least two different XPATH strings to strip them both. Now I could do this all in one XPATH statement, using OR symbols (pipe or |) but that makes it really hard to read. It turns out to be easier to just do two or three (I include the <instance> case, though it is probably never going to be needed, just to be complete) strip by XPATH tokens to maintain readability over pure elegance.

<do-strip-xpath expression="modify-attr[@attr-name='userPrincipleName']//value[component[@name='volume']!='~dirxml.auto.driverdn~']"/>
<do-strip-xpath expression="add-attr[@attr-name='userPrincipleName']//value[component[@name='volume']!='~dirxml.auto.driverdn~']"/>
<do-strip-xpath expression="attr[@attr-name='userPrincipleName']//value[component[@name='volume']!='~dirxml.auto.driverdn~']"/>



Basically this uses the XPATH of:

attr[@attr-name='userPrincipleName']//value[component[@name='volume']!='~dirxml.auto.driverdn~']"



Differing only in the first node, being either <modify-attr>, <add-attr>, or <attr> nodes in our three possible document cases. In all three, we look for the one where @attr-name = 'userPrincipleName' so we know it is our correct attribute, then knowing it is structured we look for any (the // means any child instance) <value> node where <component name = 'volume'> is NOT equal to our current driver, via the auto GCV. I.e. Strip out everything else. Then do the reformat operation attribute, and we should be good to go.

In the next article we will continue with the counterpart to the Output Transform rule, the Input Transform, that has a subtle twist we need to deal with, then continue working through the rest of the rules that are involved.




Labels:

How To-Best Practice
Comment List
  • There is a spelling oversight in some of your xpath examples - the correct attribute name is userPrincipalName not userPrincipleName as you have (sometimes) written.

    Based on self:: ancestor:: trick from Lothar's article www.novell.com/.../again-power-xpath-or-missing-max-function , the xpath I came up with (which might be able to be optimised or written a bit more clearly) is listed below. This summarises the three do-strip-xpath lines into one xpath expression (that doesn't need to rely on complicated OR symbols)

    self::*//value[ancestor::*/@attr-name="userPrincipalName"]/component[@name='volume' and text()!='~dirxml.auto.driverdn~']/..

    According to lothar, this covers add/modify/instance/query
Related
Recommended