Walking through the SIF driver - Part 1

Novell Identity Manager has long had a SIF (Student Information System) driver available that allows the rest of your identity management framework to connect to the SIF Zone you might have for your K-12 education school system. This is great as the SIF system is designed to manage the students enrollment lifecycle in the school, and possibly school system. Whereas the Identity Management system is designed to manage the students lifecycle in terms of the various accounts they might need or deserve.

Throw in Novell's File Management Suite and you can manage the lifecycle of their storage for their tenure in the school. Heck throw in Novell's ZENworks Configuration Management and you can manage the lifecycle of the applications they have access to.

If you have all this available you have a pretty compelling picture for managing your students. They get enrolled in SIF, in specific classes or courses, which you map into IDM as perhaps groups, then the File Management Suite creates their personal storage and any shared class storage they need. Then ZENworks will allow them access to the applications they need, no matter what machine they may log into. When they change classes, it is reflected in SIF, synchronized into IDM, which ZCM and FMS react too and change the storage and applications to match.

The beauty of this is that most of it is independent of each other. That is you could do the storage on its own, supposing you had a way to get the users and class lists into the directory. You can do the same with ZENworks.

But when you put it all together you get this lovely solution that just does it all for you in the backend. The only people who need to worry about class enrollments are the folks running the SIF system, which they have to do anyway!

The current SIF driver is provided by Concensus Consulting (they also provide the Google Apps driver in IDM 4 SP1, and will be releasing a Banner driver (For higher education student information systems) soon enough. Check out their web page at https://www.concensus.com/ they do a lot of great work!)

Rather than work through the older driver, I thought it would be interesting to work through the policies in the currently shipping driver. The folks at Consensus were kind enough to send me a copy of the driver so I could walk through it for you. I hope you find this of interest.

The first thing to notice is that this driver is mostly a Publisher channel driver. That means that most of the data is coming from SIF and flowing into IDM, and not much if anything is flowing back to SIF. Looking at the filter it is clear that nothing is set to synchronize on the Subscriber channel. In general this makes sense as you probably do not want to write much of anything back to SIF from the Identity System, since SIF is authoritative for student data. The only thing I would ever want would probably be the email address at most.

Looking at the filter, it is clear that a whole stack of schema extensions need to be done, as many of the attributes coming from SIF are named in eDirectory as ccSIF-* to identify them as being part of the schema for Consensus Consulting's SIF driver. This is an excellent practice as it makes it easy to identify what an attribute is related too, and prevents naming collisions later down the road.

There are three object classes in the filter, User, Group, and ccSIF-UserEnhancement. User is obvious, and has some extra attributes to hold data from SIF (21 of them!). Group looks to be greatly extended with 36 new attributes of ccSIF-* type. ccSIF-UserEnhancement looks like an interesting object that I am sure we will discover more about in the course of these articles.

Since the Subscriber channel is so barren, let's work through it first, and get it out of the way. In the Subscriber Event Transform there is a single policy object:

sub_Process Jobs:

There are three rules in the policy object:

Process Migrate Jobs
Process Check User Enhancements
Veto Trigger Events

Process Migrate Jobs:

To understand what is going on here, first we need to notice that there are several Job objects defined. They are named:
Check User Enhancements
Migrate 1 User
Migrate 2 Group
Migrate 3 ccSIF-UserEnhancement

The contents of the Jobs is not that important, since really they are meant to just trigger an event at a specific time, like a Cron job for Identity Manager.

What you do with a triggered Job is up to you in policy. A job can generate an event several ways, of which two are most common. The first is a single trigger event that your policy decides upon the scope and does what it needs. I use this my notion of Toolkit rules, where a single event triggers a rule that knows which users or objects to look for to perform its work upon. You can read more about Toolkit rules in these articles:

The other option is to select a container object as the scope of the Job, and have it generate one <trigger> event per object. The upside to that, is that each objects src-dn and association value is part of the trigger job and can be used in policy to properly identify the object. This driver is using the one trigger event per object approach. When you import the driver, the Job does not seem to have a scope so I assume this is left as an exercise to the implementer to remember to defined the scope properly.

There are usually two more valuable bits of information in the resulting event. First the event itself is of type <trigger> which means you can detect it with the test If Operation equals trigger. The second is that the name of the job is reflected in the XML attribute source. That is the event looks something like:
<trigger source="Migrate 2 Group"> with some more data in the <trigger> node.

Thus the first rule we have here does the if operation equal trigger condition test, and then does a cute XPATH test of:

This says, for the XML Attribute source, in the current event node (I am not sure the ./ is really required, but it will work), test if this one starts-with the literal string "Migrate". If it does then it is one of the three job types we would like to process.

The first action now that we know we are in a migrate case is to figure out what the class the job is referring too. You will notice that the names of the jobs follow a pattern, the string Migrate, a space, an integer (1, 2, or 3), and then a class name.

To pick up the class name, they use a set a local variable token to the class name, which they get by replacing using a regex of "Migrate \d " which is Migrate followed by a space, then an integer (\d is a shortcut for [1-9] in Regular expressions and means any single integer value) then a space. So all you are left with is a class name. Very neat way to handle multiple jobs, and picking the information needed out of the jobs.

Then they loop over a global configuration, whose name itself is calculated using variables! (How cool is that?). They build it as sif.$lv_MigrateClass$.Objectdefinition where the $lv_MigrateClass$ variable was just calculated from the source XML attribute. The variable replacement functionality in IDM is really quite powerful, and can be used in really clever ways. Might be a fun topic for an article, interesting ways to use variable replacements. I think I may try that. An interesting aside that I saw, using variable replacement that was really clever involved the Map token. With IDM 3.6 the Map token got a very minor but useful enhancement, the provision of a default value returned. This is really helpful, since you can try to map a value, and before you would get nothing back, if there was no matching value. But with the default setting, you can specify some ridiculous string that would never be in the data, so it is easier to test and detect. What was so neat about the approach I saw, was to remap an attribute name (in a variable ATTR) from the eDirectory name, to a nicer more end user friendly name. But the thing is not every attribute needs to be remapped, just a few. So if you set the default value to $ATTR$ then if the attributes name is not in the list that needs to be remapped, you get back the current attribute name. Very elegant and simple.

Now back to the problem at hand. If we look at that GCV we see that there are three similar ones, named sif.User.Objectdefinition, sif.Group.Objectdefinition, and sif.ccSIF-UserEnhancement.Objectdefinition that hold similar data in three instances of Structured GCV's. These are my all time favorite types of Global Configuration Variables, since they are so darn useful. You can read much more about GCV's in general, and Structured GCV's in particular in these articles:

In fact, they do a very neat trick in the GCV configuration that allows you to select which of the three structured GCV's you would like to show at one time. It looks great in the user interface, and I am sure was a pain to get working! I am also sure that making this work in IDM 4 Packages is going to make someone at Consensus tear out what remaining hair he has left, (Sorry Slade) as the current support for complicated GCV's in Packages is quite weak. Though I should probably spend some time figuring out how he did that with a GCV. But it is down my list of priorities right now.

There are at least 5 components to these GCV's for User and Groups, but the ccSIF-UserEnhancement version only has three.

By looping through the GCV for each class, you treat it as a nodeset, which means you get one loop through for each instance of the structured GCV and can use XPATH on it, to get the piece of information you need out of it. Thus inside the loop, a test is done to get the ccSIF-Class from the sub-GCV with an XPATH of $current-node/definition[@name='sif.sifClassName']/value/text() which says, in the current-node of this loop, which is the <instance> within the specified structured GCV, find me the <definition> node, that has an XML attribute name with a value of sif.sifClassName. This is basically a way of doing the schema mapping of class names in policy, instead of in the Schema Map.

One of the developers was explaining that there are not really discrete object classes in the SIF model, so this is probably one of the consequences, you cannot rely on class-name mapping, instead you need to manage it your self in this approach. Or another way of saying that, is that one object class in SIF needs to be pieced apart into multiple classes (Whether that is class of users or object classes) in eDirectory.

Next it generates a query for the object whose ccSIF-Class is the value we just retrieved, which is StudentPersonal or StaffPersonal for User objects. That might look something like this:

<?xml version="1.0" encoding="UTF-8"?><nds dtdversion="4.0" ndsversion="8.x">
<product version="?.?.?.?">DirXML</product>
<contact>Novell, Inc.</contact>
<query class-name="StudentPersonal" scope="subtree">
<search-class class-name="StudentPersonal"/>

However, when I read through the Output Transform, it looks like this query will fail, and I do not understand why this works, or how it accomplishes the task at hand. I have asked some of the guys who wrote it, and will report back what I find.

Anyway that looks like it is enough for this article, stay tuned for more to come.


How To-Best Practice
Comment List