A TAI code example

To complete my series posts on writing Trust Association Interceptors (TAI’s) for Websphere Application Server I wanted to show a real-life example. Not a good example necessarily but an example never the less… 🙂

The below example is a very simple TAI that simply does the following:

  1. The initialize() method reads a cookie name from the configuration done in the Websphere Application Server ISC. It illustrates how you can configure a TAI externally without having to hard code it.
  2. The isTargetInterceptor() method looks at the request and sees if a cookie with the configured name is available. If yes it continues to process the request and if not it aborts processing (from the TAI point of view).
  3. The negotiateValidateandEstablishTrust() method does the actual work by simply telling WAS that the username of user is the value from the cookie.

As you see writing a TAI is very simple but extremely powerful. Imagine what could be done if you did SSO between Websphere Application Server and Lotus Domino.

import java.util.Properties;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ibm.websphere.security.WebTrustAssociationException;
import com.ibm.websphere.security.WebTrustAssociationFailedException;
import com.ibm.wsspi.security.tai.TAIResult;
import com.ibm.wsspi.security.tai.TrustAssociationInterceptor;

public class ExampleTAI implements TrustAssociationInterceptor {
   // declarations
   private String cookie = null;

   @Override
   public void cleanup() {
   }

   @Override
   public String getType() {
      return String.format("Example TAI %s", this.getVersion());
   }

   @Override
   public String getVersion() {
      return "1.0";
   }

   @Override
   public int initialize(Properties props)
      throws WebTrustAssociationFailedException {
      System.out.println("ExampleTAI.initialize()");

      // read properties from configuration in WAS
      this.cookie = props.getProperty("cookieName");

      // return 0 to indicate success
      return 0;
   }

   @Override
   public boolean isTargetInterceptor(
      HttpServletRequest req)
      throws WebTrustAssociationException {
      System.out.println("ExampleTAI.isTargetInterceptor()");
      for (Cookie c : req.getCookies()) {
         if (c.getName().equals(this.cookie)) return true;
      }
      return false;
   }

   @Override
   public TAIResult negotiateValidateandEstablishTrust(
      HttpServletRequest req,
      HttpServletResponse res)
      throws WebTrustAssociationFailedException {
      System.out.println("ExampleTAI.negotiate...()");
      for (Cookie c : req.getCookies()) {
         if (c.getName().equals(this.cookie)) {
            // send 200 to signal we're okay
            return TAIResult.create(HttpServletResponse.SC_OK,
                c.getValue());
         }
      }

      // not authenticated
      return TAIResult.create(HttpServletResponse.SC_UNAUTHORIZED);
   }

}

Developing TAI’s for Websphere Application Server

Trust Association Interceptors (or TAI’s) for Websphere Application Server is quickly becoming my new favorite technology. They just might be best thing since sliced bread and the reason why why you want to embrace Websphere Application Server. And so quickly.

I have discussed TAI’s and why they’re important in an earlier blog post.

One thing to know however is when developing them you need to have the necessary stuff in place. For TAI’s these are the JAR required on the class path and they are:

  • <WASHOME>runtimescom.ibm.ws.webservices.thinclient_6.1.0.jar
  • <WASHOME>libbootstrap.jar
  • <WASHOME>libcom.ibm.ws.runtime.jar
  • <WASHOME>libj2ee.jar

After that it’s a matter of creating a new class and implementing the com.ibm.wsspi.security.tai.TrustAssociationInterceptor interface which only contains two methods:

  • public boolean isTargetInterceptor (HttpServletRequest req)
    “The isTargetInterceptor method determines whether the request originated with the proxy server that is associated with the interceptor. The implementation code must examine the incoming request object and determine if the proxy server that forwards the request is a valid proxy server for this interceptor. The result of this method determines whether the interceptor processes the request.”
  • public TAIResult negotiateValidateandEstablishTrust (HttpServletRequest req, HttpServletResponse res)
    “The negotiateValidateandEstablishTrust method determines whether to trust the proxy server from which the request originated. The implementation code must authenticate the proxy server. The authentication mechanism is proxy-server specific. For example, in the product implementation for the WebSEAL server, this method retrieves the basic authentication information from the HTTP header and validates the information against the user registry that WebSphere Application Serve uses. If the credentials are not valid, the code creates the WebTrustAssociationException exception, which indicates that the proxy server is not trusted and the request is denied. If the credentials are valid, the code returns a TAIResult result, which indicates the status of the request processing with the client identity (Subject and principal name) to use for authorizing the Web resource.”

In short isTargetInterceptor is called to determine if a given request matches a given TAI and if it returns true negotiateValidateandEstablishTrust is called to determine if this TAI could authenticate the user and that the username (“Subject”) is. Very easy.

It’s important to note that “authenticate” could mean whatever you decide it means. That is you could actually do some work to authenticate the request but you could just as well simply decide that the user is authenticated and that the username is “John Doe123”. Whether the authentication is done based on “real authentication”, based on a cookie being set or something else is entirely up to you. That’s why it’s so powerful.

Once deemed authenticated by negotiateValidateandEstablishTrust a valid LtpaToken/LtpaToken2 is generated and the user is granted access into the Kingdom.

Infocenter:
Trust association interceptor support for Subject creation

Do you care for TAI? You really should!!

Websphere Application Server is a beast. A big beast. But it’s a beast that good (even great?!) on a lot of levels and it’s definitely not as bad as you might think and it comes with a lot of goodness and loads of functionality. One of the real cool things about Websphere Application Server is the ability you have to extend the core application server (which is something that is hard – becoming easier but still hard – with Lotus Domino). The extendibility I want to mention today is Trust Association Interceptors – or TAI for short.

A Trust Association Interceptor is an exciting piece of technology that has been part of Websphere Application Server for quite a while and a technology that is becoming my new best friend. It’s objective is to sit between an incoming request and the application server runtime and let you manage the authentication state of incoming requests. Think DSAPI filters to manage authentication if you will except that TAI’s are written in Java and much easier to write, test, debug and deploy.

If you have a reverse proxy such as WebSEAL the way you make it work with Websphere Application server today is by installing a TAI into the application server. It’s also the way that SPNEGO support is added. As with many Java technologies you could just as well write your own – and it’s dead easy. It’s even well documented in the IBM Infocenter. So why would you want to do so? Well imagine if you’re installing IBM Connections and have an existing SSO solution you want to reuse to authentication. Writing a TAI lets you do that with a minimal hazzle.

I’ll post about how you actually go ahead and write a Trust Association Interceptor later.

Gul Skole on Friday – come hear from one of the gurus

If you’re in Denmark on Friday and want to hear about social media and social software from a Guru come to our seminar with Louis Richardson from IBM at Sofienholm. More information may be found on the event page. If you’re contemplating social software within your organization this is a must-attend event and a chance to hear from one of the masters. And it’s FREE!!

Please note that this is a business oriented event so no mention of Websphere Application Server, LDAP etc. Unless you hit me up for a conversation. 🙂

Turning the login procedure for IBM Connections on its head

In the latter part of last year I was involved in installing IBM Connections at a customer site for initially 20.000 users and then, if all went well, for the full 70.000 users. The challenges in evangelizing the solution and getting people to use it is for another blog post but the project is interesting from other perspectives as well.

Firstly they wanted to change the layout of IBM Connections and add their own colors etc. which wasn’t a biggie. Next they wanted to change certain core words within IBM Connections. In Danish the word for “Communities” is “Fællesskaber” but they wanted it to be “Grupper”. Changing that throughout IBM Connections was a hazzle and we have to migrate these changes by hand when we upgrade to version 3 but it was possible which is the good story here. The last one was the biggest requirement and the the requirement it took the most work to satisfy. They wanted to turn the entire login process for IBM Connections on its head.

So what do I mean by that?

By default IBM Connections works by you importing all valid users into the Profiles database using TDI or a handcrafted tool and then hooking Websphere Application Server up to LDAP. They didn’t want that and the users actually didn’t exist in a LDAP directory but instead in another (Domino based) member database.

They had a number of requirements:

  1. IBM Connections should work with their existing single-sign-on (SSO) solution which supported a number of different login methods incl. two-factor and digital certificates.
  2. Before being granted access to IBM Connections the user should accept an End User License Agreement (EULA) and if not the user should be denied access to IBM Connections.
  3. Users wasn’t allowed to be available in IBM Connections before opting in to using it by accepting the EULA i.e. they didn’t want users in the Profiles database before they had accepted the EULA.

The access procedure they wanted may be illustrated as below.


(click the image to a larger version)

So what does an IBM Business Partner do? Say “Sorry that isn’t possible” and “That’s really not the way that IBM Connections work”? Well of course not because it was and is possible due to IBM Connections being built on top of Websphere Application Server which is an open and highly extensible platform.

The key piece to the puzzle is a piece of technology called a Trust Association Interceptor – or TAI for short – and is a way to change the way Websphere handles authentication and how Websphere normally integrates with reverse proxies such as WebSEAL.

A TAI is a Java class written to a specification (interface) from IBM and very easy to write. The functionality may of course be complex but the way you integrate with Websphere Application server isn’t. Once the TAI was written and installed into Websphere Application Server the customer now has an access procedure like this:

  1. User tries to access IBM Connections.
  2. If the user isn’t logged in using the 3rd party SSO solution the user is sent to the login screen (1 in the diagram above).
  3. If the user is logged in (and tokens are still valid) an EULA check is performed to verify that the latest EULA has been agreed to.
  4. If not the user is sent to the EULA system (2 in the diagram above) to accept the EULA instructing the EULA system to return the user to IBM Connections afterwards.
  5. If the user did accept the latest EULA we check to see if the user is available in IBM Connections.
  6. If the user isn’t in Profiles yet the user is sent to the Populator system (3 in the diagram above) that handles collecting using information and populating Profiles. Once completed the user is returned to Websphere Application Server.
  7. If the user is in Profiles already the user is granted access to IBM Connections (bottom on the diagram).

It sounds complex but it’s done in less than 500 lines of code incl. comments and documentation. That isn’t too bad is it? What’s really cool is that it allows for some very exciting ways to integrated IBM Connections into existing environments.

I’ll post more about TAI’s over the next few days about how you write them and more about the technical underpinnings. Stay tuned.

IBM Lotus Domino: Classic Web Application Development Techniques from PACKT Publishing (a review)


Just spent an hour or so looking through the new book from PACKT Publishing called “Classic Web Application Development Techniques” and it’s a good read. It goes from A-Z through developing web applications on Domino using the classic form/view/agent approach. The table of contents reads like this:

  • Chapter 1: Preparation and Habits
  • Chapter 2: Design and Development Strategies
  • Chapter 3: Forms and Pages
  • Chapter 4: Navigation
  • Chapter 5: Cascading Style Sheets
  • Chapter 6: JavaScript
  • Chapter 7: Views
  • Chapter 8: Agents
  • Chapter 9: Security and Performance
  • Chapter 10: Testing and Debugging

If starting out in classic Domino web application development (read “non-XPages) today I would highly recommend the book to serve as a good, solid, introduction to the topic.

Well done and good to see a book for new developers.

Using a queue to wait for a job to complete

A question I get often is how to perform an operation synchronously (that is blocking) instead of asynchronously when developing plugins. The question stems from the fact that most operations are done using the Job-framework where code is run in a background thread. But what if you need the result before continuing. What if you don’t want to wait or the code doesn’t lend itself to that approach?

I find that the easiest way (without resorting to Job scheduling rules) is to use the java.util.concurrent classes to make the calling thread wait for the Job to complete. This approach works for all job-types including Notes based operations using NotesSessionJob.

Code could look like this:

import java.util.concurrent.ArrayBlockingQueue;

public FeedLoader() {
   // define queue to hold a maximum of 1 element
   final ArrayBlockingQueue<Object> queue =
      new ArrayBlockingQueue<Object>(1);

   // create and schedule job
   new NotesSessionJob("Getting Notes username") {
      @Override
      protected IStatus runInNotesThread(Session session,
       IProgressMonitor monitor)
       throws NotesException {
         // perform operation and store result
         FeedLoader.this.username = session.getUserName();

         // put stuff in the queue to signal we're done (we
         // could also have used the queue to return the value)
         queue.offer(new Object());

         // return
         return Status.OK_STATUS;
      }
   }.schedule();

   // wait for job to complete (Queue.take() wont return until
   // the job puts something in the queue)
   try {
      queue.take();
   } catch (Throwable t) {}
}

I’m sure there are other, and probably easier and better, ways to do it but this is how I often do it.

Why choosing Eclipse for Notes 8 was the right choice

It’s been quiet around the blog the last few months because I have been neck deep in work getting a new product ready. I’m slowly resurfacing and as blogged about the last few days we (OnTime) are now shipping the latest release of the group calendar product called OnTime Group Calendar 2011. We showed of the UI’s at Lotusphere 2011 but now we’re shipping and are ready to go.

Besides having a brand new backend with it’s own interesting features and performance improvements (see here) the product also ships with a brand new, all Java, Notes UI that runs full screen inside the Notes client. The client is called OnTime Group Calendar 2011 – Notes (or Notes 2011) and is a good showcase of what’s possible inside the Notes client and why choosing Eclipse as the platform for Notes 8 was important. We no longer have to use separate clients for our UI but can run it inside Notes where it belongs. The below screenshot shows the UI running inside Notes 8.5.2.



(click the image for a larger version)

The

Since the group calendar now runs full screen (a perspective in Eclipse Java parlance) it’s launched from the Open menu in Notes. Once opened it adds its own top level OnTime menu and loads data using the new OnTime Group Calendar API. One of the cool things about the UI being in Java is that it does away with the traditional Notes view limitations (for instance one document per row) and allows for some super cool, pixel level, UI drawing. It also allows us to read from an API layer that abstracts the actual reading and providing of data from the application itself and allows us to reuse the API in all our UI’s (Notes 2011, Discovery 2011, Web 2011, Mobile 2011 and Team-At-A-Glance 2011 (sidebar)).

The UI allows the user to switch between a day view (see above) where the user may choose to see from 1 to 7 days to a week view to a month view. The week view for instance gives a very nice overview of the calendar of the people you work with.

In all the views you may filter the people shown using groups and legends. Legends are what we call the types of appointments/meetings being shown. On the server you configure what makes an appointment be put in what legend and may be based on category, type or a formula you specify. Once you select one or more legends the viewer is filtered to highlight the appointments/meetings that match the legend. Below I have chosen to only see external meetings.



(click the image for larger version)

Besides the cool and slick UI (if I have to say so myself) we also provide some nice new functionality. If you have write to a calendar (your own or a colleagues) you may drag’n’drop appointments in the group calendar. The below screen shot shows me dragging an appointment from Susanne to Saiful.

The Notes 2011 also allows for full Lotus Sametime integration and customization using Eclipse based extension points but that’s a topic for another day.

If you like to try out OnTime Group Calendar 2011 you may obtain an unrestricted, 30 day, trial. Simply drop us an e-mail at sales@intravision.dk. We’ll even be happy to offer you 20% discount for all new licenses purchased in May or June as an introductory offer. Just tell us that you learned about OnTime on lekkimworld.com and we’ll discount your purchase.

A tale from a customer reaching (and exceeding) the 64 gb limit

As I’ve tweeted I have spent the last couple of days (and the weekend) helping out a customer that exceeded the hard 64 gb database size limit in Lotus Domino. Before discussing how we solved the problem and got the customer back in business I would like you to think about how situations like this could be avoided. And avoiding it is key as once you exceed the size you’re doomed.

First — how and why database platform would EVER allow a database to cross a file size that makes it break. Why doesn’t Domino start to complain at 50gb and make the warnings progressively harder to ignore as the database gets closer to 64gb. Why doesn’t it refuse data once it reaches 60gb? I find it totally unacceptable that a software product allows a database to exceed a size it knows it cannot handle.

Now I know that there are considerations for such a warning and that it could be done in application code (e.g. database script, QueryOpen event) but it really isn’t something an application developer should think about. Also it should be applied to backend logic as well and really doesn’t lend itself to a UI computation. I also know that DDM or similar could warn about it but it still doesn’t change my stance. The 64gb limit is a hard limit and reaching, and exceeding it, shouldn’t depend on me configuring a specific piece of functionality.

Second — having the option of keeping the view index in another location/file than the database would have helped. This has been brought up a number of times including at Lotusphere Ask-The-Developers sessions. One could argue that externalizing the view index from the database would just have postponed the problem but the view index takes up a substantial amount of disk for databases of this size.

Now on to how we saved the data.

The bottom line in this is that the customer was lucky. VERY lucky. The customer uses Cisco IP telephones and keeps a replica of the database in question on a secondary server for phone number lookup using a Java servlet. Due to the way the way the servlet is written only as single, very small, view was built on the secondary server. This is turn meant that the database that had exceeded 64 gb on the primary server was “only” 55 gb on the secondary server. The database on the primary server was toast and gave out very interesting messages if attempting the access or fixup the database:

**** DbMarkCorruptAgain(Both SB copies are corrupt)

So thank God they had the secondary server otherwise the outcome of the story would have been less pleasant because using the secondary server we were able to:

  1. Take the database offline (restrict access using ACL)
  2. Purge all view indexes (using Ytria ViewEZ)
  3. Create a database design only copy to hold archived documents
  4. Delete all views to avoid them accidentally being built
  5. Build a very simple view to prepare for data archiving
  6. Write a LotusScript to archive documents (copy then delete) from the database
  7. Use Ytria ScanEZ to delete deletion stubs from the database (this works for them because the database isn’t replicated to user workstations or laptops)
  8. Do a compact to reclaim unused space
  9. Make the database available on the primary server

Whew! They are now back in business after building views in the database. They were lucky – VERY lucky. If they hadn’t had that secondary replica the data would probably have been lost to much distress. To them and me.

So what are the main take aways from this?

  1. UI check — in the future all databases that I develop will have a database script check on the database size to try and prevent situations like this
  2. DAOS — enable DAOS for databases to keep attachments out of the database and keep the size down
  3. Monitoring — monitor databases either using DDM or other tools to try and prevent sitations like this

And so concludes a story from the field. 4 days later where my hair have turned gray from watching copy/fixup/compact progress indicators the customer is back in and happy once again. Whew!!