Java Authentication and Authorization Service (JAAS): LoginModule Developer's Guide
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. See the Javadoc API documentation for the JAAS API specification for more detailed information:
- javax.security.auth
- javax.security.auth.callback
- javax.security.auth.kerberos
- javax.security.auth.login
- javax.security.auth.spi
- javax.security.auth.x500
The following packages contain supported LoginModule examples:
- com.sun.security.auth
- com.sun.security.auth.callback
- com.sun.security.auth.login
- com.sun.security.auth.module
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 Introduction to JAAS and Java GSS-API Tutorials that utilize Kerberos as the underlying technology for authentication and secure communication.
Introduction to LoginModule
Authentication technology providers must implement the LoginModule interface. LoginModules 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 the LoginModule interface. A Configuration specifies the LoginModule(s) to be used with a particular login application. Different LoginModules can be plugged in under the application without requiring any modifications to the application itself.
                  
The LoginContext is responsible for reading the Configuration and instantiating the specified LoginModules. Each LoginModule is initialized with a Subject, a CallbackHandler, shared LoginModule state, and LoginModule-specific options.
                  
The Subject represents the user or service currently being authenticated and is updated by a LoginModule with relevant Principals and credentials if authentication succeeds. LoginModules use the CallbackHandler to communicate with users (to prompt for user names and passwords, for example), as described in the login method description. Note that the CallbackHandler may be null. A LoginModule that requires a CallbackHandler to authenticate the Subject may throw a LoginException if it was initialized with a null CallbackHandler. LoginModules optionally use the shared state to share information or data among themselves.
                  
The LoginModule-specific options represent the options configured for this LoginModule in the login Configuration. The options are defined by the LoginModule itself and control the behavior within it. For example, a LoginModule may define options to support debugging/testing capabilities. Options are defined using a key-value syntax, such as debug=true. The LoginModule stores the options as a Map so that the values may be retrieved using the key. Note that there is no limit to the number of options a LoginModule chooses to define.
                  
The calling application sees the authentication process as a single operation invoked via a call to the LoginContext's login method. However, the authentication process within each LoginModule proceeds in two distinct phases. In the first phase of authentication, the LoginContext's login method invokes the login method of each LoginModule specified in the Configuration. The login method for a LoginModule performs the actual authentication (prompting for and verifying a password for example) and saves its authentication status as private state information. Once finished, the LoginModule's login method returns true (if it succeeded) or false (if it should be ignored), or it throws a LoginException to specify a failure. In the failure case, the LoginModule 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, each LoginModule's login method will be called again.
                  
In the second phase, if the LoginContext's overall authentication succeeded (calls to the relevant required, requisite, sufficient and optional LoginModules' login methods succeeded), then the commit method for each LoginModule gets invoked. (For an explanation of the LoginModule flags required, requisite, sufficient and optional, please consult the Configuration documentation and Appendix B: JAAS Login Configuration File in the JAAS Reference Guide.) The commit method for a LoginModule checks its privately saved state to see if its own authentication succeeded. If the overall LoginContext authentication succeeded and the LoginModule's own authentication succeeded, then the commit method associates the relevant Principals (authenticated identities) and credentials (authentication data such as cryptographic keys) with the Subject.
                  
If the LoginContext's overall authentication failed (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules' login methods did not succeed), then the abort method for each LoginModule gets invoked. In this case, the LoginModule removes/destroys any authentication state originally saved.
                  
Logging out a Subject involves only one phase. The LoginContext invokes the LoginModule's logout method. The logout method for the LoginModule then performs the logout procedures, such as removing Principals or credentials from the Subject, or logging session information.
                  
Steps to Implement a LoginModule
The following are the steps required to implement and test a LoginModule:
                  
Step 1: Understand the Authentication Technology
First, understand the authentication technology to be implemented by your new LoginModule provider and determine its requirements.
                     
Step 2: Name the LoginModule Implementation
Decide on the proper package and class name for your LoginModule.
                     
For example, a LoginModule developed by IBM might be called com.ibm.auth.Module where com.ibm.auth is the package name and Module is the name of the LoginModule class implementation.
                        
Step 3: Implement the LoginModule Interface
The LoginModule interface specifies five abstract
                methods that you must implement:
                     
In addition to these methods, a LoginModule implementation must provide a public constructor with no arguments. This allows for its proper instantiation by a LoginContext. Note that if no constructor is provided in your LoginModule implementation, a default no-argument constructor is automatically inherited from the Object class.
Note:
If you don't implement the LoginModule interface, then a LoginException will be thrown when you try to use your login module.LoginModule.initialize Method
    public void initialize(
        Subject subject,
        CallbackHandler handler,
        Map<java.lang.String, ?> sharedState,
        Map<java.lang.String, ?> options);The initialize method is called to
                                initialize the LoginModule with the relevant
                                authentication and state information.
                        
This method
                                is called by a LoginContext immediately after this
                                        LoginModule 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 other
                                        LoginModules, and may also traverse through
                                the provided options to determine
                                what configuration options were specified to affect the
                                        LoginModule's behavior. It may save option
                                values in variables for future use.
                        
The following 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.
- tryFirstPass- If- true, 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.
- useFirstPass- If- true, 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).
- tryMappedPass- If- true, 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.
- useMappedPass- If- true, 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- If- true, then when invoking the CallbackHandler, the LoginModule provides a TextOutputCallback as the first Callback, which describes the LoginModule performing the authentication.
- debug- If- true, 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 this
                                        LoginModule (and the other configured
                                        LoginModules, as well), all share the same
                                references to the provided Subject and
                                        sharedState. Modifications to the
                                        Subject and sharedState
                                will, therefore, be seen by all.
                        
LoginModule.login Method
    boolean login() throws LoginException;The login method is called to
                                authenticate a Subject. 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 for
                                        LoginModules to remain independent of the
                                different types of user interaction. Rather, the
                                        LoginModule's login method
                                should invoke the handle method of the CallbackHandler interface passed
                                to the initialize method to perform the user
                                interaction and set appropriate results, such as the user name and
                                password. The LoginModule passes the
                                        CallbackHandler an array of appropriate
                                        Callbacks, for example a NameCallback for the user name and
                                a PasswordCallback for the password,
                                and the CallbackHandler performs the requested user
                                interaction and sets appropriate values in the
                                        Callbacks. For example, to process a
                                        NameCallback, the
                                        CallbackHandler may prompt for a name,
                                retrieve the value from the user, and call the
                                        NameCallback's setName
                                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, Linux, macOS, or Windows, this method might simply import the underlying operating system's identity information.
The login method
                                should
                        
- Determine whether or not this
                                                LoginModuleshould 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 thisLoginModuleshould be ignored,loginshould returnfalse. Otherwise, it should do the following:
- Call the CallbackHandlerhandlemethod 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
                                                commitmethod.
- Return trueif authentication succeeds, or throw a LoginException such as FailedLoginException if authentication fails.
Note that the login method
                                implementation should not associate any new
                                        Principal or credential information with
                                the saved Subject 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 the commit or
                                        abort method. Note that the result and
                                state should typically not be saved in the sharedState
                           Map, as they are not intended to be shared with
                                other LoginModules.
                        
An example
                                of where this method might find it useful to store state information
                                in the sharedState
                           Map is when LoginModules 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 multiple
                                        LoginModules. The standard conventions for
                                saving and retrieving names and passwords from the sharedState
                           Map are the following:
                        
- javax.security.auth.login.name- Use this as the shared state map key for saving/retrieving a name. The value should be a String.
- javax.security.auth.login.password- Use this as the shared state map key for saving/retrieving a password. The value should be a char array.
If authentication fails, the login
                                method should not retry the authentication. This is the
                                responsibility of the application. Multiple
                                        LoginContext
                           login method calls by an application are preferred
                                over multiple login attempts from within
                                        LoginModule.login().
                        
LoginModule.commit Method
    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 the
                                LoginContext's overall authentication succeeded
                                (that is, if the relevant REQUIRED, REQUISITE, SUFFICIENT and
                                OPTIONAL LoginModules 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 this commit method should
                                remove/destroy any corresponding state that was originally
                                saved.
                        
If the saved result instead denotes that
                                this LoginModule's login method
                                succeeded, then the corresponding state information should be
                                accessed to build any relevant Principal and
                                credential information. Such Principals and
                                credentials should then be added to the Subject
                                stored away by the initialize method.
                        
After adding Principals 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's commit
                                method should return. The different boxes represent the different
                                situations that may occur. For example, the top-left corner box
                                depicts what the commit method should return if
                                both the previous call to login succeeded and the
                                        commit method itself succeeded.
                        
Table 6-2 LoginModule.commit Method Return Values
| Login Status | COMMIT: SUCCESS | COMMIT: FAILURE | 
|---|---|---|
| LOGIN: SUCCESS | return TRUE | throw EXCEPTION | 
| LOGIN: FAILURE | return FALSE | return FALSE | 
LoginModule.abort Method
    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 the LoginContext's
                                overall authentication failed.
                        
This method first
                                accesses this LoginModule's authentication result
                                and corresponding authentication state saved by the
                                        login (and possibly
                                commit) 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's abort method
                                should return. This first chart assumes that the previous call to
                                        login succeeded. For instance, the
                                        abort method should return TRUE if both the
                                previous call to login and commit
                                succeeded, and the abort method itself also
                                succeeded.
                        
Table 6-3 LoginModule.abort Method Return Values: Login Succeeded
| Login Status | ABORT: SUCCESS | ABORT: FAILURE | 
|---|---|---|
| COMMIT: SUCCESS | return TRUE | throw EXCEPTION | 
| COMMIT: FAILURE | return TRUE | throw EXCEPTION | 
The second chart depicts what a LoginModule's abort method should return, assuming that the previous call to login failed. For instance, the abort method should return FALSE if the previous call to login failed, the previous call to commit succeeded, and the abort method itself also succeeded.
Table 6-4 LoginModule.abort Method Return Values: Login Failed
| Login Status | ABORT: SUCCESS | ABORT: FAILURE | 
|---|---|---|
| COMMIT: SUCCESS | return FALSE | return FALSE | 
| COMMIT: FAILURE | return FALSE | return FALSE | 
LoginModule.logout Method
    boolean logout() throws LoginException;The logout method is called to log out
                                a Subject.
                        
This method removes
                                        Principals, and removes/destroys
                                credentials associated with the Subject during the
                                        commit operation. This method should not
                                touch those Principals or credentials previously
                                existing in the Subject, or those added by other
                                        LoginModules.
                        
If the
                                        Subject has been marked read-only (the
                                        Subject's isReadOnly
                                method returns true), then this
                                method should only destroy credentials associated with the
                                        Subject during the commit
                                operation (removing the credentials is not possible). If the
                                        Subject has been marked as read-only and the credentials
                                associated with the Subject during the
                                        commit operation are not destroyable (they
                                do not implement the Destroyable interface), then
                                this method may throw a LoginException.
                        
The logout method should return
                                        true 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 Java Authentication and Authorization Service (JAAS) Reference Guide for information about application requirements and a sample application you can use for your testing.
Step 5: Compile the LoginModule and Application
Compile your new LoginModule and the application you will use for testing.
                     
Step 6: Prepare for Testing
Step 6a: Place Your LoginModule and Application Code in JAR Files
                        
Place your LoginModule and application code in separate JAR files, in preparation for referencing the JAR files in the policy in Step 6b: Set LoginModule and Application JAR File Permissions. 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.
Step 6b: Set LoginModule and Application JAR File Permissions
                        
If 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 run while a security manager is installed; see Permissions in the JDK.
                        
Since LoginModules usually associate Principals and credentials with an authenticated Subject, some types of permissions a LoginModule will typically require are AuthPermissions with target names "modifyPrincipals", "modifyPublicCredentials", and "modifyPrivateCredentials".
                        
The following is a sample statement granting permissions to a
                    LoginModule whose code is in MyLM.jar. Such a
                statement could appear in a policy file. In this example, the
                    MyLM.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 aLoginModule is always invoked within an AccessController.doPrivileged call, it should not have to call doPrivileged itself. If it does, it may inadvertently open up a security hole. For example, a LoginModule that invokes the application-provided CallbackHandler inside a doPrivileged call opens up a security hole by permitting the application's CallbackHandler to gain access to resources it would otherwise not have been able to access.
                        Step 6c: 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 login Configuration needs to be updated in order to indicate use of a new LoginModule.
                        
The default Configuration implementation from Oracle reads configuration information from configuration files, as described in ConfigFile.
                        
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;
    };where AppName 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 the LoginContext constructor.
                        
Step 7: Test Use of the LoginModule
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 named MyApp, it is located in MyApp.jar, and your configuration file is test.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 previous steps 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., placing the LoginModule on the class path or module path) and execution environments (with or without a security manager running). In particular, in order to ensure your LoginModule works when a security manager is installed and the LoginModule, you need to test such an installation and execution environment, after granting required permissions, as described in Step 6b: Set LoginModule and Application JAR File Permissions.
                        
- If you find during testing that your LoginModuleor application needs modifications, make the modifications, recompile (Step 5: Compile the LoginModule and Application).
- Place the updated code in a JAR file (Step 6a: Place Your LoginModule and Application Code in JAR Files).
- If needed fix or add to the permissions (Step 6b: Set LoginModule and Application JAR File Permissions).
- If needed modify the login configuration file (Step 6c: Create a Configuration Referencing the LoginModule).
- Re-run the application and repeat these steps as needed.
Step 8: Document Your LoginModule Implementation
Write documentation for clients of your LoginModule.
                     
- A README or User Guide describing- The authentication process employed by your LoginModuleimplementation.
- 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 LoginModulewhen it is run with a security manager.
 
- The authentication process employed by your 
- An example Configurationfile that references your newLoginModule.
- An example policy file granting your LoginModulethe required permissions.
- API documentation. Putting Javadoc comments into your source code as you write it will make the Javadoc API documentation easy to generate.