Using IBM Tivoli Directory Integrator for Identity Mapping with ISAM 9
Technical Overview
This article will describe how to utilize Tivoli Director Integrator (TDI) assembly lines to perform identity mapping operations for Federation configurations or Security Token Service (STS) chains configured in IBM Security Access Manager v9 appliance. It is particularly applicable to existing TFIM 6.2.2 customers that have TDI assembly lines for identity mapping that wish to re-use those assets with ISAM appliance federation or STS configurations.
In our former federation offering, Tivoli Federated Identity Manager (TFIM), one of the popular identity mapping capabilities for mapping rules used in either federated SSO configurations or STS chains was the use of the TDI Mapping Module. This module included specific TDI Java client code built into the product, and the configuration allowed you to point at a TDI server and select an assembly line to run on that server. Many example assembly lines were included in a TDI solutions file with TFIM, and customers and business partners have extended or modified these examples for their own identity mapping purposes.
In ISAM 9 the TDI mapping module is no longer included, however that does not mean you cannot leverage existing investments in TDI mapping rules with ISAM 9. In fact entitlement to ISAM 9 still includes entitlement to TDI v7.1.1 for integration needs. What is different however is that we don’t provide a native TDI client mapping module in the federation capabilities on the ISAM appliance. Instead, we now ship a new mapping module which allows you to perform a HTTP callout to any external service to complete identity mapping. In this article I will show you how you can configure an Assembly Line in TDI v7.1.1 which can use a HTTP Server connector to act as a listener for the new external HTTP callout mapping module in ISAM 9. You can make modifications demonstrated in this article to your existing TDI solution and use assembly lines you may have already developed with federation configurations or STS chains in ISAM 9.
We have made this decision to change the method of integration between the ISAM appliance and external services like TDI to provide looser coupling; resulting in less depedence on specific versions of products, and more flexibility in your choice of an external service for complex identity mapping tasks. For example you can now easily use TDI, or write your own external servlet to do identity mapping, or use another integration product like Datapower.
Solutions Overview
First we will revisit the way TDI was used with TFIM 6.2.2.

Some things to note about the TFIM 6.2.2 integration.
- The TDI mapping module inside of TFIM used a lot of TDI-specific Java API’s, which provided a rich configuration experience, but required TDI to be set up completely first
- As versions of TFIM or TDI changed, this tight API-level integration required constant revalidation, and was a source of several JVM-related compatibility issues.
- Communications between TFIM and TDI was using the TDI API’s, which internally used RMI technology for communications.
Now let’s take a look at the integration available in ISAM 9

Some things to note about the ISAM 9 integration.
- The HTTP Callout mapping module inside of ISAM uses plain HTTP(S) for communications, and can be configured completely independently of TDI
- Loose coupling between the ISAM appliance and TDI means no version depedencies if you need to make use of a different TDI version
- Communications between TFIM and TDI uses plain old HTTP, meaning transport-level security is well understood and easier to configure
Now let’s take a closer look at the Assembly Line isam9_https_al that is the focus of this article.

Some things to note about the isam9_https_al
- The primary job of the assembly line is to:
- Accept an XML STSUniversalUser via HTTP, and flatten it into name/value pairs in the TDI work entry – the same job that the TDI mapping module was doing in TFIM 6.2.2
- Invoke another assembly line with the work entry populated with STSUU-related attributes. This can be an existing AL from the TFIM 6.2.2 solution you already developed, as the work entry should look identical to the TFIM 6.2.2 solution at this point.
- Marshall the work entry back into an STSUU to be sent as an XML/HTTP response after your real assembly line has completed identity and attribute mapping
- This assembly line can be added into your existing TDI solutions folder, without having to alter any existing assembly line assets you may have developed.
- You can easily test your assembly lines by using cURL to send HTTP(S) requests to TDI, independent of having to stand up an ISAM appliance or TFIM software. We will demonstrate this later in the article.
- The way the assembly line will know which secondary assembly line to invoke will be the URL path sent in the request from the HTTP Callout module in ISAM. For example, if my TDI server runs on 192.168.42.142:8080, and the secondary assembly line I want to invoke (with the actual mapping logic in it) is called AssemblyLine2, then the URL configured in the HTTP Callout module will be http://192.168.42.142:8080/AssemblyLine2 Of course https can also be used with appropriate configuration.
Solutions Details
TDI Setup
TDI version and fixpack
In developing this solution I installed TDI v 7.1.1, with fixpack 5. Having the fixpack matters – there is one part of the integration that does not work without it. Installing TDI itself is routine – there is plenty of information center documentation on that. Installing the fixpack was fairly straight forward too, but for fast-tracking here’s some notes that I took when a colleague was assisting me with downloading and deploying the fixpack (on Redhat Linux):
- Take a look at the TDI users wiki for information on current fixpacks for various versions of TDI, and hyperlinks directly to the download pages for those: http://www.tdi-users.org/ At the time of writing this article, the most recent fixpack for TDI 7.1.1 was Fipack 5. Following the link and downloading the fixpack gave me a file called: 7.1.1-TIV-TDI-FP0005.zip
- Unzip the 7.1.1-TIV-TDI-FP0005.zip, and in the resulting directory are a number of files. The only files I needed for the components of TDI I was using were TDI-7.1.1-FP0005.zip and UpdateInstaller.jar.
- Ensure the TDI (including the developer IDE) is not running
- Copy TDI-7.1.1-FP0005.zip to /opt/IBM/TDI/V7.1.1
- Copy UpdateInstall.jar to /opt/IBM/TDI/V7.1.1/maintenance (overwrite existing file)
- cd to /opt/IBM/TDI/V7.1.1 and from the command line, as root, run: bin/applyUpdates.sh -update TDI-7.1.1-FP0005.zip
- The FP should install (takes a few minutes), and you’re done
You should follow the rest of the advice in fixpack installation, including the recommended JRE 6 updates, but I found I did not need that purely for the purposes of preparing this solution.
Adding the stsuu.jar custom jar
As part of developing this solution I wrote some Java code which handles the XML parsing related to converting the STSUniversalUser to and from a set of attributes to be included in the work entry. This custom jar is called stsuu.jar includes all source code. You can import it into a standard Java eclipse development environment. The only thing to be careful about is that if you recompile the jar, you must use Java 1.6 compatibility mode as that is the JVM version used by TDI v7.1.1.
This jar needs to be available to the TDI class path. I recommend you copy it to /opt/IBM/TDI/V7.1.1/jars/3rdparty/others
There are other locations you can put custom jars, such as in your own nominated directory and then update the location in solutions.properties (see property com.ibm.di.loader.userjars) – the choice is yours. Just make sure that stsuu.jar is in the TDI classpath or you will get ClassNotFound errors at runtime.
Creating and configuring the isam9_https_al Assembly Line
This section will take you step-by-step through creating the isam9_https_al
In the IDE, create a new assembly line called isam9_https_al, and add a HTTPServerConnection as a feed:

Press Next, then configure the HTTP port (8080 in my example) and content-type (application/xml). If you want https, configure that in the Advanced section as shown, but I’m not covering that detail in this article:

Press Finish. There is no need to configure a parser for this use case. When you return to the Assembly Line Editor, set the Input Map as shown and described below:

The ALTarget Input Map property is initialized with the following Javascript, which extracts the target secondary assembly line name from the URL path of the inbound HTTP request:
// Use the URL path to decide which AssemblyLine to run after flattening the STSUU
conn["http.url"].getValue().replaceFirst("/","")
The http.bodyAsString Input Map property is initialized with the following Javascript, which extracts the HTTP body (i.e. the XML of the STSUniversalUser) from the inbound request:
// Use the HTTP body string
conn["http.bodyAsString"]
In the Output Map, drag across the http.body, http.content-type and http.status properties, as shown:

This completes configuration of the HTTP Server Connector. We will now add a script connector to the Data Flow to handle the flattening of the XML STSUniversalUser into work entry attributes
Add an empty script connector called PopulateWorkFromHTTPRequest, and set it’s contents to the script shown below:

importPackage(Packages.com.ibm.demo.stsuu);
var body = work.getAttribute('http.bodyAsString').getValue();
//main.logmsg("body: " + body);
var d = XMLUtil.parse(body);
var stsuu = new STSUniversalUser();
stsuu.fromXML(d.getDocumentElement());
//main.logmsg("stsuu: " + stsuu.toClearTextString());
//
// Set work entry attributes from flattened STSUU map
//
var helper = new STSUUTDIHelper();
var attrMap = helper.stsuuToAttributes(stsuu);
for (var i = attrMap.keySet().iterator(); i.hasNext(); ) {
var attrName = i.next();
var attrValues = attrMap.get(attrName);
if (attrValues.length > 0) {
for (var j = 0; j < attrValues.length; j++) {
work.addAttributeValue(attrName, attrValues[j]);
}
}
}
Notice there are some commented-out trace commands in the script – you can uncomment these if you need to debug what the script is doing later
Add an Assembly Line Functional Component to the Data Flow called SecondaryAssemblyLine and press Next.

There are a number of specialized configurations we need to perform to this component. On the connector configuration panel, scroll to the right and press the little pencil on the Assembly Line/Sequence setting, as shown:

Change the evaluation method to Advanced (Javascript) and provide the Javascript shown below:

The javascript is simple:
return work.getString("ALTarget")
This allows us to decide which secondary assembly line will be invoked at runtime, based on the URL path provided in the incoming HTTP request. This means we don’t have to configure more than one HTTP listener for the set of assembly lines we want our solution to support. Simply change the URL being called! If you were only ever going to point at one secondary assembly line, this would not be necessary, and you could statically configure the secondary assembly line to call.
When you press Finish after adding this Javascript, you will see an error about Unknown member ‘contains’ in Java class ‘java.lang.Exception’. Ignore this error. It only occurs in the IDE during script validation, which is not the same context as will be available at runtime.
Once you have returned to the main assembly line editor, press the More… button for the SecondaryAssemblyLine as shown:

Change the Initialize configuration to be Initialize and terminate every time it is used. This is what allows the assembly line to call different target secondary assembly lines on each invocation. If you were only ever going to point at one secondary assembly line, this also would not be necessary.

Still on the SecondaryAssemblyLine component, change BOTH the Input Map and Output Map to map ALL attributes, as shown:


Finally, back in the Data Flow for the isam9_https_al, add another empty script connector called PopulateHTTPResponseFromWork, and set it’s contents to the script shown below:

importPackage(Packages.com.ibm.demo.stsuu);
// Optional - clear RST attributes for brevity in response
//work.removeAttribute("STSUU.RequestSecurityToken.AttributeNames");
// Find all attributes starting with STSUU. and add them to a map of String -> String[]
var attrMap = new Packages.java.util.HashMap();
var attrnames = work.getAttributeNames();
if (attrnames != null) {
for (i = 0; i < attrnames.length; i++) {
if (attrnames[i].startsWith("STSUU.")) {
var attr = work.getAttribute(attrnames[i]);
attrMap.put(attrnames[i], attr.getValues());
}
}
}
// build the final STSUU and return it as http response
var helper = new STSUUTDIHelper();
var stsuu = helper.attributesToSTSUU(attrMap);
work.setAttribute('http.content-type', 'text/xml');
work.setAttribute('http.status', '200');
work.setAttribute('http.body', stsuu.toClearTextString());
That completes the configuration of the isam9_https_al. Let’s create the secondary Assembly Line that it will call, so that we can then try it out.
Creating and configuring the add_demo_attribute secondary Assembly Line
This section will take you step-by-step through creating a secondary assembly line for demonstration purposes. This assembly line will add an extra attribute to the AttributeList of the STSUniversalUser
In the IDE, create a new assembly line called add_demo_attribute, and add an Attribute Map as the one and only connector in the data flow:

In the Attribute Map, add three attributes, with name and Javascript content as shown below:

The attributes and their corresponding Javascript content is:
Attribute Name |
Javascript content |
STSUU.AttributeList.Attribute.demoattr.values |
var attrName = "STSUU.AttributeList.Attribute.demoattr.values";
work.setAttribute(attrName, "demovalue");
ret.value = work.getAttribute(attrName);
|
STSUU.AttributeList.Attribute.demoattr.type |
var attrName = "STSUU.AttributeList.Attribute.demoattr.type";
work.setAttribute(attrName, "urn:mytype");
ret.value = work.getAttribute(attrName);
|
STSUU.AttributeList.AttributeNames |
var attrName = "STSUU.AttributeList.AttributeNames";
work.addAttributeValue(attrName, "demoattr");
ret.value = work.getAttribute(attrName);
|
This concludes the configuration of the add_demo_attribute secondary chain – we are now ready to test it out using curl to send an XML STSUniversalUser to the running isam9_https_al assembly line.
Testing with cURL
For testing purposes, we will run the isam9_https_al assembly line from the IDE. You can research alternative ways of starting up a TDI server in the product doc.
In the IDE, switch back to the isam9_https_al assembly line and press Run in console as shown:

This will start the AL, and you should see console output indicating there is a process listening on port 8080. In my case, the TDI system has an IP address of 192.168.42.142. I can now use the cURL command line tool to send a test STSUU to the AL via HTTP. The stsuu_in.xml is available for download, but is reproduced here because it’s very simple.
The stsuu_in.xml file
<?xml version="1.0" encoding="UTF-8"?>
<stsuuser:STSUniversalUser xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser">
<stsuuser:Principal>
<stsuuser:Attribute name="name" type="urn:sometype">
<stsuuser:Value>john</stsuuser:Value>
</stsuuser:Attribute>
</stsuuser:Principal>
<stsuuser:AttributeList>
<stsuuser:Attribute name="firstName">
<stsuuser:Value>john</stsuuser:Value>
</stsuuser:Attribute>
<stsuuser:Attribute name="lastName">
<stsuuser:Value>smith</stsuuser:Value>
</stsuuser:Attribute>
<stsuuser:Attribute name="phone">
<stsuuser:Value>123456</stsuuser:Value>
</stsuuser:Attribute>
</stsuuser:AttributeList>
</stsuuser:STSUniversalUser>
Testing with cURL
Note carefully in the curl command below that the URL path is /add_demo_attribute. Minus the leading slash, this is the assembly line name of the secondary assembly line that we want the primary assembly line to call after the XML version of the STSUU is flattened into work entry attributes.
$
curl -d @stsuu_in.xml http://192.168.42.142:8080/add_demo_attribute
<stsuuser:STSUniversalUser xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser"><stsuuser:Principal><stsuuser:Attribute name="name" type="urn:sometype"><stsuuser:Value>john</stsuuser:Value></stsuuser:Attribute></stsuuser:Principal><stsuuser:AttributeList><stsuuser:Attribute name="firstName"><stsuuser:Value>john</stsuuser:Value></stsuuser:Attribute><stsuuser:Attribute name="lastName"><stsuuser:Value>smith</stsuuser:Value></stsuuser:Attribute><stsuuser:Attribute name="phone"><stsuuser:Value>123456</stsuuser:Value></stsuuser:Attribute><stsuuser:Attribute name="demoattr" type="urn:mytype"><stsuuser:Value>demovalue</stsuuser:Value></stsuuser:Attribute></stsuuser:AttributeList></stsuuser:STSUniversalUser>
If you pipe the output to xmllint, then you get a nicely formatted output. Notice the additional attribute now in the STSUU:
curl -d @stsuu_in.xml http://192.168.42.142:8080/add_demo_attribute | xmllint --format -
<?xml version="1.0"?>
<stsuuser:STSUniversalUser xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser">
<stsuuser:Principal>
<stsuuser:Attribute name="name" type="urn:sometype">
<stsuuser:Value>john</stsuuser:Value>
</stsuuser:Attribute>
</stsuuser:Principal>
<stsuuser:AttributeList>
<stsuuser:Attribute name="firstName">
<stsuuser:Value>john</stsuuser:Value>
</stsuuser:Attribute>
<stsuuser:Attribute name="lastName">
<stsuuser:Value>smith</stsuuser:Value>
</stsuuser:Attribute>
<stsuuser:Attribute name="phone">
<stsuuser:Value>123456</stsuuser:Value>
</stsuuser:Attribute>
<stsuuser:Attribute name="demoattr" type="urn:mytype">
<stsuuser:Value>demovalue</stsuuser:Value>
</stsuuser:Attribute>
</stsuuser:AttributeList>
</stsuuser:STSUniversalUser>
We have now made great progress – we have configured the HTTP listener in TDI, and independently tested with curl that we can send an XML STSUniveralUser to the assembly line, have it call a secondary assembly line, and return the new XML STSUniversalUser as a response. Let’s now take a look at the configuration of the HTTP Callout STS module in ISAM 9, with the goal of building an end-to-end test flow through a simple STS chain in ISAM 9.
Configuration of the HTTP Callout STS module in ISAM appliance and testing end-to-end
For the purposes of this exercise, I am going to make an assumption that the reader is generally familiar with the ISAM STS, and how to configure a simple STS chain in ISAM 9. I have configured a simple STS template and chain in the ISAM 9 appliance which matches the following logical diagram:

The configuration of the HTTP Callout STS module uses HTTP, points to the http://192.168.42.142:8080/add_demo_attribute URL that we used with cURL earlier, and specifies to send the STSUU in XML format, as shown:

We can now use a WS-Trust request to the ISAM STS, very much following the same pattern as described in my previous article on Using Curl to send WS-Trust Requests
curl -k -H "Content-Type: application/xml" -d @rst.xml https://www.myidp.ibm.com/isam/TrustServer/SecurityTokenService
The rst.xml used in the above example is available for download, but reproduced here for completeness.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header/>
<soapenv:Body>
<wst:RequestSecurityToken>
<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Validate</wst:RequestType>
<wst:Issuer>
<wsa:Address>http://issuer/stsuu</wsa:Address>
</wst:Issuer>
<wsp:AppliesTo>
<wsa:EndpointReference>
<wsa:Address>http://appliesto/stsuu</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wst:Base>
<stsuuser:STSUniversalUser xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser">
<stsuuser:Principal>
<stsuuser:Attribute name="name" type="urn:sometype">
<stsuuser:Value>john</stsuuser:Value>
</stsuuser:Attribute>
</stsuuser:Principal>
<stsuuser:AttributeList>
<stsuuser:Attribute name="firstName">
<stsuuser:Value>john</stsuuser:Value>
</stsuuser:Attribute>
<stsuuser:Attribute name="lastName">
<stsuuser:Value>smith</stsuuser:Value>
</stsuuser:Attribute>
<stsuuser:Attribute name="phone">
<stsuuser:Value>123456</stsuuser:Value>
</stsuuser:Attribute>
</stsuuser:AttributeList>
</stsuuser:STSUniversalUser>
</wst:Base>
</wst:RequestSecurityToken>
</soapenv:Body>
</soapenv:Envelope>
A successful invocation of the WS-Trust request will result in a RequestSecurityTokenResponse that contains the same RequestedSecurityToken as seen above in the direct curl tests against TDI.
Summary and Downloads
The following files are available for download as part of this solution. As is usual with my articles, these come with no guarantees, but source is included where appropriate.
- stsuu.jar – Utility classes (including source code) used by script connectors in the isam9_https_al
- stsuu_in.xml – XML STSUniversalUser file used to POST directly to TDI for testing
- rst.xml – Sample ws-trust 1.2 RequestSecurityToken message used for testing the HTTP Callout STS module in an STS chain in the ISAM 9 appliance.
I hope that the information provided in this article is of immediate use to IBM Security practitioners working with TFIM and the new ISAM 9 appliance with federation and STS capabilities. If you have TFIM 6.2.2 today and already make use of TDI for identity and attribute mapping, this guide should get you enabled on ISAM 9. As always, please reach out if you have any feedback or issues by commenting on the article.