It is good to know that in the recently concluded essay contest on describing what’s great about Micro Focus products, the winning entry on IAM did deal quite a bit with the IDM Rest Driver. The best part about this driver is that it is Generic. But then this has introduced a few of its own problems and one such is the lack of control on transforming the JSON into ones we need. Many have adopted different methods to tackle this problem. This post tries to explore one such method.

In the IDM world it is easier to work with XML because it is the language of the Engine and the DirXML scripts. It has a strong exploring mechanism in XPATH. And of course because we are used to it! However, JSON is not all that bad. The good folks at open source did come up with an XPATH equivalent for JSON known as JSONPath. There is a similarly named java port of this here.

In this post, we try to leverage JSONPath in our rest driver implementation so that it helps us in reading those pesky little JSON values that the driver throws at us and which always seem to be out of our reach. We would need to download json-path 2.3 & json-smart 2.3. Look for “File” in the table describing the artifact to download these jar files. Copy these to the engine server under /opt/novell/edirectory/lib/dirxml/classes.

Of course, you can write your own code to wrap around these libraries and call them from the engine policies. For details read “Getting Started” on their GitHub page. In this post, I am adding a sample wrapper library jpath which will provide the below functionalities using the JSONPath libraries:

  • parse a JSON to extract a value based on the JSONPath provided.
  • read all first level keys given a jsonstring
  • read one of the first level keys as per the index provided.

Unzip and copy this jar into the above path on the engine server.

Assuming “jp” is the prefix given for the policy namespaces the URI would be “org.jpath.JSONPathWrap” and the methods would be called as:

jp:read(String jsonString, String jsonPath, boolean throwException)

jp:readAttributes(String jsonString, boolean throwException)

jp:readAttribute(String jsonString, int index, boolean throwException)

The last argument “throwException” when set throws the exception thereby terminating the policy processing. If you do not wish to stop if a particular key/value is not available, or there is error reading any of these, then set this to false. If you want deeper keys you can pass the parent JSON and slice it using JSONPath and send the new one back in.

One of the common use cases that has been with the JSON produced by the driver is to “flatten” out the values and remove the array in braces from the JSON. We will try to fix this using jpath in the policies.

<rule>
<description>jsonpath</description>
<conditions>
<and>
<if-operation mode="nocase" op="equal">driver-operation-data</if-operation>
<if-xpath op="true">$current-op/request/value/text() != ""</if-xpath>
</and>
</conditions>
<actions>
<do-set-local-variable name="oldjson" scope="policy">
<arg-string>
<token-xpath expression="$current-op/request/value/text()" />
</arg-string>
</do-set-local-variable>
<do-set-local-variable name="attributes" scope="policy">
<arg-string>
<token-xpath expression="jp:readAttributes($oldjson,false)" />
</arg-string>
</do-set-local-variable>
<do-set-local-variable name="attributes" scope="policy">
<arg-node-set>
<token-split delimiter=",">
<token-local-variable name="attributes" />
</token-split>
</arg-node-set>
</do-set-local-variable>
<do-set-local-variable name="newjson" scope="policy">
<arg-string>
<token-text xml:space="preserve">{</token-text>
</arg-string>
</do-set-local-variable>
<do-for-each>
<arg-node-set>
<token-local-variable name="attributes" />
</arg-node-set>
<arg-actions>
<do-set-local-variable name="jpath" scope="policy">
<arg-string>
<token-text xml:space="preserve">$.</token-text>
<token-local-variable name="current-node" />
<token-text xml:space="preserve">[0].add[0]</token-text>
</arg-string>
</do-set-local-variable>
<do-set-local-variable name="newjsonvalue" scope="policy">
<arg-object>
<token-xpath expression="jp:read($oldjson,$jpath, false)" />
</arg-object>
</do-set-local-variable>
<do-trace-message>
<arg-string>
<token-local-variable name="newjsonvalue" />
</arg-string>
</do-trace-message>
<do-set-local-variable name="newjson" scope="policy">
<arg-string>
<token-local-variable name="newjson" />
<token-text xml:space="preserve">"</token-text>
<token-local-variable name="current-node" />
<token-text xml:space="preserve">":"</token-text>
<token-local-variable name="newjsonvalue" />
<token-text xml:space="preserve">",</token-text>
</arg-string>
</do-set-local-variable>
</arg-actions>
</do-for-each>
<do-set-local-variable name="newjson" scope="policy">
<arg-string>
<token-substring length="-2">
<token-local-variable name="newjson" />
</token-substring>
</arg-string>
</do-set-local-variable>
<do-set-local-variable name="newjson" scope="policy">
<arg-string>
<token-local-variable name="newjson" />
<token-text xml:space="preserve">}</token-text>
</arg-string>
</do-set-local-variable>
<do-strip-xpath expression="$current-op/request/value/text()" />
<do-append-xml-text expression="$current-op/request/value">
<arg-string>
<token-local-variable name="newjson" />
</arg-string>
</do-append-xml-text>
</actions>
</rule>

Now let us see what these rules do. Our initial XDS looks like:

<driver-operation-data class-name="User" command="modify" event-id="nsa1#20170825212752#1#1:6abf5e4c-34b9-4406-f58a-4c5ebf6ab934" src-dn="\PROVO\data\users\json1">
<request>
<url-token association="eAPEDMMapk76ingDxAzDGg=="/>
<header content-type="application/json"/>
<value>{"Description":[{"add":["Identity Management"]}],"Title":[{"add":["Engineer"]}],"L":[{"add":["US"]}]}</value>
</request>
</driver-operation-data>

First the condition of the rule evaluates to true indicating that this is a driver operation and contains payload. We then make use of the call to read all the attributes.

jp:readAttributes($oldjson,false)

These attributes are split using comma as delimiter and saved back as a nodeset value. We then iterate through the nodeset values picking each of them to construct our new JSON.

Action: do-for-each(arg-node-set(token-local-variable("attributes"))).
Rest Driver ST: arg-node-set(token-local-variable("attributes"))
Rest Driver ST: token-local-variable("attributes")
Rest Driver ST: Token Value: {"Description","Title","L"}.
Rest Driver ST: Arg Value: {"Description","Title","L"}.

When iterating we construct the jsonpath that we need to extract the value for each of these attributes

arg-string("$."+token-local-variable("current-node")+"[0].add[0]")

and save it in a variable called “jpath” and use it in our “read” function call sending in our old JSON in “oldjson” variable.

token-xpath("jp:read($oldjson,$jpath, false)")

In a JSONPath, “$” indicates the json root. Dot (.) moves you to the next level child attribute. A double dot (..) indicates anywhere below the current level like in xpath. Arrays can be accessed by indices passed in square braces lie [0], [1] etc. For more details on how JSONPath works, please refer to the JSONPath GitHub page “Getting Started”.

We then use the “current-node” and the “newjsonvalue” we fetched to construct our “newjson” variable that contains the json we want. Finally, after stripping out the old JSON values and appending the new one our data would look like:

<driver-operation-data class-name="User" command="modify" event-id="nsa1#20170825212752#1#1:6abf5e4c-34b9-4406-f58a-4c5ebf6ab934" src-dn="\PROVO\data\users\json1">
<request>
<url-token association="eAPEDMMapk76ingDxAzDGg=="/>
<header content-type="application/json"/>
<value>{"Description":"Identity Management","Title":"Engineer","L":"US"}</value>
</request>
</driver-operation-data>

I hope these sample policies help you to get started and implement your own scenarios using the jpath wrapper library provided. The advantage this provides is that it puts you in familiar territory of using dirxml tokens for doing most of the things. Only when you have read specific keys and values you would need to call these extension functions.

You can evaluate your JSONPath using this site before adding them to policy rules.

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...

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
By: sdhaval
Aug 28, 2017
1:38 pm
Reads:
314
Score:
Unrated
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