User Identification and Authentication

When you log in to a machine running a multi-user operation system at console or through TELNET, you supply a login name and a password. The login name identifies you to the system by making an association with an existing entry in the user account subsystem, the entry representing you as a valid system user. Within the system, a different value may be used as the user identity to simplify processing. For example, most of the UNIX systems use an integer value, known as userid, to identify the user.

Mere knowledge of the login name is no guarantee that it is indeed you who is at the keyboard, for the login name is likely to be known to others. What you need is the ability to prove the identity claim or, in other words, authenticate yourself to the system. This proof can be one or more of the following:

  • Something that only you know

  • Something you are

  • Something that you possess

Needless to say, the system must have been fed with appropriate information at the time of account creation to handle the corresponding form of authentication. The simplest and most widely used form of authentication is to assign the user a short sequence of characters, known as a password, and let the system verify whether the user-supplied password matches with the account entry or not. To keep the password secret, the system stores a one-way hash of the password within the account entry. On being presented the password, it computes the one-way hash and matches it with the stored hash value. A positive match implies a successful authentication.

Though less often used, there are other mechanisms besides simple password-based authentication: X.509 certificate, security card, retinal scan, fingerprint, and so on. Sometimes a combination is used for enhanced security and/or better coverage.

A modern organization has a large number of different systems and it would be quite burdensome, for the system administrators as well as users, if each system maintained its own user accounts and issued different passwords. A number of organizations are moving toward a single sign-on solution for the employees, a system where all user accounts are maintained on a central system and different operating systems and applications use this system for user identification and authentication. Solutions like Microsoft Passport and Liberty Project allow single sign-on or shared identity management even across websites belonging to different organization for Web users.

It may be okay for some applications to dictate a specific account management system and authentication mechanism but in general, these decisions are better made at deployment time. Quite often, it is desirable to hook-in with the existing identification and authentication system available within the enterprise. The application development and deployment platform must allow this flexibility.

The identification and authentication support in Java meets the challenge posed by these trends and expectations through JAAS. JAAS has a powerful framework to represent users, user identities, user account systems, deployment time configuration, and permissions associated with user identities. We go through these details in this and subsequent sections.

User Login in a Java Application

As we have seen in Example #4, a Java application allows a user to login by invoking login() method on a javax.security.auth.login.LoginContext object. The application constructs a LoginContext object, specifying a login configuration name and a javax.security.auth.callback.CallbackHandler handler.

// Code fragment from DisplayFileLauncher.java
LoginContext lc = new LoginContext("DF", new DFCallbackHandler());
lc.login();

This code fragment is responsible for prompting the user for relevant identification and authentication information and carrying out the authentication as per the configured user account systems or login modules, as they are known in the Java context.

Login Configuration

The login configuration name identifies a specific entry in the login configuration database. This database is initialized and accessed through a concrete subclass of abstract class javax.security.auth.login.Configuration. This class, known as the login configuration provider, is specified in the security configuration file %JRE_HOME%libsecurityjava.security as the value of property login.configuration.provider. By default, this property is set to com.sun.security.auth.login.ConfigFile, a class that initializes the configuration database by reading one or more files. Though it is possible to specify a different configuration provider and change the behavior, we limit our discussion in rest of this section as per the default provider.

The login configuration database is read from one or more files specified through the login.config.url.<n> properties in security configuration file java.security. In cases where n >= 2, the resulting database is a union of the entries in the individual files. Optionally, the configuration file may be specified through system property java.security.auth.login.config, as is done in the following command of the illustrated example:

C:>java -Djava.security.manager -Djava.security.policy=df4.policy 
							-Djava.security.auth.login.config=login.conf -cp df.jar;dfl.jar 
							DisplayFileLauncher DisplayFile.java
						

If no configuration file is specified in java.security file or through the system property, an attempt is made to load a login configuration from URL "file:${user.home}/.java.login.config".

The syntax of a login configuration file is shown below using the following syntax: terms within square braces are optional (e.g., can have zero or one occurrence) and those within normal braces followed by a '+' sign can have one or more occurrences. Italicized terms are variables and must be replaced by specific values for a particular context.

(EntryName "{"
  (LoginModuleClass Flag [ModuleOptions] ";")+
"}" ";")+
Flag := "Required" | "Requisite" | "Sufficient" |
           "Optional"

As we can see, each entry is a stack of login module specifications and is identified by EntryName. This is the name used by the LoginContext constructor to access a particular entry from the configuration database. A login module specification consists of the fully qualified name of class that implements the login module functionality and interfaces with a user account system, a flag indicating the behavior of the authentication process with respect to the stack of login modules and certain options in the form of name value pairs that are passed to the login module.

A login module is essentially a Java class that implements the interface javax.security.auth.spi.LoginModule. A number of login modules, all under the package com.sun.security.auth.module, come bundled with J2SE v1.4 SDK. Table 5-1 lists these with brief descriptions.

Table 5-1. LoginModules bundled with J2SE v1.4 SDK
LoginModuleDescription
JndiLoginModuleAuthenticates a user against username and password stored in a directory service configured via JNDI.
KeyStoreLoginModuleAuthenticates a user against alias and password corresponding to a key entry in a keystore file.
Krb5LoginModuleAuthenticates a user using Kerberos protocol.
NTLoginModuleAuthenticates a user against security information of Windows NT system.
UnixLoginModuleAuthenticates a user against users and passwords in a UNIX or Linux system.

More information about these modules and the steps in developing your own login modules can be found in references given in the Further Reading section. Later on in the chapter, we develop a login module of our own to illustrate the various steps and have something to use in our examples.

The authentication process initiated by login() method of LoginContext starts with the first login module in the configuration entry and proceeds down the stack as per the flag associated with the current login module:

Required – Authentication must succeed. Continue on success or failure.

Requisite – Authentication must succeed. Continue on success. Return on failure.

Sufficient – Authentication need not succeed. Return on success. Continue on failure.

Optional – Authentication need not succeed. Continue on success or failure.

Let us look at a sample login configuration file:

// A sample login configuration file.
Login1 {
  com.sun.security.auth.module.KeyStoreLoginModule required
    keyStoreURL="file:test.ks";
};

Login2 {
  com.sun.security.auth.module.KeyStoreLoginModule required
    keyStoreURL="file:test.ks";
  com.sun.security.auth.module.NTLoginModule sufficient;
  com.sun.security.auth.module.Krb5LoginModule optional
debug=true;
};

Interpretation of this file is left as an exercise for the reader.

Callback Handler

A login module needs to collect some information from the user, such as user name and password, during the authentication process. This interaction is through a class implementing interface javax.security.auth.callback.Callbackhandler. This handler can be specified either by setting the security property auth.login.defaultCallbackHandler in the security configuration file java.security or as an argument to the LoginContext constructor.

We have already seen the source code of one such handler—DFCallbackHandler. The handle() method of CallbackHandler is invoked by a login module, passing an array of javax.security.auth.callback.Callback objects as argument. The code in handle() method could examine the individual objects in this array, retrieve prompt strings, display them to the user, read the user input and set the Callback attributes. Refer to the file DFCallbackhandler.java for sample code performing these steps.

It is up to the handle() method written by the application developer to decide whether to prompt the user through standard output or use a GUI window to collect user credentials. In fact, this code can also arrange to get the user credentials from command line arguments, environment variables or another program!

Running Code on Behalf of a User

An instance of LoginContext maintains information about a user in an instance of javax.security.auth.Subject. After successful execution of login() method this instance of Subject is initialized with the user credentials, including different user identities in form of java.security.Principal objects.

To run code on behalf of the user represented by a Subject instance, the code must be invoked from the run() method of a class implementing interface PrivilegedAction or PrivilegedExceptionAction (both are in the package java.security), and the Subject instance and an instance of this class must be passed to the static method doAs() of the class Subject.

// Class MyAction implements PrivilegedExceptionAction.
PrivilegedExceptionAction action = new MyAction();
Subject.doAs(lc.getSubject(), action);

You can get the Subject associated with the running code by calling Subject.getSubject(AccessController.getContext()).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.52.124