com.abiquo.abiserver.business.authentication.AuthenticationManagerApi.java Source code

Java tutorial

Introduction

Here is the source code for com.abiquo.abiserver.business.authentication.AuthenticationManagerApi.java

Source

/**
 * Abiquo community edition
 * cloud management application for hybrid clouds
 * Copyright (C) 2008-2010 - Abiquo Holdings S.L.
 *
 * This application is free software; you can redistribute it and/or
 * modify it under the terms of the GNU LESSER GENERAL PUBLIC
 * LICENSE as published by the Free Software Foundation under
 * version 3 of the License
 *
 * This software 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
 * LESSER GENERAL PUBLIC LICENSE v.3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

package com.abiquo.abiserver.business.authentication;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.wink.client.ClientAuthenticationException;
import org.apache.wink.client.ClientConfig;
import org.apache.wink.client.handlers.BasicAuthSecurityHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.providers.encoding.Md5PasswordEncoder;

import com.abiquo.abiserver.abicloudws.AbiCloudConstants;
import com.abiquo.abiserver.business.hibernate.pojohb.user.EnterpriseHB;
import com.abiquo.abiserver.business.hibernate.pojohb.user.RoleHB;
import com.abiquo.abiserver.business.hibernate.pojohb.user.UserHB;
import com.abiquo.abiserver.commands.stub.LoginResourceStub;
import com.abiquo.abiserver.commands.stub.impl.LoginResourceStubImpl;
import com.abiquo.abiserver.config.AbiConfig;
import com.abiquo.abiserver.config.AbiConfigManager;
import com.abiquo.abiserver.persistence.DAOFactory;
import com.abiquo.abiserver.persistence.dao.user.EnterpriseDAO;
import com.abiquo.abiserver.persistence.dao.user.RoleDAO;
import com.abiquo.abiserver.persistence.dao.user.UserDAO;
import com.abiquo.abiserver.persistence.dao.user.UserSessionDAO;
import com.abiquo.abiserver.persistence.hibernate.HibernateDAOFactory;
import com.abiquo.abiserver.pojo.authentication.Login;
import com.abiquo.abiserver.pojo.authentication.LoginResult;
import com.abiquo.abiserver.pojo.authentication.UserSession;
import com.abiquo.abiserver.pojo.result.BasicResult;
import com.abiquo.abiserver.pojo.result.DataResult;
import com.abiquo.server.core.enterprise.UserDto;
import com.abiquo.util.ErrorManager;
import com.abiquo.util.resources.ResourceManager;

public class AuthenticationManagerApi implements IAuthenticationManager {
    private static final Logger logger = LoggerFactory.getLogger(AuthenticationManagerApi.class);

    /**
     * Abiquo API URL.
     */
    private String apiUri;

    /**
     * Factory of DAOs and transaction manager.
     */
    private DAOFactory factory;

    private final AbiConfig abiConfig = AbiConfigManager.getInstance().getAbiConfig();

    private static final ResourceManager resourceManger = new ResourceManager(AuthenticationManagerDB.class);

    private final ErrorManager errorManager = ErrorManager.getInstance(AbiCloudConstants.ERROR_PREFIX);

    public AuthenticationManagerApi() {
        if (factory == null) {
            factory = HibernateDAOFactory.instance();
        }
    }

    /**
     * @see com.abiquo.abiserver.business.authentication.IAuthenticationManager#checkSession(com.abiquo.abiserver.pojo.authentication.UserSession)
     */
    @Override
    public BasicResult checkSession(final UserSession userSession) {
        BasicResult checkSessionResult = new BasicResult();
        getFactory().beginConnection();

        UserSession sessionToCheck = null;

        try {

            sessionToCheck = getUserSessionDAO().getCurrentUserSession(userSession.getUser(), userSession.getKey());

            if (sessionToCheck == null) {
                // The session does not exist, so is not valid
                checkSessionResult.setResultCode(BasicResult.SESSION_INVALID);
                // logger.debug("The session is invalid. Please log in again. "); // log into the
                // authentication.log
                // errorManager
                // .reportError(resourceManger, checkSessionResult, "checkSession.invalid");
                logger.trace("Invalid session. Please login again");

            } else {
                // Checking if the session has expired
                Date currentDate = new Date();
                if (currentDate.before(sessionToCheck.getExpireDate())) {
                    extendSession(sessionToCheck);

                    checkSessionResult.setSuccess(true);
                    checkSessionResult
                            .setMessage(AuthenticationManagerApi.resourceManger.getMessage("checkSession.success"));
                } else {
                    // The session has time out. Deleting the session from Data Base
                    getUserSessionDAO().makeTransient(sessionToCheck);

                    checkSessionResult.setResultCode(BasicResult.SESSION_TIMEOUT);
                    // logger.debug("The session is expired. Please log in again. "); // log into
                    // the
                    // authentication.log
                    // errorManager.reportError(resourceManger, checkSessionResult,
                    // "checkSession.expired");
                    logger.trace("Session expired. Please login again");

                }

            }

        } catch (Exception e) {
            if (getFactory().isTransactionActive()) {
                getFactory().rollbackConnection();
            }
            logger.trace("Unexpected error while checking the user session", e);
        } finally {
            getFactory().endConnection();
        }

        return checkSessionResult;
    }

    /**
     * Authentication against the Abiquo API needs a Basic Authentication (Plain text).
     * 
     * @param login credentials.
     * @return BasicAuthSecurityHandler ready to be placed in the chain.
     */
    private BasicAuthSecurityHandler createAuthenticationToken(final Login login) {
        BasicAuthSecurityHandler basicAuthHandler = new BasicAuthSecurityHandler();
        basicAuthHandler.setUserName(login.getUser());

        basicAuthHandler.setPassword(login.getPassword());
        return basicAuthHandler;
    }

    /**
     * Authentication against DB expects a Md5 hash.
     * 
     * @param login credentials.
     * @return Md5 hash of the credentials.
     */
    private String createMd5encodedPassword(final Login login) {
        Md5PasswordEncoder encoder = new Md5PasswordEncoder();
        String passwordHash = encoder.encodePassword(login.getPassword(), null);
        return passwordHash;
    }

    /**
     * Creates the usersession data.
     * 
     * @param userHB DB user.
     * @return UserSession logged user.
     */
    private UserSession createUserSession(final UserHB userHB) {
        UserSession userSession = new UserSession();
        userSession.setUser(userHB.getUser());
        userSession.setKey(String.valueOf(Calendar.getInstance().getTimeInMillis()));
        userSession.setLocale(userHB.getLocale());

        userSession.setUserIdDb(userHB.getIdUser());
        userSession.setEnterpriseName(userHB.getEnterpriseHB().getName());

        int sessionTimeout = abiConfig.getSessionTimeout();
        long expireMilis = new Date().getTime() + sessionTimeout * 60 * 1000;
        Date expireDate = new Date(expireMilis);
        userSession.setExpireDate(expireDate);

        userSession.setAuthType(userHB.getAuthType());

        // Saving in Data Base the created User Session
        getUserSessionDAO().makePersistent(userSession);
        return userSession;
    }

    /**
     * Delete old sessions from DB.
     * 
     * @param userHB
     * @param dataResult void
     */
    private void deleteOldSessions(final UserHB userHB, final DataResult<LoginResult> dataResult) {
        // Looking for all existing active sessions of this user, ordered by when were
        getUserSessionDAO().deleteUserSessionsOlderThan(userHB.getName(), new Date());
    }

    /**
     * This function should be deprecated since is an ad-hoc implementation (mostly a hack) to
     * delegates the login to the Abiquo API.
     * 
     * @see com.abiquo.abiserver.business.authentication.IAuthenticationManager#doLogin(com.abiquo.abiserver.pojo.authentication.Login)
     */
    @Override
    public DataResult<LoginResult> doLogin(final Login login)

    {
        DataResult<LoginResult> dataResult = new DataResult<LoginResult>();
        UserDto userDto = null;
        try {
            if (StringUtils.isBlank(login.getAuthToken())) {

                BasicAuthSecurityHandler basicAuthHandler = createAuthenticationToken(login);
                // We perform this call to a secure location. If success then the credentials are
                // valid
                DataResult<UserDto> dataResultDto = apiLoginCall(login, basicAuthHandler);
                userDto = dataResultDto.getData();
                // Old DB login needs a Md5 password
                String passwordHash = createMd5encodedPassword(login);
                basicAuthHandler.setPassword(passwordHash);
                login.setPassword(passwordHash);
            }

            dataResult = login(login, userDto);
        }

        catch (BadCredentialsException e) {
            if (getFactory().isTransactionActive()) {
                getFactory().rollbackConnection();
            }
            errorManager.reportError(resourceManger, dataResult, "doLogin.passwordUserIncorrect");

            dataResult.setResultCode(BasicResult.USER_INVALID);
            throw e;
        } catch (ClientAuthenticationException e) {
            if (getFactory().isTransactionActive()) {
                getFactory().rollbackConnection();
            }
            errorManager.reportError(resourceManger, dataResult, "doLogin.passwordUserIncorrect");

            dataResult.setResultCode(BasicResult.USER_INVALID);
        } catch (RuntimeException e) {
            if (getFactory().isTransactionActive()) {
                getFactory().rollbackConnection();
            }
            logger.error(e.getMessage());
            logger.info("Could not communicate with the Abiquo API, please check if the API is responding");

            dataResult.setMessage("Could not communicate with the Abiquo API");
        } catch (Exception e) {
            if (getFactory().isTransactionActive()) {
                getFactory().rollbackConnection();
            }
            errorManager.reportError(resourceManger, dataResult, "doLogin.passwordUserIncorrect");

            dataResult.setResultCode(BasicResult.USER_INVALID);
        }

        return dataResult;
    }

    /**
     * @param login login.
     * @param basicAuthHandler handler.
     * @return DataResult<UserDto>
     */
    private DataResult<UserDto> apiLoginCall(final Login login, final BasicAuthSecurityHandler basicAuthHandler) {
        ClientConfig clientConfig = new ClientConfig();
        clientConfig.handlers(basicAuthHandler);
        LoginResourceStub proxy = getLoginStubProxy();
        DataResult<UserDto> dataResultDto = proxy.getUserByName(login.getUser(), login.getPassword(),
                basicAuthHandler);
        return dataResultDto;
    }

    private DataResult<LoginResult> login(final Login login, final UserDto userDto) throws Exception {
        DataResult<LoginResult> dataResult;
        UserHB userHB;
        userHB = getUserToPersistSession(login, userDto);
        dataResult = persistLogin(userHB);
        return dataResult;
    }

    /**
     * @see com.abiquo.abiserver.business.authentication.IAuthenticationManager#doLogout(com.abiquo.abiserver.pojo.authentication.UserSession)
     */
    @Override
    public BasicResult doLogout(final UserSession userSession) {
        BasicResult basicResult = new BasicResult();

        getFactory().beginConnection();

        try {
            getUserSessionDAO().deleteAllUserSessions(userSession.getUser(), userSession.getKey());

            basicResult.setSuccess(true);
            basicResult.setMessage(AuthenticationManagerApi.resourceManger.getMessage("doLogout.success"));
            getFactory().endConnection();
        } catch (Exception e) {
            if (getFactory().isTransactionActive()) {
                getFactory().rollbackConnection();
            }

            errorManager.reportError(resourceManger, basicResult, "doLogout", e);
        } finally {
            getFactory().endConnection();
        }

        return basicResult;
    }

    /**
     * Extends current session by a time configured.
     * 
     * @param sessionToCheck current session void.
     */
    private void extendSession(final UserSession sessionToCheck) {
        // The session is valid updating the expire Date
        int sessionTimeout = abiConfig.getSessionTimeout();
        long expireMilis = new Date().getTime() + sessionTimeout * 60 * 1000;
        Date expireDate = new Date(expireMilis);
        sessionToCheck.setExpireDate(expireDate);

        // Although in the manual doesnt says so, this method does saveOrUpdate.
        getUserSessionDAO().makePersistent(sessionToCheck);

    }

    /**
     * @see com.abiquo.abiserver.business.authentication.IAuthenticationManager#findAllSessions(java.lang.String)
     */
    @Override
    public List<UserSession> findAllSessions(final String username) {
        List<UserSession> sessions = null;

        try {
            sessions = getUserSessionDAO().findByProperty("user", username);

        } catch (Exception ex) {

            BasicResult checkSessionResult = new BasicResult();
            checkSessionResult.setSuccess(false);

            errorManager.reportError(resourceManger, checkSessionResult, "checkSession.exception", ex);
        }

        return sessions;
    }

    /**
     * Generates the result. This function is provided for encapsulation purposes.
     * 
     * @param dataResult
     * @param loginResult void
     */
    private void generate(final DataResult<LoginResult> dataResult, final LoginResult loginResult) {
        // Generating the DataResult
        dataResult.setSuccess(true);
        dataResult.setMessage(AuthenticationManagerApi.resourceManger.getMessage("doLogin.success"));
        dataResult.setData(loginResult);
    }

    /**
     * Generates the login.
     * 
     * @param userHB DB user.
     * @param userSession logged user.
     * @return LoginResult pojo containing the data to login.
     */
    private LoginResult generateLoginResult(final UserHB userHB, final UserSession userSession) {
        // Generating the login result, with the user who has logged in and his session
        LoginResult loginResult = new LoginResult();
        loginResult.setSession(userSession);
        loginResult.setUser(userHB.toPojo());
        return loginResult;
    }

    /**
     * If unset, sets the URI.
     * 
     * @return Abiquo API URL.
     */
    public String getApiUri() {
        if (apiUri == null) {
            apiUri = abiConfig.getApiLocation();
        }
        return apiUri;
    }

    public EnterpriseDAO getEnterpriseDAO() {
        return getFactory().getEnterpriseDAO();
    }

    /**
     * Retrieves the gateway to the api, focused on Enterprise resource. This method instantiates a
     * new LoginResourceStubImpl
     * 
     * @return EnterprisesResourceStub.
     */
    protected LoginResourceStub getLoginStubProxy() {
        LoginResourceStub proxy = new LoginResourceStubImpl();
        return proxy;
    }

    public DAOFactory getFactory() {
        if (factory == null) {
            factory = HibernateDAOFactory.instance();
        }
        return factory;
    }

    // DAO's
    public RoleDAO getRoleDAO() {
        return getFactory().getRoleDAO();
    }

    public UserDAO getUserHBDao() {
        return getFactory().getUserDAO();
    }

    public UserSessionDAO getUserSessionDAO() {
        return getFactory().getUserSessionDAO();
    }

    // DAO's
    /**
     * Searches at DB for the user.
     * 
     * @param login login data.
     * @param userDto pojo that contains data from the current user.
     * @return DB user.
     * @throws Exception UserHB.
     */
    private UserHB getUserToPersistSession(final Login login, final UserDto userDto) throws Exception {
        // Get the user from the appropiate source
        UserHB userHB = null;
        getFactory().beginConnection();
        if (StringUtils.isBlank(login.getAuthToken())) {
            userHB = userDtoToUserHB(userDto); // getUser(login, session);
        } else {
            userHB = getUserUsingToken(login);
        }
        getFactory().endConnection();
        return userHB;
    }

    /**
     * Gets the user from DB using the authentication Token information.
     * 
     * @param login The object with the token information.
     * @param session The Hibernate session.
     * @return The user.
     */
    private UserHB getUserUsingToken(final Login login) throws Exception {
        // Get token data
        String[] token = TokenUtils.getTokenFields(login.getAuthToken());
        String tokenUser = TokenUtils.getTokenUser(token);
        long tokenExpiration = TokenUtils.getTokenExpiration(token);
        String tokenSignature = TokenUtils.getTokenSignature(token);

        // Check token expiration
        if (TokenUtils.isTokenExpired(tokenExpiration)) {
            throw new Exception("Authentication token has expired.");
        }

        // Get the token user from db
        UserHB userHB = getUserHBDao().findUniqueByProperty("user", tokenUser);

        if (userHB != null) {
            // Validate credentials with the token
            String signature = TokenUtils.makeTokenSignature(tokenExpiration, userHB.getUser(),
                    userHB.getPassword()) + userHB.getAuthType();

            // Just as we create the signature by adding the AuthType
            if (!signature.equals(tokenSignature + token[3])) {
                return null;
            }
            userHB.setEnterpriseHB(
                    getFactory().getEnterpriseDAO().findById(userHB.getEnterpriseHB().getIdEnterprise()));
        }

        return userHB;
    }

    /**
     * @see com.abiquo.abiserver.business.authentication.IAuthenticationManager#isLoggedIn(java.lang.String)
     */
    @Override
    public boolean isLoggedIn(final String username) {
        List<UserSession> sessions = findAllSessions(username);
        return sessions != null && !sessions.isEmpty();
    }

    /**
     * Stores the information we need to keep.
     * 
     * @param userHB user.
     * @return DataResult<LoginResult>
     */
    public DataResult<LoginResult> persistLogin(final UserHB userHB) {
        DataResult<LoginResult> dataResult = new DataResult<LoginResult>();
        getFactory().beginConnection();
        try {

            if (userHB != null) {
                // User exists. Check if it is active
                if (userHB.getActive() == 1) {
                    // User exists in database and is active.

                    deleteOldSessions(userHB, dataResult);

                    // Creating the user session
                    UserSession userSession = createUserSession(userHB);

                    LoginResult loginResult = generateLoginResult(userHB, userSession);

                    generate(dataResult, loginResult);
                } else {
                    // User is not active. Generating the DataResult
                    errorManager.reportError(resourceManger, dataResult, "doLogin.userInActive");
                }
            } else {
                // User not exists in database or bad credentials. Generating the DataResult
                errorManager.reportError(resourceManger, dataResult, "doLogin.passwordUserIncorrect");
                dataResult.setResultCode(BasicResult.USER_INVALID);
            }
        } catch (Exception e) {
            if (getFactory().isTransactionActive()) {
                getFactory().rollbackConnection();
            }

            errorManager.reportError(resourceManger, dataResult, "doLogin.exception", e);
        }
        getFactory().endConnection();
        return dataResult;
    }

    /**
     * Parses a dto to a db info pojo. It does not access to db. Just a parser between pojos.
     * 
     * @param userDto user dto returned from the API.
     * @return db user, representation of an Hibernate pojo user.
     */
    private UserHB userDtoToUserHB(final UserDto userDto) {
        UserHB userHB = new UserHB();
        userHB.setActive(userDto.isActive() ? 1 : 0);
        userHB.setAvailableVirtualDatacenters(userDto.getAvailableVirtualDatacenters());
        userHB.setDescription(userDto.getDescription());
        userHB.setEmail(userDto.getEmail());
        userHB.setIdUser(userDto.getId());
        userHB.setLocale(userDto.getLocale());
        userHB.setName(userDto.getName());
        userHB.setPassword(userDto.getPassword());
        userHB.setSurname(userDto.getSurname());
        userHB.setUser(userDto.getNick());
        userHB.setAuthType(userDto.getAuthType());
        EnterpriseHB enterpriseHB = getEnterpriseDAO().findById(userDto.getIdFromLink("enterprise"));

        RoleHB roleHB = getRoleDAO().findById(userDto.getIdFromLink("role"));

        userHB.setEnterpriseHB(enterpriseHB);
        userHB.setRoleHB(roleHB);

        return userHB;
    }
}