I have just completed a short vide clip that presents a simple JAAS code sample. This code sample presents a simple implementation for the authantication mechanism.

This code sample includes the following files:

PrincipleImplementation.java
The Principle interface represents an entity such as an individual, corporation or a simple login id. Our implementation for that interface will be in accordance with our needs.
public class PrincipleImplementation implements Principal, java.io.Serializable
{
    private String name;
    public PrincipleImplementation(String name) 
    {
       if (name == null)  throw new NullPointerException(“illegal null input…”);
       this.name = name;
    }
   
public String getName()
   
{
       return name;
    }
   
public String toString()
    {
       return(“principle sample implementation”);
    }
   
public boolean equals(Object other)
   
{
      if (other == null)
      {
        return false;
      }
     
if (this == other)
      {
        return true;
      }
      if (!(other instanceof PrincipleImplementation))
      {
        return false;
      }
     
PrincipleImplementation that = (PrincipleImplementation)other;
     
if (this.getName().equals(that.getName()))
      {
        return true;
      }
      return false;
   }
   public int hashCode()
   {
     return name.hashCode();
   }
}

LoginModuleImplementation.java
The LoginModule interface describes the login process. We should implement this interface assuming that the required data for approving the login (e.g. the username and the password) will be retrieved from the user through our implementation for CallbackHandler. The LoginModule and the CallbackHandler interfaces keep a clear separation between getting the username and the password from the user (CallbackHandler interface is responsible for that) and comparing them with the data in database (LoginModule interface is responsible for that). The LoginModule interface is also responsible for specifying the exact required data. It does it by specifying the exact required Callback objects. In this code sample our LoginModule implementation requires the user to enter a username and a password. It could ask for other data as well (e.g. two different passwords and one username). In this code sample our CallbackHandler implementation asks the user to enter the username and the password through the command line. The implementation could be different. It could ask the user to provide his username by putting a finger on a small scanner.
public class LoginModuleImplementation implements LoginModule
{
 private Subject subject;
 private CallbackHandler callbackHandler;
 private Map sharedStateMap;
 private Map options;
 private boolean debug = true;
 private char[] password = null;
 private String username = null;
 private boolean succeeded, commitSucceeded;
 private PrincipleImplementation userPrincipal;
 public void initialize(Subject subject, CallbackHandler callbackHandler,
 Map sharedStateMap, Map options)
 {
  this.subject = subject;
  this.callbackHandler = callbackHandler;
  this.sharedStateMap = sharedStateMap;
  this.options = options;
  debug = “true”.equalsIgnoreCase((String)options.get(“debug”));
 }
 public boolean login() throws LoginException
 {
  if(debug) System.out.println(“DEBUG within login()”);
  if (callbackHandler == null)
   throw new LoginException(“error… no CallbackHandler available…”);
  Callback[] callbacks = new Callback[2];
  callbacks[0] = new NameCallback(“user name: “);
  callbacks[1] = new PasswordCallback(“password: “, false);
  try
  {
   callbackHandler.handle(callbacks);
   username = ((NameCallback)callbacks[0]).getName();
   char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
   if (tmpPassword == null)
    tmpPassword = new char[0];
   password = new char[tmpPassword.length];
   System.arraycopy(tmpPassword, 0,password, 0, tmpPassword.length);
   ((PasswordCallback)callbacks[1]).clearPassword();
  }
  catch (java.io.IOException ioe)
  {
   throw new LoginException(ioe.toString());
  }
  catch (UnsupportedCallbackException uce)
  {
   throw new LoginException(“error… “);
  }
  if (username.equals(“user”) && new String(password).equals(“password”))
  {
   succeeded = true;
   return true;
  }
  else
  {
   System.out.println(“authentication failed…”);
   succeeded = false;
   if (!username.equals(“user”))
   {
    throw new FailedLoginException(“User Name Incorrect”);
   }
   else
   {
    throw new FailedLoginException(“Password Incorrect”);
   }
  }
}
public boolean commit() throws LoginException
{
  if(debug) System.out.println(“DEBUG within commit()”); 
  if (succeeded == false)
  {
   if(debug) System.out.println(“DEBUG within commit()… succeeded is false…”);  
   return false;
  }
  else
  {
   if(debug) System.out.println(“DEBUG within commit()… succeeded is true…”);    
   userPrincipal = new PrincipleImplementation(username);
   if(debug) System.out.println(“DEBUG within commit()… succeeded is true…”);     
   if (!subject.getPrincipals().contains(userPrincipal))
   {
    if(debug) System.out.println(“DEBUG within commit()… succeeded is true…”);  
    subject.getPrincipals().add(userPrincipal);
    if(debug) System.out.println(“DEBUG within commit()… succeeded is true…”);  
   }
   username = null;
   password = null;
   commitSucceeded = true;
   return true;
  }
}
public boolean abort() throws LoginException
{
  if(debug) System.out.println(“DEBUG within abort()… succeeded=”+succeeded
    +”commitSucceeded=”+commitSucceeded);
  if (succeeded == false)
  {
   return false;
  }
  else if (succeeded == true && commitSucceeded == false)
  {
   succeeded = false;
   username = null;
   if (password != null)
   password = null;
   userPrincipal = null;
  }
  else
  {
   logout();
  }
  return true;
}
public boolean logout() throws LoginException
{
  if(debug) System.out.println(“DEBUG within logout()”); 
  subject.getPrincipals().remove(userPrincipal);
  succeeded = false;
  succeeded = commitSucceeded;
  username = null;
  if (password != null)
  {
   for(int index=0; index<password.length; index++)
   {
    password[index] = 0;
   }
   password = null;
  }
  userPrincipal = null;
  return true;
 }
}

MyCallbackHandlerImplementation.java
The CallbackHandler interface describes an object on which we can call the handle method passing over an array of Callback objects. Each Callback object can be instantiated from a different class, that implements the Callback interface, such as PasswordCallback, NameCallback, TextoutputCallback and others. Our implementation for CallbackHandler should execute a specific code for each and every Callback object in accordance with its type (e.g. if the Callback object is of the NameCallback type we can expect our implementation to ask the user to enter his username, if the Callback object is of the PasswordCallback type we can expect our implementation to ask the user for his password etc.).

class MyCallbackHandlerImplementation implements CallbackHandler
{
  public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
  {
    for (int i = 0; i < callbacks.length; i++)
    {
     if (callbacks[i] instanceof TextOutputCallback)
     {
      TextOutputCallback call = (TextOutputCallback)callbacks[i];
      switch (call.getMessageType())
      {
       case TextOutputCallback.INFORMATION:
         System.out.println(“information… ” + call.getMessage());
         break;
       case TextOutputCallback.ERROR:
         System.out.println(“error… ” + call.getMessage());
         break;
       case TextOutputCallback.WARNING:
         System.out.println(“warning… ” + call.getMessage());
         break;
       default:
        throw new IOException(“unsupported message type… ” + call.getMessageType());
      }
   }
   else if (callbacks[i] instanceof NameCallback)
   {
    NameCallback call = (NameCallback)callbacks[i];
    System.err.print(call.getPrompt());
    System.err.flush();
    call.setName((new BufferedReader(new InputStreamReader(System.in))).readLine());
   }
   else if (callbacks[i] instanceof PasswordCallback)
   {
    PasswordCallback call = (PasswordCallback)callbacks[i];
    System.err.print(call.getPrompt());
    System.err.flush();
    call.setPassword((new BufferedReader
    (new InputStreamReader(System.in))).readLine().toCharArray());
   }
   else
   {
    throw new UnsupportedCallbackException(callbacks[i], “unrecognized callback…”);
   }
  }
 }
}
int tries;
    for (tries = 0; tries < 3; tries++)
    {
      try
      {
        loginContext.login();
        break;
      }
      catch (LoginException le)
      {
       le.printStackTrace();
      }
      try
      {
       Thread.currentThread().sleep(4000);
      }
      catch (Exception e)
      {
        e.printStackTrace();
      } 
    }
   
if (tries == 3)
    {
     System.out.println(“Authentication Failed!”);
     System.exit(-1);
    }
   
System.out.println(“Authentication Succeeded!”);
  }
}

AuthenticationSample.java
This class is a simple stand alone application that uses the other classes. The code within the main method could be part of any other type of application, such as a Java Bean, JSP document or a Java Servlet.

public class AuthenticationSample
{
  public static void main(String[] args)
  {
    LoginContext loginContext = null;
    try
    {
     loginContext = new LoginContext(“conf”, new MyCallbackHandlerImplementation());
    }
    catch (LoginException lex)
    {
     lex.printStackTrace();
    }
    catch (SecurityException se)
    {
     se.printStackTrace();
    } 
   

conf.config
The purpose of this file is to bind between com.abelski.module.LoginModuleImplementation and the name ‘conf’.

conf {
   com.abelski.module.LoginModuleImplementation required debug=true;
};

The following video clip shows how to execute this code sample.

Leave a Reply

Your email address will not be published. Required fields are marked *