Novell Identity Manager has several drivers for connecting to all sorts of other systems, one of which is the SIF driver, written by Concensus Consulting. SIF is the Schools Interoperability Framework, which is meant to manage the student life cycle, in terms of enrollment and courses they take.
If you can connect this to an Identity Management system, then you can easily manage their lifecycle within your Identity system in terms of accounts at your school.
If you can then use a product like Novell File Management Suite, you can manage the lifecycle of their files, moving them from server to server (or NAS to NAS or directory to directory) as they change school years, and provisioning shared storage for every class, and finally archiving or removing them when they graduate.
If you use a product like ZENworks Configuration Management then you can manage their lifecycle in terms of applications and workstations.
Put it all together and it is quite compelling! But to use the latter two tools, you need to get the student information into your systems, which is where the SIF driver comes in.
I started writing about this in the first article in this series Walking through the SIF driver – Part 1 where I worked through the beginnings of the Subscriber channel policies.
Then in the second article Walking through the SIF driver – Part 2, I worked through the rest of the Sub Event, Sub Command, and the beginning of the Output Transform.
In the third article Walking through the SIF driver – Part 3 I worked through the rest of the output transform and once done, moved on into the Input Transform.
In the fourth article Walking through the SIF driver – Part 4 I worked through the rest of the Input Transform, the Publisher Event Transform, and into the Matching rules.
In this article I continue on through the Creation Policy and Placement Policy Sets.
On to the Create Policy Set. There is a single policy object, with 5 rules.
- Check Generic Required Attributes
- Check Required Attributes for Users
- Check for Required Attributes Groups
- Check for Required Attributes User-Enhancement
- Set User Object Creation Attributes
Check Generic Required Attributes
This is a classic Create rule policy, just vetoing if ccSIF-Class or ccSIF-GUID is not available.
Check Required Attributes for Users
The previous rule says check required attributes and this one says check required attributes for users. Why the difference? Well this driver uses the ccSIF-Class attribute to figure out the class mapping, thus without the class info available you might not know if it is a User yet.
For a user, we need the additional info of a ccSIF-SISID, basically the student number.
Check for Required Attributes Groups
For Groups, this just always adds the nestedGroupAux to the Group object. Nested groups are a neat idea. Basically this is the notion that a group can contain a group. Now to be fair, eDirectory could have supported that simplistic notion a long time ago. But it did not confer permissions, since eDirectory group permissions are actually applied by the attribute pair of Security Equals and Equivalent To Me. And those attributes are not transitive in the fashion needed.
However with eDirectory 8.8 I think it was, nested group support was added. It is not perfect, but it allows for using them in LDAP at least. Regardless of all that, it is the presence of this is aux class that mostly makes it all work. It has a few extra attributes like excludedMember, and nestedConfig. I really should do some research into exactly how these work and some of the consequences, but will have to add that to my list of things to look into.
Check for Required Attributes User-Enhancement
If the class is ccSIF-UserEnhancement then it uses the operation property set back in the Input Transform called sifClass to set a local variable (lv_sifClass), that again is used to build a bigger GCV value through variable interpolation. This is a very cool approach that I had never really considered, using a variable in a GCV name. I wonder how deep you can go with that sort of silliness.
The name of the variable is gv_SifConfigFor_$lv_sifClass$ which means the GCV named gv_SifConfigFor_ followed by the value of the lv_sifClass variable. So it might be gv_SifConfigFor_User or gv_SifConfigFor_Group or gv_SifConfigFor_User-Enhancement.
This is a very deep structured GCV, which actually answers a question I had wondered about, that it turns out I think you CAN nest a Structured GCV in a structured GCV! That way lies madness! My hat is off to the driver developer on this one for not going mad trying to get this to work and keeping it all straight in his head. The more I try and understand this GCV the more my head hurts. It is truly wild, and the most complex example I have yet to see. Even more amusing, to try and understand it better I went and modified some of the display names, to make it easier to read and understand, since my habit is to include the actual GCV name in the display name, so I do not have to click on the info icon to get the actual name, and boy did Designer do some interesting display things! It did work, but what a light show!
Looping through the nodes of this GCV, which when treated as a nodeset lets you get away with looping through it, and then inside that loop one more, through the XPATH of:
$current-node//definition[@name="sif.UserObjectReferenceAttribute" or @name="sif.LinkedObjectReferenceAttribute"]/value/text()
This means, for each instance of the parent loop, starting at the current-node variable, look for any (the // means a look down the tree) definition whose name is sif.UserObjectReferenceAttribute of sif.LinkedObjectReferenceAttribute and then the value nodes, and finally veto if any of those are missing. It looks like there is but a single such value, and interestingly enough I could not find any sif.LinkedObjectReferenceAttribute GCV entries at all.
This looks like it basically the value of ccsIF-StudentRecord. I imagine this can be changed potentially and therefore they wanted to make it a configuration value (using a GCV) instead of hard coding the value. I strongly prefer this approach, since it means you can make reasonably large changes to driver behavior without needing any code changes, and it minimizes the amount of testing needed as well to get it passed into production. For a client that needed to handle 5 different data sources for valid users, each with its own set of attributes, and each with its own flagging attributes, but coalesced into a pair of entitlements, where any data from 4 of the 5 systems would count as one entitlement and the fifth system was its own entitlement, I used a similar approach. There I have a fun complicated rule that can handle several major use cases, all at once, but based on configuration data. One of the five sources was due to be updated and therefore they knew its requirements were going to change. Well no code changes needed, just identify the new attributes and patterns (I used Regular Expression matching support to handle cases where data inside the attribute value had to be a particular pattern) and restart the driver. Very cool what you can do in a configuration vs code model.
If you look at the Novell Consulting drivers for SAP HR, which started out being available as the CMP (Compliance Management Platform) version, and then the base drivers for Identity Manager 4, and at BrainShare an even newer version was presented, you will also see how so much of the driver behavior is being controlled by GCV’s. This is good, since it means the many possible application patterns have been considered, and you just have to select what silly approach your folk took to the same problem.
This is sometimes harder than it sounds, but it is usually a ton of fun to design, and in fact, by being forced to test all possibilities it often finds subtle edge cases that impact the others, so you get a better driver out of it.
Set User Object Creation Attributes
This is another case where the driver developers really tried to make your life easier by handling a bunch of different cases for default password assignments. After all, everybody needs to set a password for students coming out of a SIF system.
They provide a GCV that lets you decide how to do it. You can use a specified text string. Or you can select the value of some attribute, and use the value there as the default password.
This is done again by using variable interpolation on the GCV name with the sifClass variables, and then looking into it for the GCV components named, sif.InitialPasswordType to see if it is set to none, text, or some other value.
If none, of course, do nothing.
If text, then set the destination password to the specified string value, selected by an XPATH of $lv_currentObjectConfig//definition[@name='sif.InitialPasswordText']/value/text() where $lv_currentObjectConfig is just a stand in for current-node and would work equally well I would think. Though I wonder if there is some reason for not using current-node from the current loop? If we were inside a second loop, you would need that parent current-node stored in a variable to get at it. But that is not the case this time. Then the rest of the XPATH is just getting the text value from the sif.InitialPasswordText GCV.
Finally, if it is any other value, and it looks like you should be able to easily update the GCV to add a new item to the list, it will look for the GCV sif.InitialPasswordType inside the loop, and get the text value, to use as the attribute name to read out of operational document.
Alas this approach does not seem to allow for combining or substring bits and pieces. Like last name followed by last 4 of student number. Or maybe first initial last initial last four of your Social Security Number. Or anything else.
But of course, this is a simple rule to edit to add support for such a case, you would just add a test case for if the sif.InitialPasswordType is your value to then do your work as you need it done.
That was slightly more complicated than I expected, but thus ends the Creation Policy set! on to the Placement Policy set which has one policy object:
Which has one rule:
Set Object Placement
Now as we have learned so far, this driver never does anything the easy way so who wants to guess if the Placement is nice and simple or some complicated approach? Well that is an easy one, its gonna be complicated!
Looks like we start out with the usual approach of most of these policies, using the sifClass to set a local variable, which is then used to get the GCV named for this object class, by variable interpolation and looping through the GCV.
Then it looks at the class name, to have some special handling for ccSIF-UserEnhancement objects.
These interestingly enough are stored as children of the driver object in a container named by the sifClass value. Then it does something interesting to see if the container exists, it queries for it, and looks at the results. It uses the XPATH of $lv_ContainerQuery/@src-dn in a test, so if there was a container found, there will be a src-dn XML attribute, but an empty result (i.e. no container found) will not have one. I usually use count($query) > 0 to handle this. Now I wonder which is a more efficient test? A simple XPATH test for @src-dn, or a count() function call then a greater than test. I posed that to the only person I know who might possibly answer it and he suggests that an XPATH of just $lv_ContainerQuery would be most efficient. Count is apparently more efficient than the @src-dn approach. I have a fair bit of information to expand upon that topic, but that is another article.
Looking ahead, I see that we place objects (aka set their destination DN, for the engine to create them as) with the lv_ObjectBaseContainer and with the ccSIF-GUID as the object name. That is interesting. I was not expecting that. I wonder what the GUID looks like? Seems like an ugly naming pattern for users, since GUID’s are typically globally unique as the acronym would imply. I shall have to inquire with the authors what the reasoning behind this one is.
Anyway, the actual destination DN is set by the adding the ccSIF-GUID on top of the base container variable, so the rest of the rule for the cases where the class is NOT ccSIF-UserEnhancement, is basically all about parsing the configuration GCVs and building up that base container variable.
The options seem to be, a specified text string, ccSIF-SchoolRecord or else some other attribute name whose attribute value is used to specify the container top place it in.
There is something happening here with a group membership style attribute that I do not entirely understand, but it seems to apply to schools. I think it might be related to the notion of making students members of the school object, but I am not certain.
Anyway, that is it for this article. Coming up will be the Publisher Command transformation policy set and all the interesting things it will bring up.