Novell Home

Moving Users from a Flat Identity Vault to a Hierarchy Tree

Novell Cool Solutions: Feature
By David Gersic

Digg This - Slashdot This

Posted: 20 Sep 2006
 

Problem

A Forum reader asked this question:

"Does anyone have any ideas on how to place a user coming from a flat eDirectory Identity Vault to an eDirectory hierarchy tree? Please bear in mind that I have no means of building the OU except I would have to build a 500+ pulldown list in User App or iManager. UserApp doesn't allow the '\' or spaces. iManager would take forever. There is no data coming from HR that says office or location or anything like that."

And here's a solution from David Gersic ...

Solution

In my Vault tree, I have eDir/eDir and eDir/MAD drivers. The eDir and MAD trees are hierarchical, but the Vault tree is flat. Since I wanted to keep this as "simple" and centralized as possible, the placement for the hierarchical tree and for the MAD domain, are all driven by the placement rules on the respective drivers in the Vault tree. You cannot generate a dest-dn for the heirarchical tree in the vault tree's driver, though, so I have to use another attribute (accessCardNumber) as a transport mechanism.

Example

This is the XSLT from the Vault tree driver's Placement rule on the Subscriber channel:

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet
exclude-result-prefixes="query cmd dncv" version="1.0"
xmlns:b64="http://www.novell.com/nxsl/java/com.novell.xml.util.Base64Codec"
xmlns:cmd="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsCommandProcessor"
xmlns:dncv="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.DNConverter"
xmlns:exslt="http://exslt.org/common"
xmlns:query="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsQueryProcessor"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- parameters passed in from the DirXML engine -->
<xsl:param name="srcQueryProcessor"/>
<xsl:param name="destQueryProcessor"/>
<xsl:param name="srcCommandProcessor"/>
<xsl:param name="destCommandProcessor"/>
<xsl:param name="dnConverter"/>
<xsl:param name="fromNds"/>
<!-- identity transformation template -->
<!-- in the absence of any other templates this will cause -->
<!-- the stylesheet to copy the input through unchanged to the output
-->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- add your custom templates here -->
<!-- Map departmentNumber attribute to container path -->
<xsl:template match="add[@class-name='User']">
<xsl:variable name="businessUnit">
<xsl:value-of
select="add-attr[@attr-name='niuBusinessUnit']"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$businessUnit != 'STDTS'">
<xsl:choose>
<xsl:when test="$businessUnit !=
'GRADS'">
<xsl:message>Department Number
Placement</xsl:message>
<!-- read in placement table -
via query so that we don't have to restart the drivers each time the table is
updated -->
<!--

************************************************************************************************************************
*
* 12 July 2005: this should work, but doesn't. see comments
below for details.
* 13 July 2005: this does work. the problem was in the query
format. but the xpath statement to use the results is 
* still problematic, so back to using just the alternate
document() to read it in.
*

************************************************************************************************************************
<xsl:variable name="placementTable">
<xsl:call-template name="get-placement-table"/>
</xsl:variable>
-->
<!--

************************************************************************************************************************
*
* alternative table reading method.
* see
http://groups-beta.google.com/group/novell.support.nsure-identity-manager/msg/ebc1fb048ecca4d8?hl=en&
*

************************************************************************************************************************
-->
<xsl:variable
name="placementTable2"
select="document('vnd.nds.stream://NIU-FLAT/NIU/DirXML/DS1/eDirDriver-StudentNode1/PlacementTable#XmlData')"/>
<!-- Grab the value of the
departmentNumber attribute from the add document -->
<xsl:variable name="department">
<xsl:value-of
select="add-attr[@attr-name='departmentNumber']"/>
</xsl:variable>
<xsl:message>Looking up
department container placement for department <xsl:value-of
select="$department"/>
</xsl:message>
<!--

************************************************************************************************************************
*
* if the above table read via query worked, then this should
work too...
* for some reason, the xpath here doesn't work.
*

************************************************************************************************************************
<xsl:variable name="DeptPath">
<xsl:value-of
select="exslt:node-set($placementTable)/PlacementTable/Department[@DeptId=$department]/eDir_NIU/@Placement"/>
</xsl:variable>
<xsl:message>DeptPath is <xsl:value-of select="$DeptPath"/>
</xsl:message>
-->
<!-- now that the table is read
in, use it to look up the proper placement, based on departmentNumber, for this
object -->
<xsl:variable name="DeptPath2">
<xsl:value-of
select="$placementTable2/PlacementTable/Department[@DeptId=$department]/eDir_NIU/@Placement"/>
</xsl:variable>
<xsl:message>department
container path is <xsl:value-of select="$DeptPath2"/>
</xsl:message>
<xsl:copy>
<!-- Copy element's
attributes -->
<xsl:apply-templates
select="@*"/>
<!-- Use
accessCardNumber as a transport for the desired dest-dn on the other side -->
<add-attr
attr-name="accessCardNumber">
<value
type="string">

<xsl:choose>

<xsl:when test="$DeptPath2">

<xsl:value-of select="$DeptPath2"/>

</xsl:when>

<xsl:otherwise>

<xsl:value-of select="'O=NIU\OU=DK\OU=Default'"/>

</xsl:otherwise>

</xsl:choose>
</value>
</add-attr>
<!-- Copy child
element's attributes -->
<xsl:apply-templates
select="node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:message>Skipping department
placement for GRADS.</xsl:message>
<xsl:copy>
<xsl:apply-templates
select="@*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:message>Skipping department placement for
STDTS.</xsl:message>
<xsl:copy>
<xsl:apply-templates
select="@*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--

**********************************************************************************************************************************
*
* 12 July 2005
* query for placement table. should work. doesn't.
* appears to be a bug in the read-attr code that is ignoring the
type="xml" directive.
* see 
*
http://developer.novell.com/ndk/doc/dirxml/dirxmlbk/ref/ndsdtd/read-attr.html
*
http://groups-beta.google.com/group/novell.support.nsure-identity-manager/msg/ebc1fb048ecca4d8?hl=en&
*
* 13 July 2005
* Problem found. see:
*
http://groups-beta.google.com/group/novell.support.nsure-identity-manager/msg/47fb6ac0bc78f228?hl=en&
*

**********************************************************************************************************************************
-->
<xsl:template name="get-placement-table">
<!-- build an xds query as a result tree fragment -->
<xsl:variable name="query">
<nds dtdversion="1.0" ndsversion="8.5">
<input>
<query scope="entry">
<xsl:attribute name="dest-dn">
<xsl:value-of
select="'NIU\DirXML\DS1\eDirDriver-StudentNode1\PlacementTable'"/>
</xsl:attribute>
<read-attr attr-name="XmlData"
type="xml"/>
</query>
</input>
</nds>
</xsl:variable>
<!-- 
query NDS 
-->
<xsl:variable name="result"
select="query:query($srcQueryProcessor,$query)"/>
<!-- 
return an empty or non-empty result tree fragment depending on
result of query 
-->
<!-- <xsl:value-of
select="b64:decode($result//instance/attr/value)"/> -->
<xsl:value-of select="$result//instance/attr/value"/>
</xsl:template>
</xsl:stylesheet>

Notes

You could shorten this down by trimming out the commented out parts. That'd probably make it easier to understand, as well.

The way this works is to read in a table (see below for a sample of this) off of an object to build what will eventually be the dest-dn for the eDir object being created in the hierarchical tree. By doing this as a read, I do lose some performance, but I gain not having to restart all of my drivers each time the table changes.

First, I have to check for the "business unit" of the user object going through, since this placement doesn't get done for students (STDTS) or graduate assistants (GRADS), only for regular employees. Then I grab the value of the departmentNumber attribute and use it as a lookup index in to the placement table that was read in. That finds me the right departmental container for people in this department. Last, since I'm handling eDir and MAD placement, for both my Development and Production environments, all with this same XSLT and table, I pick off the right value out of the table based on whether this is an eDir driver (shown) or MAD driver.

This could probably be enhanced with GCV support, so that I could specify "production" or "development" in the GCV and not have to change the XSLT at all, but I haven't gotten around to adding that yet.

The eventual result of the stylesheet is that the accessCardNumber attribute gets added to the document with something like O=NIU\OU=DK\OU=AcadDiv\OU=AsstProv\OU=AsPrRsP in it.

The document gets passed over to the other driver in the hierarchical tree on the Publisher channel. The Placement rule over there has a simple job of putting the dest-dn in to the document using the value of accessCardNumber, then stripping accessCardNumber out of the document:

<?xml version="1.0" encoding="UTF-8"?><policy>
<rule>
<description>Users</description>
<conditions>
<or>
<if-class-name op="equal">User</if-class-name>
</or>
<or>
<if-src-dn op="available"/>
</or>
</conditions>
<actions>
<do-set-op-dest-dn>
<arg-dn>
<token-op-attr name="accessCardNumber"/>
<token-text xml:space="preserve"
xmlns:xml="http://www.w3.org/XML/1998/namespace">\</token-text>
<token-src-name/>
</arg-dn>
</do-set-op-dest-dn>
<do-strip-op-attr name="accessCardNumber"/>
<do-break/>
</actions>
</rule>
</policy>

Here's an excerpt from my placement table:

<?xml version="1.0" encoding="UTF-8"?><PlacementTable>
<Department DeptId="BA00000">
<MAD_Win2K
Placement="OU=Provost,OU=AcadDiv,OU=DK,DC=Win2K,DC=niu,DC=edu"/>
<MAD_NIUNT
Placement="OU=Provost,OU=AcadDiv,OU=DK,DC=NIUNT,DC=niu,DC=edu"/>
<eDir_NIU-Development
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=Provost"/>
<eDir_NIU Placement="O=NIU\OU=DK\OU=AcadDiv\OU=Provost"/>
</Department>
<Department DeptId="BB00000">
<MAD_Win2K
Placement="OU=AsPrRsP,OU=AsstProv,OU=AcadDiv,OU=DK,DC=Win2K,DC=niu,DC=edu"/>
<MAD_NIUNT
Placement="OU=AsPrRsP,OU=AsstProv,OU=AcadDiv,OU=DK,DC=NIUNT,DC=niu,DC=edu"/>
<eDir_NIU-Development
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=AsstProv\OU=AsPrRsP"/>
<eDir_NIU
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=AsstProv\OU=AsPrRsP"/>
</Department>
<Department DeptId="BD00000">
<MAD_Win2K
Placement="OU=FacDvlIn,OU=AcadDiv,OU=DK,DC=Win2K,DC=niu,DC=edu"/>
<MAD_NIUNT
Placement="OU=FacDvlIn,OU=AcadDiv,OU=DK,DC=NIUNT,DC=niu,DC=edu"/>
<eDir_NIU-Development
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=FacDvlIn"/>
<eDir_NIU Placement="O=NIU\OU=DK\OU=AcadDiv\OU=FacDvlIn"/>
</Department>
<Department DeptId="BF00000">
<MAD_Win2K Placement="OU=HE,DC=Win2K,DC=niu,DC=edu"/>
<MAD_NIUNT Placement="OU=HE,DC=NIUNT,DC=niu,DC=edu"/>
<eDir_NIU-Development Placement="O=NIU\OU=HE"/>
<eDir_NIU Placement="O=NIU\OU=HE"/>
</Department>
<Department DeptId="BG00000">
<MAD_Win2K Placement="OU=RF,DC=Win2K,DC=niu,DC=edu"/>
<MAD_NIUNT Placement="OU=RF,DC=NIUNT,DC=niu,DC=edu"/>
<eDir_NIU-Development Placement="O=NIU\OU=RF"/>
<eDir_NIU Placement="O=NIU\OU=RF"/>
</Department>
<Department DeptId="BI00000">
<MAD_Win2K
Placement="OU=ChancePrm,OU=AcProv,OU=AcadDiv,OU=DK,DC=Win2K,DC=niu,DC=edu"/>
<MAD_NIUNT
Placement="OU=ChancePrm,OU=AcProv,OU=AcadDiv,OU=DK,DC=niunt,DC=niu,DC=edu"/>
<eDir_NIU-Development
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=AcProv\OU=ChancePrm"/>
<eDir_NIU
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=AcProv\OU=ChancePrm"/>
</Department>
<Department DeptId="BJ00000">
<MAD_Win2K
Placement="OU=BlackStdt,OU=AcProv,OU=AcadDiv,OU=DK,DC=Win2K,DC=niu,DC=edu"/>
<MAD_NIUNT
Placement="OU=BlackStdt,OU=AcProv,OU=AcadDiv,OU=DK,DC=niunt,DC=niu,DC=edu"/>
<eDir_NIU-Development
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=AcProv\OU=BlackStdt"/>
<eDir_NIU
Placement="O=NIU\OU=DK\OU=AcadDiv\OU=AcProv\OU=BlackStdt"/>
</Department>
</PlacementTable>


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell