Identity Manager has a really neat XML based language called DirXML Script. When you look at a policy in iManager or Designer, you see a GUI rendering of the underlying XML. This is a very powerful approach, since changing some things in the GUI can be tedious or tricky. Whereas some things are really easy to change in the XML view directly. Thus you get a nice choice of which way you want to make the needed changes.

There are lots of great tokens available, occasionally new ones get added. I recently found out there is a new one in IDM 4.5 that I totally missed, Generate XDAS Event, and will need to update my book with information on the new token.

The various tokens have various use cases and can sometimes be confusing. One specific set of those are the Attribute tokens, and the Query token. They look very similar, they generate similar events, but the way the results are processed can be different and unexpected if you are not ready.

In the String/Argument Builder interface (Where you get to use the Noun and Verb tokens) there are a set of interesting nouns tokens.

     Attribute
     Destination Attribute
     Operational Attribute
     Removed Attribute
     Source Attribute
     Query

A quick review:

Source Attribute sends a query event to the source. Thus in the Subscriber channel that would be the Identity Vault. In the Publisher channel, that would be the application. In other words, it depends on the direction the event is flowing. Destination Attribute is basically the same thing, just pointing in the other direction. Subscriber channel it will be the Application, and Publisher channel it will query the Identity Vault.

Attribute by itself, is supposed to look and see if the attribute named is in the current operation, and if not, query the source for its values. However I do not find that reliable and it seems (at least in Simulator) to always query.

Operational Attribute and Removed Attribute will not generate queries, rather they select data in the current operation. Operational Attribute will collect the addition of values, and Removed Attribute will collect the removed values.

These are great, since you can use them as the target of a For Each loop and react to each attribute value being added or removed.

In Source Attribute and Destination Attribute you get the option to specify which object to get the data from. You can specify the object as

  • Current object
  • DN (in proper format in the target system)
  • Association value.

Obviously Operational Attribute and Removed Attribute only make sense in relation to the current object being processed. After all, the definition of operational and removed is that they are part of the current event document.

The Query token on the other hand is a great wrapper for a lot of functionality. The GUI builder is very powerful and has many options to make your life easier. In general you can do everything the token can do with the Java function called directly, but the GUI makes it trivial to get just what you want.

When you are retrieving a single value, this is nice and simple. Store it in a variable, test it with an If Source Attribute ‘equals’ test or the like. But what if the result is multi valued. Or worse, structured perhaps Path syntax like DirXML-Associations.

A friend emailed me a question about an article I had written in the past about using XPATH to examine DirXML-Associations values. Using XPATH to examine Association values

He was having trouble, and I admitted that doing the test in a single XPATH is usually to hard to get just right, so instead, I grab the attribute values into an attribute, loop over it with a for each token, and then inside the loop do whatever test is needed.

He tried it but it was not working. We discussed it, and I think the core issue he had was related to how the Source Attribute and Query token return data to be stored in the local variable.

Local variables can be scoped to ‘policy’ or ‘driver’. The policy scope means it will go away when this policy finishes executing. The driver scope means it will persist until it is overwritten or the driver is restarted. Be careful with ‘driver’ scope as those can be tricky.

The variable can have 3 different types of scopes. Usually we use the default of string, which makes sense. You want one value back, a string, so store it in a string variable. Object (the third, I will get to the second next) is used when you need to take the results of a Java function call to pass to another Java function.

The most interesting variable type to me is Nodeset. This is not just a nodeset of XML, it can also be a nodeset of values. That last one is confusing but useful in some cases. Imagine you wanted to loop over a set of integers. You could make a nodeset of values like a one dimensional array and loop over it. But the more usual case would be with a nodeset holding an XML nodeset, because then you can use XPATH to select pieces of it as you need them.

One really strange and poorly documented aspect of the IDM Engine is how it changes its behavior, in a string vs a nodeset context. My favorite example of that is the Structured GCV type. Structured Global Configuration Values in IDM

If you treat it as a string, you get a long string with concatenated values separated by the delimiters you specified. Reading this as a human is very hard. If you treat it as a nodeset you get the <instance> node XML that you can use XPATH on as needed. In fact if it is multi valued, you can loop over the <instance> nodes, which is really useful. Honestly if I had to parse the string format, I would actually use the Split token to convert the values into a nodeset of values and then loop over that nodeset.

That raises the question of how to you use in a string vs nodeset context? Easiest way is to copy it into a variable, using the Set Local Variable token and then depending how you define the local variable, string or nodeset, you have specified the context. I think you technically cast it to a string, since the engine stores it as a nodeset most of the time, but I am not certain of that.

This has real consequences that matter when it comes to using the Attribute tokens. If you Set Local Variable, of type String, and use the Source Attribute token to get a response, if there is a single value, all is well. But if there were two values on the source object, you would get both the string values, no spaces, no delimiters, concatenated together. That is not what you wanted, I assume.

If however the local variable type was set to Nodeset, then you get a different result. I will come back to what that looks like in a moment since I want to address how a Query result looks as well.

When you use the Query token, you pretty much always should set it in Nodeset local variable. I cannot think of a single use case where it would work as a string. This is due to what is stored.

The key thing to note, is that all these tokens that actually query will likely generate an identical looking <query> event, and possibly even return an identical <instance> node result. However what will be stored in the variable will differ.

I will use an example of DirXML-Associations, with two values, so multi-valued and structured, so kind of the worst case.

Assume we get back this result for both cases. One object queried, two values found.

<instance class-name="User" qualified-src-dn="O=ACME\OU=Active\OU=ACMEUsers\CN=bsmith" src-dn="\ACME\ACME\Active\ACMEUsers\bsmith" src-entry-id="1770792">
     <association state="migrate"></association>
     <attr attr-name="DirXML-Associations">
       <value timestamp="1387228036#16" type="structured">
         <component name="nameSpace">1</component>
         <component name="volume">\ACME\services\DriverSet1\Banner</component>
         <component name="path">PK_BANNER_ID_EMPLOYEE=ABCD1234,table=IDM_DATA_LOOKUP,schema=ACME_APPS</component>
       </value>
       <value timestamp="1387228044#100" type="structured">
         <component name="nameSpace">1</component>
         <component name="volume">\ACME\services\DriverSet1\UserApplication</component>
         <component name="path">"AnAssociation"</component>
       </value>
    </attr>
</instance>

The nodeset in the variable for the token-query case will consist of

Virtual root:

	<instance class-name="User" qualified-src-dn="O=ACME\OU=Active\OU=ACMEUsers\CN=bsmith" src-dn="\ACME\ACME\Active\ACMEUsers\bsmith" src-entry-id="1770792">
	     <association state="migrate"></association>
	     <attr attr-name="DirXML-Associations">
	       <value timestamp="1387228036#16" type="structured">
	         <component name="nameSpace">1</component>
	         <component name="volume">\ACME\services\DriverSet1\Banner</component>
	         <component name="path">PK_BANNER_ID_EMPLOYEE=ABCD1234,table=IDM_DATA_LOOKUP,schema=ACME_APPS</component>
	       </value>
	       <value timestamp="1387228044#100" type="structured">
	         <component name="nameSpace">1</component>
	         <component name="volume">\ACME\services\DriverSet1\UserApplication</component>
	         <component name="path">"AnAssociation"</component>
	       </value>
	    </attr>
	</instance>

The nodeset for the token-src-attr will consist of:

Virtual root:

       <value timestamp="1387228036#16" type="structured">
         <component name="nameSpace">1</component>
         <component name="volume">\ACME\services\DriverSet1\Banner</component>
         <component name="path">PK_BANNER_ID_EMPLOYEE=ABCD1234,table=IDM_DATA_LOOKUP,schema=ACME_APPS</component>
       </value>
       <value timestamp="1387228044#100" type="structured">
         <component name="nameSpace">1</component>
         <component name="volume">\ACME\services\DriverSet1\UserApplication</component>
         <component name="path">"AnAssociation"</component>
       </value>

Thus when you for-each over one nodeset or the other, the XPATH to select what you want differs.

In the first case, (token-query) you loop at the <instance> level, thus you get one loop, and current-node starts at the node below <instance>. To test for an association value for a specific driver, you need a test something like:

$current-node/attr[@attr-name="DirXML-Associations"]/value/component[@name="volume"]/text()=$DNofMyDriver

Where DNofMyDriver is a variable you set earlier as a string with the \TREE\O\OU\Driverset\DriverName value in it.

Breaking down the XPATH, the first element is the $current-node, which is a local variable only there in For Each Loops. If you wonder, current-value is only available in the Reformat Operation Attribute token, and represents all the values of the attribute. So you can apply Reformat Operation Attribute to the variable current-value and it will implicitly loop over each value and do the same task to each. The last one of interest is current-op which is a pointer to the current events operation. There are a lot of neat tricks you can play with this, and Alex McHugh did a great series on using this variable that is worth reading. Series: Delving into and beyond the current-op

Back to the XPATH, since our loop is over each <instance> node, your current context is at the instance node, so then to get to the attribute you want, you need to specify the ‘attr’ node, but then you want a predicate to select the specific attribute (in case there is more than one), this is the [@attr-name=”DirXML-Associations”] part. The @attr-name means the XML attribute (the @ sign) named attr-name. If you look at the attr node, it looks like:

<attr attr-name="DirXML-Associations">

The node name is attr, the attr-name is the attribute. Then we select the value node, then a component node, but again we have a predicate of [@name=”volume”] so we get the second of the three component nodes. Finally we test for text()=$DNofMyDriver so that we know we are in the right one.

In the second case (token-src-attr), you loop over the value nodes, twice in this example, and $current-node is the <value> node, so the XPATH you need to select would be more like:

$current-node/component[@name="volume"]/text()=$DNofMyDriver

As before, you start with current-node, the dollar sign means it is a variable (which I missed noting before), and since the loop is over each <value> node, that is where our current context is set. Thus we start selecting from there down, and use component, again with a predicate of [@name=”volume”] to pick the right one out of the three components. Finally we test for text()=$DNofMyDriver again. If you have ever looked at some of the other structured syntax types, like ACL, Typed Name and so on. But take a look at Postal syntax. It has six components each of them named “string” in which case selecting the one you want means you have to use the position() function. In principle the engine should always return the Path syntax components in the same order, but you never

I write that there is a virtual root, which I do not fully understand how that manifests, but XML really expects a parent node, rather than two parent nodes as would be the case in two values or two instance nodes. So there is an implicit parent node of some kind in there. I know this matters, because if you try to build the result nodeset by hand in a policy to make testing faster, I have yet been able to figure out how to do it. Imagine you have a complex policy to test with lots of queries and results. It would be nice during development and using Simulator to have the requested values in the proper form built into the policies. It makes testing the hard stuff easier. Again if you have figured out how to do this properly I would love to hear about it.

Hopefully that clarifies some of the differences between what would be stored in a nodeset variable by the Query token vs the Source Attribute token.

Let me know if that clarifies, or just muddies the water further.

2 votes, average: 5.00 out of 52 votes, average: 5.00 out of 52 votes, average: 5.00 out of 52 votes, average: 5.00 out of 52 votes, average: 5.00 out of 5 (2 votes, average: 5.00 out of 5)
You need to be a registered member to rate this post.
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
geoffc
By: geoffc
Mar 11, 2016
8:16 am
Reads:
2,061
Score:
5
Active Directory Authentication Automation Cloud Computing Cloud Security Configuration Customizing Data Breach DirXML Drivers End User Management Identity Manager Importing-Exporting / ICE/ LDIF Intelligent Workload Management IT Security Knowledge Depot LDAP Monitoring Open Enterprise Server Passwords Reporting Secure Access Supported Troubleshooting Workflow