com.cws.esolutions.security.processors.impl.AccountChangeProcessorImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.cws.esolutions.security.processors.impl.AccountChangeProcessorImpl.java

Source

/*
 * Copyright (c) 2009 - 2017 CaspersBox Web Services
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.cws.esolutions.security.processors.impl;

/*
 * Project: eSolutionsSecurity
 * Package: com.cws.esolutions.security.processors.impl
 * File: AccountChangeProcessorImpl.java
 *
 * History
 *
 * Author               Date                            Comments
 * ----------------------------------------------------------------------------
 * cws-khuntly   11/23/2008 22:39:20             Created.
 */
import java.util.List;
import java.util.Arrays;
import java.util.Calendar;
import java.util.ArrayList;
import net.glxn.qrgen.QRCode;
import java.sql.SQLException;
import java.io.ByteArrayOutputStream;
import net.glxn.qrgen.image.ImageType;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.lang.RandomStringUtils;

import com.cws.esolutions.security.dto.UserAccount;
import com.cws.esolutions.security.utils.PasswordUtils;
import com.cws.esolutions.security.config.xml.KeyConfig;
import com.cws.esolutions.security.processors.enums.SaltType;
import com.cws.esolutions.security.processors.dto.AuditEntry;
import com.cws.esolutions.security.processors.enums.AuditType;
import com.cws.esolutions.security.processors.dto.AuditRequest;
import com.cws.esolutions.security.enums.SecurityRequestStatus;
import com.cws.esolutions.security.processors.enums.LoginStatus;
import com.cws.esolutions.security.processors.dto.RequestHostInfo;
import com.cws.esolutions.security.dao.keymgmt.interfaces.KeyManager;
import com.cws.esolutions.security.processors.dto.AuthenticationData;
import com.cws.esolutions.security.processors.dto.AccountChangeRequest;
import com.cws.esolutions.security.processors.dto.AccountChangeResponse;
import com.cws.esolutions.security.dao.keymgmt.factory.KeyManagementFactory;
import com.cws.esolutions.security.processors.exception.AuditServiceException;
import com.cws.esolutions.security.processors.exception.AccountChangeException;
import com.cws.esolutions.security.dao.keymgmt.exception.KeyManagementException;
import com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor;
import com.cws.esolutions.security.dao.userauth.exception.AuthenticatorException;
import com.cws.esolutions.security.dao.usermgmt.exception.UserManagementException;

/**
 * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor
 */
public class AccountChangeProcessorImpl implements IAccountChangeProcessor {
    /**
     * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor#changeUserEmail(com.cws.esolutions.security.processors.dto.AccountChangeRequest)
     */
    public AccountChangeResponse changeUserEmail(final AccountChangeRequest request) throws AccountChangeException {
        final String methodName = IAccountChangeProcessor.CNAME
                + "#changeUserEmail(final AccountChangeRequest request) throws AccountChangeException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("AccountChangeRequest: {}", request);
        }

        AccountChangeResponse response = new AccountChangeResponse();

        final RequestHostInfo reqInfo = request.getHostInfo();
        final UserAccount requestor = request.getRequestor();
        final UserAccount userAccount = request.getUserAccount();
        final AuthenticationData reqSecurity = request.getUserSecurity();

        if (DEBUG) {
            DEBUGGER.debug("RequestHostInfo: {}", reqInfo);
            DEBUGGER.debug("UserAccount: {}", requestor);
            DEBUGGER.debug("UserAccount: {}", userAccount);
        }

        // ok, first things first. if this is an administrative reset, make sure the requesting user
        // is authorized to perform the action.
        if (!(StringUtils.equals(userAccount.getGuid(), requestor.getGuid()))) {
            // requesting user is not the same as the user being reset. no authorization here,
            // no one is allowed to change user security but the owning user
            response.setRequestStatus(SecurityRequestStatus.UNAUTHORIZED);

            return response;
        }

        try {
            // ok, authenticate first
            String userSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.LOGON.name());

            if (StringUtils.isNotEmpty(userSalt)) {
                // we aren't getting the data back here because we don't need it. if the request
                // fails we'll get an exception and not process further. this might not be the
                // best flow control, but it does exactly what we need where we need it.
                authenticator.performLogon(userAccount.getUsername(),
                        PasswordUtils.encryptText(reqSecurity.getPassword(), userSalt,
                                secBean.getConfigData().getSecurityConfig().getAuthAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getIterations(),
                                secBean.getConfigData().getSystemConfig().getEncoding()));

                boolean isComplete = userManager.modifyUserEmail(userAccount.getUsername(),
                        userAccount.getEmailAddr());

                if (isComplete) {
                    UserAccount retAccount = userAccount;
                    retAccount.setEmailAddr(userAccount.getEmailAddr());

                    response.setUserAccount(retAccount);
                    response.setRequestStatus(SecurityRequestStatus.SUCCESS);
                } else {
                    response.setRequestStatus(SecurityRequestStatus.FAILURE);
                }
            } else {
                throw new AccountChangeException("Unable to obtain configured user salt. Cannot continue");
            }
        } catch (SQLException sqx) {
            ERROR_RECORDER.error(sqx.getMessage(), sqx);

            throw new AccountChangeException(sqx.getMessage(), sqx);
        } catch (AuthenticatorException ax) {
            ERROR_RECORDER.error(ax.getMessage(), ax);

            throw new AccountChangeException(ax.getMessage(), ax);
        } catch (UserManagementException umx) {
            ERROR_RECORDER.error(umx.getMessage(), umx);

            throw new AccountChangeException(umx.getMessage(), umx);
        } catch (SecurityException sx) {
            ERROR_RECORDER.error(sx.getMessage(), sx);

            throw new AccountChangeException(sx.getMessage(), sx);
        } finally {
            // audit
            try {
                AuditEntry auditEntry = new AuditEntry();
                auditEntry.setHostInfo(reqInfo);
                auditEntry.setAuditType(AuditType.MODIFYUSER);
                auditEntry.setUserAccount(requestor);
                auditEntry.setAuthorized(Boolean.TRUE);
                auditEntry.setApplicationId(request.getApplicationId());
                auditEntry.setApplicationName(request.getApplicationName());

                if (DEBUG) {
                    DEBUGGER.debug("AuditEntry: {}", auditEntry);
                }

                AuditRequest auditRequest = new AuditRequest();
                auditRequest.setAuditEntry(auditEntry);

                if (DEBUG) {
                    DEBUGGER.debug("AuditRequest: {}", auditRequest);
                }

                auditor.auditRequest(auditRequest);
            } catch (AuditServiceException asx) {
                ERROR_RECORDER.error(asx.getMessage(), asx);
            }
        }

        return response;
    }

    /**
     * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor#changeUserContact(com.cws.esolutions.security.processors.dto.AccountChangeRequest)
     */
    public AccountChangeResponse changeUserContact(final AccountChangeRequest request)
            throws AccountChangeException {
        final String methodName = IAccountChangeProcessor.CNAME
                + "#changeUserContact(final AccountChangeRequest request) throws AccountChangeException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("AccountChangeRequest: {}", request);
        }

        AccountChangeResponse response = new AccountChangeResponse();

        final RequestHostInfo reqInfo = request.getHostInfo();
        final UserAccount requestor = request.getRequestor();
        final UserAccount userAccount = request.getUserAccount();
        final AuthenticationData reqSecurity = request.getUserSecurity();

        if (DEBUG) {
            DEBUGGER.debug("RequestHostInfo: {}", reqInfo);
            DEBUGGER.debug("UserAccount: {}", requestor);
            DEBUGGER.debug("UserAccount: {}", userAccount);
        }

        // ok, first things first. if this is an administrative reset, make sure the requesting user
        // is authorized to perform the action.
        if (!(StringUtils.equals(userAccount.getGuid(), requestor.getGuid()))) {
            // requesting user is not the same as the user being reset. no authorization here,
            // no one is allowed to change user security but the owning user
            response.setRequestStatus(SecurityRequestStatus.UNAUTHORIZED);

            return response;
        }

        try {
            // ok, authenticate first
            String userSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.LOGON.name());

            if (StringUtils.isNotEmpty(userSalt)) {
                // we aren't getting the data back here because we don't need it. if the request
                // fails we'll get an exception and not process further. this might not be the
                // best flow control, but it does exactly what we need where we need it.
                authenticator.performLogon(userAccount.getUsername(),
                        PasswordUtils.encryptText(reqSecurity.getPassword(), userSalt,
                                secBean.getConfigData().getSecurityConfig().getAuthAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getIterations(),
                                secBean.getConfigData().getSystemConfig().getEncoding()));

                boolean isComplete = userManager.modifyUserContact(userAccount.getUsername(), new ArrayList<String>(
                        Arrays.asList(userAccount.getTelephoneNumber(), userAccount.getPagerNumber())));

                if (isComplete) {
                    UserAccount retAccount = userAccount;
                    retAccount.setTelephoneNumber(userAccount.getTelephoneNumber());
                    retAccount.setPagerNumber(userAccount.getPagerNumber());

                    response.setUserAccount(retAccount);
                    response.setRequestStatus(SecurityRequestStatus.SUCCESS);
                } else {
                    response.setRequestStatus(SecurityRequestStatus.FAILURE);
                }
            } else {
                throw new AccountChangeException("Unable to obtain configured user salt. Cannot continue");
            }
        } catch (SQLException sqx) {
            ERROR_RECORDER.error(sqx.getMessage(), sqx);

            throw new AccountChangeException(sqx.getMessage(), sqx);
        } catch (AuthenticatorException ax) {
            ERROR_RECORDER.error(ax.getMessage(), ax);

            throw new AccountChangeException(ax.getMessage(), ax);
        } catch (UserManagementException umx) {
            ERROR_RECORDER.error(umx.getMessage(), umx);

            throw new AccountChangeException(umx.getMessage(), umx);
        } catch (SecurityException sx) {
            ERROR_RECORDER.error(sx.getMessage(), sx);

            throw new AccountChangeException(sx.getMessage(), sx);
        } finally {
            // audit
            try {
                AuditEntry auditEntry = new AuditEntry();
                auditEntry.setHostInfo(reqInfo);
                auditEntry.setAuditType(AuditType.MODIFYUSER);
                auditEntry.setUserAccount(requestor);
                auditEntry.setAuthorized(Boolean.TRUE);
                auditEntry.setApplicationId(request.getApplicationId());
                auditEntry.setApplicationName(request.getApplicationName());

                if (DEBUG) {
                    DEBUGGER.debug("AuditEntry: {}", auditEntry);
                }

                AuditRequest auditRequest = new AuditRequest();
                auditRequest.setAuditEntry(auditEntry);

                if (DEBUG) {
                    DEBUGGER.debug("AuditRequest: {}", auditRequest);
                }

                auditor.auditRequest(auditRequest);
            } catch (AuditServiceException asx) {
                ERROR_RECORDER.error(asx.getMessage(), asx);
            }
        }

        return response;
    }

    /**
     * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor#changeUserPassword(com.cws.esolutions.security.processors.dto.AccountChangeRequest)
     */
    public AccountChangeResponse changeUserPassword(final AccountChangeRequest request)
            throws AccountChangeException {
        final String methodName = IAccountChangeProcessor.CNAME
                + "#changeUserPassword(final AccountChangeRequest request) throws AccountChangeException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("AccountChangeRequest: {}", request);
        }

        // List<String> authList = null;
        String currentPassword = null;
        AccountChangeResponse response = new AccountChangeResponse();

        final Calendar calendar = Calendar.getInstance();
        final RequestHostInfo reqInfo = request.getHostInfo();
        final UserAccount requestor = request.getRequestor();
        final UserAccount userAccount = request.getUserAccount();
        final AuthenticationData reqSecurity = request.getUserSecurity();
        final String newUserSalt = RandomStringUtils.randomAlphanumeric(secConfig.getSaltLength());

        calendar.add(Calendar.DATE, secConfig.getPasswordExpiration());

        if (DEBUG) {
            DEBUGGER.debug("Calendar: {}", calendar);
            DEBUGGER.debug("RequestHostInfo: {}", reqInfo);
            DEBUGGER.debug("UserAccount: {}", requestor);
            DEBUGGER.debug("UserAccount: {}", userAccount);
        }

        // ok, first things first. if this is an administrative reset, make sure the requesting user
        // is authorized to perform the action.
        if (!(StringUtils.equals(userAccount.getGuid(), requestor.getGuid()))) {
            // requesting user is not the same as the user being reset. no authorization here,
            // no one is allowed to change user security but the owning user
            response.setRequestStatus(SecurityRequestStatus.UNAUTHORIZED);

            return response;
        }

        try {
            // otherwise, keep going
            // make sure the new password isnt the same as the existing
            if (StringUtils.equals(reqSecurity.getNewPassword(), reqSecurity.getPassword())) {
                throw new AccountChangeException("The new password MUST differ from the existing password.");
            } else if ((reqSecurity.getNewPassword().length() < secConfig.getPasswordMinLength()) // less than minimum
                    || (reqSecurity.getNewPassword().length() > secConfig.getPasswordMaxLength())) // greater than maximum
            {
                // password doesnt meet requirements, is either too short or too long
                throw new AccountChangeException(
                        "The chosen password does not meet the configured length requirements.");
            } else {
                if (!(request.isReset())) {
                    // ok, authenticate first
                    String userSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.LOGON.name());

                    if (StringUtils.isNotEmpty(userSalt)) {
                        // we aren't getting the data back here because we don't need it. if the request
                        // fails we'll get an exception and not process further. this might not be the
                        // best flow control, but it does exactly what we need where we need it.
                        authenticator.performLogon(userAccount.getUsername(),
                                PasswordUtils.encryptText(reqSecurity.getPassword(), userSalt,
                                        secBean.getConfigData().getSecurityConfig().getAuthAlgorithm(),
                                        secBean.getConfigData().getSecurityConfig().getIterations(),
                                        secBean.getConfigData().getSystemConfig().getEncoding()));
                    }
                }

                if (StringUtils.isNotEmpty(newUserSalt)) {
                    // get rollback information in case something breaks...
                    // we already have the existing expiry and password, all we really need to get here is the salt.
                    String existingSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.LOGON.name());

                    if (StringUtils.isNotEmpty(existingSalt)) {
                        // good, move forward
                        // put the new salt in the database
                        boolean isComplete = userSec.addOrUpdateSalt(userAccount.getGuid(), newUserSalt,
                                SaltType.LOGON.name());

                        if (DEBUG) {
                            DEBUGGER.debug("isComplete: {}", isComplete);
                        }

                        if (isComplete) {
                            // make the modification in the user repository
                            userManager.modifyUserPassword(userAccount.getGuid(),
                                    PasswordUtils.encryptText(reqSecurity.getNewPassword(), newUserSalt,
                                            secConfig.getAuthAlgorithm(), secConfig.getIterations(),
                                            secBean.getConfigData().getSystemConfig().getEncoding()));

                            if (DEBUG) {
                                DEBUGGER.debug("isComplete: {}", isComplete);
                            }

                            if (isComplete) {
                                if ((userAccount.getStatus() == LoginStatus.EXPIRED)
                                        || (userAccount.getStatus() == LoginStatus.RESET)) {
                                    // update the account
                                    userAccount.setStatus(LoginStatus.SUCCESS);
                                }

                                response.setUserAccount(userAccount);
                                response.setRequestStatus(SecurityRequestStatus.SUCCESS);
                            } else {
                                if (!(request.isReset())) {
                                    // something failed. we're going to undo what we did in the user
                                    // repository, because we couldnt update the salt value. if we don't
                                    // undo it then the user will never be able to login without admin
                                    // intervention
                                    boolean isBackedOut = userManager.modifyUserPassword(userAccount.getUsername(),
                                            currentPassword);

                                    if (!(isBackedOut)) {
                                        throw new AccountChangeException(
                                                "Failed to modify the user account and unable to revert to existing state.");
                                    }
                                }

                                response.setRequestStatus(SecurityRequestStatus.FAILURE);
                            }
                        } else {
                            response.setRequestStatus(SecurityRequestStatus.FAILURE);
                        }
                    } else {
                        throw new AccountChangeException(
                                "Unable to obtain existing salt value from datastore. Cannot continue.");
                    }
                } else {
                    throw new AccountChangeException("Unable to generate new salt for provided user account.");
                }
            }
        } catch (SQLException sqx) {
            ERROR_RECORDER.error(sqx.getMessage(), sqx);

            throw new AccountChangeException(sqx.getMessage(), sqx);
        } catch (UserManagementException umx) {
            ERROR_RECORDER.error(umx.getMessage(), umx);

            throw new AccountChangeException(umx.getMessage(), umx);
        } catch (AuthenticatorException ax) {
            ERROR_RECORDER.error(ax.getMessage(), ax);

            throw new AccountChangeException(ax.getMessage(), ax);
        } catch (SecurityException sx) {
            ERROR_RECORDER.error(sx.getMessage(), sx);

            throw new AccountChangeException(sx.getMessage(), sx);
        } finally {
            // audit
            try {
                AuditEntry auditEntry = new AuditEntry();
                auditEntry.setHostInfo(reqInfo);
                auditEntry.setAuditType(AuditType.CHANGEPASS);
                auditEntry.setUserAccount(requestor);
                auditEntry.setAuthorized(Boolean.TRUE);
                auditEntry.setApplicationId(request.getApplicationId());
                auditEntry.setApplicationName(request.getApplicationName());

                if (DEBUG) {
                    DEBUGGER.debug("AuditEntry: {}", auditEntry);
                }

                AuditRequest auditRequest = new AuditRequest();
                auditRequest.setAuditEntry(auditEntry);

                if (DEBUG) {
                    DEBUGGER.debug("AuditRequest: {}", auditRequest);
                }

                auditor.auditRequest(auditRequest);
            } catch (AuditServiceException asx) {
                ERROR_RECORDER.error(asx.getMessage(), asx);
            }
        }

        return response;
    }

    /**
     * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor#changeUserSecurity(com.cws.esolutions.security.processors.dto.AccountChangeRequest)
     */
    public AccountChangeResponse changeUserSecurity(final AccountChangeRequest request)
            throws AccountChangeException {
        final String methodName = IAccountChangeProcessor.CNAME
                + "#changeUserSecurity(final AccountChangeRequest request) throws AccountChangeException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("AccountChangeRequest: {}", request);
        }

        AccountChangeResponse response = new AccountChangeResponse();

        final Calendar calendar = Calendar.getInstance();
        final RequestHostInfo reqInfo = request.getHostInfo();
        final UserAccount requestor = request.getRequestor();
        final UserAccount userAccount = request.getUserAccount();
        final AuthenticationData reqSecurity = request.getUserSecurity();

        if (DEBUG) {
            DEBUGGER.debug("Calendar: {}", calendar);
            DEBUGGER.debug("RequestHostInfo: {}", reqInfo);
            DEBUGGER.debug("UserAccount: {}", requestor);
            DEBUGGER.debug("UserAccount: {}", userAccount);
        }

        // ok, first things first. if this is an administrative reset, make sure the requesting user
        // is authorized to perform the action.
        if (!(StringUtils.equals(userAccount.getGuid(), requestor.getGuid()))) {
            // requesting user is not the same as the user being reset. no authorization here,
            // no one is allowed to change user security but the owning user
            response.setRequestStatus(SecurityRequestStatus.UNAUTHORIZED);

            return response;
        }

        try {
            // otherwise, keep going
            // make sure the two questions and answers arent the same
            if ((StringUtils.equals(reqSecurity.getSecQuestionOne(), reqSecurity.getSecQuestionTwo()))) {
                throw new AccountChangeException("The security questions must be different.");
            } else if ((StringUtils.equals(reqSecurity.getSecAnswerOne(), reqSecurity.getSecAnswerTwo()))) {
                throw new AccountChangeException("The security answers must be different.");
            } else {
                // ok, authenticate first
                String userSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.LOGON.name());

                if (StringUtils.isNotEmpty(userSalt)) {
                    // we aren't getting the data back here because we don't need it. if the request
                    // fails we'll get an exception and not process further. this might not be the
                    // best flow control, but it does exactly what we need where we need it.
                    authenticator.performLogon(userAccount.getUsername(),
                            PasswordUtils.encryptText(reqSecurity.getPassword(), userSalt,
                                    secBean.getConfigData().getSecurityConfig().getAuthAlgorithm(),
                                    secBean.getConfigData().getSecurityConfig().getIterations(),
                                    secBean.getConfigData().getSystemConfig().getEncoding()));

                    // ok, thats out of the way. lets keep moving.
                    String newUserSalt = RandomStringUtils.randomAlphanumeric(secConfig.getSaltLength());

                    if (StringUtils.isNotEmpty(newUserSalt)) {
                        // get rollback information in case something breaks...
                        // we already have the existing expiry and password, all we really need to get here is the salt.
                        String existingSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.RESET.name());

                        if (StringUtils.isNotEmpty(existingSalt)) {
                            // make the backout
                            List<String> currentSec = authenticator.obtainSecurityData(userAccount.getUsername(),
                                    userAccount.getGuid());

                            // good, move forward
                            // make the modification in the user repository
                            boolean isComplete = userManager.modifyUserSecurity(userAccount.getUsername(),
                                    new ArrayList<String>(Arrays.asList(reqSecurity.getSecQuestionOne(),
                                            reqSecurity.getSecQuestionTwo(),
                                            PasswordUtils.encryptText(reqSecurity.getSecAnswerOne(), newUserSalt,
                                                    secConfig.getAuthAlgorithm(), secConfig.getIterations(),
                                                    secBean.getConfigData().getSystemConfig().getEncoding()),
                                            PasswordUtils.encryptText(reqSecurity.getSecAnswerTwo(), newUserSalt,
                                                    secConfig.getAuthAlgorithm(), secConfig.getIterations(),
                                                    secBean.getConfigData().getSystemConfig().getEncoding()))));

                            if (DEBUG) {
                                DEBUGGER.debug("isComplete: {}", isComplete);
                            }

                            if (isComplete) {
                                // now update the salt
                                isComplete = userSec.addOrUpdateSalt(userAccount.getGuid(), newUserSalt,
                                        SaltType.RESET.name());

                                if (isComplete) {
                                    response.setRequestStatus(SecurityRequestStatus.SUCCESS);
                                } else {
                                    // something failed. we're going to undo what we did in the user
                                    // repository, because we couldnt update the salt value. if we don't
                                    // undo it then the user will never be able to login without admin
                                    // intervention
                                    boolean isReverted = userManager.modifyUserSecurity(userAccount.getUsername(),
                                            new ArrayList<String>(Arrays.asList(currentSec.get(0),
                                                    currentSec.get(1), currentSec.get(2), currentSec.get(3))));

                                    if (DEBUG) {
                                        DEBUGGER.debug("isReverted: {}", isReverted);
                                    }

                                    boolean backoutSalt = userSec.addOrUpdateSalt(userAccount.getGuid(),
                                            existingSalt, SaltType.RESET.name());

                                    if (DEBUG) {
                                        DEBUGGER.debug("backoutSalt: {}", backoutSalt);
                                    }

                                    if (!(isReverted) && (!(backoutSalt))) {
                                        throw new AccountChangeException(
                                                "Failed to modify the user account and unable to revert to existing state.");
                                    }

                                    response.setRequestStatus(SecurityRequestStatus.FAILURE);
                                }
                            } else {
                                response.setRequestStatus(SecurityRequestStatus.FAILURE);
                            }
                        } else {
                            ERROR_RECORDER.error("Unable to generate new salt for provided user account.");

                            response.setRequestStatus(SecurityRequestStatus.FAILURE);
                        }
                    } else {
                        ERROR_RECORDER
                                .error("Unable to obtain existing salt value from datastore. Cannot continue.");

                        response.setRequestStatus(SecurityRequestStatus.FAILURE);
                    }
                } else {
                    ERROR_RECORDER.error("Unable to obtain configured user salt. Cannot continue");

                    response.setRequestStatus(SecurityRequestStatus.FAILURE);
                }
            }
        } catch (SQLException sqx) {
            ERROR_RECORDER.error(sqx.getMessage(), sqx);

            throw new AccountChangeException(sqx.getMessage(), sqx);
        } catch (UserManagementException umx) {
            ERROR_RECORDER.error(umx.getMessage(), umx);

            throw new AccountChangeException(umx.getMessage(), umx);
        } catch (AuthenticatorException ax) {
            ERROR_RECORDER.error(ax.getMessage(), ax);

            throw new AccountChangeException(ax.getMessage(), ax);
        } catch (SecurityException sx) {
            ERROR_RECORDER.error(sx.getMessage(), sx);

            throw new AccountChangeException(sx.getMessage(), sx);
        } finally {
            // audit
            try {
                AuditEntry auditEntry = new AuditEntry();
                auditEntry.setHostInfo(reqInfo);
                auditEntry.setAuditType(AuditType.ADDSECURITY);
                auditEntry.setUserAccount(requestor);
                auditEntry.setAuthorized(Boolean.TRUE);
                auditEntry.setApplicationId(request.getApplicationId());
                auditEntry.setApplicationName(request.getApplicationName());

                if (DEBUG) {
                    DEBUGGER.debug("AuditEntry: {}", auditEntry);
                }

                AuditRequest auditRequest = new AuditRequest();
                auditRequest.setAuditEntry(auditEntry);

                if (DEBUG) {
                    DEBUGGER.debug("AuditRequest: {}", auditRequest);
                }

                auditor.auditRequest(auditRequest);
            } catch (AuditServiceException asx) {
                ERROR_RECORDER.error(asx.getMessage(), asx);
            }
        }

        return response;
    }

    /**
     * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor#changeUserKeys(com.cws.esolutions.security.processors.dto.AccountChangeRequest)
     */
    public AccountChangeResponse changeUserKeys(final AccountChangeRequest request) throws AccountChangeException {
        final String methodName = IAccountChangeProcessor.CNAME
                + "#changeUserKeys(final AccountChangeRequest request) throws AccountChangeException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("AccountChangeRequest: {}", request);
        }

        AccountChangeResponse response = new AccountChangeResponse();

        final RequestHostInfo reqInfo = request.getHostInfo();
        final UserAccount userAccount = request.getUserAccount();
        final UserAccount requestor = request.getRequestor();
        final KeyConfig keyConfig = secBean.getConfigData().getKeyConfig();
        final KeyManager keyManager = KeyManagementFactory.getKeyManager(keyConfig.getKeyManager());

        if (DEBUG) {
            DEBUGGER.debug("RequestHostInfo: {}", reqInfo);
            DEBUGGER.debug("UserAccount: {}", userAccount);
            DEBUGGER.debug("UserAccount: {}", requestor);
            DEBUGGER.debug("KeyConfig: {}", keyConfig);
            DEBUGGER.debug("KeyManager: {}", keyManager);
        }

        if (!(StringUtils.equals(userAccount.getGuid(), requestor.getGuid()))) {
            // requesting user is not the same as the user being reset. authorize
            response.setRequestStatus(SecurityRequestStatus.UNAUTHORIZED);

            return response;
        }

        try {
            // delete the existing keys
            boolean keysRemoved = keyManager.removeKeys(userAccount.getGuid());

            if (DEBUG) {
                DEBUGGER.debug("keysRemoved: {}", keysRemoved);
            }

            if (keysRemoved) {
                // good, now re-generate
                boolean keysAdded = keyManager.createKeys(userAccount.getGuid());

                if (DEBUG) {
                    DEBUGGER.debug("keysAdded: {}", keysAdded);
                }

                if (keysAdded) {
                    response.setRequestStatus(SecurityRequestStatus.SUCCESS);
                } else {
                    response.setRequestStatus(SecurityRequestStatus.FAILURE);
                }
            } else {
                response.setRequestStatus(SecurityRequestStatus.FAILURE);
            }
        } catch (KeyManagementException kmx) {
            ERROR_RECORDER.error(kmx.getMessage(), kmx);

            throw new AccountChangeException(kmx.getMessage(), kmx);
        } finally {
            // audit
            try {
                AuditEntry auditEntry = new AuditEntry();
                auditEntry.setHostInfo(reqInfo);
                auditEntry.setAuditType(AuditType.CHANGEKEYS);
                auditEntry.setUserAccount(userAccount);
                auditEntry.setAuthorized(Boolean.TRUE);
                auditEntry.setApplicationId(request.getApplicationId());
                auditEntry.setApplicationName(request.getApplicationName());

                if (DEBUG) {
                    DEBUGGER.debug("AuditEntry: {}", auditEntry);
                }

                AuditRequest auditRequest = new AuditRequest();
                auditRequest.setAuditEntry(auditEntry);

                if (DEBUG) {
                    DEBUGGER.debug("AuditRequest: {}", auditRequest);
                }

                auditor.auditRequest(auditRequest);
            } catch (AuditServiceException asx) {
                ERROR_RECORDER.error(asx.getMessage(), asx);
            }
        }

        return response;
    }

    /**
     * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor#enableOtpAuth(com.cws.esolutions.security.processors.dto.AccountChangeRequest)
     */
    public AccountChangeResponse enableOtpAuth(final AccountChangeRequest request) throws AccountChangeException {
        final String methodName = IAccountChangeProcessor.CNAME
                + "#enableOtpAuth(final AccountChangeRequest request) throws AccountChangeException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("AccountChangeRequest: {}", request);
        }

        AccountChangeResponse response = new AccountChangeResponse();

        final UserAccount requestor = request.getRequestor();
        final RequestHostInfo reqInfo = request.getHostInfo();
        final UserAccount userAccount = request.getUserAccount();
        final AuthenticationData reqSecurity = request.getUserSecurity();

        if (DEBUG) {
            DEBUGGER.debug("UserAccount: {}", userAccount);
            DEBUGGER.debug("RequestHostInfo: {}", reqInfo);
            DEBUGGER.debug("UserAccount: {}", userAccount);
        }

        if (!(StringUtils.equals(userAccount.getGuid(), requestor.getGuid()))) {
            // requesting user is not the same as the user being reset. authorize
            response.setRequestStatus(SecurityRequestStatus.UNAUTHORIZED);

            return response;
        }

        try {
            String userSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.LOGON.name());

            if (StringUtils.isNotEmpty(userSalt)) {
                // we aren't getting the data back here because we don't need it. if the request
                // fails we'll get an exception and not process further. this might not be the
                // best flow control, but it does exactly what we need where we need it.
                authenticator.performLogon(userAccount.getUsername(),
                        PasswordUtils.encryptText(reqSecurity.getPassword(), userSalt,
                                secBean.getConfigData().getSecurityConfig().getAuthAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getIterations(),
                                secBean.getConfigData().getSystemConfig().getEncoding()));

                String secret = new String(
                        new Base32().encode(RandomStringUtils.randomAlphanumeric(10).getBytes()));

                if (DEBUG) {
                    DEBUGGER.debug("String: {}", secret);
                }

                String otpSalt = RandomStringUtils.randomAlphanumeric(secConfig.getSaltLength());

                if (StringUtils.isNotEmpty(otpSalt)) {
                    boolean isSaltInserted = userSec.addOrUpdateSalt(userAccount.getGuid(), otpSalt,
                            SaltType.OTP.name());

                    if (DEBUG) {
                        DEBUGGER.debug("isSaltInserted: {}", isSaltInserted);
                    }

                    if ((!isSaltInserted)) {
                        response.setRequestStatus(SecurityRequestStatus.FAILURE);

                        return response;
                    }

                    boolean isComplete = userManager.modifyOtpSecret(userAccount.getUsername(), true,
                            PasswordUtils.encryptText(secret, otpSalt,
                                    secBean.getConfigData().getSecurityConfig().getSecretAlgorithm(),
                                    secBean.getConfigData().getSecurityConfig().getIterations(),
                                    secBean.getConfigData().getSecurityConfig().getKeyBits(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                                    secBean.getConfigData().getSystemConfig().getEncoding()));

                    if (DEBUG) {
                        DEBUGGER.debug("isComplete: {}", isComplete);
                    }

                    if (!(isComplete)) {
                        response.setRequestStatus(SecurityRequestStatus.FAILURE);

                        return response;
                    }

                    String qrCodeData = String.format(IAccountChangeProcessor.KEY_URI_FORMAT,
                            userAccount.getUsername(), secret, request.getApplicationName(),
                            secConfig.getOtpAlgorithm());

                    if (DEBUG) {
                        DEBUGGER.debug("qrCodeData: {}", qrCodeData);
                    }

                    ByteArrayOutputStream qrCode = QRCode.from(qrCodeData.trim()).to(ImageType.PNG).stream();

                    if (DEBUG) {
                        DEBUGGER.debug("ByteArrayOutputStream: {}", qrCode);
                    }

                    response.setSecret(secret);
                    response.setQrCode(qrCode);
                    response.setRequestStatus(SecurityRequestStatus.SUCCESS);
                } else {
                    response.setRequestStatus(SecurityRequestStatus.FAILURE);
                }
            } else {
                ERROR_RECORDER.error("Unable to obtain configured user salt. Cannot continue");

                response.setRequestStatus(SecurityRequestStatus.FAILURE);
            }
        } catch (SQLException sqx) {
            ERROR_RECORDER.error(sqx.getMessage(), sqx);

            throw new AccountChangeException(sqx.getMessage(), sqx);
        } catch (AuthenticatorException ax) {
            ERROR_RECORDER.error(ax.getMessage(), ax);

            throw new AccountChangeException(ax.getMessage(), ax);
        } catch (SecurityException sx) {
            ERROR_RECORDER.error(sx.getMessage(), sx);

            throw new SecurityException(sx.getMessage(), sx);
        } catch (UserManagementException umx) {
            ERROR_RECORDER.error(umx.getMessage(), umx);

            throw new SecurityException(umx.getMessage(), umx);
        } finally {
            // audit
            try {
                AuditEntry auditEntry = new AuditEntry();
                auditEntry.setHostInfo(reqInfo);
                auditEntry.setAuditType(AuditType.CHANGEKEYS);
                auditEntry.setUserAccount(userAccount);
                auditEntry.setAuthorized(Boolean.TRUE);
                auditEntry.setApplicationId(request.getApplicationId());
                auditEntry.setApplicationName(request.getApplicationName());

                if (DEBUG) {
                    DEBUGGER.debug("AuditEntry: {}", auditEntry);
                }

                AuditRequest auditRequest = new AuditRequest();
                auditRequest.setAuditEntry(auditEntry);

                if (DEBUG) {
                    DEBUGGER.debug("AuditRequest: {}", auditRequest);
                }

                auditor.auditRequest(auditRequest);
            } catch (AuditServiceException asx) {
                ERROR_RECORDER.error(asx.getMessage(), asx);
            }
        }

        return response;
    }

    /**
     * @see com.cws.esolutions.security.processors.interfaces.IAccountChangeProcessor#disableOtpAuth(com.cws.esolutions.security.processors.dto.AccountChangeRequest)
     */
    public AccountChangeResponse disableOtpAuth(final AccountChangeRequest request) throws AccountChangeException {
        final String methodName = IAccountChangeProcessor.CNAME
                + "#disableOtpAuth(final AccountChangeRequest request) throws AccountChangeException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("AccountChangeRequest: {}", request);
        }

        AccountChangeResponse response = new AccountChangeResponse();

        final UserAccount requestor = request.getRequestor();
        final RequestHostInfo reqInfo = request.getHostInfo();
        final UserAccount userAccount = request.getUserAccount();
        final AuthenticationData reqSecurity = request.getUserSecurity();

        if (DEBUG) {
            DEBUGGER.debug("UserAccount: {}", userAccount);
            DEBUGGER.debug("RequestHostInfo: {}", reqInfo);
            DEBUGGER.debug("UserAccount: {}", userAccount);
        }

        if (!(StringUtils.equals(userAccount.getGuid(), requestor.getGuid()))) {
            // requesting user is not the same as the user being reset. authorize
            response.setRequestStatus(SecurityRequestStatus.UNAUTHORIZED);

            return response;
        }

        try {
            String userSalt = userSec.getUserSalt(userAccount.getGuid(), SaltType.LOGON.name());

            if (StringUtils.isNotEmpty(userSalt)) {
                // we aren't getting the data back here because we don't need it. if the request
                // fails we'll get an exception and not process further. this might not be the
                // best flow control, but it does exactly what we need where we need it.
                authenticator.performLogon(userAccount.getUsername(),
                        PasswordUtils.encryptText(reqSecurity.getPassword(), userSalt,
                                secBean.getConfigData().getSecurityConfig().getAuthAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getIterations(),
                                secBean.getConfigData().getSystemConfig().getEncoding()));

                // delete entries here
                boolean isSecretRemoved = userManager.modifyOtpSecret(userAccount.getGuid(), false, null);

                if (DEBUG) {
                    DEBUGGER.debug("isSecretRemoved: {}", isSecretRemoved);
                }

                if (!(isSecretRemoved)) {
                    response.setRequestStatus(SecurityRequestStatus.FAILURE);

                    return response;
                }

                boolean isSaltRemoved = userSec.removeUserData(userAccount.getGuid(), SaltType.OTP.name());

                if (DEBUG) {
                    DEBUGGER.debug("isSaltRemoved: {}", isSaltRemoved);
                }

                if (!(isSaltRemoved)) {
                    response.setRequestStatus(SecurityRequestStatus.FAILURE);

                    return response;
                }

                response.setRequestStatus(SecurityRequestStatus.SUCCESS);
            } else {
                ERROR_RECORDER.error("Unable to obtain configured user salt. Cannot continue");

                response.setRequestStatus(SecurityRequestStatus.FAILURE);
            }
        } catch (SQLException sqx) {
            ERROR_RECORDER.error(sqx.getMessage(), sqx);

            throw new AccountChangeException(sqx.getMessage(), sqx);
        } catch (AuthenticatorException ax) {
            ERROR_RECORDER.error(ax.getMessage(), ax);

            throw new AccountChangeException(ax.getMessage(), ax);
        } catch (SecurityException sx) {
            ERROR_RECORDER.error(sx.getMessage(), sx);

            throw new SecurityException(sx.getMessage(), sx);
        } catch (UserManagementException umx) {
            ERROR_RECORDER.error(umx.getMessage(), umx);

            throw new SecurityException(umx.getMessage(), umx);
        } finally {
            // audit
            try {
                AuditEntry auditEntry = new AuditEntry();
                auditEntry.setHostInfo(reqInfo);
                auditEntry.setAuditType(AuditType.CHANGEKEYS);
                auditEntry.setUserAccount(userAccount);
                auditEntry.setAuthorized(Boolean.TRUE);
                auditEntry.setApplicationId(request.getApplicationId());
                auditEntry.setApplicationName(request.getApplicationName());

                if (DEBUG) {
                    DEBUGGER.debug("AuditEntry: {}", auditEntry);
                }

                AuditRequest auditRequest = new AuditRequest();
                auditRequest.setAuditEntry(auditEntry);

                if (DEBUG) {
                    DEBUGGER.debug("AuditRequest: {}", auditRequest);
                }

                auditor.auditRequest(auditRequest);
            } catch (AuditServiceException asx) {
                ERROR_RECORDER.error(asx.getMessage(), asx);
            }
        }

        return response;
    }
}