Spec-Zone .ru
спецификации, руководства, описания, API
|
LoginModule
LoginModule
ImplementationLoginModule
MethodsLoginModule
and ApplicationLoginModule
LoginModule
ImplementationLoginModule
JAR
File and Documents AvailableThe Java Authentication and Authorization Service (JAAS) was introduced as an optional package to the Java 2 SDK, Standard Edition (J2SDK), v 1.3. JAAS was integrated into the Java 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.
This document is intended for experienced programmers who
require the ability to write a LoginModule
implementing an authentication technology.
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:
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.
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 the
LoginModule
interface. A
Configuration
specifies the LoginModule
(s)
to be used with a particular login application. Different
LoginModule
s 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
LoginModule
s. 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 Principal
s
and credentials if authentication succeeds.
LoginModule
s 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
.
LoginModule
s 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
LoginModule
s' 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
javax.security.auth.login.Configuration
documentation
and Appendix B: Login
Configuration Files 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 Principal
s (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
LoginModule
s' 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 Principal
s or credentials from the
Subject
, or logging session information.
LoginModule
The steps required in order to implement and test a
LoginModule
are the following:
LoginModule
ImplementationLoginModule
MethodsLoginModule
and ApplicationLoginModule
and Application Code in JAR
FilesLoginModule
and Application JAR File
PermissionsLoginModule
LoginModule
ImplementationLoginModule
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.
LoginModule
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 the
CallbackHandler
interface and the
javax.security.auth.callback
package. In that
package you will find several possible Callback
implementations to use. (Alternatively, you can create your own
Callback
implementations.) The
LoginModule
will invoke the
CallbackHandler
specified by the application itself
and passed to the LoginModule
's
initialize
method. The LoginModule
passes
the CallbackHandler
an array of appropriate
Callback
s. See the login method
in Step 3.
Note that it is possible for LoginModule
implementations not to have any end-user interactions. Such
LoginModule
s would not need to access the
callback
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.example.com" and
"server_two.example.com", for example).
LoginModule
ImplementationLoginModule
.
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.
LoginModule
MethodsThe LoginModule
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 a
LoginContext
. Note that if no such constructor is
provided in your LoginModule
implementation, a default
no-argument constructor is automatically inherited from the
Object
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 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
LoginModule
s, 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.
Note: JAAS LoginModules may use the options defined in PAM
(use_first_pass
, try_first_pass
,
use_mapped_pass
, and try_mapped_pass
) to
achieve single-signon. See
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
- 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.use_first_pass
- 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).try_mapped_pass
- 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.use_mapped_pass
- 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
LoginModule
s, 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.
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
LoginModule
s to remain independent of the different
types of user interaction. Rather, the LoginModule
's
login
method should invoke the handle
method of the
CallbackHandler
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 Callback
s, 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
Callback
s. 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 or Windows NT, this method might simply import the underlying operating system's identity information.
The login
method should
LoginModule
should
be ignored. One example of when it should be ignored is when a user
attempts to authenticate under an identity irrelevant to this
LoginModule
(if a user attempts to authenticate as
root using NIS, for example). If this
LoginModule
should be ignored, login
should return false
. Otherwise, it should do the
following:CallbackHandler
handle
method if user interaction is required.commit
method.true
if 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
LoginModule
s.
An example of where this method might find it useful to store
state information in the sharedState Map
is
when LoginModule
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 multiple LoginModule
s.
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.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. Multiple LoginContext
login
method calls by an application are preferred over multiple login
attempts from within LoginModule.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 the LoginContext
's
overall authentication succeeded (that is, if the relevant
REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
LoginModule
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 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 Principal
s and credentials should
then be added to the Subject
stored away by the
initialize
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
'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.
COMMIT: SUCCESS | COMMIT: FAILURE | |
---|---|---|
LOGIN: SUCCESS | return TRUE | throw EXCEPTION |
LOGIN: 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 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 top-left corner box depicts what the
abort
method should return if both the previous call
to login
and commit
succeeded, and the
abort
method itself also succeeded.
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 top-left
corner box depicts what the abort
method should return
if the previous call to login
failed, the previous
call to commit
succeeded, and the abort
method itself also succeeded.
ABORT: SUCCESS | ABORT: FAILURE | |
---|---|---|
COMMIT: SUCCESS | return FALSE | return FALSE |
COMMIT: FAILURE | return FALSE | return FALSE |
boolean logout() throws LoginException;
The logout
method is called to log out a
Subject
.
This method removes Principal
s, and
removes/destroys credentials associated with the
Subject
during the commit
operation. This
method should not touch those Principal
s or
credentials previously existing in the Subject
, or
those added by other LoginModule
s.
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.
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.
LoginModule
and ApplicationLoginModule
and the application you
will use for testing.
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).
The application can be stored essentially anywhere you like.
Your LoginModule
can also be placed anywhere you
(and other clients) like. If the LoginModule
is fully
trusted, it can be placed in the JRE's lib/ext
(standard extension) directory.
You will need to test the LoginModule
being located
both in the lib/ext
directory and elsewhere because in
one situation your LoginModule
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's
lib/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 by grant
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.
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 associate
Principal
s and credentials with an authenticated
Subject, some types of permissions a LoginModule
will
typically require are AuthPermissions
with target names "modifyPrincipals", "modifyPublicCredentials",
and "modifyPrivateCredentials".
A sample statement granting permissions to a
LoginModule
whose code is in MyLM.jar
appears below. 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 a LoginModule
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.
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 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; };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.
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 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 MyApp
Type 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 MyApp
Again, 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 your
LoginModule
works when a security manager is installed
and the LoginModule
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.
LoginModule
ImplementationThe next step is to write documentation for clients of your
LoginModule
. Example documentation you may want to
include is:
LoginModule
implementation.LoginModule
.LoginModule
.
For each option, specify the option name and possible values (or
types of values), as well as the behavior the option controls.LoginModule
when
it is run with a security manager (and it is not an installed
extension).Configuration
file that references your
new LoginModule
.LoginModule
the required permissions.LoginModule
JAR File and Documents AvailableThe final step is to make your LoginModule
JAR file
and documentation available to clients.