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;
}
}