Walking through the Multi-Domain Active Directory Driver – Part 4

The new Multi Domain Active Directory driver is a clever new approach to drivers in general yet reusing the hard work and maturity developed in the classic Active Directory driver.

In part 1 of this series I discussed the driver creation method, since this time it matters how you do it. (Drag it from the palette not from Right click, Add New Driver).

In part 2 of this series I discussed the Connection configuration objects and got through most of the configuration settings.

In part 3 of this series I finished the configuration and discussed the Schema extensions and started on the Subscriber Matching policy set.

When last we left off, we were working through the Subscriber Matching Policy Set.


This policy has 7 rules:

  • veto out-of-scope events

  • remember relative position in heirarchy

  • generate full name if not in Identity Vault

  • match users based on NT Logon name

  • match users based on full name

  • match everything else

Handled the first five in the previous article, just these two remain.

  • match users based on full name

  • match everything else

match users based on full name

In the case of FullNameMap is true, then the cn= in Active Directory is based on the users Full Name attribute. Which if it did not exist a previous rule (the generate full name if not in Identity Vault rule) made sure to build.

Then if we are using Flat placement on the subscriber channel, using the operation property drv.subPlacementType, instead of the more traditional GCV value (Since we have multiple domains potentially supported here) the match is for an entry, built by the string cn= followed by the Full Name operation attribute value, a comma, and then drv.user.container operation property value.

If the placement type is not flat, it should be mirror, in which case we might search within the subtree of the user container in AD for this domain, however they actually generate the full DN using the unmatched-src-dn operation property as part of it.

However there is an interesting twist in here I would like to unpack.

They build it as CN= then the Full Name attribute value, a comma, and then a processed unmatched-src-dn followed by the drv.user.container operation property. The part I am trying to understand is after the Full Name comma, they do a Replace First token, that seems to add a comma to the end of the DN, and I just do not see why.

The action is:

<do-find-matching-object scope="entry">
<token-text xml:space="preserve">CN=</token-text>
<token-attr name="Full Name"/>
<token-replace-first regex="(. )" replace-with="$1,">
<token-parse-dn length="-2" src-dn-format="dest-dn">
<token-op-property name="unmatched-src-dn"/>
<token-op-property name="drv.user.container"/>

It is the following part that I do not get.

<token-replace-first regex="(. )" replace-with="$1,">
<token-parse-dn length="-2" src-dn-format="dest-dn">
<token-op-property name="unmatched-src-dn"/>

I ran a test case through Simulator. The Parse DN to length of -2, just chops off the CN= part, I get that. But after the Replace First there is a trailing comma, which I am having trouble seeing how it generates that. Ok, I see, there is a comma after the $1 in the replace string. Thus what they are doing is trying to avoid having a double comma, if there is no depth to the Unmatched Source DN value.

If you replace (. ) which is everything, with the same string plus a comma, then when there is a value, you get the value followed by a comma. But when it is blank, you do not get the extra comma, since there was nothing to replace, so no replaced value plus comma. That is surprisingly clever and subtle. That took me quite a while to figure out!

match everything else

This is similar to the standard Active Directory policy which basically tries to match all other objects. If placement is flat, by looking for the Source Name in the base container and if mirrored, by building the DN to search for based on the Unmatched Source DN followed by the base container.

Creation Policy Set:

Here we have two packaged policies.

  • NETQMADDCFG-sub-cp-Users

  • NETQMADDCFG-sub-cp-Groups


There are seven rules in here to look at:

  • Break if not a User

  • Veto if nspmDistributionPassword is not available

  • Veto if Full Name in not available and Full Name Mapping is turned on

  • Escape object name

  • Map CN to Active Directory user logon name

  • Map CN to Active Directory user logon name (pre-Windows 2000)

  • Identity Vault Accounts are enabled if Login Disabled does not exist

Without further ado, let us begin walking through these.

Break if not a User

With packages the idea is to try and build standalone packages that can be added and removed independently. Thus you could (or should?) have a package that handles the users, and a second that handles just groups, and possibly a third for Org Units. This way you can pick and chose which you want in your driver. This policy is here to limit this to just User objects so that potentially you could do that sort of thing. Now it happens they did Groups and Users in one package, but it is a good idea to keep in mind when designing your own packages.

Veto if nspmDistributionPassword is not available

Active Directory will not let you make an active user with a null password, so if there is no password, two options, set a default or wait for a real one to come. Because of how the engine works, often we see the user create and then the password set operation comes a moment later. Sometimes we see the password set first and then the User creation arrives. Regardless, this veto means that if the user comes first, no password, then when the password does arrive, we will have done a synthetic add to convert that modify of nspmDistributionPassword (it would be a event coming on the Publisher channel, just for general interest) into an add event with all the info the filter defines as being in scope.

If you turn this off, your users get created disabled in Active Directory. When a password is actually set on them, it should reactivate them in AD.

Veto if Full Name in not available and Full Name Mapping is turned on

When using Full Name mapping the cn= component of the object name in AD is going to be CN=FullName Value. Well, if you have no Full Name in the operation document you have a problem, and will error with a bad DN message from AD, since the DN will start with CN= blank whih of course is invalid. In other name mapping modes, where the Source Name is the cn= component in AD this does not apply so they test for the FullNameMap GCV to account for that. After all, for an object to exist it must have a Source Name.

Escape object name

In both the case of UpnMap equal to edir-name-auth and LogonMameMap equal to true, we use the eDirectory Source Name as the basis of the AD name. These have some character limitations, so we do a Replace All to get rid of everything that is not legal. This is a bulky Regular Expression that was updated to match the proper excluded character sets. A while back someone noticed that it was not catching them all and they updated it in the general Active Directory driver, and also in this one. You can see that a lot of the policy code was copied from the standard Active Directory driver policies.

Map CN to Active Directory user logon name

When the GCV controlling UPN is configured for edir-name-auth, then in a normal Active Directory driver, we would set the DirXML-ADAliasName attribute. In this driver they took a page from my idea for plural DirXML-ADContexts and DirXML-ADAliasNames and ran with it. This driver has a pair of new schema attributes, DirXML-MDADAliasName and DirXML-MDADContext that are Path syntax. Amusingly they did not add the 's' on the end to make them plural, even though by definition they are plural. Path syntax means they have three components, a DN which is this driver instance, a nameSpace which I just set to the current CTIME, and a path component holding the UPN value. The UPN is built as object-name@drv.domain.dns.name GCV. The object-name variable is the santizied for AD version of Source Name.

This value is sent into the destination, to become the UPN value. Then the policy loops over the Source Attribute DirXML-MDADAliasName and checks if the driver DN matches the current driver, if so, it removes the specific value. This is important else you end up with users with lots of these attributes, so it is hard to tell which is real. Having the timestamp helps there, as the highest one is the latest.

It is important to note that the DirXML-MDAliasName is meant to allow multiple MDAD drivers to coexist in the same tree out of the box.

Once you have cleaned up any old values (note that this loop will remove ALL values for this particular driver instance) it is time to add the new one back to eDirectory. Same approach as sending it to Active Directory. Also the object class DirXML-ApplicationAttrs is added at the same time. Personally I would have wrapped that in a test to see if the Object Class already had it, and only send it if needed. But I think eDirectory does not error when you do that, if the value was already there. The reason that would matter is that the remove and add values for DirXML-MDADAliasName, and the add value for the Object Class would all be in one event document and if it failed because the object class was already there the entire document fals.

Map CN to Active Directory user logon name (pre-Windows 2000)

If the LogonNameMap GCV is true then set the CN, which maps to samAccountName in Active Directory to the cleaned up object-name variable, making sure to truncate it to 20 characters to meet the old NetBIOS restrictions.

Identity Vault Accounts are enabled if Login Disabled does not exist

This rule tests for Login Disabled, and if there is no such value in the operation document, then it sets it explicitly to false in Active Directory. Since this does not block disabled users, I am not entirely sure what this is needed to accomplish. I suspect this is a holdover from the days of passwordless creates leaving a disabled Active Directory user. If you happen to understand the use case that requires it, please post a comment since I would be interested in understanding.


This policy has two rules:

  • Strip dynamicDN from nested group member

  • Send DirXML-MDADAliasName to AD when a Group is being created

Strip dynamicDN from nested group member

This one is interesting, as for Add events for Group objects it looks at the Member attribute for a specific value. I first read this and thought this should be done with Strip Operational Attribute not XPATH. But then I read it closer and understood.

The XPATH in the Strip by XPATH Expression token is:
$current-op/add-attr[@attr-name="Member" and contains(value/text(),"[DynamicDN]")]

This is interesting as they used $current-op, which is really a pointer at the current document, but simply using nothing would have suffice. I.e. this XPATH should work as well:
add-attr[@attr-name="Member" and contains(value/text(),"[DynamicDN]")]

I am not quite sure why the variable is being used. As for the rest of it, the key is that the predicate has two parts, that the XML attribute attr-name is Member, then a logical 'and' for the value is [DynamicDN]. Thus only that one specific text string will be removed.

Again if you know what they are going for here, comment please as I would be interested in hearing.

Send DirXML-MDADAliasName to AD when a Group is being created

Groups do not have UserPrincipalName attributes, so instead we set the name of the object into the DirXML-MDADAliasName attribute which maps to samAccountName, and there is an interesting note in the commentary that they no longer trim it to 20 characters long, since Windows 2000 is not supported by Microsoft any longer. But interestingly they did not update the User policy to match. Probably not a big deal just a minor inconsistency.


The final policy object in the Subscriber Create Policy set is about Exchange Mailboxes. There is a single rule:

  • default Exchange assignment

Here we test for the GCV drv.exchMailboxMethod being equal to policy. The options are policy or entitlement, where the payload of the entitlement tells you which mailbox to use. When set to policy, the value comes from the GCV gcv.exchDefaultMDB. Then the Source Name is cleaned up again with a similar Regex to the ones before, then one extra check that is an interesting Regex in a ReplaceAll token:


. (Just a period)

I think what this is saying is find ASCII 46, which I had to look up, if you did not you are a true geek, (Of course if you know the EBCDIC value of it, you seriously need to get a life) and is of course, a period. So I think it is looking for a period, followed by any number of additional periods. So basically this is trying to catch a .. or ... or .... and so on case, and replace it with just a single period.

I have no idea why this case is needed to be handled but it certainly is interesting.

That about wraps up the Create policy set, onwards and upwards to the Placement Policy Set in the next article.


How To-Best Practice
Comment List
Related Discussions