With the release of NetIQ Identity Manager 4.0 Support Pack 1 (aka IDM 4.01) some bug fixes, and a few new features were added.
Specifically three partner provided drivers were included, an RSA Driver, a Blackboard driver, and a Google Apps driver.
I discussed some of the new features and bugs fixed in IDM 4.01 in this series of articles:
I have been working on a series of articles walking through driver configurations, policy by policy to try and understand what the driver is doing, under the covers.
You can see more of these walk throughs on a Wiki page I maintain to keep them all together: Detailed driver walk through collection.
For this series of articles I would like to start looking at the Google Apps driver in IDM 4.01, that is provided by Consensus Consulting.
In the first article in the series I worked my way through the Subscriber Event transform and half way through the Matching Policy set.
In the second article in the series I worked my way through the rest of the Matching Policy set.
In the third article in the series I worked my way through the Creation policy set.
In the fourth article in the series I started working through the Placement policy set.
In the fourth article I did not quite finish the Subscriber Command Transform, so in the fifth article I continued to the end of the Command Transform and part way through the Schema Mapping policies.
In the sixth article in this series I would like to finish the Schema mapping policy set and begin to work through the Output Transform policy set.
In the seventh article in this series I worked through most of the rest of the Output Transform. It turns out there is a fair bit more in the Output transform than I expected.
In the eighth article in this series I wrapped up the Output transform Policy set and start in on the Input Transform policy sets.
In the ninth article in this series I continued on through the Input Transform policy set.
In the tenth article in this series I continued through the Input Transform.
In this article the long slog through the Input Transform continues finally drawing to a close. That took a bit longer than expected, but I think lots of interesting things came out of it. I hope you have enjoyed it as much as I did.
This policy has two rules, lets start with the first one.
Intercept GoogleAccount (tagged identity query) query response
Again, we check for a driver scoped variable UserAccountEntitlementQuery to know that this is our special query case, and differentiate it from a driver start up event. It also needs to be an <instance> document, and the class name should be the funny driver start up class, “__driver_identification_class__”.
First action is to clear that driver scoped local variable, so we would not do this again until the Output Transform sets it again on the next relevant query.
The events object class is morphed into a GoogleAccount object (we are in the Input Transform, so in the application name space as we are before the Schema Map policy set).
Now this I do not entirely get, they do a strip by XPATH, for ‘attr’. That will remove all the <attr> nodes in the document, which is traditionally the entire payload of interest. I.e. Remove everything of interest.
Then using a series of append XML elements to add nodes (like <attr>) and set XML attribute tokens ( to add the attr-name part in, so it looks like <attr attr-name=’GoogleAccountDisplayName’> ), and append XML Text tokens to add stuff in between the <value> and </value> nodes, they rebuild the document so it begins to look as follows when you have only one domain and no sub domains. (How my default driver is configured).
<nds dtdversion="4.0" ndsversion="8.x"> <source> <product version="126.96.36.199">DirXML</product> <contact>Novell, Inc.</contact> </source> <input> <instance class-name="GoogleAccount" src-dn="PrimaryDoomain.com"> <attr attr-name="GoogleAccountDisplayName"> <value>Google Apps Account in domain: PrimaryDoomain.com</value> </attr> <attr attr-name="GoogleAccountDescription"> <value>This entitlement will grant a the user an account in the domain "PrimaryDoomain.com" which means they will have the email address in Google Apps of "username@PrimaryDoomain.com".</value> </attr> <attr attr-name="GoogleAccountValue"> <value>PrimaryDoomain.com</value> </attr> </instance> </input> </nds>
It does look like it really does throw away any data returned, and just makes a pretty response. I suppose this is because it may not be possible to query into Google, so every response is going to be empty, but this way at least you send something reasonable back into trace. Entitlements and Reporting require these queries to work and return something, so I suppose this is as reasonable as anything else.
Other than building the new document with the append XML style tokens, some other interesting things that happen is a neat strip by XPATH token of:
This means, in the current node, any <attr> node who has no sub nodes. This nicely cleans up any poorly formed nodes. I am not sure why, when the earlier strip of attr, should have removed all the attr nodes and the only ones there should have been added back by their work in this Policy. Odd. But it is a nice safety step just to be certain.
You can read more about using the XML building tokens in this article: Common Mistakes Newcomers to IDM Make – Part 10
Anyway there is a for each loop for sub domains. So my first attempt was with just a primary domain called PrimaryDoomain.com (Note the silly typo). So I added into the GCV two sub domains. when I run through a query that has nonsense data but meets the criteria in Simulator, I get back this result:
<nds dtdversion="4.0" ndsversion="8.x"> <source> <product version="?.?.?.?">DirXML</product> <contact>Novell, Inc.</contact> </source> <input> <instance class-name="GoogleAccount" src-dn="PrimaryDoomain.com"> <attr attr-name="GoogleAccountDisplayName"> <value>Google Apps Account in domain: PrimaryDoomain.com</value> </attr> <attr attr-name="GoogleAccountDescription"> <value>This entitlement will grant a the user an account in the domain "PrimaryDoomain.com" which means they will have the email address in Google Apps of "username@PrimaryDoomain.com".</value> </attr> <attr attr-name="GoogleAccountValue"> <value>PrimaryDoomain.com</value> </attr> </instance> <instance class-name="GoogleAccount" src-dn="SubDomain1.PrimaryDomain.com"> <attr attr-name="GoogleAccountDisplayName"> <value>Google Apps Account in domain: SubDomain1.PrimaryDomain.com</value> </attr> <attr attr-name="GoogleAccountDescription"> <value>This entitlement will grant a the user an account in the domain "SubDomain1.PrimaryDomain.com" which means they will have the email address in Google Apps of "username@SubDomain1.PrimaryDomain.com".</value> </attr> <attr attr-name="GoogleAccountValue"> <value>SubDomain1.PrimaryDomain.com</value> </attr> </instance> <instance class-name="GoogleAccount" src-dn="SubDomain2.PrimaryDomain.com"> <attr attr-name="GoogleAccountDisplayName"> <value>Google Apps Account in domain: SubDomain2.PrimaryDomain.com</value> </attr> <attr attr-name="GoogleAccountDescription"> <value>This entitlement will grant a the user an account in the domain "SubDomain2.PrimaryDomain.com" which means they will have the email address in Google Apps of "username@SubDomain2.PrimaryDomain.com".</value> </attr> <attr attr-name="GoogleAccountValue"> <value>SubDomain2.PrimaryDomain.com</value> </attr> </instance> </input> </nds>
This is quite clever. They added in <instance> doc nodes for the sub domains.
If you are not familiar with using Simulator, you can read more about it in this article: Using Simulator in Designer
Simulator is a great tool to test out rules and policies, with more control than you would have in a driver.
Basically they loop over the List GCV holding sub domains, and they use the XML building tokens to build the sub domain response documents, node by node.
This seems like a lot of work, in comparison to XSLT, where you can literally just type in the XML and it gets copied in, but I am still a fan of using this approach over the XSLT approach in most cases. I especially like using the token approach based on how well it works in a loop for building a XDS document.
So the <instance> node is added via an Append XML element to the XPATH of ./parent::* which is a way to address the top of the document and make it a sibling of the current event document.
Then they add in a class-name, src-dn, XML attribute using a clever approach. I would typically have used the predicate of [last()] knowing that I am always working on the last one. The reason this matters is if you do not scope WHICH node you are adding the XML component too, it will actually add them to all that match. I.e. If you set XML attribute attr-name to the XPATH of just ‘attr’ then it will set it on every attr node. This is really annoying. I have a clever example of code I wrote that demonstrates this in Simulator that I will submit in another article, since it is an interesting discussion all on it’s own.
However in this case, since they are appending an entire <instance> event as a sibling of the current one, my approach probably would not work as well. Anyway they use the following XPATH to constrain it:
./following-sibling::instance[count(@class-name) = 0]
So from the current event document, the following sibling, which is an <instance> node, whose @class-name is not there. (Count of an empty XML attribute would of course equal zero).
Since this is done just after the <instance> node is added, of course it is only a single document that is missing it and this is done for the class-name and src-dn where src-dn is the current-node, aka the current sub domain being considered.
Then for adding the <attr> node, they append XML element, where the scope it by looking for the src-dn that is current-node (Aka the one just sent). Quite clever.
./following-sibling::instance[@src-dn = $current-node]
This is looking for the sibling after the current event, that is an instance node, and whose src-dn XML attribute is the same as the current-node variable.
Now when setting the attr-name XML attribute they finally use the last() function in the predicate to place it properly:
./following-sibling::instance[@src-dn = $current-node]/attr[last()]
So it uses the same way of identifying the correct instance node, via the src-dn, and then the attr node, using the last() function in the predicate.
Then they add the <value> node with the same target XPATH. Then the text of the <value> node is the same but with the addition of value[last()] so that we write it to the last value node.
This is done for the attr-name’s of GoogeleAccountDisplayName, the GoogleAccountDescription and GoogleAccountValue.
Thus you can see the second and third <instance> event in my sample document from above.
Check target of add-association for GroupMembership entitlements that need to be granted
This rule reacts to the <add-association> event, if the check-group-entitlements op property is set to true. Then if we have the appropriate group entitlement available, then we fire.
Now this is interesting, that in an add-association event we have an entitlement in it as well, but I suspect this is using one of the neat features of the Entitlement token, when using the available option. It is sort of like the Attribute token, which is smart enough to use the operational attribute (if available) and if not there, it looks to the Source Attribute. Here Entitlement goes and looks at the object being referenced for entitlements (revoked or otherwise) to consider it.
Thus if the user has 3 group entitlements with different group names as values then we will process all of them.
Then we loop through all the available entitlements NOVLGGLEUSER-GroupMembership, and we then get the group-assoc value using the es:getEntParamField() function as discussed earlier in this series. Basically entitlement values in IDM changed formats between around IDM 4, and the ECMA function supports both.
Then we add a source attribute, which is writing back to Google, and adding them into the group. Then using the XML attribute association-ref to the modify event, because this way the engine will resolve it from an association to an object in the target system.
This is part of the standard password package from Novell, and you can read more about it in these articles:
But basically this implements
With that, it wraps up this walk through. Phew, that was a bit longer than I expected, but I quite enjoyed it. For anyone who has followed through this whole series, kudos to you! Well done, you have a greater attention span for most! For those of you who found this through searching, I hope if you have had a problem with a policy, that having had a discussion of what the policy is supposed to do helps you understand your issue. If not, well at least I enjoyed doing this.
Again, if you found this helpful, I would strongly suggest you pay it forward by picking even a single policy object in a driver that you think is interesting and try writing a similar style article. I would be happy is a couple of people just picked a single policy. If you want to do a whole driver, go for it!
If you need any help with it, let me know, would love to help. I am trying to get more and more drivers covered this way. You can read my collection of such walk through’s on this page: http://wiki.novell.com/index.php/Detailed_driver_walk_through_collection
I personally think Novell should provide this level of documentation, and wish they would, but being a realist, and needing this sort of documentation for myself, I am willing to write as much as I have time for. I think if you get an opportunity to complain to a sales person or the like try to send them feedback that we would like this kind of documentation for the various drivers. With the move to Packages it is so much easier to do now! Now that we have Packages, which divide the big monolithic configuration files into much smaller chunks of code, and because it is easy to release a new Package, it is possible to tackle this in small bits, that add up quickly. It seems like it would be an easy assignment to task various folk responsible for the various drivers to just spend a small portion of time working on adding interesting tidbits to the various policies. With the built in chunking it up into Packages, it is easy to tackle something attainable in a short period of time, and make measurable progress.
If the Comments field of every rule had some discussion added about what the goal of the rule is, and possibly why certain decisions were made, I think that would be a huge win. Releasing a documentation only updated Package would be simple, and allow for easy upgrades without testing, while adding real value to the driver. The more people that nag, bother and ask, the more weight it gathers within the company. I think all the driver writers should be doing this by default. Sadly the XSLT components are usually better documented than the Policy examples. It seems like the notion of commenting was lost with the transition to DirXML Script. You can also see in drivers like the Active Directory one the change in folk doing the configuration as the approach (and style, I guess) within the various versions of the configurations changed between releases.
I was discussing this driver with some of the guys at Consensus, in terms of asking them some questions, and found out that they are getting ready to have an updated configuration, that will come as new Packages (as they should!) via an update and I suspect will add in final support for Group Entitlements. Hopefully by the time this article is written they will be released, but I have no insight into time lines.
Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment. It just worked for at least one person, and perhaps it will be useful for you too. Be sure to test in a non-production environment.