Apama 10.15.0 | Building and Using Apama Dashboards | Dashboard Deployment | Administering Dashboard Security | Example: Implementing LoginModule
 
Example: Implementing LoginModule
Below is a sample implementation of LoginModule, which you can find under samples\dashboard_studio\tutorial\src. See Authentication for local and application server deployments.
package com.apama.dashboard.sample;
import java.security.Principal;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
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;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
/**
* SampleLoginModule is an example of a custom JAAS login module for
* Dashboard Builder. Custom JAAS login modules allow you to extend Dashboard
* Builder to use the authentication mechanism of your choosing.
* <p>
* SampleLoginModule authenticates all users, regardless of username
* and password and adds the Principal "apama_customer" to each.
*
* $Copyright(c) 2013 Software AG, Darmstadt, Germany and/or its licensors$
*
*/
public class SampleLoginModule implements LoginModule {
  // Option strings
  private final static String OPT_DEBUG = "debug";
  // Initial state
  private Subject subject;
  private CallbackHandler callbackHandler;
  // True if debug logging turned on
  private boolean debug = false;
  // Authentication status
  private boolean succeeded = false;
  private boolean commitSucceeded = false;
  // Username and password
  private String username;
  private char[] password;
  /**
   * Initialize this LoginModule.
   *
   * @param subject Subject to be authenticated
   * @param callbackHandler CallbackHandler for communicating with the user to
   * obtain username and password
   * @param sharedState Shared LoginModule state
   * @param options Options specified in the login Configuration for this
   * LoginModule.
   */
  public void initialize(
    Subject subject, CallbackHandler callbackHandler, Map sharedState,
Map options) {
    this.subject = subject;
    this.callbackHandler = callbackHandler;
    // Process options
    debug = "true".equalsIgnoreCase((String) options.get(OPT_DEBUG));
    
    // Add additional options and initialization here
    
    // Must have a callback handler
    if (callbackHandler == null) {
      throw new IllegalArgumentException (
        "Error. Callback handler must be specified.");
    }
  }
  /**
   * Authenticate the user by calling back for username and password.
   *
   * @return true in all cases
   * @exception FailedLoginException if the authentication fails
   * @exception LoginException if unable to perform the authentication
   */
  public boolean login() throws LoginException {
    // Callback to get username and password
    Callback[] callbacks = new Callback[2];
    callbacks[0] = new NameCallback("username: ");
    callbacks[1] = new PasswordCallback("password: ", false);
    try {
      // Perform the callbacks
      callbackHandler.handle(callbacks);
      
      // Get the user supplied name and password
      username = ((NameCallback) callbacks[0]).getName();
      password = ((PasswordCallback) callbacks[1]).getPassword();
      if (password == null) {
        // Treat a NULL password as an empty password
        password = new char[0];
      }
      
      // Clear password
      ((PasswordCallback) callbacks[1]).clearPassword();
    } catch (java.io.IOException e) {
      throw new LoginException("UserFileLoginModule. Error performing
callbacks. " +
        e.toString());
    } catch (UnsupportedCallbackException e) {
      throw new LoginException("UserFileLoginModule. Error performing
callbacks " +
           e.getCallback().toString() + ".");
    }
    // verify the username/password
    if (validateUser()) {
      if (debug) {
        System.err.println("UserFileLoginModule.
User authenticated: " + username);
      }
      succeeded = true;
      return true;
    } else {
      if (debug) {
        System.err.println("UserFileLoginModule. User authentication failed: " +
          username);
      }
      succeeded = false;
      clearState();
      throw new FailedLoginException("UserFileLoginModule. Login failed.");
    }
  }
  /**
   * Called if the LoginContext's overall authentication succeeded
   * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
   * LoginModules succeeded).
   * <p>
   * Add the user's principals (roles) to the Subject
   *
   * @exception LoginException Commit failed
   * @return true if commit attempts succeeded; false otherwise.
   */
  public boolean commit() throws LoginException {
    if (succeeded == false) {
      return false;
    } else {
      
      // Get the users roles from the user database and add each as a
// SimplePrincipal
      subject.getPrincipals().addAll(getUserPrincipals());
      clearState();
      commitSucceeded = true;
      return true;
    }
  }
  /**
   * Called if the LoginContext's overall authentication
   * failed. (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
   * LoginModules did not succeed).
   * <p>
   * Cleans state information.
   *
   * @exception LoginException Abort failed
   * @return true if abort successfule; false otherwise
   */
  public boolean abort() throws LoginException {
    if (succeeded == false) {
      return false;
    } else if (succeeded == true && commitSucceeded == false) {
      // login succeeded but overall authentication failed
      succeeded = false;
      clearState();
    } else {
      // overall authentication succeeded and commit succeeded,
      // but another LoginModule's commit failed
      logout();
    }
    return true;
  }
  /**
   * Logout the user.
   *
   * @return true in all cases
   * @exception LoginException Logout failed
   */
  public boolean logout() throws LoginException {
    succeeded = false;
    succeeded = commitSucceeded;
    clearState();
    return true;
  }
  /**
   * Clear out temporary state used in a single login attempt.
   */
  private void clearState () {
    username = null;
    if (password != null) {
      for (int i = 0; i < password.length; i++)
        password[i] = ' ';
      password = null;
    }
  }
  /**
   * Validate current username/password pair.
   *
   * @return true if validated.
   */
  private boolean validateUser () {
    
    //
    // Add user validation here.
    //
    System.out.println("Validate username: " + username + " password: " +
      new String(password));
    return true;
  }
  
  /**
   * Get the principals (roles) for the current username.
   *
   * @return Set of Principals
   */
  private Set<Principal> getUserPrincipals () {
    HashSet<Principal> set = new HashSet<Principal>();
    //
    // Add user principals here.
    //
    
    System.out.println("Add principal username: " + username +
      " principal: apama_customer");
    set.add (new SamplePrincipal("apama_customer"));
    return set;
  }
}package com.apama.dashboard.sample;
import java.security.Principal;
/**
* SamplePrincipal is an example of a Java security principal (role) for
* use with JAAS authentication.
* <p>
* SamplePrincipal provides a simple string based principal.
*
* $Copyright(c) 2013 Software AG, Darmstadt, Germany and/or its licensors$
*
*/
public class SamplePrincipal implements Principal {
  // Principal name
  private String name;
  /**
   * Constructor.
   *
   * @param name Principal name
   */
  public SamplePrincipal(String name) {
    this.name = name;
  }
  /**
   * Get the name of the principal.
   */
  public String getName() {
    return name;
  }
}