Walking through the Office 365 IDM driver - Part 15

over 6 years ago

In part one of this series I walked through some of the configuration, Packages, and GCVs used in the Office 365 IDM driver.

In part two of this series I walked through more of the GCVs and looked at some possible values for the License entitlements.

In part three of this series I looked at the Filter and Schema Map and some more entitlement issues.

In part four of this series I looked at the configuration settings and then on to actual policies, getting through the Subscriber Event Transform policy set.

In part five of this series I worked through the Subscriber Match and Create policy sets.

In part six of this series I started in on the Subscriber Command Transform policy set.

In part seven of this series I continued through the EntitlementsImpl policy in the Command Transform.

In part eight of this series I finished up the Command Transform and started into the Output Transform.

In part nine of this series I finished walking through the Output Transform.

In part ten of this series I started down the Input Transform policy set getting through the first six policy objects.

In part eleven of this series I finished the Input Transform policy set and got through the Publisher Event Transform policy set.

In part twelve of this series I got through the Match, Create, Placement, and almost all of the Command transform policy sets.

In part thirteen of this series I finished the Publisher channel, wrapping up the driver.

In part fourteen of this series I started comparing the newest packages, to the ones I actually reviewed.

I left off comparing the changes between the packages of the Office 365 Default Config:

  • NOVLOFFIDCFG - Default configuration

         Was:     Now:

         Intermediate step of will be ignored.

The next policy to compare in the Output Transform, where the following changes occurred.


This looks like it really changed. Designer shows 8 different changes, some bigger than others. Working through these should be interesting.

The first two are really a pair of changes together. Before they had a Strip Operation Attribute for ManagedBy, a DN syntax attribute.

Followed by grabbing some data into a nodeset variable to loop over. They used to just grab the operation attribute Member, but now expanded the XPATH to get the ManagedBy attribute as well.

<token-xpath expression="modify-attr[@attr-name='Member']//value | add-attr[@attr-name='Member']/value | modify-attr[@attr-name='ManagedBy']//value | add-attr[@attr-name='ManagedBy']/value"/>

The reality is, I am pretty sure they could have just used the Operation Attribute noun token to get this instead of XPATH. In a nodeset variable, if you add multiple tokens, they do not concatenate like in a string variable, rather each token puts its values into a nodeset.

Thus saying local variable is Operation Attribute (ManagedBy) then Operation Attribute (Member) should nicely generate a nodeset of all the values of both attributes together.

Then they loop over the variable to ParseDN it down to the root most node, and change it from a DN syntax attribute value to a string.

They ignored my comment in the previous articles that this could simply be replaced by Reformat Operation Attribute token, and cut out many lines of code. Oh well. Reinventing the wheel again.

Next change is to change a condition from:

<if-xpath op="true">./add-attr[@attr-name='UserPrincipalName']</if-xpath>

to using the If Operational Attribute token, which works on add or modify, but since they also test for add events does it clearer and easier to read.

I missed a tiny cosmetic change as well, the name of this rule changed to say "add user" instead of just "add".

The next big change block is inside this User add rule, and it used to do a Query for GUID by building the Query XML in a nodeset variable, using the Java query: function, and then looking at the results. They listened to my complaint and changed that to use a Query token, which is exactly what it exists for, well done guys! Of course a rule or two later, they left in this old approach in Handle Alternate Email Addresses. Oh well, step by step.

Next in the Check Query rule, they added a condition:

<if-xpath op="true">./search-attr[@attr-name='UserPrincipalName']</if-xpath>

Which is wise, to scope it to UserPrincipalName queries only. However I think here too, the If Operation Attribute available token test would work on a Query as well.

What the rule here does is add a @ sign, then the GCV supplied domain to the users naming attribute. Basically build the UPN as Office 365 expects it.

My experience since I wrote the original articles is that in most cases, people want better control over UPN than this simple approach, perhaps First.Last@domain. Or maybe different domains for different users, and so on. Thus I would probably be redoing this rule and its partners on my own, in the real world.

The entire Reformat ImmutableID rule is removed. This used to change a remove-value/add-value event or just a simple add-value to have a remove-all-values. (Basically ensuring a single valued attribute did not get multi valued by accident. Not sure what else has changed so that this is no longer needed.

Finally a new rule is added Initialize GroupType. This checks if a local variable grpTypeInitialized is true, and if not, sets some variables to hard coded values.

  • DistGrpType gets a value of DistributionList

  • MailSecurityGroup gets a value of MailEnabledSecurity

  • NormalGrpType gets a value of Security

and then grpTypeInitialized is set to true so this only fires once.

Several problems here.

  1. These should just be GCV values, and then this is not needed at all.

  • This rule should be in the Startup policy set. New in IDM engine 4.0.2 patch 3 and later, two new policy sets were added. Startup and Shutdown. You can read about a funny error that caused me in this article:
    IDM Array Index out of Bounds error

  • Probably wanted to do this in the Input Transform, with the rest of the older startup processing events.

Anyway, and interesting set of changes. Two steps forward, two steps back in some ways. But interesting nonetheless.

See how much fun comparing changes can be?


The rule placement for users was building a destination DN on the Publisher by simply appending the value of the CN to the User container GCV.

Now they have inserted their reinvented Reformat Op Attr code snippet, that gets the op attr CN the hard way, via XPATH, instead of the simple Operation Attribute noun token, loops over the values (which means last will win), splits the string into a nodeset based on the @ sign, and then strips the current value, and sticks in the stuff before the @ sign (by casting the nodeset to a string, which I was surprised last time I looked at this in this series, that it even worked). A text book example of a use case for Reformat Operation attribute.

Of course it could have simply changed the use of CN in the last bit, to be an XPATH of substring-before("add-attr[@attr-name='CN']/value","@") if they wanted too. This really is the 'hard way' to handle it.

A modify case will probably want to do this reformat as well, so they probably have this implemented somewhere else to handle that case.

This change seems like a bug fix, that takes a step backwards. I concede it works, but it could have been done so much simpler.


Two new attributes are added to the Schema Map both for Group objects.

GroupType, mapped to GroupType which means it did not need to be added at all.
EMail Address which maps to EmailAddresses in Office 365.

Looking at eDirectory schema, I see that EMail Address is part of the Group class, so I guess this makes sense as a way to carry the email address of a Group around. Just better remember to handle the structured attribute issue, which I do not see in any of these policies yet.


Designer shows 6 differences here, this should be good.

First is an addition of the XML name space es: which is unnecessary as the engine provides it out of the box.

Second a new rule is added, remember this is the Subscriber Create policy, that for Group objects, if CN is not available, then Veto. Which is sort of strange, since CN is the naming attribute for a Group and mandatory in schema. How do you create an object without naming it.

Yep, checked Schema, CN is both mandatory and the naming attribute for a Group. I really wonder what they are trying to fix here? The filter has CN as sync in both directions, so it seems impossible for an <add> event to get here and not have a CN attribute. Strange. But in fact as I look further along I see this is actually just a move of the code, from later in the policy set. Regardless still seems like it should never ever fire.

The next 4 changes are all in the same rule, "Check for AD driver association". I complained a lot about this one, since I assumed it would use the association, which is the objectGUID from AD and use that value as the ImmutableID in Office 365. This would be a serious value add, as that would allow ADFS style federation against the AD domain, even though the O365 driver is connected to eDirectory.

Now in the real world, it turns out, most of our customers are simply standing up a brand new AD domain/forest just for ADFS and using IDM drivers to push the users into it, and control the UPN to be exactly what they want, since the one they want in AD is almost never the one they want as the email address in O365.

This rule checks if the GCV is set, saying use the AD association, and then loops over the structured GCV drv.sync.identity so that they can handle each case.

Traces out the current drv-ad-driver-dn value, now it sets the local variable ImmutableID as the XPATH:
add-attr[@attr-name='DirXML-Associations']/value[component[@name='nameSpace']/text()='1' and component[@name='volume' and contains(.,$current-node/definition[@name="drv-ad-driver-dn"]/value/text())]]/component[@name="path"]/text()

So pop quiz hotshot, what does that mean? (Is that reference too dated? )

Simply, it says get the PATH component (the GUID) of the DirXML-Associations attribute value, where the driver DN in the volume component matches the GCV we are working on.

Breaking that up, to make it easier to read. lets try it this way:

component[@name='nameSpace']/text()='1' and component[@name='volume' and contains(.,$current-node/definition[@name="drv-ad-driver-dn"]/value/text())

So for the add-attr node, whose attr-name XML attribute is DirXML-Associations, look in the value node, and select the one who meets two conditions:

nameSpace=1 (associated)
volume= our current AD driver DN value. which is this XPATH:


This is a contains() because they want you to enter the driver DN without the Tree name in the GCV, but eDir returns the Tree name. This is the \TREE\O\OU\CN format vs what they want you to enter in the GCV as O\OU\CN format. No leading backslash and no tree name.

Now, once you have found the DirXML-Associations node for the proper driver, and it's state is associated, then get the path component to get the AD objectGUID value.

If the value is not equal to null, then add the ImmutableID after running it through the ECMA function hexString2B64().

Now the first thing I would say is that the test should be changed to if local variable, not equal, regex compare type to . (period plus) which is a safer test generally.

Secondly this answered a question I had in my original walkthroughs. In fact I was not able to get even the ADFS/DirSync guys I work with to answer. If you want ImmutableID to be the objectGUID, what is the actual format it needs to be written as? Recall that GUID is a binary format that is decoded to a string, and then represented in a particularly goofy fashion, where the 'endian'-ness changes midway through some of the elements. Look at Wikipedia entry for GUID to see what I mean.

You can look at any of the ECMA functions in Lib-AJC (Now part of a Common ECMAScript library in all your drivers as of IDM 4.0x) for the ones that convert to and from GUID format to see the silly games that get played. I know there is a good reason, and it is somewhat standardized but on the surface it seems a bit silly.

Now this is much better than the original config which did not do this step of setting the ImmutableID to the GUID, rather it would just veto if there was no GUID/Association value and still use the UPN as the ImmutableID.

Personally I think more choices would be wiser for Immutable ID. Perhaps I only want those in AD already (since I will use ADFS to connect) but to use the ImmutableID as UPN instead. A simple change if you want to customize it but a seemingly likely use case and easy to support with a couple of GCVs and a branched logic around here.

Finally the last step is to trace out a warning that there is no association for this driver. I suppose that would work for users in only one AD driver, but if they existed in two, I imagine the later would win, based upon the ordering in the GCV. Since it is ordering in the GCV that means you can control it somewhat. But worth noting.

Stay tuned for the next article, where I hope to finally wrap this up. Unless they release more package updates, in which case, I guess I will be forced to return and revisit it.


How To-Best Practice
Comment List
Related Discussions