package com.eforce.baby.auth.module;
import java.io.IOException;
import java.util.Map;
import org.apache.log4j.Logger;
import javax.security.auth.callback.Callback;
import com.eforce.baby.auth.handler.UserLoginCallback;
import com.eforce.baby.auth.handler.PasswordCallback;
import com.eforce.baby.auth.handler.DatasourceNameCallback;
import com.eforce.baby.auth.handler.DatabaseTypeCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import com.eforce.baby.auth.dao.UserDAO;
import com.eforce.baby.common.dao.DAOException;
import com.eforce.baby.common.factory.DAOFactory;
/**
* <p> <code>RDBMSLoginModule</code> implements the
* LoginModule interface. This can be plugged in under
* EEMS application to provide authentication from underlying
* database.
*
* <p> The <code>LoginContext</code> is responsible for reading the
* <code>Configuration</code> and instantiating RDBMSLoginModule.
*
* <code>RDBMSLoginModule</code> is initialized with
* a <code>Subject</code>, a <code>CallbackHandler</code>, shared
* <code>LoginModule</code> state, and LoginModule-specific options.
*
* <p> The calling application sees the authentication process as a single
* operation. However, the authentication process within the
* <code>RDBMSLoginModule</code> proceeds in two distinct phases.
* In the first phase, the RDBMSLoginModule's
* <code>login</code> method gets invoked by the LoginContext's
* <code>login</code> method. The <code>login</code>
* method for the <code>RDBMSLoginModule</code> then performs
* the actual authentication. Once finished, the RDBMSLoginModule's
* <code>login</code> method either returns <code>true</code>
* (if it succeeded) or <code>false</code> (if it should be ignored),
* or throws a <code>LoginException</code> to specify a failure.
* In the failure case, the <code>RDBMSLoginModule</code> must not retry the
* authentication or introduce delays. The responsibility of such tasks
* belongs to the application. In case the application attempts to retry
* the authentication, the LoginModule's <code>login</code> method will be
* called again.
*
* @author Arindam Mazumder
* @version 1.0, 07/08/2004
* @since EEMS architecture refresh
*/
public class RDBMSLoginModule implements LoginModule
{
private Logger log = (Logger) Logger.getInstance(this.getClass().getName());
/* Stores the subject to be authenticated */
private Subject subject;
/* Stores callback handler for gathering username, password, datasource name and database type */
private CallbackHandler handler;
/* Stores state shared with other configured LoginModules */
private Map sharedState;
/* Stores options specified in the login Configuration for this particular RDBMSLoginModule*/
private Map options;
/* Stores datasource name of the underlying database */
private String dsName;
/* Stores database type of the underlying database */
private String dbType;
/* Stores user login name */
private String username;
/* Stores user password */
private String password;
/**
* Initializes this RDBMSLoginModule.
*
* <p> This method is called by the <code>LoginContext</code>
* after this <code>RDBMSLoginModule</code> has been instantiated.
* The purpose of this method is to initialize this
* <code>RDBMSLoginModule</code> with the relevant information.
* If this <code>RDBMSLoginModule</code> does not understand
* any of the data stored in <code>sharedState</code> or
* <code>options</code> parameters, they can be ignored.
* <p>
*
* @param subject the <code>Subject</code> to be authenticated. <p>
*
* @param callbackHandler a <code>CallbackHandler</code> for gathering
* username, password, datasource name and database type. <p>
*
* @param sharedState state shared with other configured LoginModules. <p>
*
* @param options options specified in the login
* <code>Configuration</code> for this particular
* <code>RDBMSLoginModule</code>.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
{
this.subject = subject;
this.handler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
}
/**
* Method to authenticate a <code>Subject</code> (phase 1).
*
* <p> The implementation of this method authenticates
* a <code>Subject</code>. For example, it may prompt for
* <code>Subject</code> information such
* as a username and password and then attempt to verify the password.
* This method saves the result of the authentication attempt
* as private state within the RDBMSLoginModule.
* <p>
*
* @exception LoginException if the authentication fails
*
* @return true if the authentication succeeded, or false if this
* <code>RDBMSLoginModule</code> should be ignored.
*/
public boolean login() throws LoginException
{
log.debug("login() : ENTER");
boolean flag = false;
if (handler == null)
{
throw new LoginException("Error: no CallbackHandler available to garner authentication information from the user");
}
Callback callbacks[] = new Callback[4];
callbacks[0] = new UserLoginCallback("");
callbacks[1] = new PasswordCallback("");
callbacks[2] = new DatasourceNameCallback("");
callbacks[3] = new DatabaseTypeCallback("");
try
{
handler.handle(callbacks);
username = ((UserLoginCallback) callbacks[0]).getUserLogin();
password = ((PasswordCallback) callbacks[1]).getPassword();
dsName = ((DatasourceNameCallback) callbacks[2]).getDatasourceName();
dbType = ((DatabaseTypeCallback) callbacks[3]).getDatabaseType();
log.debug("user: " + username + " password: " + new String(password) + " dsName: " + dsName + " dbType: " + dbType);
}
catch (IOException ioe)
{
throw new LoginException(ioe.toString());
}
catch (UnsupportedCallbackException ce)
{
throw new LoginException("Error: " + ce.getCallback().toString());
}
UserDAO dao = (UserDAO) DAOFactory.getInstance().getDAO("com.eteam.ems.auth.dao.UserDAO");
try
{
flag = dao.authenticate(dsName, dbType, username, password);
log.debug(flag ? "TRUE" : "FALSE");
if (flag == false)
{
throw new LoginException("Login Unsuccessful");
}
}
catch(DAOException e)
{
throw new LoginException(e.toString());
}
log.debug("login() : EXIT");
return flag;
}
/**
* Method to commit the authentication process (phase 2).
*
* <p> This method is called if the LoginContext's
* overall authentication succeeded
* (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
* succeeded).
*
* <p>
*
* @exception LoginException if the commit fails
*
* @return true if this method succeeded, or false if this
* <code>RDBMSLoginModule</code> should be ignored.
*/
public boolean commit() throws LoginException
{
// TODO Auto-generated method stub
return true;
}
/**
* Method to abort the authentication process (phase 2).
*
* <p> This method is called if the LoginContext's
* overall authentication failed.
* (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
* did not succeed).
*
* <p>
*
* @exception LoginException if the abort fails
*
* @return true if this method succeeded, or false if this
* <code>RDBMSLoginModule</code> should be ignored.
*/
public boolean abort() throws LoginException
{
// TODO Auto-generated method stub
return false;
}
/**
* Method which logs out a <code>Subject</code>.
*
* <p>An implementation of this method might remove/destroy a Subject's
* Principals and Credentials.
*
*
* @exception LoginException if the logout fails
*
* @return true if this method succeeded, or false if this
* <code>RDBMSLoginModule</code> should be ignored.
*/
public boolean logout() throws LoginException
{
// TODO Auto-generated method stub
return false;
}
}