This tutorial describes how a developer can write a custom JAASTM LoginModule for using an LDAP authentication data store along with a JavaTM 2 Platform, Enterprise Edition (J2EETM) application.
The tutorial includes a sample implementation of a LDAP based LoginModule which is downloadable as jaastutorial.zip. The archive contains:
- jaastutorial.jar
- jaasclient.jar
- jaastutorial.bat
- jaastutorial.sh
- login.cfg
- Pramati Server 3.0
- Pramati Studio 3.0
- OpenLDAP 2.0.18
- Java Authentication and Authorization ServiceTM 1.0
- JavaTM 2 Platform, Enterprise Edition 1.3
- Lightweight Directory Access Protocol 3.0
Why JAAS in J2EE
J2EE model: roles, users and JAAS
Writing the JAAS security module
Step 1: Writing the LoginModule
initialize() method
login() method
commit() method
abort() method
logout() method
Exceptions thrown by LoginModule methods
Step 2: Writing the CallBackHandler
Step 3: Configuring the J2EE application
Step 4: Packaging the LoginModule along with application
Step 5: Integrating the LoginModule with the J2EE server
Sample LDAP-based LoginModule
Installing and configuring the OpenLDAP Server
LDAP parameters for LoginModule and User Manager
Configuring LoginModule with Pramati Server
Configuring the User Manager
Creating users and roles from the User Manager
Setting the client classpath
Running the sample
Summary
Why JAAS in J2EE
One of the limitations of J2EE Version 1.2 platform was it did not provide application developers with a standard route to integrating the application server realm with existing or custom security infrastructures. J2EE Version 1.3 now solves that with the inclusion of Java Authentication and Authorization Service (JAAS™) framework.
J2EE application servers that implement JAAS provide enterprise application developers with the standard Login Module API for tapping custom or legacy security systems from their applications. While application developers write to the LoginModule API (specifically, LoginContext API), the application server implements the LoginModule interface.
The standards-based LoginModule interface gives J2EE developers the freedom to tap a variety of information sources that use Java Database Connectivity, the lightweight directory access protocol (LDAP) or Shared File Systems to store authentication data - without requiring them to modify the application code.
Indeed, there are increasing number of scenarios where J2EE application developers wish to tap custom authentication repositories from their applications. They would do this by writing a Login Module, packaging it along with their application and distributing to target J2EE application servers in a prescribed way.
J2EE Model: Roles, Users and JAAS
The J2EE model defines security at two levels: system and application. System level security is defined in terms of User Groups, called Roles, and in terms of security privileges mapping definitions, called Realms. Realms are mappings of one or more User Groups to a set of privileges or permissions.
Application level security is constituted from User Groups and Realms. At the application level, security permissions also list the various application components that are accessible by each User Group in each Realm. Thus, when an application is deployed, its application level realms and roles are mapped to the system level realms and roles defined on the server.
J2EE application servers implementing JAAS enable application developers to write a custom "pluggable" login module in the server environment. Such a module provides a conduit for roles defined in the packaged application to user group information stored in some custom authentication repository, say an LDAP server.
How LoginModule helps application roles and groups map to authentication data stored in a custom repository such as LDAP.
Writing the JAAS Security Module
A J2EE application developer writing security with JAAS would basically write the Login Module. The JAAS interface implementation holds the authentication logic. Application servers typically ship with standard Login Module implementations. Application developers may want to write their own implementation, and will see how in this tutorial in the following steps:
- Writing the
LoginModule
interface (LoginContext
API) - Writing the
CallBackHandler
interface that enables client to pass authentication data to the server - Configuring the
LoginModule
andCallBackHandler
with the server and application - Packaging the application along with module classes
- Integrating the LoginModule with the application server
Step 1: Writing the LoginModule
In this tutorial, you will see code snippets from aLoginModule
implementation for an LDAP Server. We also demonstrate how to test the LDAP LoginModule sample in a typical J2EE application server environment. This is how the LoginModule implementation class is defined:
public class LDAPLoginModule implements LoginModule
The standard JAAS packages required by this class are imported as shown here:
import javax.security.*;Standards methods in the LoginModule that must be implemented are:
initialize()
login()
commit()
abort()
logout()
initialize()
The initialize method does the following:- Sets configurations required by the LoginModule
- Collects login information that is encapsulated in the CallBackHandler
- Initializes and instantiates all configuration parameters for this instance of the LoginModule
The client instantiates the LoginContext object and passes a CallBackHandler instance with the user name and password. When the LoginContext object is instantiated, the initialize() method of the LoginModule is triggered.
public static void main(String args[])
{
LoginContext lc = new LoginContext("Login",
new MyCallbackHandler(args[0],args[1]));
}
login()
This method returns a boolean variable, which is true if the authentication information provided is valid. The login method performs the following tasks:- Fetches the login information
- Authenticates the user
The login information is fetched using the CallBackHandler. The code that does this is shown here:
Callback[] calls=new Callback[2];
calls[0]=new NameCallback("name");
calls[1]=new PasswordCallback("Password",false);
callbackHandler.handle(calls);
The login
method tries to connect to the server using the login information that is fetched. If the connection is established, the method returns the value true. The following code snippet shows this:
boolean verification=false;
…try{
props.put(Context.SECURITY_PRINCIPAL,cbUserName);
props.put(Context.SECURITY_CREDENTIALS,cbPassword);
ctx = new InitialDirContext(props);
verification=true;
}…
return verification;
This code changes with the actual type of security framework for which the LoginModule is written.
commit() method
This method sets the subject in the session to the username that is validated by the login
method. It also populates the subject with roles specified in the LDAP server (in this tutorial) for that user, and returns true. If the user is not validated, the commit
method returns false. The following code snippet shows this:
if(verification)
{subject.getPrincipals().add(userName);
…subject.getPrincipals().add(role);
return true;
}else return false;
abort() method
This method is used to exit the LoginModule in case of runtime exceptions and is usually triggered by the application server. This method is invoked after the abort() method of LoginContext. The application developer must not directly call the abort method of the LoginContext interface.logout() method
This method clears the principal settings of the subject in the session. It removes the privilege settings associated with the roles of the subject. The following code snippet shows this:subject.getPrincipals().clear();
verification=false;
return true;
Exceptions thrown by LoginModule methods
According to the JAAS specifications, all LoginModule methods should only throw a LoginException. Any other exception during LoginModule execution should be caught and a LoginException thrown against it. The following code snippet shows how this can be done:
public boolean login() throws LoginException
{
…
catch(IOException e)
{throw new LoginException(e.toString());}
…}
Step 2: Writing the CallBackHandler
The CallBackHandler is the JAAS interface that defines the type of data used for authentication. For example, a username-password or a user-certificate combination forms a security identity and credential pair. The type of data used for validating the identity is defined as part of the implementation of the CallBackHandler interface.
The CallbackHandler implementation contains a single method, handle(). The following code snippet from the CallBackHandler distributed with the sample client application ClientLoginSample.java demonstrates this:
static class MyCallbackHandler implements CallbackHandler
{
private String username;
private String password;
The handle() method sets the value of the username and password attributes, passed by the client application, in the LoginModule's CallBackHandler. The following code snippet shows this:
handle(){
…
if(callbacks[i] instanceof NameCallback){
NameCallback ncb = (NameCallback)callbacks[i];
ncb.setName(username);}
if(callbacks[i] instanceof PasswordCallback){
PasswordCallback pcb = (PasswordCallback)callbacks[i];
pcb.setPassword(password.toCharArray());
}}
Step 3: Configuring the J2EE application
A J2EE application package includes descriptors that contain information about security privileges for various modules/components of the application. Security privilege is defined at the application level and is associated with realms and roles. During deployment, these roles are mapped to roles defined in the server-level realm.
Configuring a login module with a J2EE application involves the following steps:
- Creating a login UI that validates user information by calling the LoginContext interface.
- Creating application level realms and roles, and mapping permissions to application components
- Distributing the Login Module classes with the application
Step 4: Packaging the Login Module along with Application
A J2EE application developer would want to configure the LoginModule with a target J2EE application server. Therefore, the LoginModule, along with the helper classes, is packaged into a separate JAR file that may be distributed independent of the application archives, and separately loaded from the server classpath.
For this reason, there must be no code-level dependencies in the LoginModule on the J2EE application.
Step 5: Integrating the Login Module with the J2EE Application Server
The deployment process for a LoginModule is unlike J2EE applications and involves configuring the target application server.
A J2EE application server organizes its security environment into realms, each of which maps to one or more login modules, and has one or more users and roles defined on it. This differs from application realms, which are associated with security permissions for the application and do not assume the existence of any LoginModule.
Integrating a LoginModule with the application server involves the following steps:
- Configuring the server with a realm that uses a specific LoginModule for security authentication.
- Mapping the application realm and roles to the realm and roles defined by the LoginModule.
Sample LDAP-based LoginModule
The tutorial includes a sample implementation of a LDAP based LoginModule. Download the required sample files here (jaastutorial.zip).
We illustrate the steps to integrate this implementation of the LDAP-based LoginModule with Pramati Server using a sample application.
The sample application uses Pramati's implementation of the User Manager Module, which creates users on the LDAP Server and maps roles to various user names defined on the LDAP server. Get the User Manager API here.
Installing and configuring the LDAP server
This tutorial is written assuming a particular directory structure on a LDAP Server.
If you do not have a LDAP Server installed, download one from www.openldap.org. You may access this FTP site. OpenLDAP Server is distributed for Unix/Linux platforms.
Download the Quickstart Guide for LDAP and do as follows to create the required directory structure:
- Replace the directory names
MY-DOMAIN
andexample
with the namemy_company
. - In the LDAP server configuration file
slapd.conf
, set password against the namerootpw
asmy_password
. - Disable the schema checks on the LDAP server by adding the following line to the
slapd.conf
file:schemacheck off
- After configuring the LDAP Server with the directory structure, start the server as instructed in the Quickstart Guide.
LDAP parameters for Login Module and the User Manager | |
Name | Value |
LDAPServerUrl | The URL and port of the LDAP Server. If the LDAP server is running on the same host as the application server, it would be ldap://localhost:389 (with LDAP Server on port 389) |
LDAPContextFactory | A default standard context factory implementation is provided by Sun. Set this field ONLY if you are using an other Context Factory. Add the factory to the server classpath too. You will need to restart the server. |
Realmname | This is the application server-level realm. For example, ldap |
LDAPUserKey | cn |
LDAPUserSuperContext | For example, dc=my_company, dc=com |
LDAPRolesKey | sn |
LDAPSuperUserDN | For example, cn=manager,dc=my_company,dc=com. This refers to the distinguishing name of the LDAP super user and is set by the LDAP administrator. |
LDAPSuperUserPassword | The LDAP super user password to the server. This is needed to allow addition and removal of users by the LDAP User Manager. |
Configuring LoginModule with Pramati Server
- Place the
jaastutorial.jar
in the classpath of the server by editing thesetup.bat
. - Run
setup.bat
from the command line. - Start the Server and then start the Console.
- Select the Security node in the tree panel on the Console and select '+' for adding an LDAP realm.
- In the View Panel, choose an appropriate server realm name, say, ldap.
- Add the path to the LoginModule class as com.pramati.security.loginmodules.ldap.LDAPLoginModule.
- Specify the
Flag
asRequired
. - The Init options require multiple name-value pairs and these are listed as LDAP parameters in the section above.
Configuring the User Manager
- On the same page, give the fully qualified path of the User Manager class as
com.pramati.security.loginmodules.ldap.LDAPUserManager
- The User Manager needs the same name-value pairs as the LoginModule in the Init Options.
After configuring the LoginModule and the UserManager for the LDAP realm, click on Add button to register the LDAP realm with the application server.
Ensure that the jaastutorial.jar package is present in the server classpath, before starting the server.
Creating users and roles using the User Manager
From the Console, configuring new users with unique user names and passwords, roles within the realm, and mapping the roles and users effectively test the LDAP User Manager Module. If the configuration is correct, new users and their role mappings are added to the realm that can be viewed from the Console.
Setting the client classpath
The ClientLoginSample
is a sample Java client that connects to the LDAP server through Pramati Server. The client classpath is modified to point to sample classes and files, as well as the server classes required to run the Java client.
The ClientLoginSample
and helper classes are packaged in jaasclient.jar
. This must be placed in the client classpath.
The client requires the location of the Pramati Server and the realm to log in to. This information is stored in a file, login.cfg, which is packaged along with this tutorial. This file must be placed in the client classpath.
Edit the login.cfg
file to point to the server location and realm name. For example,
com.pramati.realm="realm://127.0.0.1:9191/ldap"
The client also requires the following application server packages in its classpath:jaas.jar
jta.jar
pramati_client.jar
security_interop.jar
Edit the file jaastutorial.bat
to point to the installation directory of Pramati Server. Run jaastutorial.bat
from the command line to set the client classpath.
Running the sample
After setting the client classpath, run the ClientLoginSample
program by executing:
java -Djava.security.auth.login.config=Supply the username and password that has been configured on the LDAP server. The sample program will return the Role to which the User has been mapped. It then logs out the user from the realm. An error message is displayed if the username-password submitted is invalid.
com.pramati.security.samples.ClientLoginSample
http://www.hibernate.org/328.html
ReplyDelete