10 Replies Latest reply on Apr 30, 2012 10:00 AM by ravi.jrk

    RF4: Session timeout, how?

    ssamayoagt

      There is no more A4J.AJAX.onExpired so how to handle session timeout/expiration in RF4?

       

      Regards.

       

      FOLLOW UP:

      Server sends login page with status 200 so AJAX doesnt known what to do, is not a redirect.

      I will experiment with servlet and see if does the trick.

      Regards.

       

      FOLLOW UP:

      We are toast!

      response.sendRedirect() doesn't did the trick, AJAX simple take it as valid response.

      How to trap AJAX request BEFORE RF's components?

      Regards.

        • 1. Re: RF4: Session timeout, how?
          ssamayoagt

          After reading abot in the Web (it is a common problem) I found a solution, simple and somewhat elegant.

           

          First, this is my environment:

           

          1. Glassfish 3.1 (JSF 2.1.x /  Servlet 3.0)
          2. Richfaces 4.0
          3. Container managed secutiry

           

          When server receives a request and session is already expired it doesn't sends a redirect to login page, it sends the login page itself.

          JSF AJAX js code doesn't expect that, it expects an XML which may contain partial rendering information, error information or redirect informatiom.

          So, instead of setting login-form-page to a real page (JSF or HTML) I set to a servlet;

           

          <login-config>

            <auth-method>FORM</auth-method>

            <realm-name>planillagt</realm-name>

            <form-login-config>

             <form-login-page>/ingreso</form-login-page>

             <form-error-page>/ingreso</form-error-page>

            </form-login-config>

          </login-config>

           

          Which does the redirect to real login page:

           

          @WebServlet("/ingreso")

          public class Ingreso extends HttpServlet {

                    private static final long serialVersionUID = 1L;

           

           

                    protected void doGet(HttpServletRequest request,

                                        HttpServletResponse response) throws ServletException, IOException {

                              doService(request, response);

                    }

           

           

                    protected void doPost(HttpServletRequest request,

                                        HttpServletResponse response) throws ServletException, IOException {

                              doService(request, response);

                    }

           

           

                    protected void doService(HttpServletRequest request,

                                        HttpServletResponse response) throws ServletException, IOException {

                              String facesRequest = request.getHeader("Faces-Request");

                              if (facesRequest != null && facesRequest.equals("partial/ajax")) {

                                        String url = MessageFormat.format(

                                                            "{0}://{1}:{2,number,####0}{3}/ingreso.view",

                                                            request.getScheme(), request.getServerName(),

                                                            request.getServerPort(), request.getContextPath());

                                        PrintWriter pw = response.getWriter();

                                        pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

                                        pw.println("<partial-response><redirect url=\"" + url

                                                            + "\"></redirect></partial-response>");

                                        pw.flush();

                              } else {

                                        response.sendRedirect(request.getContextPath() + "/ingreso.view");

                              }

                    }

           

          }

           

          If servlet detects that request comes from JSF AJAX ("Faces-Request" containing "partial/ajax") responses the JSF's redirect XML else just redirects to real login page.

           

          This is working for me now, hope that works for you also.

           

          Regards.

          • 2. Re: RF4: Session timeout, how?
            denebj

            Hey guys

             

            I implemented your solution - working like a charm But I noticed that on Firefox and Safari the header Faces-Request is not being send in the POST request !!

            It is working with Chrome/IE. So, there is no way to detect that it is a partial/ajax

             

            Do you any workaround for that ? Or any leads ?

             

            Thank you

            • 3. Re: RF4: Session timeout, how?
              nbelaevski

              Hi,

               

              I have this header sent from FF - are you checking AJAX request or common form submit?

              • 4. Re: RF4: Session timeout, how?
                denebj

                Hi

                 

                It does not matter apparently, I tried from a4j component (commandbutton) and also h:commandbutton.

                The result is the same, my Faces-Request value is null and when I look at Firebug I have that:

                 

                ServerApache-Coyote/1.1
                Set-CookieJSESSIONID=3D172CE279A40EE22DAB034AF930F524; Path=/; Secure
                Locationhttps://localhost:8443/servlet/
                Content-Length0
                DateThu, 09 Jun 2011 21:30:39 GMT

                Request Headersview source

                Hostlocalhost:8443
                User-AgentMozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
                Accepttext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                Accept-Languageen-us,en;q=0.5
                Accept-Encodinggzip, deflate
                Accept-CharsetISO-8859-1,utf-8;q=0.7,*;q=0.7
                Keep-Alive115
                Connectionkeep-alive
                Refererhttps://localhost:8443/settings/
                Cookie__utma=111872281.1694059113.1305215609.1307648008.1307654090.70; __utmz=111872281.1305215609.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); JSESSIONID=F4BEF48E826788A2E972A6EE3AC4A97B; __utmc=111872281; __utmb=111872281.14.10.1307654090

                 

                And from an A4J action :

                 

                Hostlocalhost:8443
                User-AgentMozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
                Accepttext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                Accept-Languageen-us,en;q=0.5
                Accept-Encodinggzip, deflate
                Accept-CharsetISO-8859-1,utf-8;q=0.7,*;q=0.7
                Keep-Alive115
                Connectionkeep-alive
                Faces-Requestpartial/ajax
                Content-Typeapplication/x-www-form-urlencoded; charset=UTF-8
                Refererhttps://localhost:8443/aircraft/
                Content-Length1231
                Cookie__utma=111872281.1694059113.1305215609.1307648008.1307654090.70; __utmz=111872281.1305215609.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); JSESSIONID=213AF872F78920A6FC581E6B496D1E90; __utmc=111872281; __utmb=111872281.18.10.1307654090
                Pragmano-cache
                Cache-Controlno-cache

                 

                But I am still having request.getHeader("Faces-Request") = null.

                • 5. Re: RF4: Session timeout, how?
                  floriandupont

                  I'm having the same issue, did you find a solution ?

                  • 6. Re: RF4: Session timeout, how?
                    denebj

                    I used a filter like that :

                     

                     

                    public class SessionTimeoutFilter implements Filter {

                     

                        private final Log    logger        = LogFactory

                                                                .getLog(SessionTimeoutFilter.class);

                     

                        private String        timeoutPage    = "YOUR URL";

                     

                        /*

                         * (non-Jsdoc)

                         * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)

                         */

                        public void init(FilterConfig filterConfig) throws ServletException {

                        }

                     

                        /*

                         * (non-Jsdoc)

                         * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,

                         * javax.servlet.ServletResponse, javax.servlet.FilterChain)

                         */

                        public void doFilter(ServletRequest request, ServletResponse response,

                                FilterChain filterChain) throws IOException, ServletException {

                     

                            if ((request instanceof HttpServletRequest)

                                    && (response instanceof HttpServletResponse)) {

                                HttpServletRequest httpServletRequest = (HttpServletRequest) request;

                                HttpServletResponse httpServletResponse = (HttpServletResponse) response;

                     

                                // is session expire control required for this request?

                                if (isSessionControlRequiredForThisResource(httpServletRequest)) {

                     

                                    // is session invalid?

                                    if (isSessionInvalid(httpServletRequest)) {

                                        String timeoutUrl = httpServletRequest.getContextPath()

                                                + "/" + getTimeoutPage();

                                        logger.info("session is invalid! redirecting to timeoutpage : "

                                                + timeoutUrl);

                     

                                        logger.info("Control on page : "

                                                + httpServletRequest.getRequestURI());

                     

                                        String facesRequest = httpServletRequest

                                                .getHeader("Faces-Request");

                                        if (facesRequest != null

                                                && facesRequest.equals("partial/ajax")) {

                     

                                            String url = MessageFormat.format(

                     

                                            "{0}://{1}:{2,number,####0}{3}/sessionexpired/",

                     

                                            request.getScheme(), request.getServerName(),

                     

                                            request.getServerPort(),

                                                    httpServletRequest.getContextPath());

                     

                                            PrintWriter pw = response.getWriter();

                     

                                            pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

                     

                                            pw.println("<partial-response><redirect url=\"" + url

                     

                                            + "\"></redirect></partial-response>");

                     

                                            pw.flush();

                     

                                        } else {

                                            httpServletResponse.sendRedirect(timeoutUrl);

                                        }

                     

                                        return;

                                    }

                                }

                            }

                            filterChain.doFilter(request, response);

                        }

                     

                        /**

                             * session shouldn't be checked for some pages. For example: for timeout

                         * page.. Since we're redirecting to timeout page from this filter, if we

                         * don't disable session control for it, filter will again redirect to it

                         * and this will be result with an infinite loop...

                         *

                         * @param httpServletRequest the http servlet request

                         * @return true, if is session control required for this resource

                         */

                        private boolean isSessionControlRequiredForThisResource(

                                HttpServletRequest httpServletRequest) {

                            String requestPath = httpServletRequest.getRequestURI();

                     

                             boolean controlRequiredLogin = !StringUtils.contains(requestPath,

                                    "login");

                     

                                   return !controlRequiredLogin ? false : true;

                     

                        }

                     

                        /**

                         * Checks if is session invalid.

                         *

                         * @param httpServletRequest the http servlet request

                         * @return true, if is session invalid

                         */

                        private boolean isSessionInvalid(HttpServletRequest httpServletRequest) {

                            boolean sessionInValid = (httpServletRequest.getRequestedSessionId() != null)

                                    && !httpServletRequest.isRequestedSessionIdValid();

                            return sessionInValid;

                        }

                     

                        /*

                         * (non-Jsdoc)

                         * @see javax.servlet.Filter#destroy()

                         */

                        public void destroy() {

                        }

                     

                        /**

                         * Gets the timeout page.

                         *

                         * @return the timeout page

                         */

                        public String getTimeoutPage() {

                            return timeoutPage;

                        }

                     

                        /**

                         * Sets the timeout page.

                         *

                         * @param timeoutPage the new timeout page

                         */

                        public void setTimeoutPage(String timeoutPage) {

                            this.timeoutPage = timeoutPage;

                        }

                     

                     

                     

                    And add the filter to the web.xml:

                     

                    <filter>

                    <filter-name>SessionTimeoutFilter</filter-name>

                    <filter-class>com.utils.SessionTimeoutFilter</filter-class>

                    </filter>

                     

                    <filter-mapping>

                    <filter-name>SessionTimeoutFilter</filter-name>

                    <url-pattern>/*</url-pattern>

                    </filter-mapping>

                     

                    And that's it, it is working perfectly.

                    • 7. Re: RF4: Session timeout, how?
                      hantsy

                      This solution can not reuse  the configuration of Spring Security paths....

                       

                      in my project, some paths are public, some are private and protected which can be accessed by anthenticated user.

                      • 8. Re: RF4: Session timeout, how?
                        fernandosc

                        I am using the above implementation, however, it does not validate the session in the call: isSessionInvalid.

                        Ing a session is always valid, even when it expires.

                         

                        Thanks.

                        • 9. Re: RF4: Session timeout, how?
                          ravi.jrk

                          The above servlet solution was working well in firefox. on session time out it was redirected to the proper URL. But It is not  working in IE 8.  We are using Richfaces 4 and the ajax repsonse is malformed.

                           

                          Following is the response in IE 8.

                           

                          Server returned responseText: <?xml version="1.0" encoding="UTF-8"?> <partial-response><redirect url="http://localhost:8080/test/login.jsp"></redirect></partial-response>

                          error[10:22:58.533]: Received 'error@malformedXML' event from <select id=alertTypeInfo:alertType ...>

                          error[10:22:58.595]: [200] undefined: undefined

                           

                          Plz let me know if you have any solution for this issue.

                           

                           

                          Thanks & Regards

                          Ravi

                          • 10. Re: RF4: Session timeout, how?
                            ravi.jrk

                            HI,

                             

                            Since We are using Spring security ,I have followed the below approach  and it fixed the problem.

                             

                            http://stackoverflow.com/questions/10143539/jsf-2-spring-security-3-x-and-richfaces-4-redirect-to-login-page-on-session-tim

                             

                             

                            But the issue now is with  SSO time out.

                             

                            Assume SSO session is timed out, application session is still active, Now if the user is performed any ajax request then SSO will interfere and tries to redirect to SSO login page. Ajax is unable to parse sso repsone and it becomes unresponsive on the page.

                             

                            Following exception is observed on a4j:log.

                             

                            error[09:41:58.012]: Received 'error@malformedXML' event from
                            <div id=dashboardForm:j_id168847210_1_7848f560:1 class=rf-tr-nd rf-tr-nd-colps ...>
                            error[09:41:58.013]: [200] undefined: undefined

                             

                             

                            Any solutions/leads will be appreciated.

                             

                            Thanks Ravi