Application Delivery Management
Application Modernization & Connectivity
CyberRes by OpenText
IT Operations Management
In Identity Manager 4.7 there is a new driver available. You can find it in Designer palette under Service, it's called Identity Gateway Integration Module (IGIM).
Sadly I couldn't find any documentation about it but I decided to try it out and see how far I got.
During the package installation it asks you several questions and from those question we can understand that it's a HTTP based driver, i.e. that it will respond on the port we select (default 7708).
Here are some screenshots from Designer during the set up phase.
Still we don't know what it will do.
After deploying the driver and starting it I checked out the trace logs.
In the trace we can see that this is a driver offering REST services:
Identity Gateway Integration Module PT:Identity Gateway Integration Module: IGRestServer: Initializing REST server servlet handlers.
Identity Gateway Integration Module PT:Identity Gateway Integration Module: IGRestServer: Done starting REST Server.
So now we know that the IGIM driver contains a HTTP server.
Let's try to access it and see what happens.
We will use curl and Soap UI during this experiment.
curl https://192.168.0.6:7708/ -v
This returns:
HTTP/1.1 401 Unauthorized
Ok, so we need some form of authentication. During the driver setup we didn't set any username and password.
Let's try with the admin user:
curl -u cn=admin,o=system:password https://192.168.0.6:7708/ -v
No luck:
HTTP/1.1 401 Unauthorized
At this point the only thing I could think of was the securityEquals identity, in my case I use a organizational role for that so I tried to change the securityEquals on the driver to point to the admin user instead.
New attempt:
curl -u cn=admin,o=system:password https://192.168.0.6:7708/ -v
HTTP/1.1 404 Not Found
Ok, now we are making progress, we are authenticated but there is nothing there.
Now we know that we need to call the driver with a basic authentication header that is the same as the user set in the securityEquals attribute and that the username needs to be in LDAP format.
We also know that we are dealing with a REST server so let's try to send an OPTION request and see what happens.
curl -X OPTION -u cn=admin,o=system:password https://192.168.0.6:7708/ -v
Nothing... HTTP/1.1 404 Not Found
Now we have a REST service but I don't know how to access it, time to search the web for tips.
This got me to a question on StackOverflow which had an interesting answer that was worth a try, it said that some webapps publish a WADL (Web Application Description Language) at the application root URL /application.wadl.
https://stackoverflow.com/questions/28993724/is-there-a-way-to-discover-all-endpoints-of-a-rest-api
This was in regards to a Java technology, JAX-RS, and since IDM is Java based it was worth a try.
curl -X GET -u cn=admin,o=system:password https://192.168.0.6:7708/application.wadl -v
What would you know, it worked!
I got back a WADL XML describing the REST API!
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://wadl.dev.java.net/2009/02">
<doc xmlns:jersey="http://jersey.java.net/" jersey:generatedBy="Jersey: 1.18 11/22/2013 03:05 AM"/>
<grammars>
<include href="application.wadl/xsd0.xsd">
<doc title="Generated" xml:lang="en"/>
</include>
</grammars>
<resources base="https://192.168.0.6:7708/">
<resource path="/idv/driver">
<resource path="/filter">
<method id="getDriverFilter" name="GET">
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
<resource path="/filter/{objClass}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="objClass" style="template" type="xs:string"/>
<method id="getDriverFilter" name="GET">
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
<resource path="/restart">
<method id="restartDriver" name="PUT">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="Authorization" style="header" type="xs:string"/>
<ns2:representation xmlns:ns2="http://wadl.dev.java.net/2009/02" xmlns="" element="restartParam" mediaType="*/*"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
</resource>
<resource path="/idv/events">
<method id="deleteEvents" name="DELETE">
<response>
<representation mediaType="application/json"/>
</response>
</method>
<resource path="/{channelId}/{pageId}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="pageId" style="template" type="xs:string"/>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="channelId" style="template" type="xs:string"/>
<method id="deleteEvents" name="DELETE">
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
<resource path="/{channelId}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="channelId" style="template" type="xs:string"/>
<method id="deleteEvents" name="DELETE">
<response>
<representation mediaType="application/json"/>
</response>
</method>
<method id="getEvents" name="GET">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="pageSize" style="query" type="xs:int"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
</resource>
<resource path="/idv/driver/consumer">
<method id="getConsumers" name="GET">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="consumerName" style="query" type="xs:string"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
<method id="registerConsumerFilter" name="POST">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="Authorization" style="header" type="xs:string"/>
<ns2:representation xmlns:ns2="http://wadl.dev.java.net/2009/02" xmlns="" element="setConsumer" mediaType="*/*"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
<method id="updateConsumerFilter" name="PUT">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="Authorization" style="header" type="xs:string"/>
<ns2:representation xmlns:ns2="http://wadl.dev.java.net/2009/02" xmlns="" element="setConsumer" mediaType="*/*"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
<resource path="/{consumerId}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="consumerId" style="template" type="xs:string"/>
<method id="deleteConsumerFilter" name="DELETE">
<response>
<representation mediaType="application/json"/>
</response>
</method>
<method id="getConsumerFilter" name="GET">
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>
Let's explore the API and see what it does.
My first try was the /idv/driver/filter endpoint:
curl -X GET -u cn=admin,o=system:password https://192.168.0.6:7708/idv/driver/filter -H "Accepts: application/json"
It returned just an empty JSON structure:
{}
Checking the driver filter in Designer I could that see that there was only a DirXML-Driver class and DirXML-DriverFilter attribute there.
Let's manually edit the driver filter using Designer and try again after changing the filter to this:
<filter-class class-name="User" publisher="ignore" publisher-create-homedir="true" publisher-track-template-member="true" subscriber="sync">
<filter-attr attr-name="Given Name" merge-authority="default" publisher="ignore" publisher-optimize-modify="true" subscriber="sync"/>
</filter-class>
The driver returns this:
{"objectClasses": {
"className": "user",
"attributes": [
"Given Name",
"GUID"
]
}}
Let's move on, we can see that we can do a PUT against /idv/driver/restart which should restart the driver.
In the WADL we can see that a JSON payload containing restartParam is needed - what the value should be is not clear.
I tried with the string "test" and because this was on Windows I had to escape all the quote characters:
curl -X PUT -d ""{\"restartParam\":\"test\"}"" -u cn=admin,o=system:password https://192.168.0.6:7708/idv/driver/restart -H "Accepts: application/json" -H "Content-Type: application/json" -v
This resulted in the following response:
{"submitted":true}
Looking at the driver trace file I could see that the driver was being restarted:
Identity Gateway Integration Module: DriverRestarter: Restarting driver....
Identity Gateway Integration Module: LdapAuthHandler: Submitting driver restart request to server - 192.168.0.6:636
Next I wanted to see what happens if I modify an object in the identity vault.
After restarting the driver I changed the Given Name attribute on a User, resulting in this driver trace:
[07/06/18 14:31:16.612]:Identity Gateway Integration Module ST:
<nds dtdversion="4.0" ndsversion="8.x">
<source>
<product edition="Advanced" version="4.7.0.0">DirXML</product>
<contact>NetIQ Corporation</contact>
</source>
<input>
<modify cached-time="20180706123116.375Z" class-name="User" event-id="idmdev#20180706123116#1#1:565d2bc4-3599-4220-9be4-c42b5d569935" qualified-src-dn="O=Meta\OU=Users\OU=POC\CN=HeAb1" src-dn="\IDMDEV\Meta\Users\POC\HeAb1" src-entry-id="1560632" timestamp="1530880276#2">
<association>dPX8dTx7XE67onT1/HU8ew==</association>
<modify-attr attr-name="Given Name">
<remove-value>
<value timestamp="1530880063#2" type="string">Henningmm</value>
</remove-value>
<add-value>
<value timestamp="1530880276#2" type="string">Henning</value>
</add-value>
</modify-attr>
</modify>
</input>
</nds>
[07/06/18 14:31:16.625]:Identity Gateway Integration Module ST:Identity Gateway Integration Module: XDSCommandHandler: EventJson:
{"eventType":"modify","objectClass":"User","srcDn":"CN=HeAb1,OU=POC,OU=Users,O=Meta","cachedTime":"20180706123116.375Z","association":"dPX8dTx7XE67onT1\/HU8ew==","attributes":{"Given Name":{"removeValue":["Henningmm"],"addValue":["Henning"]}}}
[07/06/18 14:31:16.627]:Identity Gateway Integration Module ST:Identity Gateway Integration Module: EventDistributor: Getting consumers of class 'user'
[07/06/18 14:31:16.630]:Identity Gateway Integration Module ST:SubscriptionShim.execute() returned:
[07/06/18 14:31:16.632]:Identity Gateway Integration Module ST:
<nds dtdversion="3.0">
<source>
<product build="20180222_0511" instance="Identity Gateway Integration Module" version="1.0.0.0">Identity Gateway Integration Module</product>
<contact>NetIQ Corporation</contact>
</source>
<output>
<status event-id="idmdev#20180706123116#1#1:565d2bc4-3599-4220-9be4-c42b5d569935" level="error" type="driver-general">
<exception class-name="java.lang.NullPointerException">
<stack-trace>java.lang.NullPointerException
at com.netiq.idm.driver.igdriver.eventhandler.EventDistributor.distributeEvent(EventDistributor.java:54)
at com.netiq.idm.driver.igdriver.eventhandler.XDSCommandHandler.persistEvent(XDSCommandHandler.java:132)
at com.netiq.idm.driver.igdriver.eventhandler.XDSModifyHandler.execute(XDSModifyHandler.java:32)
at com.netiq.idm.driver.igdriver.eventhandler.XDSCommandHandler.executeCommand(XDSCommandHandler.java:86)
at com.netiq.idm.driver.igdriver.IGSubscriptionShim.execute(IGSubscriptionShim.java:179)
at com.novell.nds.dirxml.engine.Subscriber.execute(Subscriber.java:473)
at com.novell.nds.dirxml.engine.Subscriber.execute(Subscriber.java:304)
at com.novell.nds.dirxml.engine.Subscriber$ModifyProcessor.process(Subscriber.java:1760)
at com.novell.nds.dirxml.engine.Subscriber.processEvent(Subscriber.java:1197)
at com.novell.nds.dirxml.engine.Subscriber.processEvents(Subscriber.java:1010)
at com.novell.nds.dirxml.engine.Driver.submitTransaction(Driver.java:901)
at com.novell.nds.dirxml.engine.DriverEntry.submitTransaction(DriverEntry.java:1174)
at com.novell.nds.dirxml.engine.DriverEntry.processCachedTransaction(DriverEntry.java:1058)
at com.novell.nds.dirxml.engine.DriverEntry.eventLoop(DriverEntry.java:866)
at com.novell.nds.dirxml.engine.DriverEntry.run(DriverEntry.java:640)
at java.lang.Thread.run(Thread.java:748)
</stack-trace>
</exception>
</status>
</output>
</nds>
From the trace we can see that the IDM XML is converted to JSON format and afterwards that the driver is looking for a consumer: EventDistributor: Getting consumers of class 'user'
This causes an exception since we have no consumers.
A qualified guess based on the information in the WADL is that we should issue the request with a JSON payload containing "consumer", I tested with this: {"consumer":"MyApp"}
This time I used SoapUI and got this response:
HTTP/1.1 200 OK
Date: Fri, 06 Jul 2018 21:35:14 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Server: Jetty(9.4.z-SNAPSHOT)
{"consumerId":"111889b6-fb18-4376-9617-1eaf0f0c075c"}
Doing a GET using curl we get this result:
curl -X GET -u cn=admin,o=system:password https://192.168.0.6:7708/idv/driver/consumer -H "Accepts: application/json" -H "Content-Type: application/json" -v
{"consumers":[{"consumerId":"111889b6-fb18-4376-9617-1eaf0f0c075c"}]}
For some reason adding a consumer reset the driver filter and deleted the changes I've made using Designer.
From my experiments I can deduce that this is some kind of "change log" driver where you can register for events in IDM using REST and then retrieve those events.
Unfortunately I could not figure out how to set the filter for my consumer using the updateConsumerFilter method, i.e. what the payload sent with the request should be.
I would expect some form of official documentation sooner or later that contains more information on how to use this driver.
It would be interesting to know if this driver comes out of the box with IDM with regards to licensing or if the customers need to purchase it. I could think of several interesting use cases if it's included with the standard subscription and if we get good documentation.