LoginModule
Developer's Guide
LoginModule
LoginModule
Implementation
LoginModule
Methods
LoginModule
and
Application
LoginModule
LoginModule
Implementation
LoginModule
JAR File and
Documents Available
The JavaTM Authentication and Authorization Service (JAAS) was introduced as an optional package to the JavaTM 2 SDK, Standard Edition (J2SDK), v 1.3. JAAS was integrated into the Java TM Standard Edition Development Kit starting with J2SDK 1.4.
JAAS provides subject-based authorization on authenticated identities. This document focuses on the authentication aspect of JAAS, specifically the
LoginModule
interface.Who Should Read This Document
This document is intended for experienced programmers who require the ability to write a
LoginModule
implementing an authentication technology.Related Documentation
This document assumes you have already read the following:
It also discusses various classes and interfaces in the JAAS API. Please reference the javadocs for the JAAS API specification for more detailed information:
- javax.security.auth Package
- javax.security.auth.callback Package
- javax.security.auth.kerberos Package
- javax.security.auth.login Package
- javax.security.auth.spi Package
- javax.security.auth.x500 Package
- com.sun.security.auth Package
- com.sun.security.auth.callback Package
- com.sun.security.auth.login Package
- com.sun.security.auth.module Package
The following tutorials for JAAS authentication and authorization can be run by everyone:
Similar tutorials for JAAS authentication and authorization, but which demonstrate the use of a Kerberos LoginModule and thus which require a Kerberos installation, can be found at
These two tutorials are a part of the Java GSS-API and JAAS sequence of tutorials that utilize Kerberos as the underlying technology for authentication and secure communication.
Introduction
The
LoginModule
documentation describes the interface that must be implemented by authentication technology providers.LoginModule
s are plugged in under applications to provide a particular type of authentication.While applications write to the
LoginContext
Application Programming Interface (API), authentication technology providers implement theLoginModule
interface. AConfiguration
specifies theLoginModule
(s) to be used with a particular login application. DifferentLoginModule
s can be plugged in under the application without requiring any modifications to the application itself.The
LoginContext
is responsible for reading theConfiguration
and instantiating the specifiedLoginModule
s. EachLoginModule
is initialized with aSubject
, aCallbackHandler
, sharedLoginModule
state, andLoginModule
-specific options.The
Subject
represents the user or service currently being authenticated and is updated by aLoginModule
with relevantPrincipal
s and credentials if authentication succeeds.LoginModule
s use theCallbackHandler
to communicate with users (to prompt for user names and passwords, for example), as described in the login method description. Note that theCallbackHandler
may be null. ALoginModule
that requires aCallbackHandler
to authenticate theSubject
may throw aLoginException
if it was initialized with anull
CallbackHandler
.LoginModule
s optionally use the shared state to share information or data among themselves.The
LoginModule
-specific options represent the options configured for thisLoginModule
in the loginConfiguration
. The options are defined by theLoginModule
itself and control the behavior within it. For example, aLoginModule
may define options to support debugging/testing capabilities. Options are defined using a key-value syntax, such as debug=true. TheLoginModule
stores the options as aMap
so that the values may be retrieved using the key. Note that there is no limit to the number of options aLoginModule
chooses to define.The calling application sees the authentication process as a single operation invoked via a call to the
LoginContext
'slogin
method. However, the authentication process within eachLoginModule
proceeds in two distinct phases. In the first phase of authentication, theLoginContext
'slogin
method invokes thelogin
method of eachLoginModule
specified in theConfiguration
. Thelogin
method for aLoginModule
performs the actual authentication (prompting for and verifying a password for example) and saves its authentication status as private state information. Once finished, theLoginModule
'slogin
method returnstrue
(if it succeeded) orfalse
(if it should be ignored), or it throws aLoginException
to specify a failure. In the failure case, theLoginModule
must not retry the authentication or introduce delays. The responsibility of such tasks belongs to the application. If the application attempts to retry the authentication, eachLoginModule
'slogin
method will be called again.In the second phase, if the
LoginContext
's overall authentication succeeded (calls to the relevant required, requisite, sufficient and optionalLoginModule
s'login
methods succeeded), then thecommit
method for eachLoginModule
gets invoked. (For an explanation of theLoginModule
flags required, requisite, sufficient and optional, please consult thejavax.security.auth.login.Configuration
documentation and Appendix B: Login Configuration Files in the JAAS Reference Guide.) Thecommit
method for aLoginModule
checks its privately saved state to see if its own authentication succeeded. If the overallLoginContext
authentication succeeded and theLoginModule
's own authentication succeeded, then thecommit
method associates the relevantPrincipal
s (authenticated identities) and credentials (authentication data such as cryptographic keys) with theSubject
.If the
LoginContext
's overall authentication failed (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONALLoginModule
s'login
methods did not succeed), then theabort
method for eachLoginModule
gets invoked. In this case, theLoginModule
removes/destroys any authentication state originally saved.Logging out a
Subject
involves only one phase. TheLoginContext
invokes theLoginModule
'slogout
method. Thelogout
method for theLoginModule
then performs the logout procedures, such as removingPrincipal
s or credentials from theSubject
, or logging session information.
LoginModule
The steps required in order to implement and test a
LoginModule
are the following:
- Step 1: Understand the Authentication Technology
- Step 2: Name the
LoginModule
Implementation- Step 3: Implement the Abstract
LoginModule
Methods- Step 4: Choose or Write a Sample Application
- Step 5: Compile the
LoginModule
and Application- Step 6: Prepare for Testing
- Step 6a: Place Your
LoginModule
and Application Code in JAR Files- Step 6b: Decide Where to Store the JAR Files
- Step 6c: Set
LoginModule
and Application JAR File Permissions- Step 6d: Create a Configuration Referencing the LoginModule
- Step 7: Test Use of the
LoginModule
- Step 8: Document Your
LoginModule
Implementation- Step 9: Make
LoginModule
JAR File and Documents AvailableThe steps required to implement and test a new
LoginModule
follow. Please reference the SampleLoginModule and other files described in the JAAS Reference Guide for examples of what may be done for the various steps.
Step 1: Understand the Authentication Technology
The first thing you need to do is understand the authentication technology to be implemented by your newLoginModule
provider, and determine its requirements.One thing you will need to determine is whether or not your
LoginModule
will require some form of user interaction (retrieving a user name and password, for example). If so, you will need to become familiar with theCallbackHandler
interface and thejavax.security.auth.callback
package. In that package you will find several possibleCallback
implementations to use. (Alternatively, you can create your ownCallback
implementations.) TheLoginModule
will invoke theCallbackHandler
specified by the application itself and passed to theLoginModule
'sinitialize
method. TheLoginModule
passes theCallbackHandler
an array of appropriateCallback
s. See the login method in Step 3.Note that it is possible for
LoginModule
implementations not to have any end-user interactions. SuchLoginModule
s would not need to access thecallback
package.Another thing you should determine is what configuration options you want to make available to the user, who specifies configuration information in whatever form the current Configuration implementation expects (for example, in files). For each option, decide the option name and possible values. For example, if a
LoginModule
may be configured to consult a particular authentication server host, decide on the option's key name ("auth_server", for example), as well as the possible server hostnames valid for that option ("server_one.foo.com" and "server_two.foo.com", for example).Step 2: Name the
LoginModule
ImplementationDecide on the proper package and class name for yourLoginModule
.For example, a
LoginModule
developed by IBM might be calledcom.ibm.auth.Module
wherecom.ibm.auth
is the package name andModule
is the name of theLoginModule
class implementation.Step 3: Implement the Abstract
LoginModule
MethodsThe
See below and theLoginModule
interface specifies five abstract methods that require implementations:LoginModule
API for more information on each method above.In addition to these methods, a
LoginModule
implementation must provide a public constructor with no arguments. This allows for its proper instantiation by aLoginContext
. Note that if no such constructor is provided in yourLoginModule
implementation, a default no-argument constructor is automatically inherited from theObject
class.public void initialize (Subject subject,
CallbackHandler handler,
Map<java.lang.String, ?> sharedState,
Map<java.lang.String, ?> options) { ... }The
initialize
method is called to initialize theLoginModule
with the relevant authentication and state information.This method is called by a
LoginContext
immediately after thisLoginModule
has been instantiated, and prior to any calls to its other public methods. The method implementation should store away the provided arguments for future use.The
initialize
method may additionally peruse the provided sharedState to determine what additional authentication state it was provided by otherLoginModule
s, and may also traverse through the provided options to determine what configuration options were specified to affect theLoginModule
's behavior. It may save option values in variables for future use.Note: JAAS LoginModules may use the options defined in PAM (
use_first_pass
,try_first_pass
,use_mapped_pass
, andtry_mapped_pass
) to achieve single-signon. See Making Login Services Independent from Authentication Technologies for further information.Below is a list of options commonly supported by LoginModules. Note that the following is simply a guideline. Modules are free to support a subset (or none) of the following options.
try_first_pass
- Iftrue
, the first LoginModule in the stack saves the password entered, and subsequent LoginModules also try to use it. If authentication fails, the LoginModules prompt for a new password and retry the authentication.
use_first_pass
- Iftrue
, the first LoginModule in the stack saves the password entered, and subsequent LoginModules also try to use it. LoginModules do not prompt for a new password if authentication fails (authentication simply fails).
try_mapped_pass
- Iftrue
, the first LoginModule in the stack saves the password entered, and subsequent LoginModules attempt to map it into their service-specific password. If authentication fails, the LoginModules prompt for a new password and retry the authentication.
use_mapped_pass
- Iftrue
, the first LoginModule in the stack saves the password entered, and subsequent LoginModules attempt to map it into their service-specific password. LoginModules do not prompt for a new password if authentication fails (authentication simply fails).
moduleBanner
- Iftrue
, then when invoking the CallbackHandler, the LoginModule provides a TextOutputCallback as the first Callback, which describes the LoginModule performing the authentication.
debug
- Iftrue
, instructs a LoginModule to output debugging information.The
initialize
method may freely ignore state or options it does not understand, although it would be wise to log such an event if it does occur.Note that the
LoginContext
invoking thisLoginModule
(and the other configuredLoginModule
s, as well), all share the same references to the providedSubject
andsharedState
. Modifications to theSubject
andsharedState
will, therefore, be seen by all.boolean login() throws LoginException;
The
login
method is called to authenticate aSubject
. This is phase 1 of authentication.This method implementation should perform the actual authentication. For example, it may cause prompting for a user name and password, and then attempt to verify the password against a password database. Another example implementation may inform the user to insert their finger into a fingerprint reader, and then match the input fingerprint against a fingerprint database.
If your
LoginModule
requires some form of user interaction (retrieving a user name and password, for example), it should not do so directly. That is because there are various ways of communicating with a user, and it is desirable forLoginModule
s to remain independent of the different types of user interaction. Rather, theLoginModule
'slogin
method should invoke thehandle
method of the theCallbackHandler
passed to theinitialize
method to perform the user interaction and set appropriate results, such as the user name and password. TheLoginModule
passes theCallbackHandler
an array of appropriateCallback
s, for example a NameCallback for the user name and a PasswordCallback for the password, and theCallbackHandler
performs the requested user interaction and sets appropriate values in theCallback
s. For example, to process aNameCallback
, theCallbackHandler
may prompt for a name, retrieve the value from the user, and call theNameCallback
'ssetName
method to store the name.The authentication process may also involve communication over a network. For example, if this method implementation performs the equivalent of a kinit in Kerberos, then it would need to contact the KDC. If a password database entry itself resides in a remote naming service, then that naming service needs to be contacted, perhaps via the Java Naming and Directory Interface (JNDI). Implementations might also interact with an underlying operating system. For example, if a user has already logged into an operating system like Solaris or Windows NT, this method might simply import the underlying operating system's identity information.
The
login
method should
- Determine whether or not this
LoginModule
should be ignored. One example of when it should be ignored is when a user attempts to authenticate under an identity irrelevant to thisLoginModule
(if a user attempts to authenticate as root using NIS, for example). If thisLoginModule
should be ignored,login
should returnfalse
. Otherwise, it should do the following:
- Call the
CallbackHandler
handle
method if user interaction is required.
- Perform the authentication.
- Store the authentication result (success or failure).
- If authentication succeeded, save any relevant state information that may be needed by the
commit
method.
- Return
true
if authentication succeeds, or throw aLoginException
such asFailedLoginException
if authentication fails.Note that the
login
method implementation should not associate any newPrincipal
or credential information with the savedSubject
object. This method merely performs the authentication, and then stores away the authentication result and corresponding authentication state. This result and state will later be accessed by thecommit
orabort
method. Note that the result and state should typically not be saved in the sharedStateMap
, as they are not intended to be shared with otherLoginModule
s.An example of where this method might find it useful to store state information in the sharedState
Map
is whenLoginModule
s are configured to share passwords. In this case, the entered password would be saved as shared state. By sharing passwords, the user only enters the password once, and can still be authenticated to multipleLoginModule
s. The standard conventions for saving and retrieving names and passwords from the sharedStateMap
are the following:
javax.security.auth.login.name
- Use this as the shared state map key for saving/retrieving a name.
javax.security.auth.login.password
- Use this as the shared state map key for saving/retrieving a password.If authentication fails, the
login
method should not retry the authentication. This is the responsibility of the application. MultipleLoginContext
login
method calls by an application are preferred over multiple login attempts from withinLoginModule.login()
.boolean commit() throws LoginException;
The
commit
method is called to commit the authentication process. This is phase 2 of authentication when phase 1 succeeds. It is called if theLoginContext
's overall authentication succeeded (that is, if the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONALLoginModule
s succeeded.)This method should access the authentication result and corresponding authentication state saved by the
login
method.If the authentication result denotes that the
login
method failed, then thiscommit
method should remove/destroy any corresponding state that was originally saved.If the saved result instead denotes that this
LoginModule
'slogin
method succeeded, then the corresponding state information should be accessed to build any relevantPrincipal
and credential information. SuchPrincipal
s and credentials should then be added to theSubject
stored away by theinitialize
method.After adding
Principal
s and credentials, dispensable state fields should be destroyed expeditiously. Likely fields to destroy would be user names and passwords stored during the authentication process.The
commit
method should save private state indicating whether the commit succeeded or failed.The following chart depicts what a
LoginModule
'scommit
method should return. The different boxes represent the different situations that may occur. For example, the top-left corner box depicts what thecommit
method should return if both the previous call tologin
succeeded and thecommit
method itself succeeded.\ LOGIN \ COMMIT \ \ SUCCESS FAILURE +--------------+-----------------+ | | | SUCCESS | return TRUE | throw EXCEPTION | | | | +--------------+-----------------+ | | | FAILURE | return FALSE | return FALSE | | | | +--------------+-----------------+
boolean abort() throws LoginException;
The
abort
method is called to abort the authentication process. This is phase 2 of authentication when phase 1 fails. It is called if theLoginContext
's overall authentication failed.This method first accesses this
LoginModule
's authentication result and corresponding authentication state saved by thelogin
(and possiblycommit
) methods, and then clears out and destroys the information. Sample state to destroy would be user names and passwords.If this
LoginModule
's authentication attempt failed, then there shouldn't be any private state to clean up.The following charts depict what a
LoginModule
'sabort
method should return. This first chart assumes that the previous call tologin
succeeded. For instance, the top-left corner box depicts what theabort
method should return if both the previous call tologin
andcommit
succeeded, and theabort
method itself also succeeded.\ COMMIT \ ABORT (assumes LOGIN method succeeded) \ \ SUCCESS FAILURE +--------------+-----------------+ | | | SUCCESS | return TRUE | throw EXCEPTION | | | | +--------------+-----------------+ | | | FAILURE | return TRUE | throw EXCEPTION | | | | +--------------+-----------------+The second chart depicts what a
LoginModule
'sabort
method should return, assuming that the previous call tologin
failed. For instance, the top-left corner box depicts what theabort
method should return if the previous call tologin
failed, the previous call tocommit
succeeded, and theabort
method itself also succeeded.\ COMMIT \ ABORT (assumes LOGIN method failed) \ \ SUCCESS FAILURE +--------------+-----------------+ | | | SUCCESS | return FALSE | return FALSE | | | | +--------------+-----------------+ | | | FAILURE | return FALSE | return FALSE | | | | +--------------+-----------------+boolean logout() throws LoginException;
The
logout
method is called to log out aSubject
.This method removes
Principal
s, and removes/destroys credentials associated with theSubject
during thecommit
operation. This method should not touch thosePrincipal
s or credentials previously existing in theSubject
, or those added by otherLoginModule
s.If the
Subject
has been marked read-only (theSubject
'sisReadOnly
method returns true), then this method should only destroy credentials associated with theSubject
during thecommit
operation (removing the credentials is not possible). If theSubject
has been marked as read-only and the credentials associated with theSubject
during thecommit
operation are not destroyable (they do not implement theDestroyable
interface), then this method may throw aLoginException
.The
logout
method should returntrue
if logout succeeds, or otherwise throw a LoginException.Step 4: Choose or Write a Sample Application
Either choose an existing sample application for your testing, or write a new one. See JAAS Reference Guide for information about application requirements and a sample application you can use for your testing.
Step 5: Compile the
LoginModule
and ApplicationCompile your newLoginModule
and the application you will use for testing.Step 6: Prepare for Testing
Step 6a: Place Your
LoginModule
and Application Code in JAR FilesPlace your
LoginModule
and application code in separate JAR files, in preparation for referencing the JAR files in the policy in Step 6c. Here is a sample command for creating a JAR file:jar cvf <JAR file name> <list of classes, separated by spaces>This command creates a JAR file with the specified name containing the specified classes.
For more information on the jar tool, see jar (for Solaris) (for Microsoft Windows).
Step 6b: Decide Where to Store the JAR Files
The application can be stored essentially anywhere you like.
Your
LoginModule
can also be placed anywhere you (and other clients) like. If theLoginModule
is fully trusted, it can be placed in the JRE'slib/ext
(standard extension) directory.You will need to test the
LoginModule
being located both in thelib/ext
directory and elsewhere because in one situation yourLoginModule
will need to explicitly be granted permissions required for any security-sensitive operations it does, while in the other case such permissions are not needed.If your
LoginModule
is placed in the JRE'slib/ext
directory, it will be treated as an installed extension and no permissions need to be granted, since the default system policy file grants all permissions to installed extensions.If your
LoginModule
is placed anywhere else, the permissions need to be granted, for example bygrant
statements in a policy file.Decide where you will store the
LoginModule
JAR file for testing the case where it is not an installed extension. In the next step, you grant permissions to the JAR file, in the specified location.Step 6c: Set
LoginModule
and Application JAR File PermissionsIf your
LoginModule
and/or application performs security-sensitive tasks that will trigger security checks (making network connections, reading or writing files on a local disk, etc), it will need to be granted the required permissions if it is not an installed extension (see Step 6b) and it is run while a security manager is installed.Since
LoginModule
s usually associatePrincipal
s and credentials with an authenticated Subject, some types of permissions aLoginModule
will typically require are AuthPermissions with target names "modifyPrincipals", "modifyPublicCredentials", and "modifyPrivateCredentials".A sample statement granting permissions to a
LoginModule
whose code is inMyLM.jar
appears below. Such a statement could appear in a policy file. In this example, theMyLM.jar
file is assumed to be in the/localWork
directory.grant codeBase "file:/localWork/MyLM.jar" { permission javax.security.auth.AuthPermission "modifyPrincipals"; permission javax.security.auth.AuthPermission "modifyPublicCredentials"; permission javax.security.auth.AuthPermission "modifyPrivateCredentials"; };Note: Since a
LoginModule
is always invoked within anAccessController.doPrivileged
call, it should not have to calldoPrivileged
itself. If it does, it may inadvertently open up a security hole. For example, aLoginModule
that invokes the application-providedCallbackHandler
inside adoPrivileged
call opens up a security hole by permitting the application'sCallbackHandler
to gain access to resources it would otherwise not have been able to access.Step 6d: Create a Configuration Referencing the LoginModule
Because JAAS supports a pluggable authentication architecture, your new
LoginModule
can be used without requiring modifications to existing applications. Only the loginConfiguration
needs to be updated in order to indicate use of a newLoginModule
.The default
Configuration
implementation from Sun Microsystems reads configuration information from configuration files, as described in com.sun.security.auth.login.ConfigFile.html.Create a configuration file to be used for testing. For example, to configure the previously-mentioned hypothetical IBM
LoginModule
for an application, the configuration file might look like this:AppName { com.ibm.auth.Module REQUIRED debug=true; };whereAppName
should be whatever name the application uses to refer to this entry in the login configuration file. The application specifies this name as the first argument to theLoginContext
constructor.
Step 7: Test Use of the
LoginModule
Finally, test your application and its use of the
LoginModule
. When you run the application, specify the login configuration file to be used. For example, suppose your application is namedMyApp
, it is located inMyApp.jar
, and your configuration file istest.conf
. You could run the application and specify the configuration file via the following:java -classpath MyApp.jar -Djava.security.auth.login.config=test.conf MyAppType all that on one line. Multiple lines are used here for legibility.
To specify a policy file named
my.policy
and run the application with a security manager installed, do the following:java -classpath MyApp.jar -Djava.security.manager -Djava.security.policy=my.policy -Djava.security.auth.login.config=test.conf MyAppAgain, type all that on one line.
You may want to configure the
LoginModule
with a debug option to help ensure that it is working correctly.Debug your code and continue testing as needed. If you have problems, review the steps above and ensure they are all completed.
Be sure to vary user input and the
LoginModule
options specified in the configuration file.Be sure to also include testing using different installation options (e.g., making the
LoginModule
an installed extension or placing it on the class path) and execution environments (with or without a security manager running). Installation options are discussed in Step 6b. In particular, in order to ensure yourLoginModule
works when a security manager is installed and theLoginModule
and application are not installed extensions, you need to test such an installation and execution environment, after granting required permissions, as described in Step 6c.If you find during testing that your
LoginModule
or application needs modifications, make the modifications, recompile (Step 5), place the updated code in a JAR file (Step 6a), re-install the JAR file (Step 6b), if needed fix or add to the permissions (Step 6c), if needed modify the login configuration file (Step 6d), and then re-run the application and repeat these steps as needed.Step 8: Document Your
LoginModule
ImplementationThe next step is to write documentation for clients of your
LoginModule
. Example documentation you may want to include is:
- A README or User Guide describing
- the authentication process employed by your
LoginModule
implementation.
- information on how to install the
LoginModule
.
- configuration options accepted by the
LoginModule
. For each option, specify the option name and possible values (or types of values), as well as the behavior the option controls.
- the permissions required by your
LoginModule
when it is run with a security manager (and it is not an installed extension).
- An example
Configuration
file that references your newLoginModule
.
- An example policy file granting your
LoginModule
the required permissions.
- API documentation. Putting javadoc comments into your source code as you write it will make the API javadocs easy to generate.
Step 9: Make
LoginModule
JAR File and Documents AvailableThe final step is to make your
LoginModule
JAR file and documentation available to clients.