com.alfaariss.oa.authentication.password.PasswordAuthenticationMethod.java Source code

Java tutorial

Introduction

Here is the source code for com.alfaariss.oa.authentication.password.PasswordAuthenticationMethod.java

Source

/*
 * Asimba Server
 * 
 * Copyright (C) 2012 Asimba
 * Copyright (C) 2007-2009 Alfa & Ariss B.V.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see www.gnu.org/licenses
 * 
 * Asimba - Serious Open Source SSO - More information on www.asimba.org
 * 
 */
package com.alfaariss.oa.authentication.password;

import java.io.IOException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;

import com.alfaariss.oa.DetailedUserException;
import com.alfaariss.oa.OAException;
import com.alfaariss.oa.SystemErrors;
import com.alfaariss.oa.UserEvent;
import com.alfaariss.oa.UserException;
import com.alfaariss.oa.api.IComponent;
import com.alfaariss.oa.api.attribute.ISessionAttributes;
import com.alfaariss.oa.api.configuration.IConfigurationManager;
import com.alfaariss.oa.api.idmapper.IIDMapper;
import com.alfaariss.oa.api.logging.IAuthority;
import com.alfaariss.oa.api.session.ISession;
import com.alfaariss.oa.api.user.IUser;
import com.alfaariss.oa.engine.core.Engine;
import com.alfaariss.oa.engine.core.crypto.CryptoException;
import com.alfaariss.oa.engine.core.crypto.CryptoManager;
import com.alfaariss.oa.engine.core.server.Server;
import com.alfaariss.oa.engine.core.user.factory.IUserFactory;
import com.alfaariss.oa.sso.authentication.service.IServiceAuthenticationMethod;
import com.alfaariss.oa.sso.authentication.web.IWebAuthenticationMethod;
import com.alfaariss.oa.util.logging.UserEventLogItem;

/**
 * The Password authentication method.
 * 
 * The password method authenticates the user using user name password
 * combination. Can be used as a web-based or service based authentication
 * method within the OpenASelect system.
 *
 * @author JVG
 * @author LVR
 * @author Alfa & Ariss
 *
 */
public class PasswordAuthenticationMethod implements IWebAuthenticationMethod, IServiceAuthenticationMethod {

    /** password handler */
    protected IPasswordHandler _oPasswordHandler;
    /** id mapper */
    protected IIDMapper _idMapper;

    private final static String AUTHORITY_NAME = "PasswordAuthenticationMethod_";
    private final static String HASCAPTCHA = "hasCaptcha";
    private final static String CAPTCHA = "captcha";
    private final static String PASSWORD = "password";

    /** CAPTCHA_HASH */
    private final static String CAPTCHA_HASH = "captcha_hash";

    private static final String DEFAULT_JSP_PASSWORD = "/ui/sso/authn/password/password.jsp";

    private String _sTemplate;
    private String _sMethodID;
    private String _sFriendlyName;
    private int _iAllowedTries;
    //Only needs to be set once.
    private final Log _logger;
    private final Log _eventLogger;
    private IConfigurationManager _configurationManager;
    private IUserFactory _oUserFactory;
    private Engine _oEngine;
    private boolean _bEnabled;
    private boolean _bCaptchaEnabled;
    private CryptoManager _CryptoManager;

    /**
     * Default Constructor
     */
    public PasswordAuthenticationMethod() {
        _logger = LogFactory.getLog(PasswordAuthenticationMethod.class);
        _eventLogger = LogFactory.getLog(Engine.EVENT_LOGGER);
        _bEnabled = false;
    }

    /**
     * Start/Initializes the Password Authentication Method.
     * 
     * @see IComponent#start(IConfigurationManager, org.w3c.dom.Element)
     */
    public void start(IConfigurationManager oConfigurationManager, Element eConfig) throws OAException {
        try {
            if ((eConfig == null) || (oConfigurationManager == null)) {
                _logger.error("No configuration supplied");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }
            _configurationManager = oConfigurationManager;
            _oEngine = Engine.getInstance();

            _CryptoManager = _oEngine.getCryptoManager();
            if (_CryptoManager == null) {
                _logger.error("No crypto manager available");
                throw new OAException(SystemErrors.ERROR_INIT);
            }

            _oUserFactory = _oEngine.getUserFactory();
            if ((_oUserFactory == null) || !_oUserFactory.isEnabled()) {
                _logger.error("User Factory is disabled");
                throw new OAException(SystemErrors.ERROR_INIT);
            }

            _sMethodID = _configurationManager.getParam(eConfig, "id");
            if ((_sMethodID == null) || _sMethodID.equals("")) {
                _logger.error("No 'id' found in 'method' section in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            _sFriendlyName = _configurationManager.getParam(eConfig, "friendlyname");
            if ((_sFriendlyName == null) || _sFriendlyName.equals("")) {
                _logger.error("No 'friendlyname' parameter found in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            String sEnabled = _configurationManager.getParam(eConfig, "enabled");
            if (sEnabled != null) {
                if (sEnabled.equalsIgnoreCase("TRUE")) {
                    _bEnabled = true;
                } else if (!sEnabled.equalsIgnoreCase("FALSE")) {
                    _logger.error("Unknown value in 'enabled' configuration item: " + sEnabled);
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }
            } else {
                _bEnabled = true;
            }

            if (_bEnabled) {
                _bCaptchaEnabled = false;
                String sCaptchaEnabled = _configurationManager.getParam(eConfig, "captcha");
                if (sCaptchaEnabled != null) {
                    if (sCaptchaEnabled.equalsIgnoreCase("TRUE")) {
                        _bCaptchaEnabled = true;
                    } else if (!sCaptchaEnabled.equalsIgnoreCase("FALSE")) {
                        _logger.error("Unknown value in 'captcha' configuration item: " + sCaptchaEnabled);
                        throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                    }
                }

                _logger.info(_bCaptchaEnabled ? "Captcha is enabled" : "Captcha is not enabled");

                _sTemplate = DEFAULT_JSP_PASSWORD;
                Element eMethodTemplate = _configurationManager.getSection(eConfig, "template");
                if (eMethodTemplate == null) {
                    _logger.warn("No optional 'template' section found in 'method' section with id: " + _sMethodID
                            + ", using default");
                } else {
                    _sTemplate = _configurationManager.getParam(eMethodTemplate, "path");
                    if ((_sTemplate == null) || _sTemplate.equals("")) {
                        _logger.error("No 'path' attribute found in 'template' section within 'method' with id: "
                                + _sMethodID);
                        throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                    }
                }
                _logger.info("Using JSP: " + _sTemplate);

                String sAllowedRetries = _configurationManager.getParam(eConfig, "retries");
                if ((sAllowedRetries == null) || sAllowedRetries.equals("")) {
                    _logger.error("No 'retries' found in 'method' section with id: " + _sMethodID);
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }
                try {
                    _iAllowedTries = Integer.parseInt(sAllowedRetries);
                    if (_iAllowedTries < 0) {
                        _logger.error("Invalid 'retries' item found in 'method' section with id: " + _sMethodID);
                        throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                    }

                    // DD Increase the value of retries. (Config uses no. of retries, code uses no. of tries)
                    // Number of tries is retries plus one.
                    if (_iAllowedTries >= 0) {
                        _iAllowedTries++;
                    }
                } catch (NumberFormatException e) {
                    _logger.error("Invalid 'retries' item found in 'method' section with id: " + _sMethodID, e);
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }

                Element ePasswordHandler = _configurationManager.getSection(eConfig, "password_handler");
                if (ePasswordHandler == null) {
                    _logger.error("No 'password_handler' section found in 'method' section with id: " + _sMethodID);
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }

                String sPasswordHandlerClass = _configurationManager.getParam(ePasswordHandler, "class");
                if ((sPasswordHandlerClass == null) || sPasswordHandlerClass.equals("")) {
                    _logger.error("No class found for password_handler");
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }

                Class cPasswordHandler = null;
                try {
                    cPasswordHandler = Class.forName(sPasswordHandlerClass);
                } catch (Exception e) {
                    _logger.error("Could not find password handler class: " + sPasswordHandlerClass, e);
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }

                try {
                    _oPasswordHandler = (IPasswordHandler) cPasswordHandler.newInstance();
                } catch (Exception e) {
                    _logger.error("Could not instantiate password handler: " + sPasswordHandlerClass, e);
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }
                _oPasswordHandler.start(_configurationManager, ePasswordHandler);
                if (_logger.isDebugEnabled()) {
                    StringBuffer sb = new StringBuffer(_sMethodID);
                    sb.append(" handler '");
                    sb.append(sPasswordHandlerClass).append("' started");
                    _logger.debug(sb.toString());
                }

                //Create mapper
                Element eIDMapper = _configurationManager.getSection(eConfig, "idmapper");
                if (eIDMapper != null) {
                    _idMapper = createMapper(eIDMapper);
                }
            }
        } catch (OAException e) {
            _logger.error("Error during start of Password authentication method");
            throw e;
        } catch (Exception e) {
            _logger.fatal("Internal error during start of Password authentication method", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
    }

    /**
     * Restart the Password Authentication Method.
     * 
     * @see com.alfaariss.oa.api.IComponent#restart(org.w3c.dom.Element)
     */
    public void restart(Element eConfig) throws OAException {
        synchronized (this) {
            stop();
            start(_configurationManager, eConfig);
        }
    }

    /**
     * Returns the Password Authentication Method Id.
     * 
     * @see com.alfaariss.oa.sso.authentication.web.IWebAuthenticationMethod#getID()
     */
    public String getID() {
        return _sMethodID;
    }

    /**
     * Returns whether the Password Authentication Method is enabled or not.
     * @see com.alfaariss.oa.api.IManagebleItem#isEnabled()
     */
    public boolean isEnabled() {
        return _bEnabled;
    }

    /**
     * @see com.alfaariss.oa.api.IManagebleItem#getFriendlyName()
     */
    public String getFriendlyName() {
        return _sFriendlyName;
    }

    /**
     * Returns Authority Name.
     * 
     * @see IAuthority#getAuthority()
     */
    public String getAuthority() {
        return AUTHORITY_NAME + _sMethodID;
    }

    /**
     * Function for online authentication.
     * 
     * Authenticates the user using the configured Password handler
     * (JDBC, JNDI, RADIUS etc.). When Captcha is enabled the user must also
     * submit the supplied text in the captcha image.
     * @see IWebAuthenticationMethod#authenticate(
     *  HttpServletRequest, HttpServletResponse, ISession)
     */
    public UserEvent authenticate(HttpServletRequest oRequest, HttpServletResponse oResponse, ISession oSession)
            throws OAException {
        IUser oUser = null;
        String sUserPassword = null;
        boolean bRetries = true;
        int iTries = _iAllowedTries;
        ISessionAttributes oAttributes = null;
        UserEvent userEvent = null;
        String sUserId = null;

        try {
            oAttributes = oSession.getAttributes();
            // Get retries left
            Integer intTries = ((Integer) oAttributes.get(PasswordAuthenticationMethod.class,
                    _sMethodID + RETRIES_ATTRIBUTE_NAME));

            //handle
            if (intTries == null) //First call to pwd method
            {
                //get user from session
                oUser = oSession.getUser();
                if (oUser == null) {
                    // If no user in session, check forced user
                    sUserId = oSession.getForcedUserID();
                    if (sUserId != null) {
                        oUser = _oUserFactory.getUser(sUserId);
                        if (oUser == null) {
                            throw new UserException(UserEvent.AUTHN_METHOD_NOT_SUPPORTED);
                        }

                        if (!oUser.isEnabled()) {
                            throw new UserException(UserEvent.USER_DISABLED);
                        }

                        // Check is user is registered for password method
                        if (!oUser.isAuthenticationRegistered(_sMethodID)) {
                            throw new UserException(UserEvent.AUTHN_METHOD_NOT_REGISTERED);
                        }
                        oSession.setUser(oUser);
                    }
                } else {
                    // Check is user is registered for password method
                    if (!oUser.isAuthenticationRegistered(_sMethodID)) {
                        throw new UserException(UserEvent.AUTHN_METHOD_NOT_REGISTERED);
                    }
                }
                forwardUser(oRequest, oResponse, oSession, iTries, bRetries, new Vector<Enum>());
                userEvent = UserEvent.AUTHN_METHOD_IN_PROGRESS;
            } else {
                iTries = intTries.intValue();
                Vector<Enum> warnings = new Vector<Enum>();
                // Check if captcha is enabled and verify if a captcha is supplied.
                String sCaptcha = null;
                if (_bCaptchaEnabled) {
                    // Get supplied captcha.
                    sCaptcha = oRequest.getParameter(CAPTCHA);
                    if ((sCaptcha == null) || (sCaptcha.trim().length() <= 0)) {
                        // does not count as an attempt
                        bRetries = false;
                        warnings.add(Warnings.NO_CAPTCHA_SUPPLIED);
                    }
                }

                //get user from session
                oUser = oSession.getUser();
                if (oUser == null) {
                    // If no user in session, get it from request
                    sUserId = oRequest.getParameter(USERID_ATTRIBUTE_NAME);
                    if ((sUserId == null) || sUserId.equals("")) {
                        // do not treat as an attempt
                        bRetries = false;
                        warnings.add(Warnings.NO_USERNAME_SUPPLIED);
                    } else {
                        oUser = _oUserFactory.getUser(sUserId);
                    }
                }

                // Get supplied password.
                sUserPassword = oRequest.getParameter(PASSWORD);
                if ((sUserPassword == null) || sUserPassword.trim().equalsIgnoreCase("")) {
                    // does not count as an attempt
                    bRetries = false;
                    warnings.add(Warnings.NO_PASSWORD_SUPPLIED);
                }

                //Check for missing request parameters
                if (!warnings.isEmpty()) {
                    //throw new DetailedUserException(warnings);
                    throw new DetailedUserException(UserEvent.AUTHN_METHOD_IN_PROGRESS, warnings);
                }

                //Verify captcha
                if (_bCaptchaEnabled) {
                    Class cCaptchaEngine = null;

                    try {
                        cCaptchaEngine = Class.forName("com.alfaariss.oa.helper.captcha.engine.CaptchaEngine");
                    } catch (ClassNotFoundException e) {
                        _logger.error(
                                "Captcha enabled, but 'com.alfaariss.oa.helper.captcha.engine.CaptchaEngine' is not available",
                                e);
                        throw new OAException(SystemErrors.ERROR_INTERNAL);
                    }
                    byte[] baCaptchaHash = (byte[]) oAttributes.get(cCaptchaEngine, CAPTCHA_HASH);
                    if (!verifyCaptcha(sCaptcha, baCaptchaHash)) {
                        throw new DetailedUserException(UserEvent.AUTHN_METHOD_IN_PROGRESS,
                                Warnings.INVALID_CAPTCHA_SUPPLIED);
                    }
                    oAttributes.remove(cCaptchaEngine, CAPTCHA_HASH);
                }

                //Verify User
                if (sUserId != null) //Submitted user
                {
                    if (oUser == null) {
                        throw new DetailedUserException(UserEvent.AUTHN_METHOD_IN_PROGRESS,
                                Warnings.NO_SUCH_USER_FOUND);
                    }
                }

                //Get the correct User ID to authenticate with the resource.
                String sAuthUserId = null;
                //If ID mapping is enabled, map the OA user name to the corresponding pwd username.
                if (_idMapper != null) {
                    sAuthUserId = _idMapper.map(oUser.getID());
                    if (sAuthUserId == null) {
                        throw new UserException(UserEvent.AUTHN_METHOD_FAILED);
                    }
                } else {
                    sAuthUserId = oUser.getID();
                }

                // Authenticate with supplied credentials against the configured password method.
                if (!_oPasswordHandler.authenticate(sAuthUserId, sUserPassword)) {
                    throw new DetailedUserException(UserEvent.AUTHN_METHOD_IN_PROGRESS,
                            Warnings.INVALID_CREDENTIALS_SUPPLIED);
                }

                if (sUserId != null) {
                    if (!oUser.isEnabled()) {
                        throw new UserException(UserEvent.USER_DISABLED);
                    }

                    // Check is user is registered for password method
                    if (!oUser.isAuthenticationRegistered(_sMethodID)) {
                        throw new UserException(UserEvent.AUTHN_METHOD_NOT_REGISTERED);
                    }
                }

                //everything Okay
                oSession.setUser(oUser);
                _eventLogger.info(new UserEventLogItem(oSession, oRequest.getRemoteAddr(),
                        UserEvent.AUTHN_METHOD_SUCCESSFUL, this, null));

                userEvent = UserEvent.AUTHN_METHOD_SUCCESSFUL;
            }
        } catch (UserException e) {
            userEvent = e.getEvent();

            _eventLogger.info(new UserEventLogItem(oSession, oRequest.getRemoteAddr(), e.getEvent(), this, null));
        } catch (DetailedUserException e) {
            if (iTries <= 0) {
                _eventLogger.info(new UserEventLogItem(oSession, oRequest.getRemoteAddr(),
                        UserEvent.AUTHN_METHOD_FAILED, this, e.getDetails().toString()));
                userEvent = UserEvent.AUTHN_METHOD_FAILED;
            } else {
                //Event logging is executed in showPage

                //Show page once again
                forwardUser(oRequest, oResponse, oSession, iTries, bRetries, e.getDetails());
                userEvent = e.getEvent();
            }

        } catch (OAException e) {
            _eventLogger.info(
                    new UserEventLogItem(oSession, oRequest.getRemoteAddr(), UserEvent.INTERNAL_ERROR, this, null));
            //already logged to system log.
            throw e;
        } catch (Exception e) {
            if (oSession != null) {
                _eventLogger.info(new UserEventLogItem(oSession, oRequest.getRemoteAddr(), UserEvent.INTERNAL_ERROR,
                        this, e.getMessage()));
            } else {
                _eventLogger.info(new UserEventLogItem(null, null, null, UserEvent.INTERNAL_ERROR, null,
                        oRequest.getRemoteAddr(), null, this, e.getMessage()));
            }

            _logger.fatal("Unexpected runtime error occured: ", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
        return userEvent;
    }

    /**
     * Function for offline authentication
     * 
     * Authenticates the user using the configured Password handler
     * (JDBC, JNDI, RADIUS etc.).
     *
     * @see IServiceAuthenticationMethod#authenticate(java.lang.String, byte[])
     */
    public UserEvent authenticate(String sUserID, byte[] baCredentials) throws OAException {
        try {
            IUser oUser = _oUserFactory.getUser(sUserID);
            if (oUser == null) {
                throw new UserException(UserEvent.USER_UNKNOWN);
            }

            if (!oUser.isEnabled()) {
                throw new UserException(UserEvent.USER_DISABLED);
            }

            if (!oUser.isAuthenticationRegistered(_sMethodID)) {
                throw new UserException(UserEvent.AUTHN_METHOD_NOT_REGISTERED);
            }

            String sUserPassword = new String(baCredentials, IPasswordHandler.CHARSET);

            if (!_oPasswordHandler.authenticate(oUser.getID(), sUserPassword)) {
                throw new UserException(UserEvent.AUTHN_METHOD_FAILED);
            }

            _eventLogger.info(new UserEventLogItem(null, null, null, UserEvent.AUTHN_METHOD_SUCCESSFUL, sUserID,
                    null, null, this, null));
            return UserEvent.AUTHN_METHOD_SUCCESSFUL;

        } catch (UserException e) {
            UserEvent event = e.getEvent();
            _eventLogger.info(new UserEventLogItem(null, null, null, event, sUserID, null, null, this, null));
            return event;
        } catch (OAException e) {
            _logger.warn("Unexpected error occured", e);
            _eventLogger.info(new UserEventLogItem(null, null, null, UserEvent.INTERNAL_ERROR, sUserID, null, null,
                    this, null));
            throw e;
        } catch (Exception e) {
            _logger.fatal("Unexpected internal error occured", e);
            _eventLogger.info(new UserEventLogItem(null, null, null, UserEvent.INTERNAL_ERROR, sUserID, null, null,
                    this, null));
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
    }

    /**
     * Function to stop all the (sub)components of the
     * Password Authentication Method correctly.
     * 
     * @see com.alfaariss.oa.api.IComponent#stop()
     */
    public void stop() {
        _bEnabled = false;
        if (_oPasswordHandler != null) {
            _oPasswordHandler.stop();
            _oPasswordHandler = null;
        }
        _sTemplate = null;
        _sMethodID = null;
        _sFriendlyName = null;
        _oUserFactory = null;
        _bCaptchaEnabled = false;
        _CryptoManager = null;
        _oEngine = null;
        _iAllowedTries = 0;
    }

    // Show the password page
    private void forwardUser(HttpServletRequest request, HttpServletResponse response, ISession session, int iTries,
            boolean bRetries, List<Enum> warnings) throws OAException {
        try {
            if (iTries == 1 && _iAllowedTries != 1) {
                warnings.add(Warnings.ONE_RETRY_LEFT);
            }
            /* 20110304;dopey fix: set session instead of session.getId() into ID_NAME */
            request.setAttribute(ISession.ID_NAME, session);
            request.setAttribute(ISession.LOCALE_NAME, session.getLocale());
            request.setAttribute(HASCAPTCHA, _bCaptchaEnabled);

            if (bRetries) {
                // Only decrease retries if error is an attempt
                iTries--;
            }
            //Set retries
            ISessionAttributes oAttributes = session.getAttributes();
            oAttributes.put(PasswordAuthenticationMethod.class, _sMethodID + RETRIES_ATTRIBUTE_NAME,
                    Integer.valueOf(iTries));
            session.persist();

            _eventLogger.info(new UserEventLogItem(session, request.getRemoteAddr(),
                    UserEvent.AUTHN_METHOD_IN_PROGRESS, this, warnings.toString()));

            request.setAttribute(DetailedUserException.DETAILS_NAME, warnings);
            request.setAttribute(AUTHN_METHOD_ATTRIBUTE_NAME, _sFriendlyName);
            request.setAttribute(Server.SERVER_ATTRIBUTE_NAME, _oEngine.getServer());
            IUser oUser = session.getUser();
            if (oUser != null) {
                request.setAttribute(USERID_ATTRIBUTE_NAME, oUser.getID());
            }

            RequestDispatcher dispatcher = request.getRequestDispatcher(_sTemplate);

            if (dispatcher != null) {
                dispatcher.forward(request, response);
            }
        } catch (IOException e) {
            _logger.warn("IO exception occured while forwarding", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        } catch (ServletException e) {
            _logger.warn("Servlet exception occured while forwarding", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
    }

    //Validate Captcha digest
    private boolean verifyCaptcha(String sSuppliedCaptcha, byte[] baSessionCaptcha) throws OAException {
        boolean bValidCaptcha = false;
        try {
            //Digest the provided answer
            MessageDigest oMessageDigest = null;
            oMessageDigest = _CryptoManager.getMessageDigest();
            oMessageDigest.update(sSuppliedCaptcha.getBytes(IPasswordHandler.CHARSET));
            byte[] baCaptcha = oMessageDigest.digest();
            bValidCaptcha = Arrays.equals(baSessionCaptcha, baCaptcha);
        } catch (CryptoException e) {
            _logger.warn("Unable to generate digest from captcha text", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        } catch (Exception e) {
            _logger.warn("Unexpected error occured while generating digest", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
        return bValidCaptcha;
    }

    private IIDMapper createMapper(Element eConfig) throws OAException {
        IIDMapper oMapper = null;
        try {
            String sClass = _configurationManager.getParam(eConfig, "class");
            if (sClass == null) {
                _logger.error("No 'class' parameter found in 'idmapper' section in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            Class cMapper = null;
            try {
                cMapper = Class.forName(sClass);
            } catch (Exception e) {
                _logger.error("No 'class' found with name: " + sClass, e);
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            try {
                oMapper = (IIDMapper) cMapper.newInstance();
            } catch (Exception e) {
                _logger.error("Could not create an 'IIDMapper' instance of the configured 'class': " + sClass, e);
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            oMapper.start(_configurationManager, eConfig);
        } catch (OAException e) {
            throw e;
        } catch (Exception e) {
            _logger.fatal("Internal error during creation of id mapper", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
        return oMapper;
    }
}