Alex headshot

AlBlue’s Blog

Macs, Modularity and More

All that JAAS

2004

I've been having fun with JAAS (Java Authentication and Authorisation Service) recently, and wanted to share my thoughts on what it's good for, and what it isn't good for.

Firstly, what is JAAS? Well, it's an API that allows programs to authenticate users against a password. These users and passwords are often referred to as a realm or domain, but in essence, JAAS allows these users to come from a number of different back-end places, such as a database table, an LDAP server, or the local operating system. The idea is that JAAS can be used to take a userid and password, and then authenticate the user from somewhere, without actually caring how this authentication works.

In principle, JAAS is a fine idea. And since it's configurable, it means that the separation of who authenticates and how authentication occurs. That means I can download and use a program, and hook it up to my existing set of users and passwords from my LDAP server, without the person who wrote the program even knowing what LDAP stands for. Further, it makes it much easier to write the program, because you don't have to manage or maintain your own set of userids and passwords.

Let's take a look with how JAAS is used:

java -Djava.security.auth.login.config=jaas.conf MyLoginApp

The jaas.conf file is an external (text) file that says where the application should get its users and passwords from. This is loosely based on the Linux PAM (Pluggable Authentication Modules) concept; each application can have its own name, followed by the login module to use, and where it gets its users from.

MyLoginApp {
  com.example.jaas.MyLoginModule required;
};
other {
  com.example.jaas.DefaultLoginModule sufficient;
};

The other synonym is a default wild-card that will be applied to all applications, regardless of name. It's like having an application name of *, except that JAAS doesn't allow wild-cards in the application name.

The LoginModule is a Java class that verifies the username and password against some back-end. It doesn't matter what the back-end is; it could be entries in a database table, or in an LDAP table, or from somewhere else completely different. The class needs to implement the default JAAS LoginModule class, and has methods to be able to validate and login users.

The last flag, required or sufficient says whether it is mandatory to pass, or optional, or not required at all. You might wonder what the point of having an optional login module is; but it is useful in the case of a fall-through (if I'm not in database A, then look in the LDAP table). Furthermore, you can also use these (in PAM) to check for password strength, and disallow insecure passwords.

For all that JAAS is a good idea, there are some fairly fundamental problems. Firstly, you can't really integrate directly into an NT domain, because Sun has written some fairly basic NT authentication modules that probably can't be redistributed. There are open-source ones out there, but there's no easy way of configuring the NT domain at runtime. You need to have the name of the class set in the JAAS module, which means that there's no way of dynamically choosing which NT provider you are going to select.

Secondly, though the NT userid and domain is returned as a string, the rest are returned as NT UUIDs. In essence, the groups, users etc. have a unique ID (1-234-5678-990-345-788), that is mapped to a more readable user name (Alex). The NT modules all seem to return these unique IDs, and whilst this is probably an artifact of how NT works, there's no easy/sensible way to convert these numbers into something meaningful. There's certainly no consistent way, which means that your client code ends up being NT specific; and since the whole point of JAAS is to abstract away the system, it fails dismally.

Thirdly, there's no decent mapping between JAAS and J2EE security. J2EE security is defined in terms of Users and Roles, whilst JAAS deals with Principals. Now there's nothing to stop these two things being related, but Sun never provided a standard way of dealing with it. As such, app servers such as JBoss provide separate types to refer to a J2EEUser and J2EERole. They are properties of the Principal returned, and often use product-specific hacks like 'instanceof' to determine whether one principal should be determined to be a group, or a user.

Lastly, support for JAAS isn't that big. Well, a few products support it, and the main benefit is for authentication against an existing domain (like NT) on your website's web app. But you really can't do much else with it, and since there are no standards for mapping to J2EE, most of the J2EE vendors don't support it very well. Indeed, you have products like WebSphere App Server that advertises itself as JAAS capable; but when you delve into the details, you find out that the support is fairly limited. This isn't a slant against WebSphere -- it provides its own Realm support for most things you'd want to do anyway -- but it's a damning verdict on JAAS as a whole. Here is a protocol, designed for doing authentication against any device, and instead of using it as standard, J2EE servers write their own Realm support.

If JAAS were a success, we'd have JAAS modules for authenticating against DB tables, against OS, and J2EE vendors would only provide a JAAS module. Instead, we've got a crap text file format for configuring it (which, despite JAAS being a standard, there's no definition of the file format; only examples on Sun's website -- which means that some app servers won't parse other server's legitimate files) and limited support for dealing with NT groups.

Don't get me wrong; the idea of JAAS is a good one. It's just been poorly rolled out. As is most often the case, ideas that have been grown by a community and developed (like the Servlets API) do the job, and do it well, whereas ideas designed by committe (or a benevolent/incompetent dictator) are often a pile of crap. One only has to look at the farcial XML Schemas to realise that ideas can be good, and implementations can suck.