org.betaconceptframework.astroboa.console.jsf.login.LoginBean.java Source code

Java tutorial

Introduction

Here is the source code for org.betaconceptframework.astroboa.console.jsf.login.LoginBean.java

Source

/*
 * Copyright (C) 2005-2012 BetaCONCEPT Limited
 *
 * This file is part of Astroboa.
 *
 * Astroboa 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, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Astroboa 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 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Astroboa.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.betaconceptframework.astroboa.console.jsf.login;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.model.SelectItem;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.StringUtils;
import org.betaconceptframework.astroboa.api.model.CmsRepository;
import org.betaconceptframework.astroboa.api.model.RepositoryUser;
import org.betaconceptframework.astroboa.api.security.AstroboaCredentials;
import org.betaconceptframework.astroboa.api.security.IdentityPrincipal;
import org.betaconceptframework.astroboa.api.security.exception.CmsInvalidPasswordException;
import org.betaconceptframework.astroboa.api.security.exception.CmsLoginAccountExpiredException;
import org.betaconceptframework.astroboa.api.security.exception.CmsLoginAccountLockedException;
import org.betaconceptframework.astroboa.api.security.exception.CmsLoginInvalidUsernameException;
import org.betaconceptframework.astroboa.api.security.exception.CmsLoginPasswordExpiredException;
import org.betaconceptframework.astroboa.api.security.exception.CmsUnauthorizedRepositoryUseException;
import org.betaconceptframework.astroboa.client.AstroboaClient;
import org.betaconceptframework.astroboa.console.commons.ContentObjectStatefulSearchService;
import org.betaconceptframework.astroboa.console.jsf.ContentObjectList;
import org.betaconceptframework.astroboa.console.jsf.UIComponentBinding;
import org.betaconceptframework.astroboa.console.security.CmsCredentials;
import org.betaconceptframework.astroboa.console.security.IdentityStoreRunAsSystem;
import org.betaconceptframework.astroboa.console.security.LoggedInRepositoryUser;
import org.betaconceptframework.astroboa.console.security.LoggedInRepositoryUser.UserActivityType;
import org.betaconceptframework.astroboa.context.AstroboaClientContext;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.betaconceptframework.astroboa.context.SecurityContext;
import org.betaconceptframework.ui.jsf.comparator.SelectItemComparator;
import org.betaconceptframework.ui.jsf.utility.JSFUtilities;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.international.LocaleSelector;
import org.jboss.seam.security.Identity;
import org.jboss.seam.web.ServletContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Gregory Chomatas (gchomatas@betaconcept.com)
 * @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
 * 
 */
@Name("login")
@Scope(ScopeType.EVENT)
public class LoginBean {

    @In
    FacesMessages facesMessages;

    private String userName;
    private String passWord;

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final static String ASTROBOA_SERVER_KEY = "astroboa-server";

    private String repositoryIdToConnectTo;

    private String serverURLToConnectTo;

    private List<CmsRepository> availableCmsRepositoriesForSelectedRemoteServer;

    private AstroboaClient astroboaClient;

    private LoggedInRepositoryUser loggedInRepositoryUser;

    @In(create = true)
    private IdentityStoreRunAsSystem identityStoreRunAsSystem;

    @In(create = true)
    private LocaleSelector localeSelector;

    //Injected beans. Check components.xml
    private ContentObjectList contentObjectList;
    private ContentObjectStatefulSearchService contentObjectStatefulSearchService;

    public String login() {

        try {

            AstroboaClientContextHolder.clearActiveClientContext();

            //Login to Astroboa repository
            astroboaClient.initialize(serverURLToConnectTo);
            astroboaClient.login(repositoryIdToConnectTo,
                    new AstroboaCredentials(getUserName(), getPassWord().toCharArray()));

            //Login is successful
            //Instantiate Jboss' Seam Identity module
            //Retrieve JAAS application security domain name
            AstroboaClientContext clientContext = AstroboaClientContextHolder.getActiveClientContext();

            if (clientContext == null || clientContext.getRepositoryContext() == null
                    || clientContext.getRepositoryContext().getCmsRepository() == null) {
                logout(false);
                throw new Exception(
                        "No JAAS application policy name is provided for repository " + repositoryIdToConnectTo);
            } else {

                loggedInRepositoryUser.reset();

                //Provide JAAS policy name
                //String jaasApplicationPolicyName = clientContext.getRepositoryContext().getCmsRepository().getApplicationPolicyName();
                // Astroboa JAAS module will ve deprecated and thus we need to find antoher way to login to JBoss SEAM
                String jaasApplicationPolicyName = "astroboa";

                // Check if logged in repository's identity store is externally managed. If so, record in LoggedInRepositoryUser bean that her id is
                // externally managed. This is required by certain UI modules in order to enable or disable user provisioning functionality.
                loggedInRepositoryUser.setExternallyManagedIdentity(StringUtils.isNotBlank(clientContext
                        .getRepositoryContext().getCmsRepository().getExternalIdentityStoreJNDIName()));

                //Reset Identity
                Identity.instance().unAuthenticate();

                Identity.instance().setJaasConfigName(jaasApplicationPolicyName);

                //Set credentials
                Identity.instance().getCredentials().setUsername(getUserName());
                Identity.instance().getCredentials().setPassword(getPassWord());

                ((CmsCredentials) Identity.instance().getCredentials()).setIdentityStoreRepositoryId(
                        clientContext.getRepositoryContext().getCmsRepository().getIdentityStoreRepositoryId());

                ((CmsCredentials) Identity.instance().getCredentials()).setIdentityStoreRepositoryJNDIName(
                        clientContext.getRepositoryContext().getCmsRepository().getExternalIdentityStoreJNDIName());

                //Login to SEAM
                String loginOutcome = Identity.instance().login();
                // clear seam messages
                facesMessages.clear();

                identityStoreRunAsSystem.reset();

                //Reset content object list
                if (contentObjectList != null) {
                    contentObjectList.resetViewAndStateBeforeNewContentSearchResultsPresentation();
                }

                if (contentObjectStatefulSearchService != null) {
                    contentObjectStatefulSearchService.setReturnedContentObjects(null);
                    contentObjectStatefulSearchService.setSearchResultSetSize(0);
                }

                UIComponentBinding uiComponentBinding = (UIComponentBinding) Contexts.getEventContext()
                        .get("uiComponentBinding");
                if (uiComponentBinding != null) {
                    uiComponentBinding.resetContentObjectTableScrollerComponent();
                    uiComponentBinding.setListViewContentObjectTableComponent(null);
                    uiComponentBinding.setListViewContentObjectTableScrollerComponent(null);
                    uiComponentBinding.setFullViewContentObjectTableComponent(null);
                    uiComponentBinding.setFullViewContentObjectTableScrollerComponent(null);
                }

                // if login was successful we should also check if a Repository User exists for the logged in user 
                // A Repository User is automatically created upon first use of astroboa but we want to catch possible exceptions and prevent rendering the astroboa console page
                if (loginOutcome != null) {
                    RepositoryUser repositoryUser = loggedInRepositoryUser.getRepositoryUser();
                    if (repositoryUser != null) {
                        JSFUtilities.addMessage(null, "login.welcome", null, FacesMessage.SEVERITY_INFO);

                        // save the password in the session
                        // this is required by the ResourceApiProxy in order to construct secured API calls to the Resource API.
                        // This is a temporary solution until the new security framework is implemented (through URL signining)
                        HttpServletRequest httpServletRequest = ServletContexts.instance().getRequest();
                        if (httpServletRequest != null && httpServletRequest.getSession() != null) {
                            httpServletRequest.getSession().setAttribute("repositoryPassword", passWord);
                        }

                        // write audit log if identity store is local, i.e. there is a local Person Object connected to the loggedin repository user
                        loggedInRepositoryUser.updateConsloleLoginLog(UserActivityType.login);

                        return loginOutcome;
                    } else {
                        //facesMessages.addFromResourceBundle(StatusMessage.Severity.ERROR, "login.authenticationServiceFailure", (Object[]) null);
                        JSFUtilities.addMessage(null, "login.authenticationServiceFailure", null,
                                FacesMessage.SEVERITY_ERROR);
                        logout(false);
                        return null;
                    }
                }

                return null;
            }

        } catch (CmsLoginInvalidUsernameException e) {
            JSFUtilities.addMessage(null, "login.invalidCredentials", null, FacesMessage.SEVERITY_WARN);
            logger.info("User performed a login with invalid user name");
            logout(false);
            return null;
        } catch (CmsInvalidPasswordException e) {
            JSFUtilities.addMessage(null, "login.invalidCredentials", null, FacesMessage.SEVERITY_WARN);
            logger.info("User performed a login with invalid password");
            logout(false);
            return null;
        } catch (CmsLoginAccountExpiredException e) {
            JSFUtilities.addMessage(null, "login.accountExpired", null, FacesMessage.SEVERITY_WARN);
            logger.info("User performed a login with an account that has expired");
            logout(false);
            return null;
        } catch (CmsLoginAccountLockedException e) {
            JSFUtilities.addMessage(null, "login.accountLocked", null, FacesMessage.SEVERITY_WARN);
            logger.info("User performed a login with an account that is locked");
            logout(false);
            return null;
        } catch (CmsLoginPasswordExpiredException e) {
            JSFUtilities.addMessage(null, "login.passwordExpired", null, FacesMessage.SEVERITY_WARN);
            logger.info("User performed a login with a password that has expired");
            logout(false);
            return null;
        } catch (CmsUnauthorizedRepositoryUseException e) {
            JSFUtilities.addMessage(null, "login.unauthorizedRepositoryAccess", null, FacesMessage.SEVERITY_WARN);
            logger.info("User tried to login into a repository to which she is not authorized");
            logout(false);
            return null;
        } catch (Exception e) {
            logger.error("An error occured during user authentication", e);
            JSFUtilities.addMessage(null, "login.authenticationServiceFailure", null, FacesMessage.SEVERITY_ERROR);
            logout(false);
            return null;
        }

    }

    // this is used by page actions so we want logging to be enabled
    public void logout() {
        logout(true);
    }

    private void logout(boolean updateConsoleLoginLog) {

        if (updateConsoleLoginLog) {
            try {
                loggedInRepositoryUser.updateConsloleLoginLog(UserActivityType.logout);
            } catch (Exception e) {
                logger.error(
                        "An error occured during the update of conslole login log to record user logout. The logout will proceed normally without any notification to the user.",
                        e);
            }
        }

        Identity.instance().logout();

        identityStoreRunAsSystem.reset();

        loggedInRepositoryUser.reset();
    }

    @Observer(Identity.EVENT_PRE_AUTHENTICATE)
    public void configSeamPrincipal() {

        SecurityContext securityContext = AstroboaClientContextHolder.getActiveSecurityContext();

        //Expect to find a principal of Type IdentityPrincipal
        //inside Subject's Principals
        if (securityContext == null || securityContext.getSubject() == null
                || CollectionUtils.isEmpty(securityContext.getSubject().getPrincipals(IdentityPrincipal.class))) {
            throw new SecurityException("Identity Principal is missing");
        } else {
            Identity.instance().acceptExternallyAuthenticatedPrincipal(new IdentityPrincipal(securityContext
                    .getSubject().getPrincipals(IdentityPrincipal.class).iterator().next().getName()));

        }
    }

    public void setRepositoryIdToConnectTo(String repositoryIdToConnectTo) {
        this.repositoryIdToConnectTo = repositoryIdToConnectTo;
    }

    public String getRepositoryIdToConnectTo() {
        return repositoryIdToConnectTo;
    }

    public String getServerURLToConnectTo() {
        return serverURLToConnectTo;
    }

    public void setServerURLToConnectTo(String serverURLToConnectTo) {
        this.serverURLToConnectTo = serverURLToConnectTo;
    }

    public List<SelectItem> getAvailableServers() {

        List<SelectItem> availableAstroboaServers = new ArrayList<SelectItem>();

        try {

            PropertiesConfiguration consoleConfiguration = new PropertiesConfiguration(
                    "astroboa-console.properties");
            consoleConfiguration.setEncoding("UTF-8");

            @SuppressWarnings("unchecked")
            List<Object> astroboaServers = consoleConfiguration.getList(ASTROBOA_SERVER_KEY);

            if (CollectionUtils.isNotEmpty(astroboaServers)) {

                for (Object astroboaServer : astroboaServers) {
                    //Get server host or ip
                    String astroboaHostOrIp = consoleConfiguration.getString((String) astroboaServer + ".host");

                    if (StringUtils.isBlank(astroboaHostOrIp)) {
                        astroboaHostOrIp = AstroboaClient.INTERNAL_CONNECTION;
                    }

                    //Get port
                    String astroboaHostPort = consoleConfiguration.getString((String) astroboaServer + ".port");

                    if (StringUtils.isBlank(astroboaHostPort)) {
                        astroboaHostPort = "1099";
                    }

                    //Get localized label
                    String localizedLabel = consoleConfiguration
                            .getString((String) astroboaServer + "." + localeSelector.getLocaleString());

                    if (StringUtils.isBlank(localizedLabel)) {
                        localizedLabel = (String) astroboaServer;
                    }

                    availableAstroboaServers
                            .add(new SelectItem(astroboaHostOrIp + ":" + astroboaHostPort, localizedLabel));
                }

                if (availableAstroboaServers.size() > 1) {
                    SelectItemComparator selectItemComparator = new SelectItemComparator();
                    selectItemComparator.setLocale(localeSelector.getLocaleString());
                    Collections.sort(availableAstroboaServers, selectItemComparator);
                }
            }

        } catch (ConfigurationException e) {
            logger.error("", e);
        }

        return availableAstroboaServers;
    }

    public void connectToSelectedServer() {

        try {

            astroboaClient.initialize(serverURLToConnectTo);

        } catch (Exception e) {
            logger.error("", e);
        } finally {
            repositoryIdToConnectTo = null;
            availableCmsRepositoriesForSelectedRemoteServer = null;
        }

    }

    public List<CmsRepository> getAvailableCmsRepositoriesForSelectedServer() {

        if (availableCmsRepositoriesForSelectedRemoteServer != null) {
            return availableCmsRepositoriesForSelectedRemoteServer;
        }

        //Check if repository service is available
        if (astroboaClient.getRepositoryService() == null) {
            connectToSelectedServer();
        }

        //If repository service is available get all repositories
        if (astroboaClient.getRepositoryService() != null) {

            try {
                availableCmsRepositoriesForSelectedRemoteServer = astroboaClient.getRepositoryService()
                        .getAvailableCmsRepositories();
            } catch (Exception e) {
                logger.error("", e);
            }
        }

        return availableCmsRepositoriesForSelectedRemoteServer == null ? new ArrayList<CmsRepository>()
                : availableCmsRepositoriesForSelectedRemoteServer;
    }

    public void setAstroboaClient(AstroboaClient astroboaClient) {
        this.astroboaClient = astroboaClient;
    }

    /**
     * @return the userName
     */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName the userName to set
     */
    public void setUserName(String userName) {
        this.userName = userName;
    }

    /**
     * @return the passWord
     */
    public String getPassWord() {
        return passWord;
    }

    /**
     * @param passWord the passWord to set
     */
    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

}