Thursday, November 09, 2006

Customize form based authentication in J2EE web container


Sometimes it is just not enough to just collect the user name and password through

the login page. In my work, it has a request to also collect the logon reason at the
same time the user logs in.

Form based authentication is adopted because it provids a logon page and
you have the chance to customize it. Since the default form based authentication
supports only two input parameters, they are j_username and j_password, and the
j_security_check is a container built-in function and you can not hack on it, how
can it be customized and support any extra parameters probably will be defined on
the logon page? I searched it on the Internet and got nothing.

It's a time to do your own invention.

I tried filter. It failed because it happens after the j_security_check. Then I
thought since the session is already there when you see the logon page, and the
logon is only for those protected resources, an unprotected resource might be
helpful to handle the extra information before it access the protected resource.
Tested it, it's through!

Here's how to make it work.

1. Define a jsp that handle the logon request before j_security_check. Let's name it
as preLogin.jsp. Assuming the extra information is called "reason", it has lines
like this.

<%
request.getSession().setAttribute("reason",request.getParameter("reason"));
System.out.println("user is "+request.getParameter("j_username"));
System.out.println("reason is "+request.getParameter("reason"));
System.out.println("j check url is "+request.getParameter("checkUrl"));
//request.getRequestDispatcher(response.encodeURL("j_security_check")).forward(request,response);
response.sendRedirect(response.encodeURL("j_security_check?
j_username="+request.getParameter("j_username")+"&j_password="+request.getParameter
("j_password")));%>

2. modify the logon page to use this preLogin.jsp instead of the standard
j_security_check.

<form action="'preLogin.jsp'" method="post">
<table cellspacing="5" border="0"><tbody>
<tr><th align="right">1Username:</th><td align="left">
<input name="j_username"></td></tr>

<tr><th align="right">Password:</th><td
align="left"><input type="password" value=""
name="j_password"></td></tr>

<tr><th align="right">Reason:</th><td align="left">
<input name="reason"></td></tr>

<tr><td align="right"><input type="submit" value="Log
In"></td><td align="left"><input type="reset"
value="Reset"></td></tr></tbody></table>
</form>

3. Make sure the preLogin.jsp is not protected in the application.

<security-constraint><display-name>Example Security
Constraint</DISPLAY-NAME><web-resource-collection>
<web-resource-name>unProtected Area</WEB-RESOURCE-NAME>
<url-pattern>/security/protected/preLogin.jsp</URL-PATTERN>
<http-method>DELETE</HTTP-METHOD><http-method>GET
</HTTP- METHOD><http-method>POST</HTTP-METHOD>
<http-method>PUT</HTTP-METHOD></WEB-RESOURCE-
COLLECTION></SECURITY-CONSTRAINT>

4. Restart the web container
5. Test it by accessing an protected resource

Note: using AJAX make it more elegant to set extra information in session before going to j_security_check.

No comments: