Skip to Main Content

Java EE (Java Enterprise Edition) General Discussion

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

j_security_check, login, Tomcat, and 408 timed out request

843838Aug 19 2005
When using a login form to access protected resources (e.g., webmail application), Tomcat will return a SC 408 error to the user should the time period from initial resource request to login submission exceed the session-timeout element in conf/web.xml. This probably happens because, as stated in Servlet Specification 2.3, "the original request parameters must be preserved by the container for use if, on successful authentication, it redirects the call to the requested resource." The result of this behavior is that if the user requests a protected resource, obtains a log in form, and lets the login linger for longer than the permitted session timeout, a successful authentication (or perhaps unsuccessful) will result in a 408 error. This might be a common occurrence given the type of application. Trapping the 408 error in web.xml and returning to the login or setting an exceedingly long session time out are viable solutions, but neither convenient nor practical.

A proposed solution is to provide an alternate login entry point which stores credentials to the session and autosubmits these credentials against j_security_check once a protected resource is accessed. The proposed method assumes your web application's existing welcome page addresses a protected resource which subsequently brings up a login form page (it is ill-advised to point to the login page directly since successful authentication results in poorly defined resource redirection, 400 error, or perhaps blank j_security_check page). It also assumes you are using j_security_check:

1) Define a welcome page directive that points to a login page; this goes against what was previously said, but the key is to change the form post action to another mapping (e.g., auth.do). Do NOT reference this login page in the login config of the deployment descriptor (web.xml); it should simply be a publicly accessible resource set as the primary welcome page to your application (so as to be the first page visitors will see when accessing the application). The form to the login page will look like this:
<form name="login" method="post" action="/auth.do">		
User ID: <input name="username" type="text" size=20 maxlength=15/>
Password: <input name="password" type="password" size=20 maxlength=15/>
<input type="submit" value="Login"/>
</form>
2) auth.do will reference/post to a JSP/servlet that creates a new session, stores the creds from the previous page's form into the session, and then redirects (NOT forward) to a protected resource URL. This step ensures that both the session and resource request are current (i.e., no 408). The fact that your login form page has "session=false" or not is irrelevant and will not be affected by this new session creation. Sessions are created automatically against a browser when accessing protected resources or JSPs w/o "session=false." Long story short, simply attempting to login (failed or not) will create a session, so one will be created nonetheless; just be sure to always retrieve your session from the request object. The JSP/servlet code should look something like this:
HttpSession session = req.getSession(true);
// set credentials in the session
session.setAttribute("username",req.getParameter("username"));
session.setAttribute("password",req.getParameter("password"));
res.sendRedirect(res.encodeRedirectURL("/<PROTECTED RESOURCE>"));
3) From the previous step's redirect to a protected resource, the container will subsequently direct the user to the login page as defined in the deployment descriptor. The trick is to build this login form to autosubmit itself against j_security_check, using the creds stored in the session object from the previous step. This login page must be referenced in the login config of the deployment descriptor. The self submitting login can simply be a JSP with the following code:
<html>
<body onLoad="document.forms.creds.submit()">
<form name="creds" method="post" action="/j_security_check">
<input type="hidden" name="j_username" value="<%=session.getAttribute("username")%>"/>
<input type="hidden" name="j_password" value="<%=session.getAttribute("password")%>"/>
</form>
</body>
</html>
Notice that this page does not have session=false, meaning that the associated session is retrieved from the forwarded request and does not need to be explicitly defined.

4) If successful, the user will be directed to the protected resource defined in step 2. If not, the form error page in the login config defined within the deployment descriptor will be accessed/executed.

5) Since the login page defined in step 1 will always be accessed from the URL's root (since it's the primary entry point), make sure to discriminate against valid users at the top of the login page and forward them to a suitable alternate application entry point (fyi, multiple welcome pages can be defined in web.xml in order of precedence). This will ensure that even in SSO environments with multiple contexts that the login page will be bypassed if the user is already authenticated. Always keep in mind that forwards from publicly available resources to protected ones are not constrained, so this poses potential security risks (use redirect if you are unsure, but redirects lose request context unless passed via URL). You can check for a valid user using a method like this:
// forward valid sessions
if (request.getUserPrincipal() != null) {
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/<ALTERNATE ENTRY POINT>");
dispatcher.forward(request,response);
}
Hope this helps. If you have a more elegant technique employing j_security_check, please feel free to offer. This solution seems cumbersome, but it has worked thus far. To test if you still get the 408, set your server.xml session timeout to 1 (mintue), then access a protected resource to force a login form page. Do not submit your login until a full minute has passed; after logging in you should see your application and not the 408. You now essentially have an idle login page that doesn't issue a resource request (that could potentially timeout) until you actually login.
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Sep 16 2005
Added on Aug 19 2005
0 comments
4,373 views