/*
* $Id: DefaultLoginModule.java 19191 2010-08-25 21:05:23Z tcarlson $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.module.jaas.loginmodule;
import org.mule.module.jaas.MuleJaasPrincipal;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
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;
/**
* This is the Default Login Module for the Mule Jaas Authentication.
* It extends Jaas' own LoginModule interface.
*/
public class DefaultLoginModule implements LoginModule
{
// Callback Handlers
private CallbackHandler callbackHandler;
// the authentication status
private boolean succeeded = false;
private boolean commitSucceeded = false;
// username and password
private String username;
private String password;
private String credentials;
private List credentialList;
private Subject subject;
/**
* Abort if authentication fails
*
* @return boolean
* @throws LoginException
*/
public final boolean abort() throws LoginException
{
if (!succeeded)
{
return false;
}
else if (succeeded && !commitSucceeded)
{
// login succeeded but overall authentication failed
succeeded = false;
username = null;
if (password != null)
{
password = null;
}
}
else
{
// overall authentication succeeded and commit succeeded,
// but someone else's commit failed
logout();
}
return true;
}
/**
* Commit if authentication succeeds, otherwise return false
*
* @return boolean
* @throws LoginException
*/
public final boolean commit() throws LoginException
{
if (!succeeded)
{
return false;
}
else
{
// set the principal just authenticated in the subject
if (subject == null)
{
return false;
}
MuleJaasPrincipal principal = new MuleJaasPrincipal(username);
Set entities = subject.getPrincipals();
if (!entities.contains(principal))
{
entities.add(principal);
}
// in any case, clean out state
username = null;
password = null;
commitSucceeded = true;
return true;
}
}
/**
* Initialises the callbackHandler, the credentials and the credentials list
*
* @param subject
* @param callbackHandler
* @param sharedState
* @param options
*/
public final void initialize(Subject subject,
CallbackHandler callbackHandler,
Map sharedState,
Map options)
{
this.subject = subject;
this.callbackHandler = callbackHandler;
this.credentials = (String) options.get("credentials");
this.credentialList = getCredentialList(this.credentials);
}
/**
* This method attempts to login the user by checking his credentials against
* those of the authorised users.
*
* @throws LoginException This is thrown either when there is no callback Handler
* or else when the user fails to be authenticated
*/
public final boolean login() throws LoginException
{
if (callbackHandler == null)
{
throw new LoginException("Error: no CallbackHandler available "
+ "to garner authentication information from the user");
}
if (callbackHandler == null)
{
throw new LoginException("no handler");
}
NameCallback nameCb = new NameCallback("user: ");
PasswordCallback passCb = new PasswordCallback("password: ", true);
// Create the callbacks to send to the Callback Handler
Callback[] callbacks = new Callback[]{nameCb, passCb};
// Call the handler to get the username and password of the user.
try
{
callbackHandler.handle(callbacks);
}
catch (IOException e)
{
throw new LoginException(e.toString());
}
catch (UnsupportedCallbackException e)
{
throw new LoginException("Error: " + e.getCallback().toString()
+ " not available to garner authentication information "
+ "from the user");
}
username = nameCb.getName();
password = new String(passCb.getPassword());
boolean usernameCorrect = false;
boolean passwordCorrect = false;
succeeded = false;
// check the username and password against the list of authorised users
for (int i = 0; i < credentialList.size(); i = i + 2)
{
if (username.equals(credentialList.get(i).toString()))
{
usernameCorrect = true;
}
else
{
usernameCorrect = false;
}
if (password.equals(credentialList.get(i + 1).toString()))
{
passwordCorrect = true;
}
else
{
passwordCorrect = false;
}
// only if both the username and password are correct will the user be
// authenticated
if ((usernameCorrect) & (passwordCorrect))
{
succeeded = true;
}
}
if (succeeded)
{
return true;
}
else
{
succeeded = false;
username = null;
password = null;
if (!usernameCorrect)
{
throw new FailedLoginException("User Name Incorrect");
}
else
{
throw new FailedLoginException("Password Incorrect");
}
}
}
/**
* Returns true when authentication succeeds or false when it fails
*
* @return succeeded
*/
public final boolean logout()
{
return succeeded;
}
/**
* This method parses the credentials string and populates the credentials list
* against which the username and password submitted with the request will be
* checked
*
* @param credentials
* @return outputList
*/
public final List getCredentialList(String credentials)
{
boolean semicolonIsFound = false;
boolean dividerIsFound = false;
char[] credentialArray = credentials.toCharArray();
String username = "";
String password = "";
List outputList = new Vector();
for (int i = 0; i < credentials.length(); i++)
{
if ((credentialArray[i] != ':') && (!dividerIsFound))
{
username = username + credentialArray[i];
}
else if ((credentialArray[i] == ':') && (!dividerIsFound))
{
dividerIsFound = true;
}
else if ((credentialArray[i] != ';') && (!semicolonIsFound) && (dividerIsFound))
{
password = password + credentialArray[i];
}
else if ((credentialArray[i] != ';') && (!semicolonIsFound) && (dividerIsFound))
{
password = password + credentialArray[i];
}
else if ((credentialArray[i] == ';') && (!semicolonIsFound) && (dividerIsFound))
{
outputList.add(username);
outputList.add(password);
semicolonIsFound = false;
dividerIsFound = false;
username = "";
password = "";
}
}
return outputList;
}
}