Sunday, January 22, 2012

JAAS - A dummy introduction












According to java documentationJavaTM Authentication and Authorization Service(JAAS) was introduced as an optional package to the J2SDK and JAAS was integrated into the J2SDK 1.4.

JAAS can be used for two purposes:
·    for authentication of users, to reliably and securely determine who is currently executing Java code, regardless of whether the code is running as an application, an applet, a bean, or a servlet; and
·    for authorization of users to ensure they have the access control rights (permissions) required to do the actions performed.

A brief idea







Authentication is the process of confirming identity of user. Its simply asking question "Who are you?"
Authorization is a process of deciding whether authenticated user is allowed to access a particular resource or not. The goal of authorization is to protect application resources or application functionalities from being used by people who  do not have right to access resources,application or subset of its functionality.

In this post, we will be focusing on authentication through JAAS and its configuration in Jboss application server.
These are  basic elements of JAAS:


  • JAAS client: JAAS client is an application wishing to perform authentication using a JAAS-compliant authentication service.
  • JAAS-compliant authentication service: It consists of one or more login modules along with logic to perform the needed authentication.
  • JAAS configuration file : The JAAS configuration file is a text/xml file that the JAAS client uses to locate the login module(s) to be used.



LoginContext (documentation)
The LoginContext reads the configuration to load all of the LoginModules included in the named login configuration.

Callback handler (documentation)
The JAAS client communicates with the authentication service using one or more login modules. Client provides a callback handler which is used by login module to obtain the user name, password, and other information needed for authentication.

Applications implement the CallbackHandler interface and pass it to the LoginContext, which forwards it directly to the underlying login modules.
In our example, MyJAASCallBackHandler is our callback handler which implements CallbackHandler.

LoginModule (documentation)

LoginModule describes the interface implemented by authentication technology providers or vendors.
Login modules use the CallbackHandler both to gather input from users, such as a password or smart-card PIN number, and to supply information to users, such as status information.

In our case, JBoss AS includes several bundled login modules suitable for most user management needs. It provides login modules like UsersRolesLoginModule, DatabaseServerLoginModule, LdapLoginModule etc.


We are using DatabaseServerLoginModule login module in our example, which is a Java Database Connectivity-based (JDBC) login module that supports authentication and role mapping  where you have your username, password and role information stored in a relational database. more about Jboss LoginModule
Authentication of a subject requires a JAAS login. The login procedure consists of the following steps:



  • A JAAS client instantiates a LoginContext passing in the name of the login configuration and a CallbackHandler to populate the Callback objects as required by the configuration LoginModules.
    •   new LoginContext("sarfJAAS"
                    new MyJAASCallBackHandler(strUser, strPassword));

  • The LoginContext consults a Configuration to load all of the LoginModules included in the named login configuration.
  • The application invokes the LoginContext.login method.
  • The login method invokes all the loaded LoginModules. As LoginModule attempts to authenticate the subject, it invokes the handle method on the associated CallbackHandler to obtain the information required for the authentication process. The required information is passed to the handle method in the form of an array of Callback objects. Upon success, the LoginModules associate relevant principals and credentials with the subject.
  • The LoginContext returns the authentication status to the application. Success is represented by a return from the login method. Failure is represented through a LoginException being thrown by the login method.
  • If authentication succeeds, the application retrieves the authenticated subject using the LoginContext.getSubject method.
  • After the scope of the subject authentication is complete, all principals and related information associated with the subject by the login method may be removed by invoking the LoginContext.logout method.









I have created a simple web application to demonstrate the jaas authentication. This web application contains one Servlet for authentication  with a callback handler class and three jsp files for view. We have also couple of xml files for configuration purpose.


MyLoginController.java
package com.sarf.controller;

import java.io.IOException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyLoginController")
public class MyLoginController extends HttpServlet {
   private static final long serialVersionUID = 1L;
   public MyLoginController() {}

   protected void doGet(HttpServletRequest request, 
    HttpServletResponse response) throws ServletException, IOException {}
     
   protected void doPost(HttpServletRequest request, 
    HttpServletResponse response) throws ServletException, IOException {
     String strUser = request.getParameter("user");
     String strPassword = request.getParameter("password");
           
     LoginContext lc = null;
     if(null != strUser && null!= strPassword)
     {
      try {
            lc = new LoginContext("sarfJAAS", 
                new MyJAASCallBackHandler(strUser, strPassword));
            lc.login();
            RequestDispatcher rd = 
             getServletContext().getRequestDispatcher("/jsp/success.jsp");
            rd.forward(request, response);
           }
           catch (LoginException e) 
           {
             System.out.println("#Error# "+e.getMessage());
             RequestDispatcher rd = 
               getServletContext().getRequestDispatcher("/jsp/error.jsp");
             rd.forward(request, response);
           }
        }
    }
}


MyJAASCallBackHandler.java 
package com.sarf.controller;

import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;

public class MyJAASCallBackHandler implements CallbackHandler {
   String name;
   String password;

   public MyJAASCallBackHandler(String name, String password) {
       this.name = name;
       this.password = password;
    }

   public void handle(Callback[] callbacks) throws IOException, 
      UnsupportedCallbackException {
      for (int i = 0; i < callbacks.length; i++) {
       if (callbacks[i] instanceof NameCallback) {
        NameCallback nameCallback = (NameCallback) callbacks[i];
        nameCallback.setName(name);
       } 
       else if (callbacks[i] instanceof PasswordCallback) {
        PasswordCallback passwordCallback=(PasswordCallback)callbacks[i];
        passwordCallback.setPassword(password.toCharArray());
        } else {
         throw new UnsupportedCallbackException(callbacks[i], 
           "The submitted Callback is unsupported");
         }
       }
    }
}


index.jsp



success.jsp



error.jsp



web.xml








Setup & Deploy











application.xml





This file should be inside META-INF directory of war file
jboss.xml



mysql-ds.xml





login-config.xml
Copy the below xml excerpt into jboss-5.1.0.GA\server\default\conf\login-config.xml at end of the file under <policy> tag







  
Database










-- Create a databse namely test using the following sql query:
CREATE DATABASE IF NOT EXISTS test;
USE test;


-- Create two table Users and UserRoles using the following command:
DROP TABLE IF EXISTS users;

CREATE TABLE Users(
      username VARCHAR(64) PRIMARY KEY,
      passwd VARCHAR(64)
      );
     
DROP TABLE IF EXISTS UserRoles;
CREATE TABLE UserRoles(
      username VARCHAR(64),
      userRoles VARCHAR(32)
      );
     
-- Populate data in Users and UserRoles  table using the following command 
INSERT INTO `users`(`username`,`passwd`) VALUES ( 'sarf','root');
INSERT INTO `users`(`username`,`passwd`) VALUES ( 'sunny','root');

INSERT INTO `userroles`(`username`,`userRoles`) VALUES ( 'sarf','admin');
INSERT INTO `userroles`(`username`,`userRoles`) VALUES ( 'sunny','manager');









You need to copy mysql-ds.xml and JAASExample.war file into jboss deploy directory.
The directory structure of the war file is shown below.