/* * @(#)SampleLoginModule.java 1.18 00/01/11 * * Copyright 2000-2002 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * -Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduct the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF * THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that Software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility. */ package sample.module; import java.util.*; import java.io.IOException; import javax.security.auth.*; import javax.security.auth.callback.*; import javax.security.auth.login.*; import javax.security.auth.spi.*; import sample.principal.SamplePrincipal; /** *
This sample LoginModule authenticates users with a password. * *
This LoginModule only recognizes one user: testUser *
testUser's password is: testPassword * *
If testUser successfully authenticates itself,
* a SamplePrincipal
with the testUser's user name
* is added to the Subject.
*
*
This LoginModule recognizes the debug option.
* If set to true in the login Configuration,
* debug messages will be output to the output stream, System.out.
*
* @version 1.18, 01/11/00
*/
public class SampleLoginModule implements LoginModule {
// initial state
private Subject subject;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;
// configurable option
private boolean debug = false;
// the authentication status
private boolean succeeded = false;
private boolean commitSucceeded = false;
// username and password
private String username;
private char[] password;
// testUser's SamplePrincipal
private SamplePrincipal userPrincipal;
/**
* Initialize this LoginModule
.
*
*
*
* @param subject the Subject
to be authenticated.
*
* @param callbackHandler a CallbackHandler
for communicating
* with the end user (prompting for user names and
* passwords, for example).
*
* @param sharedState shared LoginModule
state.
*
* @param options options specified in the login
* Configuration
for this particular
* LoginModule
.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
// initialize any configured options
debug = "true".equalsIgnoreCase((String)options.get("debug"));
}
/**
* Authenticate the user by prompting for a user name and password.
*
*
*
* @return true in all cases since this LoginModule
* should not be ignored.
*
* @exception FailedLoginException if the authentication fails.
*
* @exception LoginException if this LoginModule
* is unable to perform the authentication.
*/
public boolean login() throws LoginException {
// prompt for a user name and password
if (callbackHandler == null)
throw new LoginException("Error: no CallbackHandler available " +
"to garner authentication information from the user");
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) {
// treat a NULL password as an empty password
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: " + uce.getCallback().toString() +
" not available to garner authentication information " +
"from the user");
}
// print debugging information
if (debug) {
System.out.println("\t\t[SampleLoginModule] " +
"user entered user name: " +
username);
System.out.print("\t\t[SampleLoginModule] " +
"user entered password: ");
for (int i = 0; i < password.length; i++)
System.out.print(password[i]);
System.out.println();
}
// verify the username/password
boolean usernameCorrect = false;
boolean passwordCorrect = false;
if (username.equals("testUser"))
usernameCorrect = true;
if (usernameCorrect &&
password.length == 12 &&
password[0] == 't' &&
password[1] == 'e' &&
password[2] == 's' &&
password[3] == 't' &&
password[4] == 'P' &&
password[5] == 'a' &&
password[6] == 's' &&
password[7] == 's' &&
password[8] == 'w' &&
password[9] == 'o' &&
password[10] == 'r' &&
password[11] == 'd') {
// authentication succeeded!!!
passwordCorrect = true;
if (debug)
System.out.println("\t\t[SampleLoginModule] " +
"authentication succeeded");
succeeded = true;
return true;
} else {
// authentication failed -- clean out state
if (debug)
System.out.println("\t\t[SampleLoginModule] " +
"authentication failed");
succeeded = false;
username = null;
for (int i = 0; i < password.length; i++)
password[i] = ' ';
password = null;
if (!usernameCorrect) {
throw new FailedLoginException("User Name Incorrect");
} else {
throw new FailedLoginException("Password Incorrect");
}
}
}
/**
*
This method is called if the LoginContext's * overall authentication succeeded * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules * succeeded). * *
If this LoginModule's own authentication attempt
* succeeded (checked by retrieving the private state saved by the
* login
method), then this method associates a
* SamplePrincipal
* with the Subject
located in the
* LoginModule
. If this LoginModule's own
* authentication attempted failed, then this method removes
* any state that was originally saved.
*
*
* * @exception LoginException if the commit fails. * * @return true if this LoginModule's own login and commit * attempts succeeded, or false otherwise. */ public boolean commit() throws LoginException { if (succeeded == false) { return false; } else { // add a Principal (authenticated identity) // to the Subject // assume the user we authenticated is the SamplePrincipal userPrincipal = new SamplePrincipal(username); if (!subject.getPrincipals().contains(userPrincipal)) subject.getPrincipals().add(userPrincipal); if (debug) { System.out.println("\t\t[SampleLoginModule] " + "added SamplePrincipal to Subject"); } // in any case, clean out state username = null; for (int i = 0; i < password.length; i++) password[i] = ' '; password = null; commitSucceeded = true; return true; } } /** *
This method is called if the LoginContext's * overall authentication failed. * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules * did not succeed). * *
If this LoginModule's own authentication attempt
* succeeded (checked by retrieving the private state saved by the
* login
and commit
methods),
* then this method cleans up any state that was originally saved.
*
*
* * @exception LoginException if the abort fails. * * @return false if this LoginModule's own login and/or commit attempts * failed, and true 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; username = null; if (password != null) { for (int i = 0; i < password.length; i++) password[i] = ' '; password = null; } userPrincipal = null; } else { // overall authentication succeeded and commit succeeded, // but someone else's commit failed logout(); } return true; } /** * Logout the user. * *
This method removes the SamplePrincipal
* that was added by the commit
method.
*
*
*
* @exception LoginException if the logout fails.
*
* @return true in all cases since this LoginModule
* should not be ignored.
*/
public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
succeeded = false;
succeeded = commitSucceeded;
username = null;
if (password != null) {
for (int i = 0; i < password.length; i++)
password[i] = ' ';
password = null;
}
userPrincipal = null;
return true;
}
}