An illuminating bug in Remote Loader Package Prompts Template

geoffc

By: geoffc

July 23, 2013 11:03 am

Reads: 1064

Comments:0

Rating:5.0

With the release of Identity Manager 4, one of the major changes was the introduction of Packages. This is an attempt to make the configuration of drivers (as distinct from the code base of the driver shims themselves) supportable and upgradeable.

With Packages, the constituent contents of a driver are broken into smaller chunks, that can be added or removed independent of each other.

Thus a driver may now have a Base package that provides the shim info, basic configuration and not much else. Then there is a Default Configuration Package that delivers a filter, schema map, basic match, create, and placement rules. Then there are a couple of packages (long story why you need two at least) for password synchronization.

The notion is by making each Package independent, you can upgrade them independently. Note that point you can upgrade (and downgrade!) them one at a time. This means when a bug in say the Work Order driver default configuration, where the object class in the Subscriber Match rule is wrong (It says DirXML-WorkOrder when it should say DirXML-nwoWorkOrder) is now a trivial fix. Make the three character change, release version 1.0.1 of the package to the wild, and enter a TID suggesting anyone experiencing this issue upgrade their package.

(Bug entered: https://bugzilla.novell.com/show_bug.cgi?id=743267)

Now for third party developers and consultants Packages are great as well, since you can deliver much of your work as a Package, which means while the first version, moving from a configuration is not perfect, after that, an upgrade to roll out a new build is easy, and hard to screw up late at night during a roll out, but also the rollback is much easier. Downgrade to the previous package build.

However the docs for this are weak at best. I made an attempt to help with that when I rambled on about Packages in this series of articles:

Let’s talk some more about Packages in Designer 4

But even then, I noted that the whole concept of Package Prompts was not entirely clear to me.

Recently I was working on converting some existing driver to Packages when I ran into an interesting bug that I think is instructive as an example to explain HOW package prompts should work, and WHY they are needed, using a case where they are broken and the way they fail demonstrates a lot.

While I found this while working on an Active Directory driver, this is not per se, AD Base package specific, rather it is a bug in the default XSLT Template in Designer, for Remote Loader package prompts. This happens with any driver, that you specify an SSL certificate on it, and then apply a base package upgrade.

You can simulate this trivially. Just go find in your Package Catalog, any driver that has a base package with more than one version. In mine I have at least Active Directory and GroupWise base that match this case. (There were some beta Active Directory package updates. Go to Designer, Window menu, Preferences, expand Novell, expand Package Manager, select Online Updates, and put a tick box next to Novell Beta, then do a Check for Package updates from the Help menu) In a scratch pad project or tree, try to add an AD or GroupWise driver. You only need the Base package, so get rid of the rest, no need to complicate things.

Then edit the Driver properties, Driver Configuration side tab, Authentication top tab, and then look at the Remote Loader section. Add on the KMO line, any string. Usually this might be something like SSL CertificateIP or some other certificate object name (Though in eDirectory they are shown as “SSL CertificateIP – Servername” and the space dash space servername is not needed in this case.)

Once you have a KMO (Key Material Object) set, save it, and go back in Properties, and Packages side tab, this time upgrade your Base package from 1.0.0 to say 1.0.3 or whatever version you have.

Now when you get to the Prompts page for the Remote Loader, you will get an error if you try to proceed that the format for the Port field is illegal. This is because the Port field will have port=’8190′ kmo=’SSL CertificateIP’ Other=’Something’ in it due to this bug.

Basically it assumes you did not configure SSL and if you did, it erases the value on a Base package upgrade, or applying a base package to an existing driver.

So figuring that out cleared up one major issue for me. When you look at the XSLT, you see these variables that magically have the data. But I still need to see the XML source to visualize XPATH selections.

So what does the source look like? Well in digging into the Remote Loader issue I noticed something I had previously missed.

There are 2 objects called PACKAGE-Remote Loader prompts when you use a Package Prompt object. One in the Package Catalog, there you see the Transforms, and one under the driver object in the Outline view.

The transforms make sense, they are Prompt and Target, Prompt Transform is to copy the values from the XML into the display prompts when you see when you add the Package. Then Target Transform is to apply any changes you want after the user customizes it and copy to the driver.).

In the Remote Loader case this makes sense. The attribute in eDirectory DirXML-ShimAuthServer attribute and is stored in something like this format:

REMOTE(hostname=ip of RL port=8190 kmo='SSL CertificateIP' something='Else')

Or from a JDBC driver example:

REMOTE(hostname=10.100.100.41 port=8090 )jdbc:oracle:thin:@10.100.100.41:1555:AVDB

Or from an Active Directory Driver:

REMOTE(hostname=RemoteLoaderIP port=8090 kmo='SSL CertificateIP')DomainControllerDNSName

But Designer parses this into 4 fields. Hostname, Port, KMO, and Other. Well sort of parses it, ultimately that is the root of this problem.

So it actually stores it in the project somewhere as eDir stores it as a single string, I suspect, so the Prompts transform has to read it, pick it into 4 parts, to display it. Then the Target Transform has to put it back together into its single string form.

The problem there is that the KMO and Other field were forgotten in the transforms. (And as far as I can tell in most base packages. I only tested AD and GW, but I suspect all of them have this issue).

Now, in doing this I found the second object, PACKAGE-Remote Loader prompts under the driver, that is NOT a DirXML-Resource, with DirXML-ContentType of PackagePrompt (as it is in the Package Catalog), and it contains what appears to be the XML that is the source for the Prompts Transform to read.

This helps answer a key issue I was unclear on. What does the Prompts XML that the is in $curDoc look like?

The Prompt object contents look like:

<?xml version="1.0" encoding="UTF-8"?>
<configuration-values>
       <definitions>
               <header display-name="Remote Loader"/>
               <group>
                       <definition display-name="Connect To Remote Loader"
name="use-remote-loader" type="enum">
                               <description/>
                               <enum-choice display-name="yes">true</enum-choice>
                               <enum-choice display-name="no">false</enum-choice>
                               <value>true</value>
                       </definition>
                       <subordinates active-value="true">
                               <definition display-name="Host Name" name="rl-hostname" type="string">
                                       <description>Enter the Host Name or IP Address where the Remote
Loader Service has been installed and is running for this driver.
[Host Name or IP Address; ###.###.###.###]</description>
                                       <value/>
                               </definition>
                               <definition display-name="Port" name="rl-port" range-hi=""
range-lo="" type="integer">
                                       <description>Enter the Port Number where the Remote Loader
Service has been installed and is running for this driver. The Default
Port is 8090.</description>
                                       <value>8090</value>
                               </definition>
                               <definition display-name="Remote Password" name="rl-password"
type="password-ref">
                                       <description>The Remote Loader password is used to control access
to the Remote Loader instance.  It must be the same password that is
specified as the Remote Loader password on the Identity Manager Remote
Loader.</description>
                                       <value>rl-password</value>
                               </definition>
                               <definition display-name="Driver Password" name="driver-password"
type="password-ref">
                                       <description>The Driver Object Password is used by the Remote
Loader to authenticate itself to the Identity Manager server.  It must
be the same password that is specified as the Driver Object Password
on the Identity Manager Remote Loader.</description>
                                       <value>driver-password</value>
                               </definition>
                       </subordinates>
               </group>
       </definitions>
</configuration-values>

Thus now we can see what $currDoc looks like so it makes sense to XPATH against it.

As you can see, there is no field for certificate info, nor for the Other option Designer shows.

The default Prompt Transform XSLT knows to parse the line:

REMOTE(hostname='someServer.acme.com port='8190') 

into several pieces, Hostname and Port specifically. But it does not account for kmo= since the prompts by default do not include it.

So when the Package is applied to an existing driver with values, or upgraded on an existing driver, the port ends up as

8190 kmo='SSL CertificateIP'

instead of just 8190 and then the field validation (which knows this should be an interger) reports an error and won’t let you continue untill you clean it up.

The XSLT doing the transformation from the Prompts Transform option tab, which is in the Packge Catalog itself (as opposed to being an object in the driver you have applied the package to) on the Prompts object is used to take the values already in the configuration (In an upgrade, downgrade, etc) and then convert them to fit into the Prompts you will see displayed when use the Package. Usually this is just a straight copy through of values, but as you can see in the case of the Remote Loader where one string is stored as 4 or more values, there is valid work to be done.

The XSLT looks like:

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <!--
       Remote Loader - Prompt Style Sheet
       ==================================

       This style sheet handles the special Remote Loader configuration prompts.
       It also works in combination with the initial settings style
       sheets to correctly overload the shim-auth-server and the
       shim-auth-password with the remote loader parameters and password.

       This style sheet is applied to the XML representation of the prompts
       (GCV's) for this prompt resource before the prompts are displayed for
       input.

       Updated: 20100915
       -->
       <!--
       defsDoc
       =======
       XML document containing the prompts (configuration value definitions)
       including their values that were entered for this prompt page.

       Sample document:
       <configuration-values>
               <definitions>
                       <header display-name="Authentication"/>
                       <definition display-name="SAP User ID" mandatory="true"
name="shim-auth-id" type="string">
                               <description>The ID of the User this driver will use for SAP
Logon.  This is referred to as 'User' in the SAP Logon
screen.</description>
                               <value>idmdriver</value>
                       </definition>
                       <definition display-name="SAP User Password" mandatory="true"
name="shim-auth-password" type="password-ref">
                               <description>The User password this driver will use for SAP Logon.
 This is referred to as 'Password' in the SAP Logon
screen.</description>
                               <value>shim-auth-password</value>
                       </definition>
               </definitions>
       </configuration-values>
       -->
       <xsl:param name="defsDoc"/>
       <!--
       curDoc
       ======
       In the case of an upgrade or downgrade, this parameter contains the XML
       content of the currently installed prompt target.

       Sample document (only an excerpt, these docs are rather large):
       <ds-attributes>
               <ds-attribute ds-attr-name="shim-auth-id">
                       <ds-value>idmdriver</ds-value>
               </ds-attribute>
               <ds-attribute ds-attr-name="shim-auth-server">
                       <ds-value>127.0.0.1</ds-value>
               </ds-attribute>
               <ds-attribute ds-attr-name="driver-start-option">
                       <ds-value>2</ds-value>
               </ds-attribute>
       </ds-attributes>
       -->
       <xsl:param name="curDoc"/>
       <!--
       npDoc
       =====
       In the case of an upgrade or downgrade, this parameter contains an XML
       representation of all named password available on the prompt target.

       Note:
       Only the names of existing passwords are available, not their values. If a
       named password has been set through a prompt, both its  name and value are
       available.

       Note2:
       To set a named password, append the following structure to the target
       (target must support named passwords):
       <ds-attribute ds-attr-name="named-password">
               <ds-value display-name="Password 1" name="pwd1">1</ds-value>
               <ds-value display-name="Password 2" name="pwd2">2</ds-value>
       </ds-attribute>

       Sample document:
       <named-passwords>
               <named-password name="promptedPwd">promptedValue</named-password>
               <named-password name="existingPwd"/>
       </named-passwords>
       -->
       <xsl:param name="npDoc"/>
       <!--
       propertyWizard
       ==============
       Flag (true or false) indicating if the installation is from the package
       installation wizard (PIW, launched from the "Packages" property page) or
       from the driver configuration wizard (DCW, launched by installing a new
       driver). This flag can be useful to show or hide prompts or to set or not
       set values based on which wizard is being run.

       E.g. the driver name should only be prompted for in the DCW, not in the
       PIW where the driver already exists.

       Possible values:
       'true' -> PIW
       'false' -> DCW
       -->
       <xsl:param name="propertyWizard"/>
       <!-- identity transformation template -->
       <xsl:template match="definition[@name='use-remote-loader']/value">
               <xsl:variable name="shimAuthServer"
select="$curDoc//ds-value[../@ds-attr-name='shim-auth-server']/text()"/>
               <xsl:choose>
                       <!-- use remote loader if the driver is already configured to use
the remote loader -->
                       <xsl:when test="starts-with($shimAuthServer, 'REMOTE(')">
                               <value>true</value>
                       </xsl:when>
                       <!-- don't use remote loader if the driver is not configured to use
the remote loader -->
                       <xsl:when test="string-length($shimAuthServer)>0">
                               <value>false</value>
                       </xsl:when>
                       <!-- if we can't tell, use the prompt default setting -->
                       <xsl:otherwise>
                               <xsl:copy>
                                       <xsl:apply-templates select="@*|node()"/>
                               </xsl:copy>
                       </xsl:otherwise>
               </xsl:choose>
       </xsl:template>
       <xsl:template match="definition[@name='rl-hostname']/value">
               <xsl:variable name="shimAuthServer"
select="$curDoc//ds-value[../@ds-attr-name='shim-auth-server']/text()"/>
               <xsl:choose>
                       <xsl:when test="starts-with($shimAuthServer, 'REMOTE(')">
                               <xsl:variable name="hostName"
select="translate(substring-before(substring-after($shimAuthServer,
'REMOTE(hostname='), ' '), ' ', '')"/>
                               <value>
                                       <xsl:value-of select="$hostName"/>
                               </value>
                       </xsl:when>
                       <xsl:otherwise>
                               <xsl:copy>
                                       <xsl:apply-templates select="@*|node()"/>
                               </xsl:copy>
                       </xsl:otherwise>
               </xsl:choose>
       </xsl:template>
       <xsl:template match="definition[@name='rl-port']/value">
               <xsl:variable name="shimAuthServer"
select="$curDoc//ds-value[../@ds-attr-name='shim-auth-server']/text()"/>
               <xsl:choose>
                       <xsl:when test="starts-with($shimAuthServer, 'REMOTE(')">
                               <xsl:variable name="port"
select="translate(substring-before(substring-after($shimAuthServer,
'port='), ')'), ' ', '')"/>
                               <value>
                                       <xsl:value-of select="$port"/>
                               </value>
                       </xsl:when>
                       <xsl:otherwise>
                               <xsl:copy>
                                       <xsl:apply-templates select="@*|node()"/>
                               </xsl:copy>
                       </xsl:otherwise>
               </xsl:choose>
       </xsl:template>
       <xsl:template match="definition[@name='rl-password']/value">
               <xsl:variable name="shimAuthPwd"
select="$curDoc//ds-value[../@ds-attr-name='shim-auth-password']/text()"/>
               <xsl:choose>
                       <xsl:when test="starts-with($shimAuthPwd, 'REMOTE(')">
                               <xsl:variable name="rlPwd"
select="substring-before(substring-after($shimAuthPwd, 'REMOTE('),
')')"/>
                               <value>
                                       <xsl:value-of select="$rlPwd"/>
                               </value>
                       </xsl:when>
                       <xsl:otherwise>
                               <value/>
                       </xsl:otherwise>
               </xsl:choose>
       </xsl:template>
       <xsl:template match="node()|@*">
               <xsl:copy>
                       <xsl:apply-templates select="@*|node()"/>
               </xsl:copy>
       </xsl:template>
</xsl:stylesheet>


Probably this part:

       <xsl:template match="definition[@name='rl-port']/value">
               <xsl:variable name="shimAuthServer"
select="$curDoc//ds-value[../@ds-attr-name='shim-auth-server']/text()"/>
               <xsl:choose>
                       <xsl:when test="starts-with($shimAuthServer, 'REMOTE(')">
                               <xsl:variable name="port"
select="translate(substring-before(substring-after($shimAuthServer,
'port='), ')'), ' ', '')"/>
                               <value>
                                       <xsl:value-of select="$port"/>
                               </value>
                       </xsl:when>
                       <xsl:otherwise>
                               <xsl:copy>
                                       <xsl:apply-templates select="@*|node()"/>
                               </xsl:copy>
                       </xsl:otherwise>
               </xsl:choose>
       </xsl:template>

needs to accommodate the kmo= part, not sure how to do that in XSLT, probably have to fork into an IF there is a kmo= in there or not. What is worse is there is a valid localaddreess = 1.1.1.1 Other entry that is legal and semi supported.

Then the prompts need an update with a section for kmo= to use both as a source and as a target.

The nice thing is, you can use the UI tools to build these prompts, since they use the same DTD as the Configuration settings (Shim Config, Global Config, and Engine control values use). It could look something like this:

<definition display-name="SSL Certificate Name" name="rl-kmo" type="string">
       <description>If you wish to use SSL, then specify the name of the Key Material Object in eDirectory, without the ending that names the server.  Thus in eDir you might have SSL CertificateIP - ServerName and here you would just enter SSL CertificateIP</description>
       <value>rl-cert</value>
</definition>

Then you have a location to copy the value too.

This means pretty much anyone who tries to use one of these in a Package will find it broken, on an upgrade, if they set a KMO, in fact, anyone trying to upgrade for 1.01 to 1.03 build ought to experience this issue. I have reported a bug and there will be updated packages and default template XSLT in Designer in 4.02 but what I found most interesting is what the failure indicates about the purpose of the Prompts and Target Transformation package prompts. The updated XSLT is much more complicated, because it needs to handle a number of cases, and is trying to detect them all by taking the string apart, using spaces as the delimiter, which looks like it is just waiting for an odd edge case to break it. I did test that a space in the certificate name, which is immensely common, did not break it, so that was comforting.

The Prompts transform, takes the existing values, and if needed, reformats them to look proper in the UI when you install or upgrade a package. This is the part where you can see the existing values (Default on first install) and change them if needed. Then the Target Transformation takes the data and reformats it to the way it needs to look to be written back with either the existing values you approved or the modified values you changed.

Most of the time, it seems like the Identity Transform in XSLT would suffice, you know the very common copy of all nodes and subnnodes:

<xsl:template match="node()|@*">
       <xsl:copy>
	       <xsl:apply-templates select="@*|node()"/>
       </xsl:copy>
</xsl:template>

In fact the biggest issue I have been finding with these prompts is how they relate to GCV values, where the default XSLT basically tries to copy the values selected for each GCV one by one, being somewhat clever. However, when you have slightly more complicated GCV data types, like a List, Enumerated, or Structured GCV, where the XML is not simply, take the <value> node and copy that through then it runs into trouble.

It seems that the simple solution is just to use the Identity Transform to copy the data into the Prompts, and then the same to copy it back in the Target Transform.

The good news is that by the time you read this a new Package for all the various Base driver packages will be available, and that Designer will have this issue fixed. But I think it is useful to examine how it fails, because in the process you get enlightened as to what the original intention and goal of the process was. I did not really understand why we needed these Prompt objects with their XSLT until this point, and further, what the difference between the two were.

If you have figured out any other interesting tidbits related to Packaging, I would love to see you submit it, since the more we can get out there and written, the better it is for everyone since this is a neat feature with all sorts of subtleties and complexities and the current documentation does not do a good job at all of covering them.

VN:D [1.9.22_1171]
Rating: 5.0/5 (2 votes cast)
An illuminating bug in Remote Loader Package Prompts Template, 5.0 out of 5 based on 2 ratings

Tags: , ,
Categories: Identity Manager, Technical Solutions

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.

Comment