PsPro
PsPro

Reputation: 1

Understanding HTTP sessions in JSF as session attributres are going null unexpectedly while working actively on the application

We're having a very large web application, entirely built with JSF (2.0)/PrimeFaces (8.0). Running on remote Tomcat 8 server (Linux OS) We are facing a very serious issue due to which our server logs are filling up enormously.

The issue is : A user, after login, while working actively on the application [Inactivity timeout (30 mins, default) not reached] like filling up a form, the session attributes are going null unexpectedly and on an Ajax call, filters intercept the request and check for username which is stored in session created at login, on getting username from session, it is giving null value and redirecting the user to login page.

And when user logs in again, same issue. And in 3rd attempt it is working absolutely fine. (This is just an example, sometimes started working as expected in 2nd attempt)

This is happening randomly, not always.

We have checked entire code for session.invalidate() but no issues, it is written where it should be like on Primefaces IdleMonitor timeout (10mins) and on logout. Also checked for .getSession(true) but no issues, it is written where it should be. Not anywhere in between.

We are trying to get it solved for last 3 days but no success...

Below is the approach which we are using in our application for session management.

Login Bean

@ManagedBean(name="login")
@ViewScoped

public class LoginBean implements Serializable
{
    private String username;
    private String password;
    String baseURL;
    public constructor()
    {
        HttpSession ss = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        if(ss!=null)
        {
             ss.invalidate();
        }

        baseURL = //some https://url where the application is hosted.
    }

    public void login()
    {
        //login DAO to check for login success
        if(loginSuccess)
        {
            HttpSession ss = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
            if(ss!=null)
            {
                 ss.invalidate();
            }
            
            ss = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
            ss.setAttribute("username", username);

            PrimeFaces.current().executeScript("window.location.replace('"+baseURL+"homePage.xhtml');"); // just to avoid navigation to login page using browser's back button
        }
    }
}

After login, getting values from session on homePage.xhtml's associated bean, this way:


@ManagedBean(name="home")
@ViewScoped

public class HomeBean implements Serializable
{
    private String username;
    
    public constructor()
    {
        HttpSession ss = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        username = (String) ss.getAttribute("username");
    }
}

This way, we're accessing username from session in our entire application

Filter :

public class MyFilter implements Filter {

    String userName="";
    
    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

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

        HttpSession session = req.getSession(false);
        userName=(String) req.getSession().getAttribute("username");
        
        String requestUrl = req.getRequestURI();
        String loginURL = req.getContextPath() + "/login.xhtml";
        String expiryURL = req.getContextPath() + "/expired.xhtml";
        
        
        if (!requestUrl.contains(ResourceHandler.RESOURCE_IDENTIFIER))
        {
            if(!requestUrl.contains("/login.xhtml") && !requestUrl.contains("/expired.xhtml"))
            {
                if(session == null) {
                    if ("partial/ajax".equals(req.getHeader("Faces-Request"))) {
                        res.setContentType("text/xml");
                        res.getWriter()
                            .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
                            .printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", expiryURL);
                    } else {
                        res.sendRedirect(expiryURL);
                    }
                }
                else
                {
            
                    if(userName==null  || userName.equals("") )
                    {
                        session.invalidate();

                        if ("partial/ajax".equals(req.getHeader("Faces-Request"))) {
                            res.setContentType("text/xml");
                            res.getWriter()
                                .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
                                .printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", expiryURL);
                        } else {
                            res.sendRedirect(expiryURL);
                        }
                    }
                    else
                    {
                        chain.doFilter(request, response);
                    }
                }
            }
            else
            {
                if(requestUrl.contains("/expired.xhtml"))
                {
                    if(session!=null)
                    {
                        session.invalidate();
                    }
                }

                chain.doFilter(request, response);
            }
        }
        else
        {
            chain.doFilter(request, response);
        }

    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub

    }

}

Primefaces Idle Monitor :

<h:form>
   <p:idleMonitor timeout="600000">
       <p:ajax event="active" listener="#{idleBean.expire()}" />
   </p:idleMonitor>
</h:form>

This is included in our UI template using <ui:include>

Idle Monitor Bean

@ManagedBean(name="idleBean")
@ViewScoped

public void expire() throws IOException
{
    HttpSession ss = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
    if(ss!=null)
    {
        ss.invalidate();
    }
    
    FacesContext.getCurrentInstance().getExternalContext().redirect(baseURL+"/expired.xhtml");

    return;
}

One more thing I wanted to add, as the application and the code is a bit old (~5years), it is having a random navigation or page switching mechanism like somewhere return(pagename.xhtml) and somewhere ExternalContext#redirect(pagename.xhtml). I'm not sure but suspecting this also for session issues.

The issue mentioned above is not coming always but randomly and is very annoying. Like it is happening anytime, while navigating to other page or while filling up a form and during ajax call or button clicks within 3-4 minutes of logging in.

Please help me understanding whether this approach is fine or not. If there are any flaws which are causing session attributes going null. Please suggest for solving this issue or improving this approach.

Upvotes: 0

Views: 94

Answers (0)

Related Questions