Cybersecurity
DevOps Cloud
IT Operations Cloud
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.
Let's continue on with the rest of the output transform and once done, move on into the Input Transform. The Publisher channel is where the meat of this driver resides anyway, so much more interesting stuff to see coming up!
Output Transform:
Remember as we entered this Policy Set, there is only one Policy object, output_Query_Transform, and as a first rule it limits processing to just Query events.
Change Query to query specific Class found in ccSIF-Class Attribute
Now that we have removed the search-class from the query event document we need to add back the proper search class name, since schema mapping is not working as we have many SIF classes mapped to one class in eDirectory. So while it may have been a search for a User in SIF, but we need to look back at the source objects sifClass to find out whether it is a StaffPersonal or StudentPersonal.
This is done if there is a sifClass attribute available using the set XML attribute for class-name (that we stripped out in the second rule) to the Attribute sifClass from this user. Then append an XML node search-class, to add back the value we stripped earlier as well, and set the XML attribute class-name on the search-class node. Then strip sifClass from the document.
Change Query to query specific association found in ccSIF-GUID Attribute
Now if we have no association but we do have an operational attribute called Key, then set the objects association to the value of Key, remove the Key op-attr from the document, and change the scope of the query via a Set XML attribute for scope in the current event document to entry.
Basically what this entire policy set does is re-implement the schema map for a many to one class mapping. This is always a problem with IDM projects, where the Schema map is designed to be a one to one mapping of object classes.
This is also a pretty common problem in SOAP drivers, where in the SOAP world many things are either combined into one class, or separated into many classes. I have seen both approaches in the real world.
Now the event enters the shim, gets sent to the SIF Zone server, and whatever comes back is processed.
Input Transform:
Now that we have worked through the Subscriber channel that mainly focused on supporting queries into SIF, lets now look at where the bulk of this driver resides, in the Publisher channel. Now technically the Input transform is not part of a channel, but since it is the first inbound policy set processed, lets start there.
There are two policy objects.
input-StartupEvents
This policy object has three rules.
It looks like this driver supports three different time based events. Current, Future, and Historical. Each is controlled in a GCV as to whether it is allowed, and if the operational attribute TimeFrame (which I assume the shim sends) is equal to one of those three values, then there is a corresponding GCV that should be set to true, to allow the event through.
If not, veto it to scope events to what the driver is configured to handle.
This rule sets the Globally scoped local variables (which are different than a Global Configuration Variable) at driver start time.
The conditions of this rule watch for a <status> event to come through, whose @type="driver-status" with an @level="success" and a driver scoped variable gv_sifObjectConfigsSet not true. Basically make sure we only execute this on successful driver startup, and only once. This is actually a good point, as if the remote loader drops off the network, when it comes back we will get another driver startup success message, and there is no need to do that work, unless the driver itself is restarted, which would clear the local variables from memory.
First up is set the gv_sifObjectConfigsSet variable to true so we do not come through here again.
Get the list nodeset for the School Short Name List into a driver scoped variable. These driver scoped variables will be used in rules all over the place, so easier to just set them all once at driver start time.
Then for each of the three eDirectory object classes (User, Group, and ccSIF-UserEnhancement) loop through their matching GCV which has more than one SIF Class that it is mapped too. Grab the <instance> doc for that SIF Class into the gv_sifConfigFor_$var$ where $var$ is one of:
StaffPersonal, StudentPersonal for Users
SchoolInfo, SchoolCourseInfo, RoomInfo, SectionInfo for Groups
StudentSchoolEnrollment, and StudentSectionEnrollment for ccSIF-UserEnhancement
We have already seen how these are used in the Subscriber channel in previous articles in this series.
Now if the sifClass operational attribute is available, then this rule fires. Set an operational property sifClass to the attribute value sifClass.
Then loop through the global variable we set just moments ago for this specific sifClass value (gv_sifConfigFor_XXXXX) looking for the eDir Class component of the structured GCV. Then set that value as an operation property and furthermore set the operational class, a pretty cool token, to the same eDir class.
The set operation class token is cool as it lets you morph the current object class to whatever you need at the moment. One hypothetical way to use it might be if you are using the unique name token, and know you have more than one object class in the target name space that might be using the name you are trying to uniquely generate. But the unique name token only looks for objects of a single class name. The current event class name. You could run the unique name token to get a value for the User, then double check by changing the operational class name to the other likely class, and check a second time with a unique name token which of course will now look exclusively for the current class name. It would a lot nicer if the token supported specifying a class, and if null checking all classes, and I believe there is at least one Enhancement Request in for just that functionality at http://www.novell.com/rms the Enhancement Request portal.
Of course it is probably easier to use Unique Name on your user class, and then just check if there is any object returned in a Query token, with that calculated name. If so, kick it up one, test again and move on.
input-Data_Transform_Policy
This policy object has 5 rules:
The operation property, sifClass is read into a local variable, since in XPATH or variable expansion, it is easier to use a local variable than a op property. To use an operational property in XPATH you would have to get it via an XPATH of something like operation-data/propertyName. Additionally, having it in a local variable means it can be used in crazy ways, like building a local variable name, USING a local variable as part of the name! Stay tuned for the Veto User Enhancement Object that are no longer effective rule to see it in action.
If the sifClass is SchoolInfo, then we set the Short Name (ccSIF-SchoolShortName attribute) on the SchoolInfo object.
The association value is the School ID, and we lookup in the driver scoped variable that is set from a structured GCV called sif.school.SchoolShortNameList
This is where Structured GCV's get to be fun, since you can treat them as a node set (which we have stored from earlier in the gv_sifSchoolShortNameConfig local variable) and since it is a node set we can for each over the nodes.
The XPATH in the for each loop looks like:
$gv_sifSchoolShortNameConfig/definition[@name = "sif.school.SIFGuid" and value/text() = $lv_SchoolID]/../definition[@name = "sif.school.ShortName"]/value/text()
To deconstruct that, it helps to remember what a Structured GCV looks like. There is a <template> section of the GCV that defines what is inside each instance of the GCV. Then for each instance you define, there is a <instance> node. Inside each <instance> node is the standard GCV XML DTD as if it were a standalone GCV, and if more than one, one after another. (Never tried a nested Structured GCV, I wonder if that would work, and how crazy it would look? )
So you have a <definition> node, with a name XML attribute, which this XPATH looks for one named sif.school.SIFGUID and whose text string in the value node is the SchoolID (which we set from the association into the lv_SchoolID variable a moment ago). I.e. What does the GCV define for THIS School as the Short Name?
Then like walking a directory tree, it goes up one node in the XML DOM, and looks for the GCV whose XML attribute name is sif.school.ShortName to get the value. That is because there is a parent node that defines each School in the GCV, and has two siblings, SIFGUID and ShortName, and we need to find the one whose SIFGUID matches our objects association, and then look at its sibling.
Interestingly enough, I wonder why they did a for each, since they could just have selected a value using the same XPATH, since it is based on the GUID of the School it seems implausible to have two with the same values. After all, the GU in GUID means Globally Unique. Probably because if there is one value, you loop once. If there is no value that matches the XPATH then you loop zero times, and save a second test of if the value not equal to null. I am not sure if it matters from a performance perspective which way this is done.
If the object class coming from SIF is ccSIF-UserEnhancement and the SchoolInfo attribute is available then as in the previous rule it grabs the association value into a variable (lv_SchoolID) and does a similar loop through the Structured GCV with XPATH looking for:
$gv_sifSchoolShortNameConfig/definition[@name = "sif.school.SIFGuid" and value/text() = $lv_SchoolID]/../definition[@name = "sif.school.ShortName"]/value/text()
If it loops and finds such a node then it uses that value of that node to add a ccSIF-SchoolShortName to the current object.
For ccSIF-UserEnhancement objects, this rule loops through gv_SifControlFor_$lv_sifClass$ local variable. Note that they used variable interpolation, inside a variable name! How cool is that? So the this way, one rule works for all the various possible classes.
Inside the loop, the Start Date attribute is read out of the structured GCV with XPATH of:
$current-node//definition[@name="sif.UserEnhancementStartDateAttr"]/value/text()
That is, inside the nodeset GCV we are looping through, find any definition node (the // means search all the way down the DOM tree) whose XML attribute name (@name) is sif.UserEnhancementStartDateAttr and get the text of the value node.
Do the same to get the attribute name that stores the End Date. Then get the actual Start and end dates from the operational attributes of those names into local variables (lv_EndDate, lv_StartDate).
Get the lv_CurrentTime using the Time token to get current time in CTIME (Count of seconds since 1970).
Now we have an IF THEN test to see if this is a future event. First make sure lv_EndDate is not blank. Then if the Current time is not less than the EndDate (i.e. not yet finished) and the StartDate is not greater than the end date. (Always good to double check that one for sanity's sake!) then veto since this is current dated.
Otherwise we might have a future dated event, so check if the Current time is less than the Start Date and then we do have a future event so set the attribute ccSIF-FutureEnhancement to true.
(see Part 4 of this series for information on this rule)
That's about it for this article, stay tuned for the next in this series as we finish the Input Transform, and start on the Publisher's Event Transformation policies.