Walking through the Office 365 IDM driver – Part 9
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 this article I will continue through the Output Transform.
There are five policy objects in the Output Transform policy set.
I worked through the first and half of the second in part 8, and will continue on now.
There are seven rules in this policy, and here we see some Office 365 specific attribute manipulations.
- strip "Managed By" from group
- re-format Member values
- Update add event
- Check Query
- reformat BlockCredential
- reformat ImmutableID
- Handle AlternateEmailAddresses
Got through the first three in the previous article, so lets continue from there.
4. Check Query
This looks for Query events, and then loops over any search-attr nodes for UserPrincipalName and then stored the current value in a variable, removes that value by a Strip by XPATH token, just for the value node, and then rebuilds the UserPrincipalName as the variable, followed by an @ sign followed by the GCV for the O365 domain.
This is the same basic approach from earlier in the Update add event rule, and my comments there still apply, they should have used a reformat operation attribute token to more simply and consistently fix it and only need to be done once, since it would work on a modify, add, and query event, by design.
Since UserPrincipalName is mapped to CN, it makes sense to expand the name to a proper UPN. Personally I think storing a UPN value that can be modified and managed would make more sense. In fact in real world Office 365 implementations we are finding that storing and managing a single UPN is the key task we need to accomplish
5. reformat BlockCredential
If the operation attribute BlockCredentail, which is mapped from Login Disabled is available, then it removes the remove-value node, and adds a remove-all-values node to the modify for the BlockCredentails. I.e. Converts it from a standard IDM generated modify of remove old value, add new one, to a set the new value, removing whatever was there before indiscriminately.
6. reformat ImmutableID
The same thing done just a moment ago for BlockCredentail is now done for ImmutableID, where the remove-value node is removed, and a remove-all-values inserted in its place.
I am not sure why this is needed, unless the concern is that the value in those two attributes might be out of sync with the IDV and thus the remove of a very specific value might fail?
The Strip By XPATH in both cases looks like this:
That is, in the current context (the dot slash, which is not needed, since it is 'implied' already) for the modify-attr node, whose XML attribute attr-name is equal to ImmutableId, and then strip the remove-value node and down.
7. Handle AlternateEmailAddresses
If the AlternateEmailAddresses attribute is available, on a modify event, they then do an extra step of testing if the XPATH is true:
This is what an add value for the attribute would look like, which is what the Available test has already indicated. So a little redundant here. The operation attribute is available if there is an add-value in the document for it. It is changing if there is a remove-value, add-value, or remove-all-values for it. Thus you could test if op attr X is changing (add, remove, or clear) AND op attr X is not available (no add-value node) to see it is only a remove or clear case. Here this XPATH is ultimately redundant to the If Operation Attribute test.
After that little bit of redundant testing, you get to the actions, which builds a Query document in a nodeset variable, which is totally unnecessary as they could have just used the Query token, and then uses the Java query function that the engine exposes to query the source, for the Internet EMail Address of this object. They have a Text() token that holds the XML:
<token-text xml:space="preserve"><input><query class-name="User"</token-text>
<token-text xml:space="preserve"> dest-dn="</token-text>
<token-text xml:space="preserve">" scope="entry"><read-attr attr-name="Internet EMail Address"/></query></input></token-text>
So the document it generates will be
<query class-name="User" dest-dn="Source DN Of object" scope="entry">
<read-attr attr-name="Internet EMail Address"/>
Then they XML Parse it to turn it into a nodeset that is usable for the Java query function.
In fact, I take it back, they should have just used a Source Attribute token, and nothing else would be needed.
They do the query with an XPATH call of:
The query: is a prefix, defined by default, as is $srcQueryProcessor for use in querying. But since we have the Query token, and in this case, as simple as the Source Attribute, it seems kind of a wasteful approach to do it this hard, old fashioned way. The $query-back is the nodeset of the XML document they built as a text string and XML Parsed.
Then they remove the add-value nodes for AlternateAddresses with a Strip by XPATH like above, and then add a destination attribute, AlternateAddresses, the value is the XPATH of:
$query-results//attr[@attr-name="Internet EMail Address"]/value[last()]/text()
This says look into the query-results variable, for any (the double slash) attr node whose XML attribute attr-name is Internet EMail Address, and then take the last() value of the set.
The only benefit I see to this is if the attribute is possibly changing, to just take the last value from the attribute. This is not a reliable way to single value a possibly multivalued attribute, since the ordering is not reliable nor consistent. I am not sure that you can rely that the last value is the last one changed.
Finally, they append a remove-all-values node via Append XML element like before. But this could have been skipped entirely by using the set destination attribute value, instead of the add destination attribute value.
Overall this rule seems a bit odd.
This is a standard Account Tracking policy object, from a shared package which I have reviewed before. It is fairly complicated and interacts with the other rules in the set. Basically they want to maintain a simple attribute that has a value for each connected system and the state of the user. So DirXML-Accounts is used and recalculated every tie one of the known activity/inactivity attributes is changed. Then it can be synchronized to Sentinel to identify what accounts a user is active in. This is a little better than Associations or entitlements but adds additional maintenance.
There are three rules in this policy.
- Move User add Password
- Disable password change at first login
- Set Password Never Expires
1. Move User add Password
On an Add operation, if the Password attribute (note, not a <modify-password> event, nor an nspmDistributionPassword attribute, but rather a Password attribute) is not available, but the XPATH test of password is true then the rule fires.
That last XPATH test for a node called password, is related to the Subscriber Command Transform policy, NOVLOFFIPSWD-sub-ctp-TransformPwd which firs after the normal password sync rules transformed the <modify> for an attribute nspmDistributionPassword to a <modify-password> event. That rule then transforms the <modify-password> to a modify of the attribute named "Password". As I noted at that time, it seems likely that a direct schema mapping of nspmDistribtuionPassword to Password would probably have accomplished the same thing with a lot less processing.
However, I have that a bit backwards. If that rule had fired, then the Operation Attribute Password would be available. However on an <add> event, we get a <password> node usually, and this is meant to transform the add case.
Anyway. here, they change the <password> node, to an <add-attr> node for an attribute named Password, and flag it as sensitive using the Append XML tokens.
They do this by first adding the XML element add-attr, setting the attr-name attribute to Password, setting its type XML attribute to password-ref. Then add a value node, set the value nodes XML attribute is-sensitive to true to protect the password contents and then with a no-trace flag, setting the password nodes value into the add-attr's value node as the text. Finally strip the password node.
<nds dtdversion="4.0" ndsversion="8.x">
<nds dtdversion="4.0" ndsversion="8.x">
<add-attr attr-name="Password" type="password-ref">
<value is-sensitive="true"><!-- content suppressed --></value>
2. Disable password change at first login
A lot of systems, when a password change is done by Admin, which IDM often looks like, depending upon the API in use, have a setting to force a password change at first login. Thus if the Helpdesk changes your password, you are forced to change it on next login so that they no longer no it. Generally this is a good thing, it just happens to defeat the purpose of IDM synchronizing passwords, and needs to be disabled here. In the case of SAP User Modules, I happen to know that the driver does some interesting stuff. It does an Admin reset to a known random password value. Then it does a password change as the user, from the password it just set, to the actual password in the event. This way it looks like someone did an admin reset, then the user logged in and changed the password to comply.
Here, the flag attribute ForceChazngePassword get set to false to avoid the user needing to change it in the O365 interface again.
So if the class is MsolUser, since we are post schema map, and it is an add or modify, and the GCV ForceChangePassword is true and the Password op attr is available then the rule will fire. That GCV is probably named backwards. The description is, Disabled Force Password change at first login, so true means false here. Not that it matters just confusing and I had to go back and double check the meaning. I prefer to keep the name descriptive to save confusion.
In this case, the ForceChangePassword attribute gets set to false. Which tells the shim to set the flag in O365.
3. Set Password Never Expires
Similar to the previous rule, if the GCV PasswordNeverExpires is true, for an MsolUser, on an add or modify event and we have a Password attribute in the event documents, then the destination attribute PasswordNeverExpires is set to true. In this case, the GCV is named better, since true is true. Interestingly they manually add a remove-all-values node to the event, with an interesting Append XML element target of:
../modify/modify-attr[@attr-name="PasswordNeverExpires"] | ./add-attr[@attr-name="PasswordNeverExpires"]
That is, they want to be sure that if there is a previous value on the object to remove it. Of course in the case of an <add> I am not sure how that would be possible. But the XPATH is interesting, since they are trying to handle two cases, the Add and Modify case.
Thus you can break it up into two possibilities, separated by a pipe sign.
I think I see why the modify uses a dot dot (..) and the add case uses a single dot. They are thinking that maybe in an add, you might have a modify following it with a modify so you need to go back one level from the current event, if it were an add, to then come back and find the modify with this attribute. If it is a regular modify coming on its own without an add, it would still work. In the add case, the leading period slash is unnecessary, and could just be ignored entirely.
I am unsure what specific case they are trying to handle, that they could not just use the Set Destination Attribute value, instead of the Add Destination Attribute value. In the case of an add, it would mean no difference, since by definition, an add does not have an existing user to modify, and on a modify they are just now sending in the attribute and the value, so a Set Destination Attribute value would do the trick.
This is the generic password policy set rule that sends an email if the password change fails, and I discussed the entire set of password sync policies in my articles on how they work here:
That concludes the Subscriber channel and the Output transform. Next up the Input Transform then the Publisher channel.