0

I've been playing around with code inspired from one of balusC's answers. Basicly its a webfilter that tries to login the user if there is a remember me cookie.

The login happens so that it first fetches the MyUser entity from the userService-EJB and places it in the MUserSessionBean which is a @SessionScoped jsf-ManagedBean

Problem is that in the first response, the user appear as not logged in.

But in the logs i can see it is being logged in and if I just request a page refresh in the browser, the response will show a logged in user.

I've tried to place a redirect in som various places after the login happens, but the page-layout breaks when i tried that..

How can i successfully display a logged-in user in first response?

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
        ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    MUserSessionBean mUserSessionBean = (MUserSessionBean) request.getSession(true)
            .getAttribute("mUserSessionBean");

    if (mUserSessionBean != null && mUserSessionBean.getCurrentUser() == null) {

        String uuid = CookieUtil.getCookieValue(request, CookieUtil.COOKIE_NAME);

        if (uuid != null) {
            MyUser user = userService.findUserByUUID(uuid);

            if (user != null) {
                mUserSessionBean.setCurrentUser(user);
                CookieUtil.addCookie(response, CookieUtil.COOKIE_NAME, uuid, CookieUtil.COOKIE_AGE); 
            } else {
                CookieUtil.removeCookie(response, CookieUtil.COOKIE_NAME);
            }
        }
    }

    // pass the request along the filter chain
    chain.doFilter(req, res);
}
Community
  • 1
  • 1
Aksel Willgert
  • 11,367
  • 5
  • 53
  • 74

2 Answers2

1

From what I can see, you're not actually logging the user in on the first go around. All you're doing so far is simply setting a value in a session created without the container actually authenticating the user.

The remember-me feature requires you to authenticate against the realm on behalf of the user, using the credentials you pulled up with the remember-me token. You haven't done that. Even on the page refreshes where it appears the user has logged in, technically that's not true. It only appears as logged in because

     if (mUserSessionBean != null && mUserSessionBean.getCurrentUser() == null) 

resolves to true after the page has been requested the first time and skips all checking. Subsequent requests pass through simply because you forcefully placed an instance of MyUser in the session. In reality, the user is not logged in and this is probably responsible for the page breaks that occur elsewhere within your application.

You need to truly authenticate the user against the realm for peace to reign :)

    if (uuid != null) {
        MyUser user = userService.findUserByUUID(uuid);

        if (user != null) {
            request.login(user.username,user.password); //Authenticate!!!!
            mUserSessionBean.setCurrentUser(user);
            CookieUtil.addCookie(response, CookieUtil.COOKIE_NAME, uuid, CookieUtil.COOKIE_AGE); 
        } else {
            CookieUtil.removeCookie(response, CookieUtil.COOKIE_NAME);
        }
    }
kolossus
  • 20,559
  • 3
  • 52
  • 104
  • hmm i dont fully understand. is it mandatory to login the user using the servlet apis. shouldnt it be enough to place the user in a sessionscoped bean. maybe im drawing the wrong conclusions, but that is how i interpret this answe: stackoverflow.com/questions/3841361/jsf-http-session-login – Aksel Willgert Mar 06 '13 at 07:04
  • @AkselWillgert, if all that was needed to authenticate was to put some information in the session, `HttServletRequest#login` would be completely unnecessary as an API. Follow the comment thread in the post you reference in your question, BalusC omitted that bit too and got the same effect. Also see [this](http://stackoverflow.com/a/6324252/1530938) answer. But to put all doubt to rest, try it and let us know. – kolossus Mar 06 '13 at 16:02
  • @AkselWillgert, also note that the login was performed in the question you linked too – kolossus Mar 06 '13 at 16:08
0

I did a quick-fix that solved the problem. Instead of storing the user-entity in a SessionScoped ManagedBean, I stored it directly in the session. So the filter method looks like this:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
        ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    MyUser user = (MyUser) request.getSession(true).getAttribute("user");

    if (user == null) {

        String uuid = CookieUtil.getCookieValue(request, CookieUtil.COOKIE_NAME);

        if (uuid != null) {
            user = ub.findUserByUUID(uuid);

            if (user != null) {
                request.getSession().setAttribute("user", user);
                CookieUtil.addCookie(response, CookieUtil.COOKIE_NAME, uuid, CookieUtil.COOKIE_AGE);
            } else {
                CookieUtil.removeCookie(response, CookieUtil.COOKIE_NAME);
            }
        }
    }

    // pass the request along the filter chain
    chain.doFilter(req, res);
}

The advantage is the filter doesnt have to wait for ManagedBean to be constructed. Then the SessionScoped-Bean peak into the session and fetch the entity the filter might have put there.

@ManagedBean
@SessionScoped
public class MUserSessionBean {

    private MyUser currentUser;

    @PostConstruct
    public void init() {
        if (currentUser == null) {
            ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

            currentUser = (MyUser) context.getSessionMap().get("user");
        }
    }
...
}

I will look into to servlet-managed-authentication or what it may be called as Kollossus sugested, but the immediate problem is gone atleast.

Aksel Willgert
  • 11,367
  • 5
  • 53
  • 74