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 == '') {
    document.write(warningString);
} 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?


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

Thursday, September 09, 2010

User Provisioning Basics

I had the pleasure of spending some time at the IBM Innovation Labs in Hursley yesterday. The idea, bring Pirean expertise in the Tivoli Security space to a retail environment.

Having IBM Tivoli Identity Manager provision to a SAP Point of Sale system, Motorola CA50 VOIP system, Lotus Domino and having ID cards generated as a result was the intention and the result is a slick demonstration of the power and effect that an automatic provisioning tool can have in an environment with a high turnover of staff. Let's face it, retail outlets have a tendency to hire and fire (particularly over the Christmas and holiday periods) that just wouldn't happen in most other vertical markets.

The result is a retail environment that is (at last) fully joined-up and I even  managed to get a souvenir from the experience. A Zebra Quickcard generated ID card with a barcode allowing me to logon to the Motorola CA50 VOIP system (see right).

But what would make the experience even better? Well, enterprise applications should adhere to a few fundamental principles when it comes to exposing an API for user management. That is:
  • Ability to add a user to the system
  • Ability to modify the user details on the system
  • Ability to suspend the user
  • Ability to un-suspend the user
  • Ability to delete the user
  • Ability to perform a lookup of all users on the system

Unfortunately, not every "enterprise" application provides these fundamental abilities. Typical problem areas are the inability to perform a lookup of all users; the inability to suspend access rights and the real heartache that is the lack of a proper delete mechanism! One nameless Cloud based provider doesn't provide a delete mechanism at all and instead the account must be made inactive (although quite how you tell the difference between an account that you want to suspend and an account that you want to delete is left up to your imagination/ingenuity).

Identity Management principles have been around for quite some time now and vendors of enterprise applications have had plenty of notice when it comes to providing either a sensible API for user management or adopting an industry recognised external user repository which can be easily managed.

It would seem, however, that while progress has been made, we're still not quite there.

Tuesday, August 03, 2010

Tivoli Directory Integrator, Availability and ActiveMQ

I previously tackled how we can get IBM Tivoli Directory Integrator (TDI) to interface with Twitter and use the power of Twitter as a simplistic Message Queue mechanism. Today, I thought I would cover having TDI put messages onto and receive messages from an MQ queue with a view that it could be a useful means of introducing a number of concepts which could be critical in the enterprise:
  • High Availability
  • Abstraction

High Availability can be achieved with queues because I can have multiple TDI instances reading from a queue and performing actions as dictated by messages in the queue. I could have a queue called "actionQueue" which contains messages with actions embedded; a queue called "responseQueue" which could contain the status return code for each action and a queue called "errorQueue" for all the nasty things that may happen to us. I could have many TDI instances pick up a message, perform the action, respond and I would sleep soundly in bed each night safe in the knowledge that the way in which MQ queues operate would mean that I would not get duplication of effort and all messages would be processed even if a TDI instance were to crash.

Abstraction, of course, means that I can send a message to another TDI Server or Assembly Line without having any real need of understanding what or where that process is. I can merely put a message on a queue (in a format previously agreed) and proceed with my normal processing safe in the knowledge that my message will be delivered - eventually.

Environment Setup
If you want to follow this article, you will need:

Installing ActiveMQ is really very straightforward. Grab it from the Apache website and unzip it somewhere on your file system - I chose c:\apache-activemq-5.3.2 as my location on a Windows 2003 Server host.

As I like my Windows Services, I installed ActiveMQ as a service by running the c:\apacher-activemq-5.3.2\bin\win32\InstallService.bat batch file. After a few minutes, I could see ActiveMQ listed as a service though not, at this stage running. I started the service!

The activemq-all-5.3.2.jar file (found at c:\apache-activemq-5.3.2) should be made available to TDI. A simple way of achieving this is to drop the file into the TDI\V7.0\jars\3rdparty directory .

We're now ready to create an Assembly Line which will write messages to an ActiveMQ queue!

MQ Connector

The first step we should take when we start the TDI GUI and create an Assembly Line is to drop in a JMS Connector (in Add mode) and populate the form as follows:

The JMS Driver Script needs to be populated with the following code so that the connector understands how to communicate with the ActiveMQ instance:

var brokerURL = env.get("jms.broker").trim();
var connectionFactory = new org.apache.activemq.ActiveMQConnectionFactory();
connectionFactory.setBrokerURL(brokerURL);
ret.queueConnectionFactory = connectionFactory;
ret.topicConnectionFactory = connectionFactory;

I used the Simple XML Parser on this connector to parse my output in XML format:


As I decided I'd write to an errorQueue, I updated my Output Map to include an errorCode attribute and an errorMessage attribute:

NOTE: Although not shown, my work entry was populated by an iterator which read through an input file of error codes and messages!

Running the Assembly Line, which is always the exciting bit, resulted in my ActiveMQ errorQueue queue being populated with 9 messages. Queues can be "browsed" with a standard browser by pointing the browser at http://localhost:8161/demo/queueBrowse/{queue-name}:

9 messages. As expected.

The Consumer
Now that I have populated my queue, I need "something" to consume these messages. A JMS Connector in iterator mode can be used to act as a mechanism to constantly poll the queue for new messages:

This will certainly read the messages and with an appropriately configured Parser and Input Map I will end up with a work entry containing the errorCode and errorMessage attributes I expect. At this point, I can take decisions on what I want to do with these "errors". I could merely write them to a file. I could send an email to someone. I could even send an alert to the world via Twitter (see previous article). And I can base these decisions on the contents of my message. For example, if my errorMessage contained the word Tweet, I could send the message to Twitter, right?




The End Result
For simplicity's sake, I wrote each errorCode and errorMessage to a flat file (along with a timestamp) and the result was this:
dateTime|errorCode|errorMessage 
"2010-08-02 21:02:18"|"1"|"Msg1" 
"2010-08-02 21:02:18"|"2"|"Msg2" 
"2010-08-02 21:02:18"|"3"|"Msg3" 
"2010-08-02 21:02:18"|"4"|"Msg4" 
"2010-08-02 21:02:18"|"5"|"Msg5" 
"2010-08-02 21:02:18"|"6"|"eMail me a message 6" 
"2010-08-02 21:02:18"|"7"|"Tweet me a message 7" 
"2010-08-02 21:02:18"|"8"|"Tweet me a message 8" 
"2010-08-02 21:02:18"|"9"|"Msg9"

Within my IF branch, I include an AssemblyLine Function call to my Twitter Status Update AL (from my previous tutorial) and saw messages 7 and 8 appear on my Twitter timeline.

Conclusion
ActiveMQ is a very simple product to deploy and get working. Of course, it would be prudent to secure the queues. It would also be prudent to introduce some serious error handling in the Assembly Lines - for example, reading a message from a queue removes it from the queue immediately which may or may not be desirable before the message has actually been processed!

Hopefully, however, this will give you a taster of how TDI can interact with MQ. Good luck "queueing".

Tuesday, July 13, 2010

Twitter and ITDI - Part 2

In my "Twitter and ITDI" article I showed how we can use ITDI to send a tweet and I stated that getting ITDI to read tweets might be a good next step in the process of fully Twitter-enabling our ITDI Assembly Lines. This article will hopefully shed some light on how we could go about doing just that.

The first thing we need to do is create ourselves an ITDI Assembly Line and drop in a FOR-EACH Connector Loop of type HTTP Client. I configured my HTTP Client connector to perform a GET on the following URL:

http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=stephenjswann&count=5

I slected the Simple XML Parser as a parser for this connector and assigned the Root Tag and Entry Tag as "statuses" and "status" respectively, as such:
I performed a connection on my Input Map tab, clicked on next and dragged the created_at and text schema attributes to my map.

Fantastic! I now have a connector which will loop around the tweets it receives as a result of performing a GET request on the user_timeline.xml resource on Twitter. So what next? Well, within the loop, I would probably want to drop in an IF branch with the following script in place:

a = work.getString("text");
if (a.contains("#tditest")) {
    return true;
} else {
    return false;
}

This script will query the contents of each tweet looking for the hashtag #tditest. Any tweet containing this hashtag will invoke the contents of our IF branch. Of course, you could put whatever you want into the IF branch but for the purposes of my test, I dropped in the sendTweet function used in yesterday's article to post a response back to Twitter stating that a tweet with the #tditest hashtag had been found. I'm quite sure there are many more practical actions which could be performed at this stage!

Now the intelligencia reading this will be wondering what use this loop connector is in its present form. After all, once we have read through the tweets that we have requested, the Assembly Line will stop. And if we run it again, it will just process the same tweets again, right?

Right. Unless we expand our solution with a couple of minor tweaks. We can enable the delta processing in our HTTP Client Connector which ensures that we will only ever process NEW tweets. Any unique attribute of the tweet should suffice (and there are a few) but I settled on created_at, for no particular reason:
Now I can run my Assembly Line over and over again safe in the knowledge that it won't trigger my IF branch at all unless there is a new Tweet that it hasn't ever seen before. The final step for me was to wrap this Assembly Line in a timer controlled Assembly Line. I created a readTweetsController Assembly Line with a timer function as an iterator and all time attributes set to * (which means the AL will fire every minute). In my data flow, I placed an Assembly Line Function component to call the AL I built above.

The result? A mechanism which polls Twitter every minute looking for new tweets with a particular hashtag and "does stuff" if a matching tweet is found.

So what are the real world applications for such a mechanism? Theoretically, I could:
  • post a tweet "TDI: getStatistics" and my TDI AL could return "TDI RESPONSE: 20,000 records processed"
    post a tweet "TDI: startSync" and my TDI AL would kick off a synchronisation process and return "TDI RESPONSE: synchronisation started" followed some time later with "TDI RESPONSE: synchronisation complete"
  • post a tweet "TDI: switchOnLights" and my TDI AL could switch on the lights in my house
    post a tweet "TDI: exec "su - shutdown now" and my TDI AL would ignore me as a fool
Of course, there may be better ways of doing any or all of these tasks but using Twitter for non-critical communcations with your ITDI Assembly Lines should be relatively straightforward. After all, we aren't always within easy reach of our laptops, but we rarely go anywhere without our phones and remote management via phone and Twitter could be useful.

Hopefully this article will give you some food for thought.

Monday, July 12, 2010

Twitter and ITDI

It is becoming clear that Twitter isn't just a platform for telling the world what you are having for your dinner. Twitter is used as a marketing tool, a news information service and a tool for comedians to test new jokes. It's robustness and message persistence make it an excellent candidate for creating a Message Queue service for those who haven't the inclination for deploying a "proper" MQ service and it can also be used as an alerting mechanism.

For example, I would be quite happy to receive a tweet stating that something had happened to my enterprise application during the night with relevant information like an error code. After all, it is a free way to send the equivalent of a SMS.

Twitter offers a great API and a simple single command can update your Twitter status as such:
curl -u user:password -d "status=This is my first tweet via the Command Line"

But what if curl isn't available on your system? What if you have a suite of ITDI Assembly Lines which you would like to interface with Twitter? Well, nothing could be simpler (until Twitter disable their Basic Authentication mechanism).

An HTTP Client Connector should be created in LookUp mode within your Assembly Line and the connection details updated as such:

The Link Criteria should be updated to include a status parameter:


And the returning http.body attribute can be converted into a string for further analysis such as checking that the tweet was sent successfully:


Our sendTweet connector would be a great addition to our arsenal of alerting mechanisms which should already include sendMail, sendSNMPAlert and updateLog.

Next Steps

Building a Twitter Assembly Line which can perform the OAuth authentication would be a natural next step as would a connector which can read a "twitter stream" (as the equivalent of an MQ Consumer).

NOTE: The above screenshots were taken from a TDI v7.0 instance running on Windows 2003 but the concepts can be used in older versions of TDI with little (or no) modification.

Monday, July 05, 2010

How To Provision TAM GSO Credentials

Most of the time, getting IBM Tivoli Identity Manager to provision accounts successfully in target systems is a breeze. And you could be forgiven for thinking that provisioning to IBM Tivoli Access Manager (another stalwart of the IBM Tivoli portfolio) would be the simplest of the lot.

You would, of course, be wrong. At least, if you want to make use of GSO credentials, you would be wrong. Maybe. Possibly.

You see, the provisioning of GSO credentials just doesn't seem to be that easy!

This article assumes the following:
  • the reader has a basic understanding of IBM Tivoli Identity Manager
  • the reader has a basic understanding of IBM Tivoli Access Manager
  • the reader understands GSO credentials within TAM
  • the version of ITIM being used is v5.0 (or higher)
  • the version of TAM being used is v6.0 (or higher)
  • the TAM Combo Adapter is being used (v5.0.9)

For an explanation of the problem, let us assume that a resource has been created within the TAM domain called backed. In pdadmin, we can create this resource as such:

rsrc create backend

In ITIM, we have a provisioning policy created with all the standard default TAM attributes being populated (such as cn, sn, our TAM groups, etc.). We check the box for Single Sign On Capability which leaves us with the Resource Credentials to populate.

In our environment, we have password synchronisation enabled across all systems and the GSO credentials will be no different. In other words, should a user change their password in ITIM, their TAM password and their GSO resource credential passwords will also be updated.

The "Constant Value" option for the Resource Credentials on our Provisioning Policy form is of no help for a User ID and Password that will be different for each user:


Which leaves us with the option of scripting the credentials. The documentation provided with the TAM Combo Adapter at least tells us that the TAM Resource Credentials must be provided in the following format:

RESOURCE NAME|USER ID|PASSWORD

In our case, that means that our javascript will look something like this:

"backend (Web Resource)" + "|" + parameters.eruid[0] + "|" + {something}

We have a problem. We've always known that we can use parameters.eruid[0] for our User ID but what do we use for our password? A little bit of crawling around the documentation tells us that when password synchronisation is enabled, the ersynchpassword can be used to retrieve the password. So our {something} becomes ersynchpassword, right?

Wrong!

In fact, when we do this and provision an account (with a password of auiTNG85) our secAuthData attribute in LDAP contains the following:

secAuthnData:: IUAja0BAQEBAQEDJKioqKioqKqgh5CMjIyMjIyMjIyMjgiMjIyMjIyMjIyMjniMjIyMjIyMjIyMjNyQk

How do I know that this is wrong? I know because I manually created the Resource Credential via the pdadmin command prompt and know that the result I'm looking for is:

secAuthnData:: IUAjZyoqKioqKip6JiYmJiYmJiYmJiZpIVQhT0BAQEBAQEBIQEBAQEBAQDghOSUlJSUlJSUlJSUlJSUA

Indeed, if I hardcode my Provisioning Policy to set {something} to my password (auiTNG85), I get the same incorrect result. Odd? Not really. If you dig further into the documentation you will see that there is some funny business going on with the TAM Combo Adapter and the password in the Resource Credential attribute on the Provisioning Policy MUST be prefixed with {clear}. In our hardcoded entitlement, we would therefore have:

"backend (Web Resource)" + "|" + parameters.eruid[0] + "|" + "{clear}auiTNG85"

Now, when we create our account, the secAuthnData is set correctly! Of course, I'm hardcoding the password still so I need to do something about that! We need to re-introduce our ersynchpassword attribute but ensure we are prefixing is with {clear}. And the reason we do that is because ITIM is just too clever by half and has already Base64 Decoded the attribute on our behalf!


The resulting secAuthnData is now set to:

secAuthnData:: IUAjZyoqKioqKip6JiYmJiYmJiYmJiZpIVQhT0BAQEBAQEBIQEBAQEBAQDghOSUlJSUlJSUlJSUlJSUA

Perfection. I'm sure the documentation contains all the information required to get this result but it isn't instantly clear that this is how you should be going about the GSO Credential Password Synchronisation problem.

Sunday, July 04, 2010

IBM Tivoli Identity Manager Data Object Relationships

IBM Tivoli Identity Manager can be a beast at times. On the face of it, having a tool that can manage your account objects in various data repositories/systems doesn't sound like it ought to be complicated. However, the reality can be quite tricky. Person objects, account objects, role objects, organisational hierarchy objects, service objects, provisioning policies, identity policies, adoption policies, password policies, entitlements, accesses... that's a lot of data and the relationships these data objects have with each other can get confusing for some.

Person objects own account objects which are provisioned by virtue of an access request or a provisioning policy which contains entitlements granted by role membership for specific services or service types and the accounts' User ID is governed by an Identity Policy, etc.

There are some excellent technical documents available on the IBM website which attempt to explain these objects but I've rarely found a visual description of the objects which works - thus my attempt using Visio:


Now, it should be pointed out that this visual representation is incomplete. How could I possibly have shown ALL the relationship lines without them criss-crossing in a way which would make the diagram "unviewable". For example, almost every object gets "placed" in a Business Unit yet I've only shown a person object belonging to a business unit! However, I hope it helps explain the basic relationships.

If you want the Visio 2007 version of this diagram, you can get it from http://www.stephen-swann.co.uk/downloads/itim-object-relationships.vsd. Enjoy.

NOTE: This diagram refers to IBM Tivoli Identity Manager v5.1