Package org.groovymud.shell.security

Source Code of org.groovymud.shell.security.MudLoginModule

package org.groovymud.shell.security;

import java.io.IOException;
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.ConfirmationCallback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import org.apache.log4j.Logger;
import org.groovymud.object.alive.Player;

/**
* this little beast is the implementation of a JAAS login module
*
* see http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.html
*
* using JAAS should allow us to plug in modules a bit more easily by using a
* standard framework we should be able to use platform login modules too if
* required.
*
* @author matt
*
*/
public class MudLoginModule implements LoginModule {

  private static final String GUEST_USER = "guest";
  private static final String PLAYER_PRINCIPAL = "player";
  // 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;

  Player player = null;
  Player dupe = null;

  private Set<Principal> playerPrincipals;

  private final static Logger logger = Logger.getLogger(MudLoginModule.class);

  public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
    this.subject = subject;
    this.callbackHandler = callbackHandler;
    this.sharedState = sharedState;
    this.options = options;
    playerPrincipals = new HashSet<Principal>();
    getPlayerPrincipals().add(createPrincipal(GUEST_USER));
    // initialize any configured options
    debug = "true".equalsIgnoreCase((String) options.get("debug"));

  }

  protected MudPrincipal createPrincipal(String principal) {
    return new MudPrincipal(principal);
  }

  public boolean login() throws LoginException {
    try {
      NameCallback nameCallback = createNameCallback("username: ");
      Callback[] cb = createCallbackArray(nameCallback);

      getCallbackHandler().handle(cb);
      setUsername(nameCallback.getName());
      retrieveExistingPlayer(); // populate dupe player if there is one
      doLoadPlayerCallback(); // load the player
      boolean confirmed = false;

      if (getPlayer() == null) {
        ConfirmationCallback confirm = new ConfirmationCallback("Your name is not in our annuls:" + nameCallback.getName() + "..  Did you type it correctly?", ConfirmationCallback.INFORMATION, ConfirmationCallback.YES_NO_OPTION, ConfirmationCallback.YES);
        cb = createCallbackArray(confirm);
        getCallbackHandler().handle(cb);
        confirmed = (confirm.getSelectedIndex() == ConfirmationCallback.YES);
      }
      if (confirmed || getPlayer() != null) {

        if (!getUsername().equals(GUEST_USER)) {
          getPlayerPrincipals().add(createPrincipal(PLAYER_PRINCIPAL));
          checkPasswordValid(player);
          confirmDestIfDupeExisted();

        } else {
          // always create guests
          doCreatePlayerCallback();
        }
        // successful log in
        setSucceeded(true);
        return true;
      } else {
        TextOutputCallback toc = new TextOutputCallback(TextOutputCallback.WARNING, "Ok, try again then..");
        cb = createCallbackArray(toc);
        getCallbackHandler().handle(cb);
        return false;
      }
    } catch (IOException e) {
      logger.error(e, e);
      throw new LoginException(e.getMessage());
    } catch (UnsupportedCallbackException e) {
      logger.error(e, e);
      throw new LoginException(e.getMessage());
    }
  }

  protected Callback[] createCallbackArray(Callback... callback) {
    return callback;
  }

  protected NameCallback createNameCallback(String prompt) {
    return new NameCallback(prompt);
  }

  protected void doLoadPlayerCallback() throws IOException, UnsupportedCallbackException {
    Callback[] cb;
    ActionCallback loadCallback = createActionCallback(username, ActionCallback.LOAD_ACTION);
    cb = createCallbackArray(loadCallback);
    getCallbackHandler().handle(cb);
    setPlayer((Player) loadCallback.getMudObject());
  }

  protected ActionCallback createActionCallback(String username, String action) {
    return new ActionCallback(username, action);
  }

  protected void confirmDestIfDupeExisted() throws IOException, UnsupportedCallbackException, FailedLoginException {
    Callback[] cb;
    Player dupe = getDupe();
    if (dupe != null) {
      // we need to dest this player if they say yes
      ConfirmationCallback alreadyPlaying = new ConfirmationCallback("You are already playing. Throw the other copy out?", ConfirmationCallback.INFORMATION, ConfirmationCallback.YES_NO_OPTION, ConfirmationCallback.NO);
      cb = createCallbackArray(alreadyPlaying);
      getCallbackHandler().handle(cb);
      if (alreadyPlaying.getSelectedIndex() == ConfirmationCallback.YES) {
        dupe.dest(true);
      } else {
        throw new FailedLoginException("cannot log in, already logged in!");
      }
    }
  }

  protected void checkPasswordValid(Player player) throws IOException, UnsupportedCallbackException, FailedLoginException {
    Callback[] cb;
    PasswordCallback passwordCallback = null;
    PasswordCallback checkPassword = null;

    if (player == null) {

      checkPassword = createPasswordCallback("again:", false);
      passwordCallback = createPasswordCallback("enter a password:", false);

      cb = createCallbackArray(passwordCallback, checkPassword);
    } else {
      passwordCallback = createPasswordCallback("password: ", false);
      cb = createCallbackArray(passwordCallback);
    }
    getCallbackHandler().handle(cb);
    setPassword(passwordCallback.getPassword()); // set the password
    boolean passwordValid = false;
    if (checkPassword != null) {
      passwordValid = checkSamePassword(getPassword(), checkPassword.getPassword());
    } else {
      PlayerCredentials testCredentials = new PlayerCredentials(getUsername(), String.valueOf(getPassword()));
      passwordValid = player.getSubject().getPrivateCredentials().contains(testCredentials);
    }
    if (!passwordValid) {
      throw new FailedLoginException("passwords do not match.");
    }
    if (checkPassword != null) {
      doCreatePlayerCallback();
    }
  }

  protected PasswordCallback createPasswordCallback(String prompt, boolean echo) {
    return new PasswordCallback(prompt, echo);
  }

  protected void doCreatePlayerCallback() throws IOException, UnsupportedCallbackException {
    Callback[] cb;
    ActionCallback createCallback;
    createCallback = new ActionCallback(getUsername(), ActionCallback.CREATE_ACTION);
    cb = createCallbackArray(createCallback);
    getCallbackHandler().handle(cb);
    setPlayer((Player) createCallback.getMudObject());

  }

  protected void retrieveExistingPlayer() throws IOException, UnsupportedCallbackException, FailedLoginException {
    Callback[] cb;
    ActionCallback checkIfLoggedIn = createActionCallback(getUsername(), ActionCallback.EXISTS_ACTION);
    cb = createCallbackArray(checkIfLoggedIn);
    getCallbackHandler().handle(cb);
    setDupe((Player) checkIfLoggedIn.getMudObject());
  }

  protected boolean checkSamePassword(char[] password, char[] passwordOther) throws FailedLoginException {
    boolean passwordValid = true;
    if (passwordOther.length == 0) {
      throw new FailedLoginException("password cannot be 0 length");
    }
    for (int x = 0; x < passwordOther.length; x++) {
      if (passwordOther[x] != password[x]) {
        passwordValid = false;
      }
    }
    return passwordValid;
  }

  public boolean abort() throws LoginException {
    if (!hasSucceeded()) {
      return false;
    }
    if (hasSucceeded() && hasCommitSucceeded()) {
      logout();
    } else {
      setSucceeded(false);
    }
    return true;
  }

  public boolean logout() throws LoginException {
    getSubject().getPrincipals().removeAll(getPlayerPrincipals());
    cleanup();
    player = null;
    playerPrincipals = null;
    setSucceeded(setCommitSucceeded(false));
    return true;
  }

  public boolean commit() throws LoginException {
    if (!hasSucceeded()) {
      cleanup();
      return false;
    }
    Player player = getPlayer();
    if (player != null) {
      getPlayerPrincipals().addAll(player.getSubject().getPrincipals());
      logger.info("player principals:");
      for (Principal p : getPlayerPrincipals()) {
        logger.info(p.getName());
      }
      getSubject().getPrincipals().addAll(getPlayerPrincipals());
      player.setSubject(getSubject()); // update the players principals
      PlayerCredentials playerCredentials = new PlayerCredentials(getUsername(), String.valueOf(getPassword()));
      getSubject().getPrivateCredentials().add(playerCredentials);
      player.setPlayerCredentials(playerCredentials);
      cleanup();
      setCommitSucceeded(true);

    } else {
      throw new LoginException("player was null");
    }
    return true;
  }

  protected void cleanup() {
    username = null;
    password = null;
    dupe = null;
  }

  public Player getPlayer() {
    return player;
  }

  public void setPlayer(Player player) {
    this.player = player;
  }

  public CallbackHandler getCallbackHandler() {
    return callbackHandler;
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public char[] getPassword() {
    return password;
  }

  public void setPassword(char[] password) {
    this.password = password;
  }

  public Subject getSubject() {
    return subject;
  }

  public void setSubject(Subject subject) {
    this.subject = subject;
  }

  public Player getDupe() {
    return dupe;
  }

  public void setDupe(Player dupe) {
    this.dupe = dupe;
  }

  public void setCallbackHandler(CallbackHandler callbackHandler) {
    this.callbackHandler = callbackHandler;
  }

  public Set<Principal> getPlayerPrincipals() {
    return playerPrincipals;
  }

  public void setSucceeded(boolean succeeded) {
    this.succeeded = succeeded;
  }

  public boolean hasSucceeded() {
    return succeeded;
  }

  public boolean setCommitSucceeded(boolean commitSucceeded) {
    this.commitSucceeded = commitSucceeded;
    return commitSucceeded;
  }

  public boolean hasCommitSucceeded() {
    return commitSucceeded;
  }

}
TOP

Related Classes of org.groovymud.shell.security.MudLoginModule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.