The Java Authentication Authorization Service (Jaas,java authentication and Authorization API) provides a flexible and scalable mechanism to guarantee client or server-side Java programs. The early Java security framework emphasizes protecting users from downloaded code by validating the source and author of the Code. Jaas emphasizes that by verifying who is running the code and his or her permissions to protect the system face from user attacks. It allows you to integrate some standard security mechanisms, such as Solaris NIS (Network information Services), Windows NT, LDAP (Lightweight Directory Access Protocol), Kerberos, and so on, in a common, configurable way into the system. This article first introduces you to some of the core aspects of Jaas validation, and then shows you how to develop the login module by example.
Have you ever needed to implement a login module for an application? If you are a more experienced programmer, believe that you have done so many times, and each time is not exactly the same. It is possible for you to build your login module on an Oracle database, possibly using NT user authentication, or using an LDAP directory. It must be a lucky thing for programmers to have a way of supporting all of these security mechanisms without changing application-level code.
You can now use Jaas to achieve the above goals. Jaas is a relatively new Java API. In J2SE 1.3, it is an expansion pack; it becomes a core package in J2SE 1.4. In this article, we'll introduce some of the core concepts of Jaas, and then illustrate how to apply Jaas to the actual program. The example of this article is based on a web-based Java application, in which we use a relational database to hold the user's login information. With the use of JAAS, we have implemented a robust and flexible login and authentication module.
Java validation and authorization: An introduction
Prior to the advent of Jaas, the Java security model was designed to meet the needs of Cross-platform network applications. In earlier versions of Java, Java was often used as a remote code, such as an applet. So the initial security model focuses on protecting users by validating the source of the code. Early Java security included concepts such as Sercuritymanager, sandbox concepts, code signing, and policy files, mostly to protect users.
The advent of Jaas reflects the evolution of Java. Traditional server/client programs require login and access control, and Jaas achieves the purpose of protecting the system by validating the user who runs the program. Although Jaas also has the ability to authenticate and authorize, in this article, we mainly introduce validation capabilities.
By adding an abstraction layer between the application and the underlying authentication and authorization mechanisms, JAAS simplifies the development of programs involving Java security packages. The abstraction layer's platform-independent nature enables developers to use a variety of security mechanisms without modifying application-level code. Similar to other Java security APIs, Jaas guarantees that the program is independent of the safety mechanism through an extensible framework: the service Provider Interface (Provider INTERFACE,SPI). The service Provider interface is composed of a set of abstract classes and interfaces. The overall frame chart of the Jaas program is given in Figure I. Application-level code primarily handles LoginContext. Below LoginContext is a set of dynamically configured Loginmodules. Loginmodule Use the correct security mechanism for authentication.
Figure I gives an overview of Jaas. The code for the application layer only needs to deal with LoginContext. Under LoginContext is a set of dynamically configured Loginmodule objects that use the relevant security infrastructure for validation operations.
Figure I Overview of Jaas |
The
Jaas provides some loginmodule reference implementation code, such as Jndiloginmodule. Developers can also implement Loginmodule interfaces themselves, just as in our example of Rdbmslonginmodule. We will also show you how to use a simple configuration file to install the application.
Jaas is stackable to satisfy the pluggable nature. In the case of single sign-on, a set of security modules can be stacked together and then invoked by other security mechanisms in the order in which they are stacked. The implementation of the
Jaas models The Jass based on some of the popular security architecture patterns and frameworks now in place. For example, stackable features are very similar to the Stackable authentication modules (pam,pluggable authentication module) framework under UNIX. From a transactional perspective, Jaas resembles the behavior of a two-step commit (two-phase commit,2pc) protocol. The concept of security configuration in Jaas (including the policy file (Police file) and license (Permission)) comes from J2SE 1.2. Jaas also borrows a lot of ideas from other mature security frameworks.
The
client and server-side Jaas
developer can apply Jaas to both the client and server side. Using Jaas on the client is simple. It is a bit more complicated when using Jaas on the server side. The Jaas products currently in the application server market are not very consistent, and the Java EE Application Server with Jaas has some slight differences. For example, JBOSSSX uses its own structure to integrate Jaas into a larger security framework, and while WebLogic 6.x uses JAAS, the security framework is completely different.
Now you can understand why we need to look at Jaas from a client-and server-side perspective. We'll list two examples in the following cases. To make the server-side example program simpler, we used the resin application server.
core Jaas class
before using Jaas, you first need to install Jaas. Jaas has been included in J2SE 1.4, but not in J2SE 1.3. If you want to use J2SE 1.3, you can download Jaas from Sun's official site. When Jaas is installed correctly, you will find Jaas.jar in the Lib directory of the installation directory. You need to add the path to the classpath. (Note: If you have installed an application server, which already includes Jaas, read the application server's Help documentation for more detailed information). In the Java Security properties file Java.security, you can change some of the system attributes associated with Jaas. The file is saved in the /lib/security directory.
Using Jaas validation in your application typically involves the following steps:
1. Create an instance of LoginContext.
2. To be able to obtain and process validation information, a CallbackHandler object is passed as a parameter to LoginContext.
3. Verify by calling the LoginContext login () method.
4. Implements some special features (assuming login success) by using the Subject object returned by the login () method. The following is a simple example of
:
LoginContext LC = new LoginContext ("Myexample"); try { Lc.login (); } catch (Loginexception) { Authentication failed. }
Authentication successful, we can now continue. We can use the returned Subject if we like. Subject sub = Lc.getsubject (); Subject.doas (Sub, New Myprivilegedaction ()); |
When you run this code, the following work is done in the background.
1. When initialized, the LoginContext object first finds the Myexample entry in the Jaas configuration file, and then the content of the item determines which Loginmodule object to load (see figure II).
2. At logon time, the LoginContext object invokes the login () method for each Loginmodule object.
3. Each login () method validates the operation or obtains a Callbackhandle object.
4. The Callbackhandle object interacts with the user by using one or more callback methods to obtain user input.
5. Fill in the validation information into a new subject object.
We'll explain the code further. But before that, let's look at the core Jaas classes and interfaces involved in the code. These classes can be grouped into three different types:
Generic type Subject,principal, voucher
Verifying Logincontext,loginmodule,callbackhandler,callback
Authorized Policy,authpermission,privatecredentialpermission
Most of the classes and interfaces listed above are in the Javax.security.auth package. In J2SE 1.4, there are some implementation classes for the interface in the Com.sun.security.auth package.
Common type: Subject,principal, voucher
The subject class represents a validation entity that can be a user, Administrator, Web service, device, or other process. This class contains three types of security information:
Identity (identities): represented by one or more principal objects
Public credentials: For example, name or public secret key
Private credentials: For example, password or private key
The Principal object represents the identity of the subject object. They implement the Java.security.Principal and Java.io.Serializable interfaces. In the subject class, the most important method is GetName (). The method returns an identity name. Multiple principal objects are included in the Subject object, so it can have more than one name. Because the login name, ID number and email address can be identified as the user's identity, it is obvious that having multiple identity names is very common in practical applications.
The voucher mentioned above is not a specific class or excuse, it can be any object. Credentials can contain authentication information that is required by any particular security system, such as a label (ticket), a key, or a password. The Subject object maintains a specific set of private and public credentials that can be obtained through the getprivatecredentials () and Getpubliccredentials () methods. These methods are usually invoked in the security subsystem of the application layer.
Verification: LoginContext
In the application layer, you can use the LoginContext object to validate the Subject object. The LoginContext object also embodies the dynamic pluggability of Jaas, because when you create an instance of LoginContext, you need to specify a configuration. LoginContext typically loads configuration information from a text file that tells the LoginContext object which Loginmodule object to use when logging on.
The following is a list of three methods that are frequently used in LoginContext:
Login () to log in. This method activates all the Loginmodule objects that are set in the configuration. If successful, it creates a validated subject object, otherwise throws a Loginexception exception.
Getsubject () returns the validated Subject Object
Logout () unregister the Subject object and delete the principal object and voucher associated with it
Verification: Loginmodule
Loginmodule is an interface that invokes a specific authentication mechanism. Java EE 1.4 contains the following implementation classes for Loginmodule:
Jndiloginmodule used to verify directory services configured in Jndi
Krb5loginmodule using the Kerberos protocol for authentication
Ntloginmodul uses the current user's user information in NT to authenticate
Unixloginmodule uses user information from the current user in UNIX to authenticate
Bundled with the above modules are also the implementation classes for the corresponding principal interfaces, such as Ntdomainprincipal and Unixprincipal. These classes are in the Com.sun.security.auth package.
The Loginmodule interface contains five methods:
Initialize () is called by the constructor when a Loginmodule instance is created
Login () for verification
Commit () This method is called when the Lgonincontext object accepts the results of all the Loginmodule objects returned. This method assigns principal objects and vouchers to the subject object.
Abort () This method is invoked when any one of the Loginmodule objects fails validation. No principal objects or vouchers are associated with the subject object at this time.
Logout () deletes the principal object and credentials associated with the subject object.
In the code of the application, programmers usually do not call the methods listed above directly, but invoke them indirectly through Ligoncontext.
Validation: CallbackHandler and callback
The CallbackHandler and callback objects enable the Loginmodule object to gather the necessary authentication information from the system and the user, while being independent of the interaction process that occurs when the actual information is collected.
Jaas contains seven callback implementation classes and two CallbackHandler implementation classes in the Javax.sevurity.auth.callback package: Choicecallback, Confirmationcallback , Logcalecallback, NameCallback, PasswordCallback, Textinputcallback, Textoutputcallback, Dialogcallbackhandler and Textcallbackhandler. The callback interface will only be used on the client. I'll explain how to write your own CallbackHandler class later.
configuration file
As I mentioned above, the extensibility of jaas stems from its ability to dynamically configure information, which is usually stored in text. These text files are composed of a number of configuration blocks, which we typically refer to as applications (application). Each request corresponds to one or more specific Loginmodule objects.
When your code constructs a LoginContext object, you need to pass the name of the application in the configuration file to it. LoginContext will decide which loginmodule objects to activate, in what order, and what rules to activate, based on the information in the application.
The configuration file structure looks like this:
Application { Moduleclass Flag moduleoptions; Moduleclass Flag moduleoptions; ... }; Application { Moduleclass Flag moduleoptions; ... }; ... |
The following is a request called sample
Sample { Com.sun.security.auth.module.NTLoginModule rquired debug=true; } |
The simple application above specifies that the LoginContext object should be validated using Ntloginmodule. The name of the class is specified in the Moduleclass. Flag controls the behavior of logging on when a requisition contains multiple loginmodule: Required, sufficient, requisite, and optional. The most commonly used is required, which means that the corresponding Loginmodule object must be invoked and must pass all validation. Because of the complexity of flag itself, this article does not delve into it here.
Moduleoption allows multiple parameters. For example, you can set the debug parameter to True (Debug=true) so that the diagnostic output is sent to the System.out.
The configuration file can be arbitrarily named and can be placed in any location. The JAAS framework uses the Java.securty.auth.long.config property to determine the location of the configuration file. For example, when your application is jaastest, the configuration file is the Jaas.config in the current directory, and you need to enter at the command line:
Java-djava.security.auth.login.config=jass.config Javatest
Figure II describes the relationships between the elements in the configuration file
Figure II Configuration file for Jaas
Logon authentication by command line
To illustrate what Jaas really does, I've written two examples here. One is a simple program called by the command line input, and the other is a server-side JSP program. Both programs log on by means of a username/password and then authenticate them using the relational database.
To verify through the database, we need to:
1. Implement the Rdbmsloginmodul class, which validates the information entered.
2. Edit a configuration file to tell LoginContext how to use Rdbmsloginmodule.
3. Implement the Consolecallbackhandler class, through which you can get input from the user.
4. Write application code.
In the Rdbmsloginmodul class, we must implement the five methods in the Lgoinmodule interface. The first is the Initialize () method:
public void Initialize (Subject Subject, CallbackHandler CallbackHandler,
Map sharedstate, map options) { This.subject = subject; This.callbackhandler = CallbackHandler; This.sharedstate = sharedstate; this.options = options;
url = (String) options.get ("url"); Driverclass = (String) options.get ("Driver"); debug = "true". Equalsignorecase ((String) options.get ("Debug"); } |
LoginContext calls the Initialize () method when calling the login () method. The first task of Rdbmsloginmodule is to hold a reference to the input parameter in the class. After the validation is successful, the principal object and credentials are sent to the subject object.
The CallbackHandler object will be used in the login () method. Sharedstate can allow data to be shared among different loginmodule objects, but we won't use it in this example. Finally, the map object named options. The options pass the value of the parameter defined in the configuration file moduleoption domain to the Lgoinmodule object. The configuration file looks like this:
Example { Rdbmsloginmodule Required Driver= "Org.gjt.mm.mysql.Driver" Url= "Jdbc:mysql://localhost/jaasdb?user=root" Debug= "true"; }; |
In the configuration file, Rdbmsloginmodule contains five parameters, where the driver, url, user, and password are required, and debug is an optional elaboration. The driver, URL, user, and password parameters tell us how to get a JDBC connection. Of course you can also add information from a table or column in a moduleoption domain. The purpose of using these parameters is to be able to manipulate the database. In the Initialize () method of the Loginmodule class, we save the value of each parameter.
We mentioned earlier that a logincontext corresponding configuration file tells it which application in the file should be used. This information is passed through the Lgoincontext constructor. The following is the code that initializes the client, creates a Logincontex object in the code, and invokes the login () method.
Consolecallbackhandler CBH = new Consolecallbackhandler (); LoginContext LC = new LoginContext ("Example", CBH); Lc.login (); |
When the Lgoincontext.login () method is invoked, it invokes the login () method of all loaded Loginmodule objects. In our example, the login () method in Rdbmsloginmodule.
The login () method in Rdbmsloginmodule has the following actions:
1. Create two callback objects. These objects get the username/password from the user input. Two callback classes in Jaas are used in the program: NameCallback and PasswordCallback (these two classes are included in the Javax.security.auth.callback package).
2. Activate callback by passing the callbacks as a parameter to the CallbackHandler handle () method.
3. Obtain username/password via callback object.
4. Verify the acquired username/password in the database by JDBC in the Rdbmsvalidate () method.
The following is the code for the login () method in Rdbmsloginmodule
public Boolean login () throws Loginexception { if (CallbackHandler = null) throw new Loginexception ("no handler");
NameCallback NAMECB = new NameCallback ("User:"); PasswordCallback PASSCB = new PasswordCallback ("Password:", true); Callbacks = new callback[] {NAMECB, PASSCB}; Callbackhandler.handle (callbacks);
String username = namecb.getname (); String password = new string (Passcb.getpassword ()); Success = rdbmsvalidate (username, password);
return (true); } |
In the handle () method of the Consolecallbackhandler class, you can see how the callback object interacts with the user:
public void handle (callback[] callbacks) Throws Java.io.IOException, Unsupportedcallbackexception {
for (int i = 0; I callbacks.length i++) { if (Callbacks[i] instanceof NameCallback) { NameCallback NAMECB = (namecallback) callbacks[i]; System.out.print (Namecb.getprompt ()); String user= (New BufferedReader
InputStreamReader (system.in)). ReadLine (); Namecb.setname (user); else if (Callbacks[i] instanceof PasswordCallback) { PasswordCallback PASSCB = (passwordcallback) callbacks[i]; System.out.print (Passcb.getprompt ()); String pass= (New BufferedReader
InputStreamReader (system.in)). ReadLine (); Passcb.setpassword (Pass.tochararray ()); } else { Throw (new Unsupportedcallbackexception (Callbacks[i), "Callback class not supported")); } } } logon validation using JSP and relational databases Now we want to have the program invoked through the command line continue into the Web application. Because Web applications differ in how they interact with ordinary applications, we will not be able to use the standard callback and CallbackHandler classes provided by Jaas. Because we can't open a command window in the Web program to let the user enter information. You might think that we can also use HTTP based authentication so that we can get user input from the username/password window that pops up in the browser. But there are also problems with this, which requires a two-way HTTP connection (in the login () method is difficult to achieve two-way connectivity). So in our example we use a form to log in, get the user input from the form, and then validate it through the Rdbmsloginmodule class. Because we are not dealing directly with Loginmodule in the application tier, but through Lgoincontext to invoke the method, how do we get the username and password into the Loginmodule object? We can use other methods to circumvent this problem, for example, we can initialize a Subject object before creating the LoginContext object and save the user name and password in the Subject object's credentials. We can then pass the subject object to the LoginContext constructor. While this approach is technically not a problem, it adds a lot of code to the application layer that is relevant to the security mechanism. and is usually sent to subject after validation, not before. We mentioned earlier that you can implement a CallbackHandler class and then pass its instance to the LoginContext object. Here we can use a similar method to handle user names and passwords. We have implemented a new class Passivecallbackhandler. The following is code that uses the class in a JSP:
String user = Request.getparameter ("user"); String pass = request.getparameter ("Pass"); Passivecallbackhandler CBH = new Passivecallbackhandler (user, pass); LoginContext LC = new LoginContext ("Example", CBH); |
The parameters of the constructor in Passivecallbackhandler contain the username and password. So it can set the correct value in the Callbick object. The following is the code for the handle () method of the Passivecallbackhandler class:
public void handle (callback[] callbacks) Throws Java.io.IOException, Unsupportedcallbackexception { for (int i = 0; I callbacks.length i++) { if (Callbacks[i] instanceof NameCallback) { NameCallback NAMECB = (namecallback) callbacks[i];
Namecb.setname (user); else if (Callbacks[i] instanceof PasswordCallback) { PasswordCallback PASSCB = (passwordcallback) callbacks[i]; Passcb.setpassword (Pass.tochararray ()); } else { Throw (new Unsupportedcallbackexception (Callbacks[i), "Callback class not supported")); } } } } |
You can see from the code above that we're actually just going to remove the code that prompts the user for input from the Consolecallbackhandler.
In running this JSP example, we need to set the system properties so that the Lgoincontext object knows how to find the configuration named "Example". We are using the resin server. In resin.conf, we added a <caucho.com> node:
java.security.auth.login.config= "/resin/conf/jaas.config"/> |
Summary
JAAS enables applications to have a more robust security mechanism by providing a dynamic, extensible model for user authentication and control permissions. It also enables you to easily create your own login mechanism. Jaas can work on both client and server-side applications at the same time. Although the server-side Jaas is not very stable at the moment, it is believed to be a good solution to the problem as technology progresses. |