Using XPATH to examine Association values

Novell Identity Manager has an advantage over some of its competitors based on how it stores the association values for synchronized objects. Other products may use a directory to combine all the data about the users, but often they do not store the information about associations, that is connections between objects in the different systems, within that directory.

The way Novell Identity Manager does it is quite advantageous, since you can examine the directory on any object and see what the association values are, without needing to look into another location to retrieve the information.

The values are stored in eDirectory in an attribute called DirXML-Associations. The DirXML-Associations attribute uses an interesting syntax, called Path syntax. Path is a compound or structured attribute syntax that has three parts to it. An integer (I think it has a max range, but we only ever use 0-5 so not sure) named nameSpace, then a distinguished name syntax field called "volume", and finally a string field called "path". This was designed to store things like a home directory path, where you need to specify the name space the path is in, (DOS, NFS, LONG, OS2, MAC, etc... Shades of the old NetWare days eh?), then the distinguished name of the volume object, and finally a free form text field for the path on the volume.

The DN reference to the volume is the reason why if you deleted a server or volume object in eDirectory, all the Home Directory mappings would go away. DN syntax fields do not store the string of the DN of the object, rather it stores a 32 bit integer that describes the entry in the eDirectory database. Thus every tool that displays the DN to a human, basically does a look up for the current display name of the object. Thus renames, and moves, are automatically displayed correctly at all times. However, if you delete the object and then recreate it, even when the names are the same, the object IDs are different (eDirectory may eventually reuse an object ID, but there is no way to force it or request it, so you can basically be guaranteed a different object ID).

That does bring up an important point with DirXML-Associations values, and if you are updating the drivers. You might be tempted, when the time comes to do an upgrade to the system, to just delete all the DirXML Driver objects and re-import them from your lab model, but this illuminates a big pitfall. All the DirXML-Association values are based on the DN (the Volume part of the structured attribute) of the current DirXML Driver object. If that gets deleted, all the DirXML-Association values just magically go away.

If you have to take that approach, then delete everything UNDER the Driver object, but leave the Driver object behind so that the DirXML-Associations remain.

There are several good tools to back up the values. From the commercial world Blackbird Detroubler ( one of the best tools for backing up eDirectory in general, since it is smart enough to recognize cross links between objects. That is, if you deleted your DirXML Driver object accidentally (or on purpose) and regret it, it can restore the objects, but also it can restore the association values on all the objects that had them. It is quite impressive, and to the best of my knowledge a unique feature in the market. Other products will restore the objects (possibly with the same object ID, but not likely) and then it is up to you to restore the references on the other objects.

From the free world, Novell Professional services out of Hungary released the super cool tool, DAModifier. You can get it from: or modifier

This free tool is a Windows tool, that requires an NCP over Client 32 connection. You can pick the tree, the driver object, the context to search in, and the kind of association value you wanted. You can use it to show the current values, and save it to a file, and at a later date restore them from a file. This gets around the DN syntax issue, by storing and referencing the names of the DirXML Driver object, so that when it goes to restore the value, it has to lookup the actual current Object ID that belongs to the name.

For a listing of the various known association values (The "Path" part of the structured attribute) check out this article on the topic:
Open Call - IDM Association Values for eDirectory Objects

Within a driver, there are a couple of DirXML Script tokens, conditions, and actions that can look at Association values.

In the Condition block of rules, you can select an If association, and the tests are things like, Associated, not associated, available, and then the usual set of equal, not equal, less than, not less than, and friends.

The less than, greater than tests do not seem all that useful, until you consider that the value of the association, the "Path" part of the structured attribute is just a text string. So perhaps in the case of a driver to a Unix style system, it might be storing uid numbers, in which case testing if the number is below 1024 could be useful and tell you something about the user. (Now it happens that the bi-directional Linux Unix driver happens to use the users CN followed by the string User or Group, so a User named jsmith would have an association value of jsmithUser and group named Shovellers would have an association value of ShovellersGroup but it was a nice example even if it makes no sense in reality). Some databases might use the value of a primary key sequence number (say a column called pk_sequence) that is incremented, and you want to know if a users row in the database is below or above some value.

In the Action block of a rule, you can Add Association or Remove Association. Remove Association is a great action, if you want to dis-associate users after an event, say if one system deletes the user, we often convert the delete event into a Remove Association and disable user (Set Login Disabled equal true). Lets say in the case of a JDBC driver, where you are synchronizing a view, instead of a real table, and there is some criteria that defines your view, and users can change to be in or out of the view. Say some value is Active or Inactive and that defines your view. When they go inactive, it would come across as a delete, since it has disappeared from the view. In a case such as that, you would want to remove the association so that if the user becomes Active again, and appears in the view, you would want to match on the user again, but if the user still has an association value it will not match correctly.

In the Argument Builder, basically anywhere you can build a string, you can use the Association token to use the current association value. Source Attribute and Destination Attribute can reference a specific object other than the one in the current operation if you give a DN or Association value to look for.

The problem of all these approaches however if that they are focused on the Association of the current object, and for the current driver. There are many powerful use cases where in a different driver (often a Null or Loopback driver) it would be useful to know if the user is associated to a particular system.

The good news is that with XPATH you can accomplish much of what you need. I am trying to do a series of articles on the use of XPATH in Identity Manager, since the context for an Identity Manager event (which is key when selecting in XPATH), is different than you would see in documentation for XPATH elsewhere on the web. You can see the previous articles at:

You can query for the DirXML-Associations on an object with the Query token quite readily.

For example this action will set a local variable ASSOC-VAL with a node set filled with the data from the Query for a user with a workforceID of the local variable WORKFORCE-ID.

<do-set-local-variable name="ASSOC-QUERY" scope="policy">
<token-query class-name="User" datastore="src">
<arg-match-attr name="workforceID">
<arg-value type="string">
<token-local-variable name="WORKFORCE-ID"/>
<token-text xml:space="preserve">DirXML-Associations</token-text>

This will return a document something like the following into the node set.

<nds dtdversion="3.5" ndsversion="8.x">
<product version=" ">DirXML</product>
<contact>Novell, Inc.</contact>
<instance class-name="User" qualified-src-dn="O=LAB\OU=EMPLOYEES\OU=NEW\CN=JSmith" src-dn="\ACME-LAB\LAB\EMPLOYEES\NEW\LJohnson1" src-entry-id="56795">
<attr attr-name="DirXML-Associations">
<value timestamp="1217007039#71" type="structured">
<component name="nameSpace">1</component>
<component name="volume">\ACME-LAB\LAB\SERVICES\IDVAULT\APP-JDBC</component>
<component name="path">PK_SEQUENCE=350110,table=CLIENTS,schema=IDM</component>
<value timestamp="1217007039#72" type="structured">
<component name="nameSpace">1</component>
<component name="volume">\ACME-LAB\LAB\SERVICES\IDVAULT\LinuxUnixSettings</component>
<component name="path">YE98 yxf3AGAleAAAwAAAA==</component>
<value timestamp="1217007039#73" type="structured">
<component name="nameSpace">1</component>
<component name="volume">\ACME-LAB\LAB\SERVICES\IDVAULT\UserApplication35</component>
<component name="path">"AnAssociation"</component>
<value timestamp="1217007039#74" type="structured">
<component name="nameSpace">1</component>
<component name="volume">\ACME-LAB\LAB\SERVICES\IDVAULT\Active Directory</component>
<component name="path">f0648eab27d6da4283246583112d6319</component>
<value timestamp="1217007039#75" type="structured">
<component name="nameSpace">1</component>
<component name="volume">\ACME-LAB\LAB\SERVICES\IDVAULT\Corporate Password Sync</component>
<component name="path">E101738</component>

You could also use the Source attribute token if you are interested in the current user object, or can specify its DN or Association value. That might look like:

<do-set-local-variable name="ASSOC-VALS" scope="policy">
<token-src-attr name="DirXML-Associations"/>

That will generate a query and result much like above in DSTrace, but the value held in the node set will be different, which means the XPATH to get the values will be different.

For the first case, where we used a Query, the nod set is based on the instance document which is where the current context is, so something like the following (assuming you know the DN of the driver you want to test for and it is stored in the local variable TARGET-DRIVER-DN):

$ASSOC-QUERY/attr[@attr-name="DirXML-Associations"]/value/component[(@name='volume') and (text()=$TARGET-DRIVER-DN)]/parent::component[@name='nameSpace']/text()='1'

<if-xpath op="true">$ASSOC-QUERY/attr[@attr-name="DirXML-Associations"]/value/component[@name='volume']/text()=$TARGET-DRIVER-DN</if-xpath>
<if-xpath op="true">$ASSOC-QUERY/attr[@attr-name="DirXML-Associations"]/value/component[@name='nameSpace']/text()='1'</if-xpath>

This ought to do it in one operation. Test that the component named volume, with a text of the DN of the target driver local variable, is true and then up a node to the parent, and look for the component named namespace, having a value of 1. That will evaluate true if one of the nodes meets those requirements.

For a the second case, where the node set contains the values returned by a Source attribute token, although the same basic instance document is returned, the current context is different and instead of being at the top of the instance document, the nodes are just the values (without the attr node above it).

Therefore you would have to use different XPATH, in this case it is easier to do it in two XPATH statements, that both need to be true.

<if-xpath op="true">$ASSOC-VALS/component[@name='volume']/text()=$TARGET-DRIVER-DN</if-xpath>
<if-xpath op="true">$ASSOC-VALS/component[@name='nameSpace']/text()='1'</if-xpath>

The node set is basically composed of several nodes, one per Value node returned for the user, so you want to check right at the component level, instead of the attr[@attr-name="DirXML-Associations"] level.

If you needed to do something with the value of the association, you could select it into a variable with an XPATH that looks something like setting a local variable equal to the XPATH expression, depending on the


just after you had gotten to the correct node with a test as shown previously.


How To-Best Practice
Comment List
  • First off, posting trace into a comment does not work well, as it has to be sanitized to look like HTML. I THINK you can use "code" tags (I would have put an angle bracket (less than, greater than) sign around "code" but of course, that too would not work here. :) Hmm, let me try it here:

    Oh well, that did not work at all... Lot sure how to do that in a comment. When I submit an article the busy gnomes at Cool Solutions (I note they do not use KDE's but rather Gnomes) make it look all pretty for me.

    Anyway, look at this patch:

    This was patched on Dec 8. Get the engine 2a patch for IDM 3.6 and then try the code again, as is, lets see if that fixes it.

    Crazy bug, but if you read the README it says:
    Technical Support Information:

    Current fixes:
    - Fixed problems with the readme files.

    Previous fixes:
    - Resolved issue where synthetic add's failed with "value required for attribute 'src- dn'" error. Bug 432959

    - Resolved issue where querying for the DirXML-associations attribute returned an empty result. Bug 442426
  • Hi -
    I tried to use the same code as above but could not make it working.

    Below is the trace -

    16:00:00 BusinessDriver ST: Applying rule 'Add ADUserCN in IDStore Object'.
    19:38:08 BusinessDriver ST: Action: do-set-local-variable("ASSOC-VALS",scope="policy",arg-node-set(token-query(datastore="src",scope="entry",arg-dn(token-src-dn()),"DirXML-Associations"))).
    16:00:01 BusinessDriver ST: arg-node-set(token-query(datastore="src",scope="entry",arg-dn(token-src-dn()),"DirXML-Associations"))
    16:00:00 BusinessDriver ST: token-query(datastore="src",scope="entry",arg-dn(token-src-dn()),"DirXML-Associations")
    16:00:00 BusinessDriver ST: arg-dn(token-src-dn())
    20:34:10 BusinessDriver ST: token-src-dn()
    16:00:00 BusinessDriver ST: Token Value: "\DEV1-TREE\IDVAULT\ACTIVEUSERS\alaskamro".
    16:00:04 BusinessDriver ST: Arg Value: "\DEV1-TREE\IDVAULT\ACTIVEUSERS\alaskamro".
    20:34:10 BusinessDriver ST: arg-string("DirXML-Associations")
    16:00:00 BusinessDriver ST: token-text("DirXML-Associations")
    16:00:00 BusinessDriver ST: Arg Value: "DirXML-Associations".
    19:38:08 BusinessDriver ST: Query from policy
    19:38:08 BusinessDriver ST:

    Novell, Inc.

    16:00:00 BusinessDriver ST: Pumping XDS to eDirectory.
    16:00:00 BusinessDriver ST: Performing operation query for \DEV1-TREE\IDVAULT\ACTIVEUSERS\alaskamro.
    16:00:00 BusinessDriver ST: Query from policy result
    19:13:26 BusinessDriver ST:

    Novell, Inc.

    19:38:08 BusinessDriver ST: Token Value: { @class-name = "User" @qualified-src-dn = "O=IDVAULT\OU=ACTIVEUSERS\CN=alaskamro" @src-dn = "\DEV1-TREE\IDVAULT\ACTIVEUSERS\alaskamro" @src-entry-id = "39293"}.
    09:32:10 BusinessDriver ST: Arg Value: { @class-name = "User" @qualified-src-dn = "O=IDVAULT\OU=ACTIVEUSERS\CN=alaskamro" @src-dn = "\DEV1-TREE\IDVAULT\ACTIVEUSERS\alaskamro" @src-entry-id = "39293"}.
  • I am pretty sure Father Ramon offered the right solution in the forums. Did the driver object for your loopback driver have sufficient rights to read the attribute on the user?

    Check the Security Equals attribute on the Driver object and then check the effective eDir rights to the target user.

    PS: Alas, posting XML in a comment does not work. I usually include it in a text file, and let the Cool Solutions editor sanitize it to be posted. This is of course done on puprose, else you could embed arbitrary HTML/Javascript to execute a cross site scripting attack. (XSS).
  • I'm trying to run your code above, but i cannot get the Association value!

    Im runng the code from Event Transformation Subscriber on a Loopback driver. The current user is not and will not be associated on the Loopback driver.

    I can see the query document in the trace, but result comesback empty in the result. i know the user has 4 DirXML-Associations on the different Idm drivers.

    CN is unique.

    Novell, Inc.


    Novell, Inc.