0
votes

I am using JSF2, Spring 3 and Mybatis. On user login, I am doing authentication from ConfigAutomationLoginBean.java which has other beans as its Managed properties. The problem is that my beans are being shared across multiple users in different browser window. All my beans are SessionScoped and if I don't keep it that way, I may not get navigation screen after login. I guess JSF creates all managed bean with SessionScoped attribute by default singleton. Would it be good idean if I make the initial bean authentication bean ie. ConfigAutomationLoginBean and other beans autorwired to it using Spring 3 and remove the JSF for intial bean loading? Below is my login code:

import java.io.Serializable;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.telus.routerconfigurationtool.dto.UserProfileDTO;
import com.telus.routerconfigurationtool.service.UserManagementService;
import com.telus.routerconfigurationtool.util.CommonUtil;

@Component
@ManagedBean(name = "configAutomationLoginBean")
@SessionScoped
public class ConfigAutomationLoginBean implements Serializable {

  private static final long serialVersionUID = 1L;

  private static final Logger LOGGER = Logger.getLogger(ConfigAutomationLoginBean.class);

  private String id;

  private String password;

  private String role;

  @ManagedProperty(value = "#{userManagementService}")
  private UserManagementService userManagementService;

  @ManagedProperty(value = "#{treeNavigationBean}")
  private TreeNavigationBean treeNavigationBean;

  @ManagedProperty(value = "#{breadCrumbBean}")
  private BreadCrumbBean breadCrumbBean;

  public String authenticateUser() {
    /** Reset and Update BreadCrumb - Add Nodes for Create User **/
    breadCrumbBean.resetBreadCrumbModel(); 
    Boolean authenticUser = false;
    //TODO logic to authenticate user. authenticUser set true if authentication
    //TODO Temporary setting to true
    authenticUser = true;
    if (authenticUser) {
      return authorizeUser();
    } else {
      CommonUtil.displayFacesMessage(this.getClass(), FacesContext.getCurrentInstance(),
          FacesMessage.SEVERITY_ERROR, "ERR1", id);
      return "index";
    }

  }

  private String authorizeUser() {

    UserProfileDTO userProfileDTO = new UserProfileDTO();
    CommonUtil.copyProperties(userProfileDTO, this);

    Boolean authorizedUser = false;
    // logic to authorize user. authorizedUser set true if authorization is
    // successful
    authorizedUser = userManagementService.authorizeUser(userProfileDTO);

    if (authorizedUser) {
      // Set User Role fetched from Database
      this.role = userProfileDTO.getRole();
      treeNavigationBean.setLoggedInUserId(id);
      treeNavigationBean.setLoggedInUserRole(role);
      treeNavigationBean.createTreeByUserRole();
      treeNavigationBean.setViewCenterContent(null);
      return "treeNavigation";
    } else {
      // Display Error Message that user is not authorized.
      CommonUtil.displayFacesMessage(this.getClass(), FacesContext.getCurrentInstance(),
          FacesMessage.SEVERITY_ERROR, "ERR2", id);
      return "index";
    }
  }

  /**
   * @return the id
   */
  public String getId() {
    return id;
  }

  /**
   * @param id the id to set
   */
  public void setId(String id) {
    if (StringUtils.isBlank(id)) {
      this.id = id;
    } else {
      this.id = id.toUpperCase();
    }
  }

  /**
   * @return the password
   */
  public String getPassword() {
    return password;
  }

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

  /**
   * @return the role
   */
  public String getRole() {
    return role;
  }

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

  /**
   * @return the userManagementService
   */
  public UserManagementService getUserManagementService() {
    return userManagementService;
  }

  /**
   * @param userManagementService the userManagementService to set
   */
  public void setUserManagementService(UserManagementService userManagementService) {
    this.userManagementService = userManagementService;
  }

  /**
   * @return the treeNavigationBean
   */
  public TreeNavigationBean getTreeNavigationBean() {
    return treeNavigationBean;
  }

  /**
   * @param treeNavigationBean the treeNavigationBean to set
   */
  public void setTreeNavigationBean(TreeNavigationBean treeNavigationBean) {
    this.treeNavigationBean = treeNavigationBean;
  }

  /**
   * @return the breadCrumbBean
   */
  public BreadCrumbBean getBreadCrumbBean() {
    return breadCrumbBean;
  }

  /**
   * @param breadCrumbBean the breadCrumbBean to set
   */
  public void setBreadCrumbBean(BreadCrumbBean breadCrumbBean) {
    this.breadCrumbBean = breadCrumbBean;
  }

}

Note: Since TreeNavigation bean is sessionscoped and single instance is shared, loggedInUserName is changed everytime different user is logging in. If user1 and user 2 logged in, then user1 who logged in first will see the screen of user2.

@ManagedBean(name = "treeNavigationBean")
@SessionScoped
public class TreeNavigationBean implements Serializable {
  private static final long serialVersionUID = 1892577430001834938L;

  private static final Logger LOGGER = Logger.getLogger(TreeNavigationBean.class);
  private TreeNode root;

  private TreeNode selectedNode;

  private String loggedInUserId;

  private String loggedInUserRole;

  private String loggedInUserName;

  private String viewCenterContent;

  private String userAction;

  @ManagedProperty(value = "#{userProfileBean}")
  private UserProfileBean userProfileBean;

  @ManagedProperty(value = "#{createConfigurationBean}")
  private CreateConfigurationBean createConfigurationBean;

  @ManagedProperty(value = "#{placeholderBean}")
  private CreateConfigPlaceholderBean placeholderBean;

  @ManagedProperty(value = "#{ncParamMappingBean}")
  private NCParamMappingBean ncParamMappingBean;

  @ManagedProperty(value = "#{breadCrumbBean}")
  private BreadCrumbBean breadCrumbBean;

  @ManagedProperty(value = "#{createTemplateBean}")
  private CreateTemplateBean createTemplateBean;

  @ManagedProperty(value = "#{configurationManagementBean}")
  private ConfigurationManagementBean configurationManagementBean;

  public void createTreeByUserRole() {
    root = new DefaultTreeNode("Root", null);
    if (TreeNodesEnum.SUPER_USER.equals(loggedInUserRole)) {
      addCreateConfigurationNodes();
      addTemplateAdministrationNodes();
      addUserAdministrationNodes();

    } else if (TreeNodesEnum.ADMIN_USER.equals(loggedInUserRole)) {
      addCreateConfigurationNodes();
      addTemplateAdministrationNodes();

    } else if (TreeNodesEnum.NORMAL_USER.equals(loggedInUserRole)) {
      addCreateConfigurationNodes();
    }
  }

.....................

1
If it is session scoped it will not be shared. How are you testing? Single browser with multilpe tabs? Also one of your beans is a spring singleton and JSF managed bean, don't mix.M. Deinum
I have tested it with multiple browsers of morzilla and multiple tabs, its the same behavior. My beans are session scoped, but since only single instance of bean is created, it is being shared across multiple users. I tried creating prototype bean per user, but I am not getting right way of doing it in JSF.Pallavi Shetty
The problem with one of the beans is that it isn't a jsf but a spring bean (due to the @Component). Don't do that. If JSF is creating a single instance you aren't using JSF right. Make sure you are using the correct @SessionScoped the one from the javax.faces.bean package. Make sure that JSF is managing the beans and not Spring (else you will have to make spring manage the session scope). My guess is that you are basically mixing different strategies leading to a big scope management mess.M. Deinum
Even if I remove @Component, the behavior is same. I cannot remove JSF nor Spring as it is too late and we have production release. Please let me know how to avoid a jsf bean in session scope to be singleton and being shared across multiple browsers. Even the sessionid is same in multiple browser window.Pallavi Shetty
Define multiple browser window here? How are you starting a window? Make sure you are testing 2 seperate browsers (firefox and chrome for instance). Starting a new session from a browser isn't a new session! It basically is the same as starting a new tab....M. Deinum

1 Answers

0
votes

With @Component you are using spring mvc beans instead of JSF beans. You can either switch to JSF beans or use Spring scopes, for example @Scope("session").