A while ago I reported a bug in the Remote Loader Prompt Stylesheet, where additional remote loader parameter (other than hostname, port and kmo) will not be picked up properly during a package update if the kmo parameter is not used. This is a common scenario (actually considered “best practice” in my book) when using remote loaders locally on the IDM engine server to keep shims out of engine memory space and allow to update them without having to restart eDirectory.

In this use case you’d use the following parameters on the driver’s authentication tab:

 Connection Information: <application server ip/hostname>
 Hostname: 127.0.0.1
 Port: <your choice>
 Other: localaddress=127.0.0.1

which results in an authentication parameter string of

 REMOTE(hostname=127.0.0.1 port=<your choice> localaddress=127.0.0.1)<application server ip/hostname>

behind the scenes (Designer displays this as separate input fields but it’s stored as shown above internally and on the driver object in eDirectory).

The “localaddress” parameter sets the engine’s source IP for the remote loader connection to the loopback interface. Use this together with the following remote loader parameters in your rdxml.conf file:

-connection "port=<your choice> address=127.0.0.1 fromaddress=127.0.0.1"

to make the remote loader listen on the loopback interface as well, and only allow incoming connections from loopback.

In this setup no data transferred between engine and remote loader will be exposed on the network and because of that there’s no need to secure the connection with SSL and use the “KMO” parameter. (Please note: of course you can use SSL here if you want and you do not have to limit local remote loader connections to the loopback interface. I just prefer things as simple as possible and since we all know that SSL certs *will* expire some time – usually without anyone noticing in advance, on a long weekend, when the only PKI literate admin is on a hiking trip in Greenland or Moab – your driver will eventually stop working when you least expect it.)

Unfortunately even the latest Designer version (4.0.2 AU4a at the time of writing) does not handle this set of parameters properly and puts the “localhost=127.0.0.1″ right after the port number in the “Port” prompt and leaves the “Other” prompt empty. The “Port” prompt is of integer syntax which prevents you from using cut/paste to move it over in to the “Other” field, so you’ll have to manually type and delete the additional parameter – not nice.

Basically the same situation occurred a while ago with the “KMO” prompt and has been discussed in Geoffrey’s article https://www.netiq.com/communities/cool-solutions/an-illuminating-bug-in-remote-loader-package-prompts-template and on the support forums at https://forums.netiq.com/showthread.php?338-Remote-Loader-Prompt-for-KMO. The solution described in that thread has been added to the default stylesheets in the mean time, but the same issue still occurs with other parameters if “KMO” is not used, because the default stylesheet does not handle each parameter independently but expects them in a certain order and is limited to the rather poor string manipulation capabilities of XPATH.

Limited to XPATH string functions? Really? Certainly not in XSLT driver policies, where you can call java functions from XPATH by mapping a namespace to the class you want to utilize. And as it turn out quickly: prompt stylesheets can do the same. So all we need to get access to a set of more powerful string functions is map a namespace to the java String class:

xmlns:jstring="http://www.novell.com/nxsl/java/java.lang.String"

and now we can use e.g. jstring:replaceAll() to regex our way around with the parameters and extract the values independently of their relative position.
An additional complication I ran into later was the fact that default server certificated are often used to secure remote loader connections and the names of those certs usually contain white space. KMO values can therefore be enclosed in single or double quotes, but they do not have to. Now, how do you match the value of the kmo parameters in all of the following three cases with a single regex?

REMOTE(hostname=1.2.3.4 port=8000 kmo=MyCertificate)5.6.7.8
REMOTE(hostname=1.2.3.4 port=8000 kmo='SSL CertificateIP' localaddress=127.0.0.1)5.6.7.8
REMOTE(hostname=1.2.3.4 port=8000 kmo="SSL CertificteDNS")5.6.7.8

I quickly gave up on this (let me know if have a solution, though!) and settled on a two-step approach that seems to work fine, though it probably won’t win the XSLT Prompt Stylesheet Elegance in Coding Contest.

So here’s the Remote Loader Prompt Transformation stylesheet I came up with. Be sure to change the prompt resource’s type to “Custom” on the “General” tab if you use it to prevent it from being overwritten with the buggy default version at a later time. “Custom” prompts are always kept “as is” just for cases like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:jstring="http://www.novell.com/nxsl/java/java.lang.String" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!--
    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: 2014-03-31 by Lothar Haeger (lothar.haeger@is4it.de): fixed "Other" parameter handling during update if "KMO" parameter is not used
    -->
    <!--
    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)&gt;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="normalize-space(jstring:replaceFirst($shimAuthServer, '.*hostname=([^ \)]+)[ \)].*', '$1'))"/>
                <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(') and contains($shimAuthServer,'port=')">
                <xsl:variable name="port" select="normalize-space(jstring:replaceFirst($shimAuthServer, '.*port=([^ \)]+)[ \)].*', '$1'))"/>
                <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-kmo']/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(') and contains($shimAuthServer,'kmo=')">
                <xsl:variable name="kmo1" select="normalize-space(jstring:replaceFirst($shimAuthServer, '.*kmo=([\u0027\u0022][^\u0027\u0022]*[\u0027\u0022])[ \)].*', '$1'))"/>
                <xsl:variable name="kmo2" select="normalize-space(jstring:replaceFirst($kmo1, '.*kmo=([^ \)]*)[ \)].*', '$1'))"/>
                <value>
                    <xsl:value-of select="$kmo2"/>
                </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-other']/value">
        <xsl:variable name="shimAuthServer" select="$curDoc//ds-value[../@ds-attr-name='shim-auth-server']/text()"/>
        <xsl:variable name="other1" select="normalize-space(jstring:replaceAll($shimAuthServer, '.*REMOTE\(|(hostname|port)=[^ \)]*|\).*', ''))"/>
        <xsl:variable name="other2" select="normalize-space(jstring:replaceAll($other1, 'kmo=[\u0027\u0022][^\u0027\u0022]*[\u0027\u0022]', ''))"/>
        <xsl:variable name="other3" select="normalize-space(jstring:replaceAll($other2, 'kmo=[^ ]*', ''))"/>
        <xsl:choose>
            <xsl:when test="starts-with($shimAuthServer, 'REMOTE(') and contains($other3, '=')">
                <value>
                    <xsl:value-of select="$other3"/>
                </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>
0 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 5 (0 votes, average: 0.00 out of 5)
You need to be a registered member to rate this post.
Loading...Loading...

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.

Leave a Reply

No Comments
lhaeger
By: lhaeger
Apr 1, 2014
3:09 pm
Reads:
1,470
Score:
Unrated