Have you ever needed to create a login authentication mechanism for an application? Odds are, you have, and probably more than once, with each new implementation being close, but not identical, to the previous one. For example, one implementation might use an Oracle database, another might use an NT authentication, and another, an LDAP (lightweight access directory protocol) directory. Wouldn't it be nice to support all these security mechanisms without changing any application-level code?
Now in the Java world, you can with the Java Authentication and Authorization Service (JAAS). This relatively new API was an extension in J2SE (Java 2 Platform, Standard Edition) 1.3, is a core API in J2SE 1.4, and is also part of the J2EE (Java 2 Platform, Enterprise Edition) 1.3 specification. In this article, we'll teach you JAAS essentials and show you how to effectively apply JAAS to real-world applications. We based this article's application on our own experiences integrating JAAS into an existing Java Web-based system that used an RDBMS (relational database management system) for storing user login information. With JAAS, we designed more robust, flexible, and consistent login and authentication mechanisms.
You can download a complete set of working examples from Resources below (includes Java sources, JSPs (JavaServer Pages), JAAS configuration, with database and build scripts). We tested these examples using the Resin server with JDBC (Java Database Connectivity) and the MySQL database.
Java Authentication and Authorization: The big picture
Before JAAS, Java's security model was mostly shaped by its origin as a platform-independent language for distributed, networked applications. In its early days, Java often appeared as mobile code, such as browser-based applets, and therefore, the initial security model focused on protecting users based on where the code originated and who created it. Early Java security mechanisms such as SecurityManager
s, the sandbox concept, code signing, and policy files were all intended to protect users from the system.
The invention of JAAS reflects Java's evolution into a general-purpose programming language, used for implementing traditional client and server applications that require login and access control. JAAS protects the system from users by allowing or denying access based upon who or what runs the program. While JAAS can perform both authentication and authorization, in this article, we focus primarily on authentication.
JAAS can simplify your Java security development by putting an abstraction layer between your application and disparate underlying authentication and authorization mechanisms. This independence from platforms and algorithms allows you to use different security mechanisms without modifying your application-level code. As with most Java security APIs, JAAS achieves this implementation-independence through an extensible framework of pluggable service provider interfaces (SPIs): a set of abstract classes and interfaces to which specific implementations are developed.
Figure 1 below gives a high-level overview of how JAAS achieves this pluggability. Your application-layer code deals primarily with a LoginContext
. Underneath that LoginContext
is a set of one or more dynamically configured LoginModule
s, which handle the actual authentication using the appropriate security infrastructure.

JAAS provides some reference LoginModule
implementations, such as the JndiLoginModule
; you can also develop your own, as we'll do here with the RdbmsLoginModule
. We'll also show how you can quickly set up an application with a choice of implementations using a simple configuration file.
In addition to being pluggable, JAAS is stackable: in the context of a single login, a set of security modules can stack on top of one another, each called in order and each interacting with a different security infrastructure.
JAAS aspects are modeled on some familiar security architectural patterns and existing frameworks. The stackable feature, for example, deliberately resembles the Unix Pluggable Authentication Module (PAM) framework. From a transactional viewpoint, JAAS adopts behaviors similar to two-phase commit (2PC) protocols. JAAS's security configuration concepts, including Policy
files and Permissions
, come from the J2SE 1.2 security packages. JAAS also borrows ideas from other established security frameworks, such as X.509 certificates, from which the name Subject
is derived (you'll learn more about Subject
later).
Note: JAAS is just one of several new Java security APIs. For more on Java security, see the sidebar "The Java Security Puzzle" and Resources below.
Client- and server-side JAAS
You can apply JAAS on both the client and the server. Using it on the client side is straightforward, as we'll demonstrate shortly. On the server-side things grow a bit more complex. Currently, JAAS in the application server market is a bit inconsistent; J2EE app servers use JAAS slightly differently, depending on which one you use. For example, JBossSX, using their own architecture, nicely integrates JAAS into its overall security framework (which is detailed in Scott Stark's excellent JavaWorld article "Integrate Security Infrastructures with JBossSX" (August 2001)). However, though WebLogic 6.x supports JAAS, the details differ.
So you can understand JAAS from both server- and client-side perspectives, we'll demonstrate examples of both in this article. And for the purposes of simplicity on the server, we'll use the Resin application server so we can start off with a cleaner slate (Resin does have a pluggable authentication scheme of its own, but it's nonstandard, so using JAAS gives us more portability options later).
Core JAAS
To get started with JAAS, you must first ensure it's installed. J2SE 1.4 already includes JAAS; J2SE 1.3 does not. If you want to continue to use J2SE 1.3, download JAAS from Sun Microsystems. Once you download and install JAAS to a given directory, you will see a subdirectory called lib
, which contains one file named jaas.jar
. You'll need to add this file to your classpath or copy it to your JRE (Java Runtime Environment) extensions directory (in <jre-home>\lib\ext
, where <jre-home>
is your JRE's location). You are then JAAS-ready. Note: If you use an application server, it may already include JAAS. Check your server's documentation for details.
With any of these approaches, note that you can change some of the JAAS-related system property settings (as well as many other Java security settings) in the Java security properties file. This file, java.security
, is located in the <jre-home>/lib/security
directory and written in the standard Java properties file format.
Using JAAS authentication from your application typically involves the following steps:
- Create a
LoginContext
- Optionally pass a
CallbackHandler
to theLoginContext
, for gathering or processing authentication data - Perform authentication by calling the
LoginContext
'slogin()
method - Perform privileged actions using the returned
Subject
(assuming login succeeds)
Here's a minimal example:
LoginContext lc = new LoginContext("MyExample"); try { lc.login(); } catch (LoginException) { // Authentication failed. } // Authentication successful, we can now continue. // We can use the returned Subject if we like. Subject sub = lc.getSubject(); Subject.doAs(sub, new MyPrivilegedAction());
Underneath the covers, a few other things occur:
- During initialization, the
LoginContext
finds the configuration entry"MyExample"
in a JAAS configuration file (which you configured) to determine whichLoginModule
s to load (see Figure 2) - During login, the
LoginContext
calls eachLoginModule
'slogin()
method - Each
login()
method performs the authentication or enlists aCallbackHandler
- The
CallbackHandler
uses one or moreCallback
s to interact with the user and gather input - A new
Subject
instance is populated with authentication details such asPrincipal
s and credentials
We'll explain further details below, but to begin, let's look at the key JAAS classes and interfaces involved in the process. These are typically divided into the following three groups:
Common | Subject , Principal , credential (credential is not any specific class, but can be any object) |
Authentication | LoginContext , LoginModule , CallbackHandler , Callback |
Authorization | Policy , AuthPermission , PrivateCredentialPermission |
Most of these classes and interfaces are in the javax.security.auth
package's subpackages, with some prebuilt implementations in the com.sun.security.auth
package, included only in J2SE 1.4.
Note: Because we focus on authentication in this article, we don't delve into the authorization classes.
Common: Subjects, Principals, and Credentials
The Subject
class represents an authenticated entity: an end-user or administrator, or a Web service, device, or another process. The class contains three sets of security information types:
- Identities: In the form of one or more
Principal
s - Public credentials: Such as name or public keys
- Private credentials: Like passwords or private keys
Principal
s represent Subject
identities. They implement the java.security.Principal
interface (which predates JAAS) and java.io.Serializable
. A Subject
's most important method is getName()
, which returns an identity's string name. Since a Subject
instance contains an array of Principal
s, it can thus have multiple names. Because a social security number, login ID, email address, and so on, can all represent one user, multiple identities prove common in the real world.
The last element here, credential, is not a class or an interface, but can be any object. Credentials can include any authentication artifact, such as a ticket, key, or password, that specific security systems might require. The Subject
class maintains unique Set
s of private and public credentials, which can be retrieved with methods such as getPrivateCredentials()
and getPublicCrendentials()
. These methods are more often used by security subsystems than at the application layer.
Authentication: LoginContext
Your application layer uses LoginContext
as its primary class for authenticating Subject
s. LoginContext
also represents where JAAS's dynamic pluggability comes into play, because when you construct a LoginContext
, you specify a named configuration to load. The LoginContext
typically loads the configuration information from a text file, which in turn tells the LoginContext
which LoginModule
s to use during login.
The three commonly used methods in LoginContext
are:
login() | Performs login, a relatively complex step that invokes all LoginModule s specified for this configuration. If it succeeds, it creates an authenticated Subject . If it fails, it throws a LoginException . |
getSubject() | Returns the authenticated Subject . |
logout() | Logs out the authenticated Subject and removes its Principal s and credentials. |
We will show how to use these methods later.
Authentication: LoginModule
LoginModule
is the interface to specific authentication mechanisms. J2SE 1.4 ships with a set of ready-to-use LoginModules
, including:
JndiLoginModule | Verifies against a directory service configured under JNDI (Java Naming and Directory Interface) |
Krb5LoginModule | Authenticates using Kerberos protocols |
NTLoginModule | Uses the current user's NT security information to authenticate |
UnixLoginModule | Uses the current user's Unix security information to authenticate |
Along with these modules comes a set of corresponding concrete Principal
implementations in the com.sun.security.auth
package, such as NTDomainPrincipal
and UnixPrincipal
.
The LoginModule
interface has five methods:
initialize() | Called after the LoginModule is constructed. |
| Performs the authentication. |
commit() | Called by the LoginContext after it has accepted the results from all LoginModule s defined for this application. We assign Principal s and credentials to the Subject here. |
abort() | Called when any LoginModule for this application fails (even though earlier ones in sequence may have succeeded—thus akin to a 2PC model). No Principal s or credentials are assigned to the Subject . |
logout() | Removes the Principal s and credentials associated with the Subject . |
The application layer calls none of these methods directly—the LoginContext
invokes them as needed. Our example below will elaborate on these methods' implementations.
Authentication: CallbackHandlers and Callbacks
CallbackHandler
s and Callback
s let a LoginModule
gather necessary authentication information from a user or system, while remaining independent of the actual interaction mechanism. We'll leverage that capability in our design—our RdbmsLoginModule
does not depend on how the user credentials (username/password) are obtained and can thus be used in the different application environments we will illustrate (either from the command line or from a JSP).
JAAS comes with seven built-in Callback
s in the javax.security.auth.callback
package: ChoiceCallback
, ConfirmationCallback
, LocaleCallback
, NameCallback
, PasswordCallback
, TextInputCallback
, TextOutputCallback
. And J2SE 1.4 supplies two CallbackHandler
s in the com.sun.security.auth.callback
package: DialogCallbackHander
and TextCallbackHandler
. Many Callback
s resemble each other, and all are oriented towards client-side scenarios. We'll show you below how to develop your own CallbackHandler
later.
Configuration files
As we mentioned, much of JAAS's extensibility comes from its ability to be dynamically configured. This configuration is typically specified through a text file consisting of one or more configuration blocks, called applications. Each application is a set of one or more specified LoginModule
s.
When your code instantiates a LoginContext
, you pass it the name of one of the application blocks in the configuration file. The LoginContext
will use LoginModule
s based on what you specify in the application entry. These specifications drive which LoginModule
s are invoked, in which order, and according to which rules.
The configuration file has the following structure:
Application { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; ... }; Application { ModuleClass Flag ModuleOptions; ... }; ...
Here's an example of an application block named Sample
:
Sample { com.sun.security.auth.module.NTLoginModule Required debug=true; };
This basic application specifies that a LoginContext
should use the NTLoginModule
for authentication. The class name is specified in the ModuleClass
entry. The Flag
entry controls the login behavior when multiple modules exist for a single block. Flag
's four allowable values: Required
, Sufficient
, Requisite
, and Optional
. The most common is Required
, which means the module is always called, and its authentication must pass for the overall authentication to succeed. The Flag
field's idiosyncrasies can grow complex, and, since we're using only one module per block in our example, we won't go into elaborate detail here (see javax.security.auth.login.Configuration
's manual page for more specifics).
The ModuleOptions
entry allows any number of module-specific variables to be specified in name-value pairs. For example, many prebuilt login modules let you specify a debug flag such as debug=true
to see diagnostic output sent to System.out
.
The configuration file can have any name and location. A running JAAS framework locates it using the java.security.auth.login.config
system property. Running our sample application, JaasTest
, with a configuration file called jaas.config
, we would specify the location on the command line as follows: java -Djava.security.auth.login.config=jaas.config JaasTest
.
Figure 2 demonstrates the relationship among these configuration elements.

Login: Command line
To demonstrate what you can do with JAAS, we'll walk you through the development of two examples: a simple, traditional command-line program and a more complex server-side JSP application. Both will query the user for a username/password combination and authenticate using a RDBMS via JDBC.
To authenticate against the database, we:
- Create an
RdbmsLoginModule
that can authenticate against the data - Set up a configuration file that tells a
LoginContext
how to useRdbmsLoginModule
- Create a
ConsoleCallbackHandler
to gather user input - Add the application code to use the
RdbmsLoginModule
, the configuration file, and theConsoleCallbackHandler
In our RdbmsLoginModule
, we must implement the five methods defined in the LoginModule
interface. The first of these is the initialize()
method, which we define as follows:
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = options; url = (String)options.get("url"); driverClass = (String)options.get("driver"); debug = "true".equalsIgnoreCase((String)options.get("debug")); }
LoginContext
calls this method at the beginning of every call to its login()
method. As with typical LoginModule
s, RdbmsLoginModule
's first task is to keep a reference of the four arguments it has been given. The Subject
, which was either supplied at the application layer or created by the LoginContext
, can later be populated with Principal
s and credentials if we successfully authenticated. The CallbackHandler
will be used in our login()
method. The sharedState
Map
can share data across LoginModules
; a nice feature, but we won't use it in this example.
Last, but certainly not least, is the Map
of named options
. The options Map
is the way LoginModule
receives the option values from its corresponding ModuleOptions
field in the configuration file. When the LoginContext
loads the configuration, it creates a Map
from these name-value pairs and passes them through an options
parameter.
Our example's configuration file looks like this:
Example { RdbmsLoginModule required driver="org.gjt.mm.mysql.Driver" url="jdbc:mysql://localhost/jaasdb?user=root" debug="true"; };
As you can see, the RdbmsLoginModule
takes three options; driver
and url
are required, and debug
is optional. The first two options tell us how to make our JDBC connection: through a standard JDBC driver class name and a JDBC URL. A more advanced implementation might use additional option entries to specify a portion of the actual database query, such as the table or column names. The main idea is that you can use the configuration file to parameterize the JDBC access. Our LoginModule
's initialize()
method keeps a copy of each option.
Earlier, we mentioned that a LoginContext
's configuration file tells it which application entry to use. That information passes through the LoginContext
's constructor. Here's the initial application/client-layer code that creates and invokes LoginContext
(we will explain the CallbackHandler
shortly):
ConsoleCallbackHandler cbh = new ConsoleCallbackHandler(); LoginContext lc = new LoginContext("Example", cbh); lc.login();
Now when the LoginContext.login()
method is called, it will invoke the login()
method on all LoginModule
s it has loaded, which for this configuration is only our RdbmsLoginModule
.
Our login()
method then performs the following steps:
- Creates two
Callback
s that will receive username/password information from the user. It uses two of the built-in JAAS callbacks from thejavax.security.auth.callback
package:NameCallback
andPasswordCallback
. Both of these classes implement theCallback
interface, a marker interface with no methods. - Invokes the
Callback
s indirectly by passing them to thehandle()
method of theCallbackHandler
parameter specified in the call toinitialize()
. - Retrieves the username/password from the
Callback
s. - Uses the username/password in our own
rdbmsValidate()
method, which checks them against the database via a JDBC query.
This sequence is shown below in this snippet from RdbmsLoginModule
's login()
method:
public boolean login() throws LoginException { if (callbackHandler == null) throw new LoginException("no handler"); NameCallback nameCb = new NameCallback("user: "); PasswordCallback passCb = new PasswordCallback("password: ", true); callbacks = new Callback[] { nameCb, passCb }; callbackHandler.handle(callbacks); String username = nameCb.getName(); String password = new String(passCb.getPassword()); success = rdbmsValidate(username, password); return(true); }
Our rdbmsValidate()
method, if successful, assigns any Principal
s or credentials necessary for our application. You can view the rdbmsValidate()
method and the rest of this LoginModule
by downloading the code from Resources.
We can see how user interaction works with the Callback
s by examining the implementation of ConsoleCallbackHandler
's handle()
method:
public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { NameCallback nameCb = (NameCallback)callbacks[i]; System.out.print(nameCb.getPrompt()); String user=(new BufferedReader(new InputStreamReader(System.in))).readLine(); nameCb.setName(user); } else if (callbacks[i] instanceof PasswordCallback) { PasswordCallback passCb = (PasswordCallback)callbacks[i]; System.out.print(passCb.getPrompt()); String pass=(new BufferedReader(new InputStreamReader(System.in))).readLine(); passCb.setPassword(pass.toCharArray()); } else { throw(new UnsupportedCallbackException(callbacks[i], "Callback class not supported")); } } }
Login: Use JAAS plus JSP plus RDBMS
Now that we have our command-line version working, we want to reuse it in a Web application. You might be asking yourself, "Well, how the heck am I supposed to launch a command prompt for a Web user to login?"
And you're right—that login approach won't work. Because of the differences between traditional JAAS callback-based authentication and stateless HTTP, we can't use any of the provided standard Callback
s or CallbackHandler
s; they just don't make sense for connectionless HTTP, and you can't very well open up a command prompt for user input.
You might also be thinking that we could instead use HTTP basic authentication, whereby we could get the input through the browser's pop-up Username/Password dialog box. But that has many complications; it requires multiple round-trip HTTP connections (hard to do from our single login()
method) and is used less often than form-based Web logins. We'll follow the form-based Web approach in this article's example: we'll get the information from an HTML form and process it via our RdbmsLoginModule
.
Given that we don't interact with our LoginModule
directly from the application layer, only indirectly through the LoginContext
, how we will get our username and password from the form into our LoginModule
for authentication is not immediately apparent. Alternatives are available. One option: Prior to creating the LoginContext
, we could instantiate a Subject
and store the username and password in that Subject
's credentials. Then we could supply this prepopulated Subject
to the LoginContext
constructor. Although technically that would work, it's a bit unwieldy as it adds more security-related code at the application layer, and Subject
s are typically populated after authentication, not before.
But given, as we showed above, that we can create our own CallbackHandler
and give that to the LoginContext
, we can use a similar design here to manage our username/password data. To do that, we created a new class called PassiveCallbackHandler
. Here's how we'll use it from our JSP:
String user = request.getParameter("user"); String pass = request.getParameter("pass"); PassiveCallbackHandler cbh = new PassiveCallbackHandler(user, pass); LoginContext lc = new LoginContext("Example", cbh);
Our new CallbackHandler
has a constructor that takes the username and password so it doesn't actually need to prompt anyone for information. Then later it simply sets the appropriate values in the Callback
s so the LoginModule
can remove them as it did in the command-line example. Here's how the PassiveCallbackHandler
's handle()
method works:
public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { NameCallback nameCb = (NameCallback)callbacks[i]; nameCb.setName(user); } else if(callbacks[i] instanceof PasswordCallback) { PasswordCallback passCb = (PasswordCallback)callbacks[i]; passCb.setPassword(pass.toCharArray()); } else { throw(new UnsupportedCallbackException(callbacks[i], "Callback class not supported")); } } } }
We only removed a line or two from the ConsoleCallbackHandler
—the lines that prompted for user input. Thus, we decided to call our implementation passive: because it does not need to interact with the user.
A note about using this example from JSP: We need to set the system property so the LoginContext
knows where to look for the "Example"
login configuration. In this example, we use the Resin application server. With its configuration setup, we edit the resin.conf
file, and add a node under the <caucho.com>
node that looks like this:
<system-property java.security.auth.login.config="/resin/conf/jaas.config"/>
Here are some additional ideas for JSP-based JAAS:
- By creating a
CallbackHandler
with anHttpServletRequest
argument, you can authenticate using additional information from the request, including the client's IP address. - By having your
LoginContext
also implement theHttpSessionBindingListener
interface, you can log users out when their sessions end (see example classSessionLoginContext
). - Some application servers' proprietary authentication and authorization interfaces can integrate with JAAS. For example, you can build an implementation of the Jakarta Project's Tomcat Realm interface, which verifies access for users of Tomcat Web applications, around JAAS code.
Other notes
We detailed the authentication half of JAAS only. If you're interested in learning more about the authorization half, including Policies
and Permissions
, we list many Resources below.
Note that you can use server-side JAAS as the basis for a single sign-on framework, whereby a user is authenticated once and is subsequently granted appropriate access to multiple protected systems and services. Such a framework might use JAAS for authentication and JNDI (Java Naming and Directory Interface) for accessing secured services.
Develop more secure apps with JAAS
By providing a dynamic and extensible model for authenticating users and controlling permissions, JAAS gives you the tools to add more robust security to your applications. The flexibility of creating your own login mechanisms, while simultaneously leveraging prebuilt modules and a consistent framework, is a big plus.
JAAS works both on client-side and server-side applications. Though the state of affairs for JAAS on the server is certainly in flux right now, it will certainly stabilize going forward. As long as you're aware of what JAAS is and how it works, you'll be in a good position to leverage its capabilities however it evolves.
Learn more about this topic
- Download the source code that accompanies this article
http://images.techhive.com/downloads/idge/imported/article/jvw/2002/09/jw-0913-jaas.zip - Sun's JAAS homepage
http://java.sun.com/products/jaas - Scott Stark's "Integrate Security Infrastructures with JBossSX" (JavaWorld, August 2001) features detailed examples of standard J2EE declarative security (for both Enterprise JavaBeans and Web applications), covers JAAS, and explains how to set up security domains within JBoss
http://www.javaworld.com/javaworld/jw-08-2001/jw-0831-jaas.html - "Java Security Evolution and Concepts," Raghavan N. Srinivas (JavaWorld)
- Part 1Learn computer security concepts and terms in this introductory overview (April 2000)
- Part 2Discover the ins and outs of Java security (July 2000)
- Part 3Tackle Java applet security with confidence (December 2000)
- Part 4Learn how optional packages extend and enhance Java security (May 2001)
- Part 5J2SE 1.4 offers numerous improvements to Java security (December 2001)
- Sun's J2SE 1.4 includes JAAS as well as Java Cryptography Extension (JSE), Java Secure Socket Extension (JSSE), Generic Security Service (GSS) API, and the Certificate Path API
http://java.sun.com/j2se/1.4 - Reference page for javax.security.auth.login.Configuration, which details the structure and semantics of the login configuration file
http://java.sun.com/j2se/1.4/docs/api/javax/security/auth/login/Configuration.html - BEA's guide to using JAAS with WebLogic
http://e-docs.bea.com/wls/docs61/security/prog.html#1039659 - Sun's Java security homepage
http://java.sun.com/security/ - JSR (Java Specification Request) 115Java Authorization Contract for Containers
http://www.jcp.org/jsr/detail/115.jsp.com - Sun's paper on understanding its Pluggable Authentication Framework (PAM), "Making Login Services Independent of Authentication Technologies," Vipin Samar and Charlie Lai
http://java.sun.com/security/jaas/doc/pam.html - Resin application server homepage
http://www.caucho.com/ - MySQL open source database homepage
http://www.mysql.com - For more security stories, visit the Security section of JavaWorld's Topical Index
http://www.javaworld.com/channel_content/jw-security-index.shtml - Browse the JavaServer Pages section of JavaWorld's Topical Index
http://www.javaworld.com/channel_content/jw-jsp-index.shtml - Discuss security in our Java Security discussion
http://forums.idg.net/webx?230@@.ee6b80e!skip=166 - For more security-related articles, sign up for JavaWorld's free weekly Applied Java email newsletter
http://www.javaworld.com/subscribe - You'll find a wealth of IT-related articles from our sister publications at IDG.net