Adding IDM4 Reporting support to pre-IDM4 drivers part 2:
Novell Identity Manager 4 has a bunch of new features. You can read what I think of them in this series of articles:
Based on requests from customers, the feature most are interested in is Reporting. That is, most of our customers interested in upgrading to IDM4 are interested in it for the new Reporting features.
You can read part one of this discussion at the link for more discussion on what is going on:
Adding IDM4 Reporting support to pre-IDM4 drivers - Part 1
I believe there are at least four things needed to support Reporting in an existing driver, based on looking at what is needed in a Packaged driver. I am still trying to fully validate that I did not miss anything, but so far so good.
There are 3 Policy objects that need to be added:
The first two were discussed in the first article.
There is one Global Configuration Variable object:
You can follow along by opening a Project in Designer 4, making an Identity Vault that is set to be IDM 4 level, and then import an Active Directory driver using Packages. Then you will find all the policies and objects I am going to discuss.
In this article I would like to discuss the last policy rule, and the GCV that it both requires and modifies.
One trend I have noticed from the latest crop of driver design folk at Novell is the notion of self modifying a driver. That is, on startup go out and create or modify an object inside the driver itself. This does add an interesting conundrum for folk who like to severely limit the rights a driver has to the eDirectory tree. You actually need to remember to grant the object the driver using for Security Equivalence to get rights to the eDirectory tree to the drivers own container. Otherwise every driver startup you start getting 672 Insufficient Access errors in the trace.
The first instance I saw of this was in the SAP HR CMP drivers, which I talk about in this series of articles:
Where the driver on its first startup will actually check for the existence of a bunch of containers (children of the driver object) and if not there, create them!
Then the more common example is the way that the mapping of Entitlements to Resources is done to support the Roles Based Provisioning Module (RBPM) 3.7 which adds the abstraction of Resources on top of Entitlements. In that case, the configuration is read at startup and a DirXML-Resource object is created named EntilementConfiguration with the data expected and needed for the Entitlement to Resource mapping.
Here we have another example of this approach, however, since new with IDM 4 is the notion of Global Configuration (GCV) objects, and the object being mucked about with is a DirXML-GlobalConfigDef object class.
You can see in the image how IDM 4 (well Designer 4 really) handles the notion of having multiple GCV objects associated with a single driver. The GCV tab now has more tabs along the top, showing each object. What is interesting is that although the object in eDirectory is named MSysInfo, the tab says Managed Systems Information. Well I looked at the XML for it, and it turns out that the <definitions> node under which would normally be all the actual <definition> nodes with GCV's in them, can have a display-name= "Managed System Information" and it is shown as the name in the tab. Neat.
What you should also note is that at the bottom is a section (made with a <header display-name="some text"> node that is currently hidden when using a <group> in a GCV definition. These last two examples are not available in the GUI, you have to edit the XML yourself to add or modify them. You can read more about the magic you can do in GCVs in these articles:
When you select the 'show' option, you see something more like this screen shot, though mine is empty of values, since I never actually ran this specific driver, it is part of my scratchpad project.
Basically the ID, Type, Authentication IP Address, Authentication Port, and Authentication ID information will all be generated by the driver using the rule we are about to look at.
With that diversion into the GCVs to be managed, lets dig into the policy itself.
First up is a classic test, make sure we are ready to run (I.e. the driver is fully started up) and that it only runs once. This is done with two tests. The later is be sure a driver scoped local variable that we will set at the end of this policy object is not yet set to true. Clearly if it is, move on, nothing to see here.
The other test is a little less clear. We will see in a moment that there is a policy to set a driver scoped local variable objectClass with the object class of the driver. During a driver startup, queries will not work until both channels have initialized themselves to a certain point. During that time, a query to the driver object (which is easy as there is an auto GCV for it) will fail, and you can use that to demonstrate that the driver is at least mostly ready to go. The definitive explanation of the limits of this test where provided by Shon Vella, (formerly known as Father Ramon, one of the programmers of the IDM engine), where he stated very clearly:
(The test for reading object class) will fail in input/output transformations when they are processing the initialization handshake because there are no query processors set up at that point - however it would be much more effective to just check if the operation you are processing is an init-params operation.
That is, during a driver startup a number of events are processed, and if you are seeing an <init-params> then you know the driver is not yet fully up and running. For our purposes, this test to see if we can query, should be sufficiently initialized to get going.
Next up is the rule that if the objectClass variable is not yet set, tries to set it. If it fails, break.
Now for the core of this policy. The Managed System Information rule.
Get the current DirXML-ConfigValues data from the MSysinfo driver in the current driver into the msysinfo nodeset local variable so we can XPATH within it. (All the new packaged drivers assume that there shall be a MSysInfo object in each driver.)
Local variable xml is the nodeset you get when you base 64 decode the DirXML-ConfigValues attribute, and then XML Parse the resulting text string into an XML nodeset. The XPATH used to get the value is probably a bit more verbose than needed with:
Should have been sufficient without the // which is considered bad form in XPATH, but probably does not matter in this case.
Next up a variable driver is set with the attributes GUID, DirXML-ShimConfigInfo, DirXML-ShimAuthID, DirXML-ShimAuthServer into a nodeset. This is more efficient than getting it 4 times into different variables.
Then driverGUID is set with the XPATH of: es:guid2string($driver//attr[@attr-name='GUID']/value/text())
This uses the ECMA function in the lib-AJC to take a binary GUID, and convert it to the string format everybody likes, which is really quite odd, but apparently quite common and almost standard, to the point there is a Wikipedia page describing the format. Go figure: http://en.wikipedia.org/wiki/Globally_unique_identifier
The input to the ECMA is the GUID value pulled out of the query result for the driver variable.
Then we start the first bit of writing back the data. Into the xml variable, which is a nodeset, so we can use the append XML text token, stick the calculated GUID at the point defined by the XPATH: $xml//definition[@name='msysinfo.drv.ms.id']/value
The MSysInfo object comes with the data defined, but empty, as you saw in my second screen shot. Thus the GCV definitions are there already, just bereft of information.
Therefore the XPATH works, when it looks for any (the // part) <definition> node who XML Attribute 'name' is msysinfo.drv.ms.id.
Then there is a strip by XPATH for the msysinfo.drv.ms.type, which I do not entirely understand why just this one needs to be stripped and not GUID. But then the value is added back, and you can see it is hard coded in this policy to AD. This seems like the sort of thing to maybe store somewhere else, but I guess Reporting is expecting a canned set of strings, thus they provide the expected value here.
Now to get the info out of DirXML-ShimAuthServer is kind of fun. This is the Authentication Context as seen in Designer or iManager. If you are running Local then it is the IP address or name of the Domain controller being connected too. If you are running a Remote Loader, then the string is more like REMOTE(hostname=ip.address.com port='8190' kmo='SSL CertificateIP')ip.of.DC.com This is a bit confusing as the Active Directory driver (my example driver to work from) can have several possible different values here. If you are running on a Member server, with a Remote Loader, then the REMOTE(stuff) is followed by the IP Address of the Domain Controller used by that Remote Loader. If you are running the Remote Loader on a Domain Controller, it is not specified, and talks to the local host.
Thus the variable authServer is set, and now to decide is this a local or remote case. If the string starts with (XPATH of starts-with() function) REMOTE,
If its REMOTE, we have two cases, running on a DC where there is nothing at the end of the REMOTE(something) string. If we are running on a member server talking to a DC, then the stuff after the REMOTE() is the IP Address of the DC.
If it is running local, then this DirXML-ShimAuthServer should just be an IP address for the domain controller.
There is a IF-THEN test here to handle these three cases using XPATH string functions to see if there is something of interest after the close bracket or not.
The first test that got us into the IF-THEN block was if XPATH is true, starts-with($authServer,'REMOTE(') and note the open bracket, since of course you might have a server whose name really starts with REMOTE which would break this rule. Since round brackets are not legal in DNS names, adding that extra character to the test makes sure to avoid that trap.
Then we check if XPATH true string-length(substring-after($authServer, ')'))>0 that if you take all the string AFTER the close bracket, and look how long it is, if it is greater than zero. (I.e. Has an IP Address at the end of the REMOTE() string).
To get the various values, use XPATH's string functions, to either substring-after($authServer, ')') to get the stuff after the close bracket, or use substring-before(substring-after($authServer, 'hostname='), ' ') to get the stuff after hostname= and before the next space. Finally if running local, and not remote then the value of the authServer variable is what we wanted.
Once this is determined strip the previous version from the xml variable, then add in the value we just calculated,.
Get the value of DirXML-ShimAuthID from the earlier query, into the authID variable, then strip the previous value from the xml variable, and add in the new value.
That has retrieved the GCVs of interest from the driver configuration. It has built up an entire XML document with the new values in the nodeset variable xml, and now to write it back to eDirectory, which is done in the rile Create or update Managed System Information (MSysInfo) object.
I do not get why this starts by loading up a local variable msysInfoObj, when the previous rule made the exact same query into the msysinfo variable. It should not really matter since the IDM engine caches events like this within one Policy, so the query is not wasting time exactly, just a little bit of memory.
Now comes an interesting test. It looks at the nodeset for the -dn XML attribute. If there is no returned value (string-length is zero), then the object did not exist, and the else condition is that the object needs to be created, so add destination object class of DirXML-GlobalConfigDef and set the DirXML-ConfigValues to base 64 encoded values of the XML Serialized nodeset variable xml. That is, pump the data in the variable into the object in the right attribute.
Now if the length of src-dn was greater than zero, we then do the THEN block, where we do a replace all on \s which is Regular Expression speak for white space characters, on each of the XML payloads. The one we just read, is base 64 decoded. By removing the white spaces, we make comparing them much easier.
Then a test to see if the two versions of the XML payload are the same, in which case, just trace out a message that no change is needed. Otherwise there is a change, and lets write that back to eDirectory in the DirXML-ConfigValues attribute of the MSysInfo object.
Finally in the last rule, make sure this only runs once, so set the driver scoped local variable mSysInfoInitialized to true.
Interesting approaches. I am not sure why they do not just make the admins type the info in, instead of doing all this work, but it is straightforward enough.
Actually, I guess we could skip this rule entirely on an IDM 3.6.1 driver, and just make sure to properly make the MSysInfo object and set the values by hand. While we might get away with skipping the rule, we do need the GCV's.
Next up is to discuss how to add all these into an existing driver, and when I reviewed further, I realized there might be some filter changes as well.