JAAS Authentication — An Introduction

Introduction

This article introduces JAAS authentication via a relatively simple example. The example presented here is based upon the Sun tutorial of the same subject. The thinkmiddleware.com example extends the tutorial to use LDAP to authenticate users.

JAAS

JAAS–Java Authentication and Authorization Service–was introduced in Java 1.3 as an optional extension to J2SE, but became required in Java1.4.0. As the name would imply, JAAS provides for authentication and authorization. JAAS is not dependent on any particular authentication technology; JAAS is a pure-Java version of PAM (Pluggable Authentication Module). JAAS authorization extends the Java Security Manager to grant permissions and make authorization decisions based upon who is executing the code. This tutorial focuses only on the authentication aspect of JAAS.

Although, not a required piece of the J2EE Security specification, the J2EE community encourages the use of JAAS under the covers of J2EE Security. Some of the major J2EE Container vendors use JAAS under the covers to implement their security sub-systems; however, all J2EE Containers are required to provide partial support for JAAS through the Java Connector Architecture Specification. So, “security credentials” will generally refer to a JAAS Subject in a J2EE Container, but it is not required.

JAAS Concepts/Nomenclature

JAAS introduces several new concepts and terminology that are briefly described here. For additional information, refer to the JAAS Reference Manual.

Subject

A Subject is an abstraction that represents the source of a request; this source could be a person, a computer system, a program, or your toaster. A Subject is represented by javax.security.auth.Subject. After the source of a request is authenticated, a JAAS Subject is created.

The Subject is a wrapper for other pieces of security information that belong to the represented entity. The Subject contains Principals, Private Credential objects, and Public Credential objects. These items are discussed below.

Principal

A Principal can be associated with a Subject after successful authentication; these objects give a name to the represented entity. A Principal object implements java.security.Principal
and java.io.Serializable. There can be zero or more Principals associated with a Subject.

A Principal will often be the “username” of the calling entity.

Credentials

Credential objects contain anything that an entity uses to prove its identity. A credential can be any Java object. How a Credential object is used is defined by the application; in other words, a Credential objects . The semantics of Credential Objects are defined entirely by the application(s) making authorization decisions. There are two types of Credential objects: public and private.

Private Credentials

Private Credential objects contain information that is private. These objects contain information that the calling entity would not want to become public. For example, a password or social security number.

Public Credentials

Public Credential objects contain information that is public. These objects contain information that can be seen by the public.

Login Module

A Login Module performs the actual authentication step. For example, it may compare a username and password to information stored in LDAP by attempting to bind to LDAP with the provided credentials (what the example given in this article does). Upon successful authentication, a Login Module associates a Subject with Principals, Private Credentials, and Public Credentials. The JAAS LoginModule Developer’s Guide should be reviewed before creating Login Modules.

Login Context

A LoginContext object describes the authentication methods used by an application. It allows the application to be developed independently of the authentication mechanisms. The LoginContext requires an application name–this maps to a list of Login Modules in the JAAS Configuration file (given on the command line).

Callbacks

Implementations of the javax.security.auth.Callback Interface allow security service implementations to get information from a calling application. For example, the JSE comes with Callback implementations that can retrieve userids & passwords from applications and return errors to applications. A developer can also write custom callback implementations, but the default Callback implementations can handle many cases.

Callback Handler

Each application using JAAS must create a Callback Handler, which implements the CallbackHandler Interface. The CallbackHandler gathers information for Callbacks–see above.

A default CallbackHandler implementation class can be specified by setting the “auth.login.defaultCallbackHandler” property in $JRE_HOME/lib/security/java.security.

Authentication

Authentication is the process of a calling entity proving it is who or what it claims. The Sun JAAS Authentication tutorial provides detailed information of how this is accomplished.

Authorization

Authorization is the process of making a determination of whether a calling entity has the necessary permission(access) to perform some action. JAAS enhances the basic Java Security Manager to be able to grant permissions based upon user/caller. This is the basic idea behind JAAS Authorization. See the JAAS Authorization tutorial for more information.

JAAS Configuration File

Java Applications running JAAS need to pass the java process an “-Djava.security.auth.login.config=-path_to_file” parameter to configure JAAS. For the thinkmiddleware.com example presented below, the configuration file contains the following:

ThinkMiddleware
{
com.tm.jaas.module.TMModule required;
};

This tells the LoginContext object to use the TMModule LoginModule when instantiated with “ThinkMiddleware” as the application name. More information about this file can be found in the JAAS Tutorial.

JAAS Tutorial

Several references to various sections of the Sun JAAS Reference Guide have been made in this article. The Thinkmiddlware.com example is largely based upon it–we just added LDAP authentication support.

Openldap

Look at the Thinkmiddleware.com OpenLdap setup instructions to build an Openldap database that can be used with this tutorial and the JNDI tutorial.

More information about Openldap can be found here

JNDI — Java Naming & Directory Interface

JNDI concepts and examples are presented in this Thinkmiddleware.com article.

Thinkmiddleware.com Example Using JNDI To Authenticate Against LDAP

The Sun JAAS Authentication Tutorial was used as a starting point for the following example. It was extended to authenticate users by binding to LDAP using JNDI.

The primary classes used to implement this example are given below:

LoginExample
TMCallbackHandler
TMPrincipal
TMModule

The JNDI & LDAP code used in this example can be found here.

An Ant build.xml that can build this project is here

The tm_jaas.config file can be found here.

If a user is successfully authenticated, the following output is produced:

$ ant run
Buildfile: build.xml

config:

copyProperties:

init:

compile:

copies:

jars:

build:

run:
Username:
1234
Password:
secret
Authentication successed
Authentication Succeeded
Full dump of JAAS Subject
JAAS Subject: Subject:
Principal: TMPrincipal: 1234

Principal: 1234
Public Credentials:
Private Credentials:

BUILD SUCCESSFUL
Total time: 5 seconds

So, 1234/secret is a valid username/password combination. If invalid credentials were given, the output would look like:

$ ant run
Buildfile: build.xml

config:

copyProperties:

init:

compile:

copies:

jars:

build:

run:
Username:
12345
Password:
secret
javax.naming.AuthenticationException: [LDAP: error code 49 – Invalid Credentials]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:2985)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2931)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2732)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2646)
at com.sun.jndi.ldap.LdapCtx.(LdapCtx.java:283)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:247)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.(InitialContext.java:197)
at javax.naming.directory.InitialDirContext.(InitialDirContext.java:82)
at com.tm.jndi.ldap.JndiLdapConnection.connect(JndiLdapConnection.java:134)
at com.tm.jndi.ldap.JndiLdapConnection.connect(JndiLdapConnection.java:104)
at com.tm.jaas.module.TMModule.login(TMModule.java:139)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
at com.tm.jaas.LoginExample.authenticate(LoginExample.java:87)
at com.tm.jaas.LoginExample.main(LoginExample.java:77)
com.tm.jndi.ldap.ConnectionException
at com.tm.jndi.ldap.JndiLdapConnection.connect(JndiLdapConnection.java:142)
at com.tm.jndi.ldap.JndiLdapConnection.connect(JndiLdapConnection.java:104)
at com.tm.jaas.module.TMModule.login(TMModule.java:139)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
at com.tm.jaas.LoginExample.authenticate(LoginExample.java:87)
at com.tm.jaas.LoginExample.main(LoginExample.java:77)
javax.security.auth.login.FailedLoginException: Login Incorrect
at com.tm.jaas.module.TMModule.login(TMModule.java:151)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
at com.tm.jaas.LoginExample.authenticate(LoginExample.java:87)
at com.tm.jaas.LoginExample.main(LoginExample.java:77)

BUILD SUCCESSFUL
Total time: 4 seconds

The JNDI LDAP API threw an “Invalid Credentials” exception. This, in turn, caused the JndiLdapConnection.connect() method to through a ConnectionException, which resulted in the TMModule.login() method throwing a FailedLoginException. The FailedLoginException was returned to the calling application attempting to authenticate 12345/secret,which is not a valid userid and password in the OpenLdap database.

Dumping JAAS Subject Contents

The LoginExample.java program contains a dumpJAASSubject() method that prints out the contents of all Principal, Private Credential, and Public Credential objects contained in the JAAS Subject. See this article for more information.

Reference

[1] www.openldap.org
[2] http://www.openldap.org/doc/admin24/quickstart.html
[3] http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASRefGuide.html
[4] http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tutorials/GeneralAcnOnly.html
[5] http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tutorials/GeneralAcnAndAzn.html
[6] http://en.wikipedia.org/wiki/Pluggable_Authentication_Modules
[7] http://thinkmiddleware.com/blog01/2008/11/15/the-java-security-manager
[8] http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/LoginContext.html
[9] http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/callback/Callback.html
[10] http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASLMDevGuide.html