Friday, October 19, 2007

Jboss Seam Jaas authentication and jbpm Actors

The Identity component in Seam is a pretty handy thing. You can authenticate users by providing your own Authentication method or you can use JAAS. At my company we prefer JAAS. However there is a catch. When you also use jbpm, you should be able to populate the Actor component. But because we use JAAS there is no direct way to execute some custom code.

Fortunatly the seam developers provide a event model. Several components can emit events which our code can Listen on. It is very simple. You can simply add the @Observer annotation to a method with the correct event.

Now for populating the Actor component, we are going to write a Observer that listens to the "org.jboss.seam.postAuthenticate" event. You can read about these events in the seam documentation.

The next problem is that the JAAS API completely sucks. It is easy to find out if the users is in a specific role, but finding all the roles a user has is not possible. Fortunatly i found some code on the seam forums from a clever guy that allows me to do it. The drawback is that you make your code container specific. But for the moment being it serves me well.

So my authentication handler looks like this now:


import java.util.Enumeration;
import java.util.Iterator;

import javax.security.auth.Subject;

import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.core.Actor;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Identity;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;

@Name("postAuthenticationHandler")
public class PostAuthenticationHandler {

@Logger
Log log;

@In
Identity identity;

@In
Actor actor;

@SuppressWarnings("unchecked")
@Observer("org.jboss.seam.postAuthenticate")
public void doPostAuthenticate() {
log.info("Entering doPostAuthenticate...");
actor.setId(identity.getUsername());
Subject subject = identity.getSubject();

Iterator principleItr = subject.getPrincipals().iterator();
while (principleItr.hasNext()) {
Object principle = principleItr.next();
if (principle instanceof SimpleGroup) {
SimpleGroup simpleGroup = (SimpleGroup) principle;
Enumeration simpleGroupMembers = simpleGroup.members();
while (simpleGroupMembers.hasMoreElements()) {
Object o = simpleGroupMembers.nextElement();
SimplePrincipal aPrincipal = (SimplePrincipal) o;
log.info ("User " + identity.getUsername() + " is a member of group " + aPrincipal.getName());
actor.getGroupActorIds().add(aPrincipal.getName());
}
}
}
}
}


So first we inject the Actor/Identity components. Also notice the @Observer annotation which causes this method to be invoked when the postAuthenticate event is raised.

In the method itself we will get the JAAS subject from the identity component. This Subject class is some kind of container which contains all authentication specific attributes for this users called Principals. Now we can iterate over these Principals and extract the roles from it and insert them into the Actor component. As you see we cast the principle to a SimpleGroup which is a jboss specific implementation. So deploying this code on something other than jboss or even on another version of jboss than version 4.0.5.GA will break this code. But i found no other way to get to this information otherwise.

No comments: