Wednesday, October 27, 2010

ITIM Spooky Password Behaviour

TIM and TAM experts will already be aware of how to provision TAM accounts from TIM and you will probably already be aware of how to provision GSO credentials from TAM to TIM. If so, this article may bore you but I did come across some rather odd behaviour that I wasn't really expecting.

In my provisioning policy for my TAM account, I was attempting to set my GSO credentials using Javascript and for some reason I decided to use the ersynchpassword attribute.

All was well when creating TAM accounts for existing PERSON objects in TIM. However, when I created a new PERSON object, I was presented with a failure in the provisioning of my TAM account:

CTGIMA617E The account {account} cannot be created either because the account is disallowed for the user or one or more attributes are not compliant with provisioning policy.
Odd. Because when I manually requested the account to be created... it appeared without fuss.

My suspicions were that the ersynchpassword was not "available" at provisioning time so I dropped the following code into the provisioning policy:

Enrole.log("SSO", "uid is " + subject.getProperty("uid")[0]);
Enrole.log("SSO", "ersynchpassword is " + subject.getProperty("ersynchpassword"));
Enrole.log("SSO", "personpassword is " + subject.getAndDecryptPersonPassword());

The result wasn't terribly surprising in that ersynchpassword was null or empty. At least, that's what it seemed like at first glance when I noticed the following log messages:

Error: uid is account01
Error: ersynchpassword is
Error: personpassword is passw0rd

The real surprise, however, came when I read on through the log. Within milliseconds of the above messages, the following messages were presented:

Error: uid is account01
Error: ersynchpassword is passw0rd
Error: personpassword is passw0rd

CTGIMA617E The account account01 cannot be created either because the account is disallowed for the user or one or more attributes are not compliant with provisioning policy.

So what do I make of this?

Well, it's best to use the getAndDecryptPersonPassword() method within this particular provisioning policy, that's for sure. But ONLY on account creation. Password changes need to be evaluated using the ersynchpassword. Luckily, there is a catch-all:

if (subject.getProperty("ersynchpassword")[0] == null) {
    return "sapGSO (Web Resource)"
        + "|" + subject.getProperty("uid")[0]
        + "|{clear}" + subject.getAndDecryptPersonPassword();
} else {
    return "sapGSO (Web Resource)"
        + "|" + subject.getProperty("uid")[0]
        + "|{clear}" + subject.getProperty("ersynchpassword")[0];

There are still some questions left unanswered here, though. Why was the policy evaluated TWICE and why did the first failure drive the CTGIMA617E message (rather than the second successful evaluation). Maybe someone in the land of the development team can explain it. And also explain why the ersynchpassword didn't manage to appear until the second evaluation just a 100 milliseconds after the first evaluation.

Then again... maybe it's because it is almost Halloween and it's the time of year for strangeness!

The above scenario was produced using ITIM v5.1 (Fix Pack 1) running on WebSphere 6.1 on a Windows 2003 Server. I'm quite sure I've used ersynchpassword in the past on ITIM v5.0 instances and did not see this behaviour!

Tuesday, October 12, 2010

MASSL Between WebSEAL And Apache On Windows

Every now and again I get faced with Windows infrastructure. As I've previously stated on this blog, I'm not "religious" about my Operating Systems but Windows does present one or two slightly different challenges and SSL enabling Apache (though very easy) does have a gotcha!

Here's how to generate the certificates necessary to create a Mutually Authenticated SSL junction between a WebSEAL and an Apache instance on Windows.

Let's assume that Apache (v2.2) has been installed at c:\Apache2.2 and that OpenSSL (v1.0.0a) has been installed at c:\openssl-win32 using the Win32 binary installer.

Setting Up The Environment
The environment setup for OpenSSL requires some directories to be created:

cd c:\openssl-win32\bin
mkdir TAM
mkdir TAM\keys
mkdir TAM\requests
mkdir TAM\certificates
mkdir TAM\newcerts
> TAM\index.txt
echo "01" > TAM\serial

The openssl.cfg file should be updated so that the "dir" directive within the CA_default stanza reads:

dir = ./TAM 

Within the req_distinguished_name stanza, add the following:

stateOrProvinceName_default = xx

xx can be set to anything you want, but it is important that a stateOrProvinceName is provided during certificate generation.

Creating a Certificate Authority
openssl genrsa -out TAM\cacert.key 1024
openssl req -new -key TAM\cacert.key -out TAM\cacert.csr
openssl x509 -req -days 365 -in TAM\cacert.csr -out TAM\cacert.crt -signkey TAM\cacert.key
openssl x509 -in TAM\cacert.crt -text

That was painless, wasn't it? We now have a certificate authority which can be used for the signing of other certificates. Our next step is to create certificates for the Apache and WebSEAL instances. Note, we have no need for Apache or WebSEAL to generate the certificate requests, we can do that with OpenSSL:

Create Apache Certificate
This is a four step process which involves the generation of a key, a request, a certificate and a conversion of the key to unencrypted format because Apache on Windows "hissy-fits" when attempting to use an encrypted key.

openssl genrsa -des3 -out TAM\keys\apache.key 1024
openssl req -new -key TAM\keys\apache.key -out TAM\requests\apache.csr
openssl ca -days 365 -in TAM\requests\apache.csr -cert TAM\cacert.crt -keyfile TAM\cacert.key -out TAM\certificates\apache.crt -config openssl.cfg
openssl rsa -in TAM\keys\apache.key -out TAM\keys\apache_unenc.key

We can now move these certificates to the correct location:

mkdir c:\Apache2.2\certs
copy TAM\cacert.crt c:\Apache2.2\certs\cacert.pem
copy TAM\certificates\apache.crt c:\Apache2.2\certs\apache.crt
copy TAM\keys\apache_unenc.key c:\Apache2.2\certs\apache.key

Configuring Apache
The c:\Apache2.2\conf\httpd.conf file should have the handful of references to SSL uncommented:
LoadModule ssl_module modules/
Include conf/extra/httpd-ssl.conf

The c:\Apache2.2\conf\extras\httpd-ssl.conf should be updated as such:
  • Update SSLCertificateFile to point at c:\Apache2.2\certs\apache.crt
  • Update SSLCertificateKeyFile to point at c:\Apache2.2\certs\apache.keyUpdate
  • SSLCACertificateFile to point at c:\Apache2.2\certs\cacert.pem
Apache can now be restarted.

Create WebSEAL Certificate
The generation of the key, request and certificate for WebSEAL is also a four step process though the final step isn't the conversion of the key to unencrypted format but rather the generation of a #PKCS12 format certificate:

openssl genrsa -des3 -out TAM\keys\webseald.key 1024
openssl req -new -key TAM\keys\webseald.key -out TAM\requests\webseald.csr
openssl ca -days 365 -in TAM\requests\webseald.csr -cert TAM\cacert.crt -keyfile TAM\cacert.key -out TAM\certificates\webseald.crt -config openssl.cfg
openssl pkcs12 -export -clcerts -in TAM\certificates\webseald.crt -inkey TAM\keys\webseald.key -out TAM\certificates\webseald.p12

Importing the webseald.p12 file into the pdsrv.kdb keystore can be tricky unless your Java Policy Files allow the level of encryption that will have been applied to the p12. So, update the Java Policy Files on the WebSEAL by visiting Download the Policy Files for Java 1.4.2 or above and copy the two policy files to {java_home}/jre/lib/security

The #PKCS12 file can now be imported with the following commands:

java -cp {gsk7_location}/classes/gsk7cls.jar;{gsk7_location}/classes/ -cert -add -file cacert.pem -format ascii -db pdsrv.kdb -pw pdsrv -type cms -label TAMCA -trust enable

java -cp {gsk7_location}/classes/gsk7cls.jar;{gsk7_location}/classes/ -cert -import -file webseald.p12 -type pkcs12 -target pdsrv.kdb -target_pw pdsrv -target_type cms -pw {p12 password}

You should now determine the label that has been assigned to the certificate:

java -cp {gsk7_location}/classes/gsk7cls.jar;{gsk7_location}/classess/ -cert -list -db pdsrv.kdb -pw pdsrv -type cms

The label will look like something like this: "2cn=webseald, o=x,st=x,c=x, etc"

Create a WebSEAL Junction
The WebSEAL junction can now be created with the -K option (plus the above label) which should result in a "Created junction" message with no other warnings.

Notes & Observations
The certificates used to created a MASSL connection between WebSEAL and Apache won't ever be seen by any client - remember, WebSEAL acts as the client to the Apache server. As such, there is no strong need for these certificates to be generated by the likes of a Verisign. There is no need for these certificates to make any reference to the actual host names at all - the names Apache and WebSEAL seem like good names to me for the Common Name of the certificate. In reality, using the above method for generating the certificates is as good than any other (if not better as it has been tried and tested).

Friday, October 08, 2010

Securing Lotus Connections With WebSEAL

There are a few documents on the web that try to explain how to integrate Lotus Connections with WebSEAL and they do actually work to a certain extent. However, there are holes in their explanations that prevent the full rich experience of a Lotus Connections environment when fronted with a WebSEAL.

Here's how to "plug" those holes for a Lotus Connections v2.5 and Tivoli Access Manager v6.1 infrastructure.

Firstly... I should point out that the integration guide written by En Hui Chen is excellent and was used as the basis for this guide. His guide can be found at

Lotus Connections Data Flow
To understand why WebSEAL and Connections should be configured the way they are, it is important to understand how the components communicate with and through each other. Fundamentally, a user's experience with Connections is not constrained to the HTTP traffic bouncing between a browser and (ultimately) the Connections applications. Instead, we need to be mindful of Ajax components being rather chatty with the back end as well as inter-service communications across Connections applications. When we introduce WebSEAL, we need to ensure that the traffic is being routed appropriately as such:

The Holes

Hole 1
The connectionsAdmin account must be an account known to TAM. The following pdadmin commands should therefore be called to ensure that the account is imported correctly and valid:

pdadmin> user import connectionsAdmin {connectionsAdmin dn}
pdadmin> user modify connectionsAdmin account-valid yes

Hole 2
This might not necessarily be called a hole, but rather an amalgamation of information on the Lotus Wiki and the information on the IBM Infocenter sites. However, the following objects required the Connections ACL to be applied to them:

acl attach /WebSEAL/{webseal}/profiles/dsx {connections_acl}
acl attach /WebSEAL/{webseal}/communities/dsx {connections_acl}
acl attach /WebSEAL/{webseal}/blogs/blogsapi {connections_acl}
acl attach /WebSEAL/{webseal}/blogs/blogsfeed {connections_acl}
acl attach /WebSEAL/{webseal}/files/basic/anonymous/atom {connections_acl}
acl attach /WebSEAL/{webseal}/files/form/anonymous/atom {connections_acl}
acl attach /WebSEAL/{webseal}/files/wl {connections_acl}
acl attach /WebSEAL/{webseal}/activities/images {connections_acl}

Hole 3
This probably isn't a hole either, to be honest. Instead, it's best to see it as a re-iteration or re-clarification.
The LotusConnections-config.xml file should be updated to contain the following:

<dynamichosts enabled="true">
<host href="http://fully-qualified-host-name" ssl_href="https://fully-qualified-host-name">

Also, ensure that the static href, static ssl_href and interService URLs for all services are pointing at the WebSEAL cluster:

<sloc:static href="http://fully-qualified-host-name" ssl_href="https://fully-qualified-host-name" />
<sloc:interservice href="https://fully-qualified-host-name" />

Note, the fully-qualified-host-name MUST be set to the host name where the WebSEAL is to be found.

Hole 4
Lotus Connections applications will attempt to open server to server communications with other Lotus Connections applications via Tivoli Access Manager. If forms-auth has been set to https in the webseald-.conf file, then the signer certificate for WebSEAL client-side SSL communications should be added to the WebSphere trust stores. In addition, the LotusConnections-config.xml file should be updated to contain the following:

<forceconfidentialcommunications enabled="true"></forceconfidentialcommunications>

Following En Hui Chen's guide and applying the "plugs" above should get you a perfectly working TAM-Lotus Connections environment. If not, drop me a line... I may be able to help. Failing that, have a chat with @dilftechnical who provided some invaluable Lotus Connections insight while diagnosing the issues we faced during integration.

Tuesday, October 05, 2010

WebSEAL Javascript Toolkit

Every good systems integrator needs to have ready access to their essential toolkits. You know the ones I mean? Those little snippets of code that absolutely, must be dropped into every deployment you ever complete.

In the WebSEAL world, I find that the following get my vote over and over again.

Frame Busting
Isn't it horrible when a WebSEAL login form appears in a frame? Aren't frames horrible in the first place? Anyway, I like the brutal approach in destroying those frames by dropping this piece of code into the login page:

if (self.location != top.location) {
        top.location = self.location; 

And, if you want to swap from http to https?

if (window.location.href.indexOf("https") == -1) {
        var uri = window.location.href.substring(4);
        window.location = "https" + uri;

The Cookie Crumbler
This is another favourite of mine. Upon logout, let's be brutal in trashing all cookies for the domain. Of course, the key word here is brutal. You may not want to do this. In fact, there are any number of reasons why this might be an incredibly bad idea for your environment. But if this is the case, then the code can be tailored to leave those "special" cookies intact. The rest? Crumble away.

var warningString = "WARNING: To maintain your login session, make sure that your browser is configured to accept Cookies.";
document.cookie = 'acceptsCookies=yes';
if(document.cookie == '') {
} else {
    // Cookie Crumbler
    var strSeparator1 = " ";
    var strSeparator2 = "=";
    var strCookie = document.cookie;
    var strCookieName = null;
    var intCount;
    var intStart = 0;
    var intEnd = 0;
    for (intCount = 1; intCount < strCookie.length; intCount++) {
        if (strCookie.charAt(intCount) == strSeparator2) {
            intEnd = intCount;
            strCookieName = strCookie.substring(intStart, intEnd);
            document.cookie = strCookieName + "=yes; expire=Fri, 13-Apr-1970 00:00:00 GMT";
            strCookieName = null;
        if (strCookie.charAt(intCount) == strSeparator1) {
            intStart = intCount + 1;

Cache Handling
Amazingly, the vanilla/default pages for login and logout pages will get cached by browsers which can cause confusion to users. Am I authenticated? Am I not? Maybe it would be best to instruct the browser to not cache these pages (and probably others). So we can drop the following meta-tags into our pages:

content="No-Cache" http-equiv="Pragma"
content="No-Store" http-equiv="Cache-Control"
content="No-Cache" http-equiv="Cache-Control"
http-equiv="Cache-Control", "private"
content="0" http-equiv="Expires"

Why so many statements? Well, as we all know, not all browsers behave in accordance with agreed standards. Enough said?

This isn't an exhaustive list of must-do tasks for a vanilla WebSEAL installation and it certainly isn't even accurate for all installations. But they are certainly a good starting point for putting good navigational structure around your WebSEAL protected environment.