15

I have an application which uses the welcome-page index.jsp with an <iframe></iframe> the contents of the iframe is a jsf page. If I access index.jsp I see a cookie already on the first get in firebug:

Set-Cookie  JSESSIONID=C615DA89B6EF73F801973EA3DCD3B226; Path=/

The page of the <iframe> inherits this jsessionid. BUT: when I directly access the page of the <iframe/> I get the jsessionId rewritten to all URLs without a cookie - on the first request. Afterwards the cookie is used. This is all fine - if: The security system would allow me to perform url rewrites.

I run jboss 4.2.2

I want to achieve the same behaviour as I have with the index.jsp - e.g. always use cookies and always avoid http rewrite.

[EDIT] thanks to balusc's answer I wrote this:

public class JsessionIdAvoiderFilter implements Filter {

            public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
                    ServletException {
                boolean allowFilterChain = redirectToAvoidJsessionId((HttpServletRequest) req, (HttpServletResponse)res);

                         //I'm doing this because if I execute the request completely, it will perform a pretty heavy lookup operation. No need to do it twice.
                if(allowFilterChain)
                    chain.doFilter(req, res);
            }


            public static boolean redirectToAvoidJsessionId(HttpServletRequest req, HttpServletResponse res) {
                HttpSession s = req.getSession();
                if(s.isNew()) {

 //after the redirect we don't want to redirect again.
if(!(req.isRequestedSessionIdFromCookie()&&req.isRequestedSessionIdFromURL()))
                    {
                                //yeah we have request parameters actually on that request.         
                        String qs = req.getQueryString();

                        String requestURI = req.getRequestURI();
                        try {
                            res.sendRedirect(requestURI+"?"+qs);
                            return false;
                        } catch (IOException e) {
                            logger.error("Error sending redirect. " + e.getMessage());
                        }
                    }
                }
                return true;
            }
}

Don't forget to add it to your web.xml

    <filter> 
    <display-name>JsessionId Filter</display-name> 
    <filter-name>jsessionIdAvoiderFilter</filter-name> 
    <filter-class>my.namespace.JsessionIdAvoiderFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>jsessionIdAvoiderFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter> 
Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
Toskan
  • 13,911
  • 14
  • 95
  • 185

3 Answers3

14

Since Servlet 3.0 you could use <tracking-mode>COOKIE</tracking-mode> for this. But as JBoss 4.2.2 isn't Servlet 3.0 compilant, this isn't an option.

Easiest would be to create a servlet filter which sends a redirect to HttpServletRequest#getRequestURI() when HttpSession#isNew() returns true. Don't forget to check the HttpServletRequest#isRequestedSessionIdFromCookie() to prevent an infinite redirect loop when the client doesn't support cookies at all.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 2
    thanks. Is there a 'donate for kindness lucky pig' on your website somewhere? Can I order you a pizza? – Toskan Jul 06 '12 at 12:11
  • You're welcome. On the right hand column of my website/blog you can find a paypal donate button. That's the only way so far. – BalusC Jul 06 '12 at 12:15
  • seems like I cannot send you a personal message. You should figure out how to force paypal to be english. That dutch is slightly confusing :-) "Snel doneren" :-D – Toskan Jul 06 '12 at 13:03
  • Oh, it's just in English to me? I'll take a look. – BalusC Jul 06 '12 at 13:05
  • I think I fixed it. Paypal documentation is horrible. Can you please verify if it's in English for you? – BalusC Jul 06 '12 at 14:35
  • 2
    It would be simpler to write a Filter that overrides `HttpServletRequest.encodeURL` and `HttpServletRequest.encodeRedirectURL` to simply return the `String` argument passed to it: no redirection is necessary and you end up disabling the use of URL-encoded session ids (and requiring cookies). – Christopher Schultz Jul 07 '12 at 11:55
  • BalusC yes it is english now. @Christopher Schultz: why don't you make an answer instead of a comment? – Toskan Jul 09 '12 at 10:44
  • There is a bug in JBoss EAP 6.0.0.GA (AS 7.1.2.Final-redhat-1) which prevents COOKIE from removing the session ID from the URL. This bug is fixed in JBoss EAP 6.1 and newer versions. – Reddymails Nov 04 '13 at 15:32
  • In case anyone wondered, like I did, `` should be added as a child to the `` element in `web.xml`. – Bjørn Stenfeldt Mar 14 '17 at 13:09
3

Based on Christopher Schultz recommendation I tried this and it works.

    package com.rama.test.jsessionfilter

    public class JsessionIdAvoiderFilter implements Filter {

        protected static final Logger LOGGER = LogManager.getLogger(JsessionIdAvoiderFilter.class);

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

            if (!(req instanceof HttpServletRequest)) {
                chain.doFilter(req, res);
                return;
            }

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

        // Redirect requests with JSESSIONID in URL to clean old links
        /* If you really want clean up some old links which have Jsession id bookmarked clean it. If its new app 
            this  below check is not required. */
            if (request.isRequestedSessionIdFromURL()) {
                String url = request.getRequestURL().append(request.getQueryString() != null ? "?"
                                + request.getQueryString() : "").toString();
                response.setHeader("Location", url);
                response.sendError(HttpServletResponse.SC_MOVED_PERMANENTLY);
                LOGGER.info(" Found url with jsession id in it:"+ request.getRequestURL() +": url="+url);
                return;
            }

            // Prevent rendering of JSESSIONID in URLs for all outgoing links
            HttpServletResponseWrapper wrappedResponse = new HttpServletResponseWrapper(
                    response) {
                @Override
                public String encodeRedirectUrl(String url) {
                    return url;
                }

                @Override
                public String encodeRedirectURL(String url) {
                    return url;
                }

                @Override
                public String encodeUrl(String url) {
                    return url;
                }

                @Override
                public String encodeURL(String url) {
                    return url;
                }
            };
            chain.doFilter(req, wrappedResponse);

        }

        public void destroy() {
        }

        public void init(FilterConfig arg0) throws ServletException {
        }
    }

and the following entry in web.xml

<filter> 
        <display-name>JsessionId Filter</display-name> 
        <filter-name>jsessionIdAvoiderFilter</filter-name> 
        <filter-class>com.rama.test.jsessionfilter.JsessionIdAvoiderFilter</filter-class> 
    </filter> 
    <filter-mapping> 
        <filter-name>jsessionIdAvoiderFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

Works great !!!.

Reddymails
  • 793
  • 1
  • 10
  • 24
  • If cookies are disabled you better check in your code and give a warning. The assumption is that cookie is enabled on client side. – Reddymails Nov 04 '13 at 21:26
2

This can be done with a simple Filter that wraps the request with an HttpServletRequest which overrides HttpServletRequest.encodeURL and HttpServletRequest.encodeRedirectURL. Simply return the String argument passed to it and you will disable URL re-writing. Note that this will only work for a single webapp unless you want to either configure it in conf/web.xml (not recommended) or configure it in all of your separate webapps.

This technique is superior to that posted later in your question because it does not require redirection which can slow-down your requests. IMO, it's also cleaner.

Christopher Schultz
  • 20,221
  • 9
  • 60
  • 77
  • i'll have a look at it asap. What do you mean with "single" webapp? I'm not quite sure what you mean – Toskan Jul 09 '12 at 14:20
  • Filters are configured in `WEB-INF/web.xml` which will only protect one webapp as described. – Christopher Schultz Jul 09 '12 at 17:01
  • the reason i'm accepting balusc answer is because that's what I implemented and it suits well to the described problem - I have no time trying out your solution but it sounds good – Toskan Jul 24 '12 at 09:03