TDI Connector Initialisation

Tuesday, 24 January 2012
Tivoli Directory Integrator can be a great tool for quickly building routines that can move data from one repository to another. It can also be the perfect answer for building robust data synchronisation routines in the enterprise environment where the failure can be catastrophic. But let me tell you about a "gotcha".

The default initialisation sequence for a TDI Assembly Line's connectors is to initialise on Assembly Line startup. That might not sound too unreasonable but let's consider the following scenario.

Two connectors, in iterator mode, connecting to Active Directory instances are instantiated on Assembly Line startup. Connector A trundles retrieves data from its Active Directory container and passes its work entry to a myriad of other connectors and scripts which perform some logic on the data before committing it to another repository.

10 minutes later, Connector A gets to the end of its cycle and control passes to Connector B which similarly retrieves data from its Active Directory container and logic and commitment are performed.

All is well and good. Unless, of course, Connector A has a lot of data to process and more time is taken to do so.

If Connector A takes longer than 15 minutes, Connector B will keel over unceremoniously. Why? Well, it is all to do with the MaxConnIdleTime setting within Active Directory which has a default setting of 900 seconds (or 15 minutes). Microsoft's website gives an explanation for this setting as:

"The maximum time in seconds that the client can be idle before the LDAP server closes the connection. If a connection is idle for more than this time, the LDAP server returns an LDAP disconnect notification."

The TDI documentation states that when a connector in Iterator mode initializes, however, "the Prolog – Before Selection Hook is processed, and the Connector performs the entry selection; this triggers a data source specific call, like performing an SQL SELECT or an LDAP search."

So if the LDAP search was invoked at initialisation time, how can the MaxConnIdleTime have any impact on our processing? The answer, my friend, is that search requests are paged. On initialization, the LDAP search is indeed invoked, but only the first page of data is returned - 500 entries, for example. Only when Connector A has finishing iterating through its data will control pass to Connector B at which point Connector B can request the next page of data. At this point, however, the MaxConnIdleTime has been surpassed and Active Directory refuses to play ball.

To get around the problem, though, is really quite straightforward. Instead of initialising the connector when the Assembly Line starts, initialise it when it is required. Clicking on the little more button and selecting only when used for the initializate parameter as such:


Next time you write an Assembly Line, have a think about how connectors should be initialised. It might save you from a whole world of pain!

NOTE: Just because a connector in your test environment can process data inside 15 minutes, doesn't mean you will get the same result in your production environment ;-)

WebSEAL and WebSphere Portal - An Integration Pattern

Monday, 14 November 2011
Thanks to Niall, I've been encouraged to provide my thoughts on how Single Sign On from WebSEAL to WebSphere Portal can be achieved.

In reality, the integration pattern is one of the simpler patterns to adopt. I say simple, but as Niall alluded to when asking me to provide my thoughts on the issue he quite rightly stated that there are at least two approaches to the problem - the LTPA approach and the TAI approach.

Which way is the right way? It's rather like asking why do some airplanes have wings over the fuselage and others have wings under. Surely one of them is better than the other and I really don't want to find myself in a plane that has its wings in a sub-optimal position, right? (Thanks to Mr. Gunning for the analogy!)

To re-use a well-worn phrase... it's more a matter of "horses for courses"... but here is my view.

WebSphere Portal cries out for its own WebSphere instance. I wouldn't host other applications alongside Portal. Not, mind you, because you can't! But because future upgrades paths may make it more prudent to ensure that off-the-shelf applications are isolated from one another.

Given this isolation, the decision as to whether you adopt LTPA or TAI becomes a lot more simplified. Here, the path of least resistance would suggest that LTPA is the way forward. It is a well-trodden path that is well documented and requires virtually no effort on the part of the system administrators.

To give an example, a recent engagement with a client on a separate issue was enlightened when they declared an interest in SSO to their Portal. "Have you got a test environment with TAM and Portal in it?" was met with a "Yes". "Walk this way my dear friends!"

In just under 10 minutes, SSO from WebSEAL to Portal had been achieved. Jaws thumped tables! The approach? LTPA.

So, the approach:

Firstly, ensure that the Realm Name in the Federated Repositories section of the WebSphere Application Server console uses the same value as the LDAP name (including port number).

Step 1: Generate the LTPA key on the Application Server. Navigate to Security/Secure Administration/Applications & Infrastructure/Authentication Mechanisms & Expiration/Cross Cell Single Sign On!

Step 2: Enable "Use Available Authentication Data When An Unprotected URI Is Accessed" after navigating to Security/Secure Administration/Applications & Infrastructure/Web Security/General Settings. (Copy the resulting file as you need it on the WebSEAL server!)

Step 3: Copy the file generated in Step 2 to the WebSEAL server and generate some WebSEAL junctions:

   /wps
   /searchfeed
   /ibmjsfres
   /wps_semanticTag

The command for generating the junctions should include the following directives:
   -A -2 -F (file generated above) -Z (password used in Step 2)
   -x
   -j

Gotchas
When integrating WebSEAL and IBM Portal, it is necessary to understand the implications of the individual session caches that each component uses.

Portal, by default, has a 30-minute idle time-out and 2-hour session time-out on its user sessions. These values must be changed to accommodate the session times configured for WebSEAL (in that they should be slightly longer than the WebSEAL session). This recommendation helps to ensure that a consistent user experience is provided for a user. If a back-end HTTP application timed-out session data before the WebSEAL session for example, the user might experience errors from the back-end application.

In addition, a timeout.resume.session parameter can be added to automatically resume a session.

Login to the WebSphere admin console Select Resources -> Resources Environment providers -> WP ConfigService -> Custom properties. Add a new parameter as "timeout.resume.session" with value "true" as type "Boolean". Restart WebSphere Application Server.

Determine how you want the system to behave when users log out of portal. By default, when users click the Log out button in the SSO environment, they are not fully logged out of portal. Similarly, clicking the Log out button in the Portal environment does not mean that their SSO session has ended.

To accommodate a clean logout of Portal followed by a clean logout from the SSO environment, the IBM HTTP Server can be configured to perform a redirect to the WebSEAL logout page after the Portal Logout function has been requested. To achieve this, you need to edit the IBM HTTP Server configuration file to implement the post-log out behaviour. The IBM HTTP Server configuration file is called httpd.conf.

To capture requests to /ibm_security_logout and redirect them to /pkmslogout, add the following rewrite rules to the httpd.conf file:

RewriteEngine On
RewriteCond %{REQUEST_URI} /(.*)/ibm_security_logout(.*)
RewriteRule ^/(.*) /pkmslogout [noescape,L,R]

Note: You must add these rules to both the HTTP and HTTPS entries.

Ensure that the line that enables mod_rewrite is not commented out by removing the preceding # symbol. For example:

LoadModule rewrite_module modules/mod_rewrite.so

After all of that, you should have a perfectly operational WebSEAL/Portal integration.

Tivoli Directory Integrator Web Services Revisited

Monday, 17 October 2011
I really wanted to talk about two issues that have presented themselves to me recently when hacking my way around Tivoli Directory Integrator's implementation of web services functionality using the Apache Axis framework.

It has struck me, however, that the issues weren't really TDI issues at all. They were pure Axis issues that have been documented elsewhere on the web. That said, it can be difficult to find the information, and even more difficult to use the information in a TDI context. So, despite repeating what others have already found, I thought I'd share the solutions with you.

Integrated Windows Authentication
I like the idea that the WWW is fairly platform agnostic and encourages the use of open standards. But things don't always work out that way. Finding that a WSDL is being served by some Microsoft technology isn't necessarily a bad thing but when the server providing the service insists on the client using Integrated Windows Authentication to authenticate, then I start to scratch my head in a "why would someone do that" manner.

They do, though. And the Axis implementation within TDI won't perform Integrated Windows Authentication without some "tweakage".

That "tweakage" requires Axis to make use of the CommonsHTTPSender method as an HTTP transport rather than the default HTTPSender method. How did I find this out? I Googled it! Great news. Hurrah. But how do we tell Axis to make use of the CommonsHTTPSender method?

Axis 1.4 will search for a file called client-config.wsdd in the current working directory and this file contains the necessary parameters which tell Axis how to behave and more importantly, what transport to use. I figured that placing such a file somewhere in the Classpath would suffice, but I only managed to get Axis to load up the contents of my client-config.wsdd by placing it in the TDI home directory. In my case, that was:

c:\Program Files\IBM\TDI\V7.1\client-config.wsdd

And what were the contents of this file you might ask? Thankfully, I found one already on my system hidden in the bowels of the WebSphere file structure. A change of HTTPSender to CommonsHTTPSender resulted in this:

<?xml version=”1.0” encoding=”UTF-8”?>
<deployment
    name=”defaultClientConfig”
    xmlns=”http::://xml.apache.org/axis/wsdd/”
    xmlns:java=”http://xml.apache.org/axis/wsdd/providers/java”>
  <globalConfiguration>
    <parameter name=”disablePrettyXML” value=”true”/>
    <parameter name=”enableNamespacePrefixOptimization” value=”false”/>
  </globalConfiguration>
  <handler name=”WSSResponseConsumerHandler” type=”java:org.eclipse.higgins.sts.binding.axis1x.security.WSSResponseConsumerHandler”/>
  <service name=”Trust” provider=”java:RPC” style=”document user=”literal”>
    <responseFlow>
      <handler type=”WSSResponseConsumerHandler”/>
    </responseFlow>
  </service>
  <transport name=”http” pivot=”java:org.apache.axis.transpotr.http.CommonsHTTPSender”/>
  <transport name=”local” pivot=”java:org.apache.axis.transpotr.http.LocalSender”/>
  <transport name=”java” pivot=”java:org.apache.axis.transpotr.http.JavaSender”/>
</deployment>

A restart of TDI, and hey-presto! Without any further code changes, I was able to connect to my target web-service and authenticate using Integrated Windows Authentication.

Java Object Clashes
Another problem I had, however, was an issue with Complex Types. I've already spoken at length on this blog on Complex Types and how easy they are to handle and I staill maintain that this is true despite the issue I faced.

The target namespace listed in the WSDL I was pointing at had a URL style construction like such:

https://LARGECOMPANY.APPLICATION.SecurityManager/WSDL

Now, generating complex types was throwing an error within my TDI console and the root cause was the namespace above and the fact that it was attempting to create a package called LARGECOMPANY.APPLICATION.SecurityManager.

Some head-scratching and a tweak of the WSDL so that SecurityManager read securitymanager instead resulted in my complex type jar file being created successfully? Why would this be the case, you might ask? I think it may have something to do with java.lang.SecurityManager and a clash of names!

Tweaking the WSDL is fine for solving the problem, but it didn't seem like a sensible approach to me. Asking the owner of the WSDL if they would mind changing the namespace resulted in a "Computer Says No" response. (Actually this is unfair - it resulted in a perfectly valid response explaining that many other clients were using the web-services in this state!)

Looking at the TDI console and the Complex Type Generator function reveals the WSDL2Java Options attribute and a blank value! Using the -p option here got me around the problem quite nicely as such:

-p bigcorpsecurity

The -p option overrides the namespace to package mappings and ensures that Axis will use the value assigned to this option as the package name. Details on all the WSDL2Java Options can be found on the Apache Axis website and it's worth a read if you ever come unstuck attempting to use the Complex Types Generator.

Tivoli Security for Dummies

Friday, 30 September 2011
I've had the pleasure to work with a very entertaining IT consultant from the Land of Dracula recently. He's as self-deprecating as anyone I think I've ever met and constantly refers to himself as a Dummy. To be fair, he refers to himself as a Dummy when he is working with technology that is new to him - I don't for one minute believe that he is actually a Dummy!

When discussing the Tivoli security products, he would constantly over-state his Dummy credentials and ask me questions such as "How do dummies find out how to set up replication on these LDAPs?"

The standard response of reading the manual would be met by "I can't find the manual, or the manual isn't written for dummies like me. Why can't it be written in a format that dummies can understand."

On this particular issue - he's probably right. There are manuals, there are presentations, there are all sorts of documents scattered across the web but very few of them show a simple step-by-step approach to enabling replication for dummies.

"How does the dummy enable Single Sign On from WebSEAL to ITIM?" he would ask.

Again, there are plenty of documents around, but they haven't really been written for dummies and they are rarely complete!

It got me thinking... Maybe I should write a series of Dummies Guides covering some of the basics of the Tivoli Security suite of software. Of course, I'm sure the publishers of that well known series of guide books would take exception to my use of the word Dummies, so I'd need something else. Maybe "Tivoli Security for Newbies"?

Regardless of the title for the series, it seems like a worthwhile thing to-do as I'm conscious that my blog has become ever more technical as time passes with an assumption that my readers grow up alongside me. Refreshers for those readers would be useful and it may encourage the newbies to as well.

So, with that in mind, I'd like to call upon my readers to suggest topics that could be covered (taking the above two as givens for the start of the series). All topics will be considered!


Tivoli Directory Integrator Delta Processing

Friday, 19 August 2011
Tivoli Directory Integrator seems to be a favourite of mine when it comes to writing snippets of information on this blog. I can only assume that the reason for this is that it is so powerful and so capable in a wide variety of situations and that it never ceases to surprise.

It certainly surprised me last week when playing around with the Delta engine. Delta processing wasn't necessarily a new experience for me but requiring delta processing within a single Assembly Line for multiple data sources did present a challenge.

It is straightforward to write an Assembly Line and have the connection details for a connector be programmatically assigned at runtime. Take, for example, the following code:


LDAPConnector.connector.terminate();
LDAPConnector.connector.setParam("ldapSearchFilter", work.SearchFilter);
LDAPConnector.connector.setParam("ldapSearchBase", work.SearchBase);
LDAPConnector.connector.initialize(null);

This code will re-initialize my LDAPConnector using new connection parameters that I retrieve from my work entry.

However, I cannot use the same mechanism when attempting to set the Delta details! The reason was explained to me by Eddie Hartman who writes the excellent TDIing Out Loud. The Delta engine is initialised when the Assembly Line starts, not when the connector is initialised. So any attempts to programmatically set a DeltaDB parameter and re-initialise the connector is doomed to failure. (At least, this is true up to and including TDI v7.1 Fix Pack 4 though Eddie hinted that this "gap" may be "plugged" in the near future.)

So... what to do? The simple answer is to write two Assembly Lines! One of the Assembly Lines will determine the Delta DB table to be assigned (and presumably the target data source for your delta enabled connector). The other will be your main Assembly Line with the delta enabled connector.

The first Assembly Line - which I like to call the driver - would contain code like this:
java.lang.System.setProperty("deltastore", work.DeltaStore);

This would be followed by a call to the second Assembly Line which would have the Delta Store on the connector set as Advanced (Javascript) as such:

return java.lang.System.getProperty("deltastore");

Now, when my delta enabled connector starts up, a properly assigned Delta Store appropriate for the data source is assigned.

One word of warning though. The work.DeltaStore attribute used in the assignment of the Java property should NOT contain any funny characters of any shape or form. For example, if you wanted to assigned a Delta Store name which matched your data source name (which sounds like a mighty fine plan), you may find you have to translate one to the other as such:

Domino Address Book Name >>> Delta Store Name
Scotland.nsf >>> scotland
Northern-Ireland.nsf >>> northernireland