0

I'm using JSF 2.0, CDI 1.0 within WebSphere App Server v8.0.0.5.

I have a bizarre situation... Upon successful login, a CDI session-scoped bean is created, and the user is redirected to a welcome page. The session-scoped bean is injected into a request-scoped bean referened on the welcome page. The problem is that the session-scoped bean ONLY retains its field values upon first successful login per browser. I've tried the same user using Chrome, Firefox, and even IE. If I log out or restart WAS and attempt to log in again, the session-scoped bean's values are all set to null when injected into the request-scoped bean.

I'm using javax.enterprise.context for all my scopes.

Please, I need emergency help. A lot is riding at stake due to this problem.

Relevant snippet of login form's Auth bean (I've omitted some code after the redirect):

import com.ibm.websphere.security.WSSecurityException;
import com.ibm.websphere.security.auth.WSSubject;
import com.ibm.websphere.security.cred.WSCredential;
import com.ibm.websphere.wim.exception.WIMException;
import com.ibm.websphere.wim.util.SDOHelper;

import java.io.IOException;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.security.Principal;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.security.auth.Subject;
import javax.security.auth.login.CredentialExpiredException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import com.ibm.websphere.wim.SchemaConstants;
import com.ibm.websphere.wim.Service;
import com.ibm.websphere.wim.client.LocalServiceProvider;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import com.ibm.ws.security.core.ContextManagerFactory;

import commonj.sdo.DataObject;

@Named
@ConversationScoped
public class Auth implements Serializable {
/**
 * 
 */
private static final long serialVersionUID = -6106803531512607236L;
private String userId;
private String password;
private String originalURL;

@Inject
UserService userService;
private Service service;
private String uniqueSecurityName;
private String l;

@PostConstruct
    public void init() {
    ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
    originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);

    System.out.println("The PostContstruct has been called.");

    if (originalURL == null) {
        originalURL = externalContext.getRequestContextPath() + "/index.xhtml";
    } else {
        String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);

        if (originalQuery != null) {
            originalURL += "?" + originalQuery;
        }
    }
}

public void login() throws IOException, WIMException, PrivilegedActionException {
    FacesContext context = FacesContext.getCurrentInstance();
    ExternalContext externalContext = context.getExternalContext();
    HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
    System.out.println("The login method has been called.");

    try {
        Principal userPrincipal = request.getUserPrincipal();
        request.getUserPrincipal();
        if (userPrincipal != null) {
            request.logout();
        }
        request.login(userId, password);

        User user = new User();

        if (request.isUserInRole("STAFF")) {
            Staff staff = userService.getStaff(userId);
            user.setLocation(staff.getCenter().getCity());
            user.setRole("STAFF");
            user.setUserId(userId);
            externalContext.getSessionMap().put("user", user);
            externalContext.redirect("staff/staff-home?faces-redirect=true");
        }
}

public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    return "/index?faces-redirect=true";
}  

The User bean:

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class User implements Serializable {
/**
 * 
 */
private static final long serialVersionUID = 7198980241243868166L;
private String role;
private String location;
private String userId;
private Role sessionRole;

public User() { }

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

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

/**
 * @return the location
 */
public String getLocation() {
    return location;
}

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

/**
 * @return the userId
 */
public String getUserId() {
    return userId;
}

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

relevant portion of welcome page's bean:

import java.text.DateFormatSymbols;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

@Named
@RequestScoped
public class CenterInfoBean {    
@Inject
CenterInfo centerInfo;

@Inject
User user;

private State state;
private Center center;

@PostConstruct
public void init() {
    center = centerInfo.getCenterByCityName(user.getLocation());
}

Why is auth only populated with values upon the initial login with a unique browser and never populated with values upon subsequent logins?

Chris Harris
  • 1,329
  • 4
  • 17
  • 28

1 Answers1

0

It is not a good idea to mix the container managed bean code with something like ,

User user = new User();

adding it in sessionMap should work but what if container has already resolved the injection of session bean in your request bean as you are already in session.

Try avoiding code like User user = new User(); when User is container managed.

In your case I would suggest checking if the User is already there in session.

User user = (User)externalContext.getSessionMap().get("user");

if so then update this reference , if it is not available then go with

User user = new User();
Avinash Singh
  • 3,421
  • 2
  • 20
  • 21
  • Thanks for responding, @AvinashSingh. I was following [Best way for user authentication on JavaEE 6 using JSF 2.0?](http://stackoverflow.com/questions/2206911/best-way-for-user-authentication-on-javaee-6-using-jsf-2-0). I was wondering about the session map...since it was more of the non-CDI JSF 2.0 way of handling Servlet Spec 3.0 programmatic login. I think I understand what you're saying. Is there a CDI way where I can avoid putting the user bean into the SessionMap and/or declare new User();? – Chris Harris Mar 07 '13 at 07:08
  • You can add your whole logic of usr initialization from Auth class in a PostConstruct method in User , in this way User is always initialized whenever userbean is created. if you want to keep user details in a separate bean then add it as a model class User (noscope) and keep it in UserBean – Avinash Singh Mar 07 '13 at 07:18
  • Intersting...One thing I'm trying to wrap my head around is putting all of Auth's logic in the User's PostConstruct method. I'm dealing with a federated repository, so I have a whole other code portion in Auth that deals with getting the userPrincipal for AD users and then using WAS's WIM/VMM libraries for a AD vital attribute. I'm using EJB 3.1, so maybe that can help. I could set Auth to RequestScoped, pass the form info to an SLSB's login method, and from there figure out how to call a bean that injects the SessionScoped User bean. Do I sound like I'm on the right track? – Chris Harris Mar 07 '13 at 07:41
  • based on your impl , the closest simplest thing would be to convert Auth to SessionScoped and remove SessionScoped from User and keep a User object in Auth class . Using SLSB for login method is also a good idea. – Avinash Singh Mar 07 '13 at 07:47
  • Thanks! Your first suggestion served as a good temporary solution. My project is a little past the POC phase, so it will do until I have time to delve into how to properly handle sessions via CDI with JSF and/or SLSB's or SFSB's. Once I figure out the best way to leverage all 3 technologies for my implementation, I'll post it here. – Chris Harris Mar 07 '13 at 23:57
  • I found a great example of how I wanted to implement login. Here's a [link](https://github.com/weld/core/tree/2.0/examples/jsf/login) to a login example from JBoss's Weld. – Chris Harris Mar 24 '13 at 04:50