Walking through the Office 365 IDM driver – Part 7


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 this article I will continue through the Subscriber Command Transform.

The remaining policy objects in the Command Transform are:

  1. NOVLOFFIENTEX-sub-ctp-EntitlementsImpl

  • NOVLPWDSYNC-sub-ctp-TransformDistPwd

  • NOVLPWDSYNC-sub-ctp-DefaultPwd

  • NOVLPWDSYNC-sub-ctp-CheckPwdGCV

  • NOVLPWDSYNC-sub-ctp-AddPwdPayload

  • NOVLOFFIPSWD-sub-ctp-TransformPwd

4. NOVLOFFIENTEX-sub-ctp-EntitlementsImpl

Entitlements by themselves do nothing, they are just packets of data. Something must implement them. You will commonly see in the packaged driver a rule like the one here, and as we saw in the Subscriber Match policy set that do something with the data. Back in the Matching policy, it checked the GCV to see if entitlement support was on, and if so, checked an object before matching to see if it had the UserAccount entitlement. If not, no go.

Here we are past that point, having decided to either create or match and merge the current user, so UserAccount is here, if needed by this point. But what if the event was changing the entitlement status (Revoked or Granted) or some different type of entitlement? That is what we shall see next.

There are eight rules in this policy to implement the various needed entitlement functionality.

  1. GroupMembership entitlement: veto membership without entitlement

  • Login Disabled attribute change in IDVault

  • Disable account for delete operation when using account entitlement

  • User Account Entitlement change (Delete Option)

  • User Account Entitlement change (Disable Option)

  • Check User modify for group membership being granted or revoked

  • Assign Licenses for License Entitlement being granted or revoked

  • Assign Roles for Role Entitlement being granted or revoked

1. GroupMembership entitlement: veto membership without entitlement

Similar to how in the Matching policy, we do not match or create users who do not have an entitlement, if we are using entitlements (GCV controlled), so too here for Groups, if we see a membership change on a user, then if we have the drv.entitlement.Group GCV set to true, we require a Group entitlement to control this membership.

Now this one is a little odd in how they approached it. They watch the Group object, and if its member list (Member attribute) is changing, and the GCV for Group entitlements is set to true then they strip the Member attribute (Using Strip by XPATH Expression instead of the simpler Strip Operation Attribute).

Initially I thought they were watching User objects for Group Membership and the lack of an entitlement, but in fact, any change to a Group member is what gets blocked. I guess just removing Member from the filter would do the trick as well. Probably the reason to ignore Group Membership attribute changes on a user is that Office 365 being Active Directory under the covers does not likely support the Group Membership (or in LDAP parlance memberOf) attribute on a User.

Here is another example of where a built in token can be done via XPATH as well, but the built in token is just simpler.

This XPATH for the Strip statement is:
./add-attr[@attr-name="Member"] | ./modify-attr[@attr-name="Member"]

You can see they needed to logically OR it (pipe symbol | ) to handle both the add and modify case, which of course the Strip Operation Attribute token does out of the box.

2. Login Disabled attribute change in IDVault

Login Disabled mapping with Entitlements is always an interesting one. Should the entitlement control the enabled state, or should Login Disabled. This rule is looking for the case where entitlements are enabled by GCV (drv.entitlement.UserAccount is true), syncing Login Disabled is not (drv.sync.disabled is false) and its a modify event with Login Disabled.

In which case, strip it out. If you wanted to disable this user in this case, you should have revoked the entitlement (and had the Disable on Revoke setting configured).

Interestingly here they use the Strip Operation Attribute token instead of Strip by XPATH Expression.

3. Disable account for delete operation when using account entitlement

This case is another fun one. If you delete the eDirectory object, is that a delete in Office 365? Maybe or maybe not, that is a good question. However one thing we know for sure, it is an implicit Entitlement revoke. After all the object holding the entitlement value is gone, by definition the entitlement grant is gone as well which makes it an implicit revoke.

This seems like one of those things to use the Disable vs Delete GCV to further fine tune. That is, if you are set to disable on entitlement revoke, disable. If you are set to delete on entitlement revoke, then delete it. However this just implements the disable case.

Regardless, the action is to set the destination attribute Login Disabled (Which will map to BlockCredential) to True, with a when = before. Direct or after would probably have worked as well. The only concern there is that the next action is a veto for the event, and thus you want to be sure not to accidentally veto this change you are sending on.

4. User Account Entitlement change (Delete Option)

This is a pretty common rule, in fact, I think it was just copied from another package it looks so familiar. If the GCVs for entitlements are enabled, and on remove/revoke of an entitlement we delete, then for a user modify with UserAccount changing, we do two loops.

First for all removed entitlements, delete the target user. and remove the association back in eDirectory to clean up for IDM license costs.

Since this is a modify not an add, in our second loop over any added UserAccount entitlements we set Login Disabled to false, to re-enable the account. After all the user must be associated and not a synthetic add (though I suppose it could be a merge), so the user must exist in Office 365 and just be disabled.

5. User Account Entitlement change (Disable Option)

This is the same basic rule as the Delete option, just a slightly different condition (different GCV value of course, disable vs delete) and inside the loop over Removed Entitlements, it sets Login Disabled instead of deleting the target user.

6. Check User modify for group membership being granted or revoked

The first rule in this policy we saw was about Groups but in fact it was blocking changes that were not entitlement driven. Here we are looking at the user to drive Group membership in the remote system via entitlements.

If the GCV drv.entitlement.Group is true then Group Entitlements are in use, then if it is a User, an add or modify event, and the Group entitlement is changing this rule will fire.

As is common for the Entitlement processing, there are two loops. One over Removed Entitlements and then a second over the Added Entitlements. For both cases there is a slightly odd call, if you are not expecting it.

<do-set-local-variable name="assoc" scope="policy">
<token-xpath expression="es:getEntParamField($current-node,'ID') "/>

This assoc variable is used to figure out the ID of the group to use. Even more amusingly, they left a hidden carriage return in the token, which is escaped and visible in the XML view. In ECMA It is just whitespace and does not really count. But does look a bit ugly.

It really should look more like:

<token-xpath expression="es:getEntParamField($current-node,'ID')"/>

This is copied throughout this policy and I have reported it so I expect it to be cleaned up in a later version of the package.

Anyway the point I started down was that Entitlements and their payloads changed format around IDM 3.6.1 and then again in IDM 4.0. The Entitlement tokens, in this case looping over the Removed or Added Entitlement noun tokens get treated sort of funny and the current-node local variable will be the <param> node of the path.xml component of the attribute not the entire attribute value that you might have expected. DirXML-EntitlementRef uses Path syntax which has three components, nameSpace (1 for Granted, 0 for Revoked), volume (the DN of the DirXML-Entitlement object being granted) and normally path. Which would be a text string. However specific to the Entitlement case (not sure if there are any others) the third component is actually shown as path.xml which MUST be valid XML. The error is actually pretty funny (Well I find odd things funny):

DirXML Log Event -------------------
Driver: \ACME\services\IDM\DriverSet\MyDriver
Channel: Subscriber
Status: Warning
Message: Code(-8031) NDS attribute DirXML-EntitlementRef treated as XML failed to parse:
'': (1): unclosed token
[09/09/11 16:08:30.492]:WACKEE SELECT ST:
DirXML Log Event -------------------
Driver: \ACME\services\IDM\DriverSet\MyDriver
Channel: Subscriber
Status: Error
Message: Code(-9010) An exception occurred: java.lang.NullPointerException
at com.novell.nds.dirxml.engine.event.DSEPath.toXML(DSEPath.java:182)
at com.novell.nds.dirxml.engine.event.DSEEventInfo.constructModifyValue(DSEEventInfo.java:1534)
at com.novell.nds.dirxml.engine.event.DSEEventInfo.constructRemoveValue(DSEEventInfo.java:1144)
at com.novell.nds.dirxml.engine.event.DSEEventInfo.toXML(DSEEventInfo.java:714)
at com.novell.nds.dirxml.engine.event.DSEEventInfo.toXML(DSEEventInfo.java:669)
at com.novell.nds.dirxml.engine.Driver.buildDocument(Driver.java:436)
at com.novell.nds.dirxml.engine.Driver.submitTransaction(Driver.java:625)
at com.novell.nds.dirxml.engine.DriverEntry.submitTransaction(DriverEntry.java:1050)
at com.novell.nds.dirxml.engine.DriverEntry.processCachedTransaction(DriverEntry.java:934)
at com.novell.nds.dirxml.engine.DriverEntry.eventLoop(DriverEntry.java:756)
at com.novell.nds.dirxml.engine.DriverEntry.run(DriverEntry.java:561)
at java.lang.Thread.run(Unknown Source)

Anyway the payload of the DirXML-EntitlementRef is carried in the path.xml component as XML that looks something like below:


This is the original format. The current node will be the <param> node. With IDM 3.61 and the CMP edition of the SAP drivers, they needed a way for one entitlement to carry multiple values, so they did something like:


Using the pipe symbol (|) to delimit values. With IDM 4.0 a new format, using JSON in the <param> node was added. To parse this, an ECMA function called getEntParamField() is used. Conveniently it is aware of both formats and will parse either.

The JSON version might look more like this example:

<param>{"ID":"{26dfb70f-0371-4fe2-a67f-bc101101e5d7}", "ID2":"cn=geoffc,ou=acme,dc=com"}</param>

The getEntParamField() function takes two arguments, the first is the data string, and the second is the name of the key you want. So passed in is $current-node, the current value presented by the loop, and then the string ID, since that is the key value pair we want to retrieve the value. One of the neat things I recently noticed is that they seem to be using ID1 and ID2 for the GUID and the DN of the target of the entitlement which is actually really nice, since you often need to know both at some point, so storing it at grant time seems wise.

Thus the set local variable for assoc, using this function retrieves the value for the ID key in the JSON string. The assoc value is used to define the target object to be modified, by referencing it by association. Then they append an XML attribute, association-ref to the remove-value or add-value generated in the loops, to give the current object (the user) association value.

This is needed so the shim can convert to the proper references in the target system.

If you are interested in reading more about Entitlements, I have written a series with a lot more details for your future edification:

I have a fifth one started, still collecting more info to bulk that one up, as it has a bunch of samples.

7. Assign Licenses for License Entitlement being granted or revoked

The license entitlement is basically the same approach as the other entitlements. A loop over the removed entitlements and a loop over the added entitlements.

In this case the change being effected in Office 365 is a removal or add of an attribute LicenseAssignment with the value from the entitlement. This makes my earlier concern in this series about the specific values allowed more pressing. In the add case an extra attribute of UsageLocation is added, then a <remove-all-values> node is added via a Append XML Element token call. This would have been simpler to just use the Set Destination Attribute Token instead of Add Destination Attribute Token.

What remains unclear here is how the GCV granted 'reverse' rights are handled? That is, if you wish to create an Entitlement value for License that removes the ability of a user to use say PowerPoint, it seems like you can do that by setting a value in the GCV and then I suppose granting that value in a License entitlement. But it is unclear how this is implemented and enforced. Perhaps at driver startup, the shim informs Office 365 of the 'reverse' license values? I would like to find this aspect out.

8. Assign Roles for Role Entitlement being granted or revoked

This rule is basically identical to the previous one, just the attribute in Office 365 being set is Role instead of LicenseAssignment. So on a Removed Entitlement it removes the specific Role value from a user. On an Added Entitlement it adds the specific Role value, using the payload of the association via the ECMA function.

That about wraps up this part of the Command Transform. Stay tuned for more in the next article.


How To-Best Practice
Comment List