Custom login module

 

+

Search Tips   |   Advanced Search

 

We can also write your own login module for WebSphere Application Server. You need to implement the LoginModule interface and code the following methods:

public void initialize (Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) Initialize the login module after loading.
public boolean login() throws LoginException Perform the actual login. We can code the authentication check using callbacks.
public boolean commit() throws LoginException After a successful login, we need to commit the login. We can insert the new subject into the security context.
public boolean abort() throws LoginException In case of any problem, this method aborts the login process.
public boolean logout() throws LoginException After a successful login and by the end of the session, the application needs to log out and remove the subject from the security context.

Here is a simple custom login module...

package redbook.sg246316.loginmodule;

import java.util.*;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.*;
import redbook.sg246316.loginmodule.SamplePrincipal;

public class CustomLoginModule implements LoginModule 
{

 // initial state
 private Subject subject;
 private CallbackHandler callbackHandler;
 private Map sharedState;
 private Map options;

 // the authentication status
 private boolean succeeded = false;
 private boolean commitSucceeded = false;

 // username and password
 private String username;
 private String password;

 // testUser's SamplePrincipal
 private SamplePrincipal userPrincipal;



 public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) 
 {
  this.subject = subject;
  this.callbackHandler = callbackHandler;
  this.sharedState = sharedState;
  this.options = options;
 }

 public boolean login() throws LoginException 
 {

  // prompt for a user name and password
  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();
   password = new String(((PasswordCallback) callbacks[1]).getPassword());
   ((PasswordCallback) callbacks[1]).clearPassword();
  } 
  catch (java.io.IOException ioe) 
  {
   throw new LoginException(ioe.toString());
  } 
  catch (UnsupportedCallbackException uce) 
  {
   throw new LoginException("Error: " + uce.getCallback().toString());
  }

  // verify the username/password
  // this code is using hard-coded user name and password for the sake of simplicity
  boolean usernameCorrect = false;
  boolean passwordCorrect = false;
  if (username.equals("testUser")) usernameCorrect = true;

  if (usernameCorrect && password.equals("testPassword")) 
  {

   // authentication succeeded!!!
   passwordCorrect = true;
   succeeded = true;
   return true;

  } 
  else 
  {

   // authentication failed
   succeeded = false;
   username = null;
   password = null;
   throw new FailedLoginException("Authentication failed!");

  }
 }

 public boolean commit() throws LoginException 
 {
  if (succeeded == false) 
  {
   return false;
  } 
  else 
  {

   // add a Principal (authenticated identity) to the Subject
   // this is a custom principal: SamplePrincipal
   // in WebSphere you may want to use the WSPrincipalImpl class

   userPrincipal = new SamplePrincipal(username);

   if (!subject.getPrincipals().contains(userPrincipal))
    subject.getPrincipals().add(userPrincipal);

   username = null;
   password = null;
   commitSucceeded = true;
   return true;
  }
 }



 public boolean abort() throws LoginException 
 {
  if (succeeded == false) 
  {
   return false;
  } 
  else if (succeeded == true && commitSucceeded == false) 
  {

   // login succeeded but overall authentication failed
   succeeded = false;
   username = null;
   password = null;
   userPrincipal = null;
  } 
  else 
  {
   // overall authentication succeeded and commit succeeded, but someone else's commit failed
   logout();
  }
  return true;
 }



 public boolean logout() throws LoginException 
 {
  subject.getPrincipals().remove(userPrincipal);
  succeeded = false;
  succeeded = commitSucceeded;
  username = null;
  password = null;
  userPrincipal = null;
  return true;
 }
}

You will find that the custom login module uses a custom principal (SamplePrincipal). For more information about the principals, refer to the next section.

The login module basically performs the following steps:

  1. Initializes the login module, instantiates the necessary objects.

  2. Sets up the callback handler and the callback methods.

  3. Walks through the callbacks one after the other.

  4. Authenticates the user using the information returned from the callbacks.

      a. If authentication is successful, it creates a principal based on the authentication data and inserts it into the subject setup during initialization. b. If authentication fails, the module destroys the objects and returns with a failed flag.

  5. In the meantime, the login process can be aborted.

  6. After a successful login, the application can also log out. The logout method should take care of removing the principal from the subject and destroying the objects in the login module.