Saturday, November 14, 2009

Authenticated Subject and Principals in Geronimo

JavaEE doesn't provide a standard way of determing the authenticated JAAS Subject or it's Principals. In general this isn't needed as there are mechanisms for authorization, which allows for other authorization frameworks to be plugged in without changing the authorization code.

Though, what if you have a remote client that should be authorized in the same way? Sometimes this requires doing it yourself. For instance, I have a front end where I construct the UI and available actions based on the roles of the user. I did this in the Netbeans Platform by annotating actions with @RolesAllowed and then to determine if the user is in the specified role.

To speed this up without doing a lot of back/forth between the server and client I fetch the list of roles from the server (which is determined by my authenticated remote JAAS session via OpenEJB to Geronimo) and build the UI from this information.

OpenEJB unfortunately doesn't provide a way to get this information client side. In fact, if I'm correct it doesn't even have this information client side. From what I can see it only has a reference to what Geronimo calls a "SubjectId", which is a numeric identification of the authenticated session.

So what I did was create an EJB method getAuthenticatedSubject() and getAuthenticatedSubjectRoles(). The former returns a javax.security.auth.Subject, and the latter returns a List of role names.

This is unfortunately not standard JavaEE and will only work on a Geronimo hosted EJB application. It would be great if the JavaEE folks could develop some specifications for remote authentication. They have the Application Client concept, but that's a half baked excuse for remote client sessions if there ever was any.

To compile this you would need to add the "geronimo-security" JAR to your classpath, and anything else it requires. This list can get quite extensive, so a bit of research or brute force might be needed to get this going, or you can take the smart route and use Maven.

So, here's the 2 methods:

  public Subject getAuthenticatedSubject()
  {
    return ContextManager.getCurrentCaller();
  }

  public List<String> getAuthenticatedSubjectRoles()
  {
    Subject subject = ContextManager.getCurrentCaller();
    Set<Principal> principals = subject.getPrincipals();

    List<String> roles = new ArrayList<String>();
    for (Principal p : principals)
    {
      if (p instanceof GeronimoGroupPrincipal)
      {
        roles.add(p.getName());
      }
    }

    return roles;
  }

No comments: