Ajax-like J2EE security login

how-to
Nov 8, 20095 mins

J2EE Web security is based on the separation of content into two web contexts – protected and public. But there are lots of cases (in my experience majority of cases) when you provide the same content (e.g. a web page) but with different information displayed for different types of users. For non-authenticated (non logged-in) users you hide some sensitive info from your content, and for authenticated (logged-in) users you may choose to hide of display some data depending on their authorization (the user role). The form-based J2EE security automatically protects the ‘secure’ part of the web application. Which in reality means that J2EE container automatically asks for user credentials when the user tries to access the protected context. Context here means a folder on the server (something like ‘secure’), which is accessible by a URL path (something like ‘https://server.com/secure‘). But what if you just have a page or two (or a dozen) that render themselves differently depending on the user type? In this case you don’t have anything that could be considered a secure context, as you can’t physically separate you content into two, unless you want to copy all your pages to a ‘secure’ folder. The bitter truth is that the only way J2EE container authenticates (logs-in) a user is by intercepting user’s access to the protected context. You just can’t manually ask J2EE container to log your users in, and to present a form to enter their credentials. This situation is a long-lived problem for all J2EE devlopers. Under the hood the J2EE form-based security has three entities: the log-in page (where the user enters his login/password) which pops-up when user tries to access the protected content, the error page (the one that shows up if login/password entered was incorrect), and the /j_security_check URL which is built-into any J2EE container. The latter is capable of receiving login/password info from the login page, validating them, and upon successfull validation redirecting to the page that was originally requested, or, in case of validation failure, redirect the user to the error page (to give him another try). The tricky part is that /j_security_check URL cannont be used manually. You can’t just send user/password to it, J2EE container requires that this URL be called automatically. Wouldn’t it be wonderful if it was possible to make an AJAX call and pass login/password to /j_security_check? The solution that I’ve come to for situations with no physical separation between protected and public content is based on an

So, lets suppose that we have configured a form-based secured web-application, in web.xml it looks something like:


<security-constraint>
	<web-resource-collection>
		<web-resource-name>secured</web-resource-name>
		<url-pattern>/secure/*</url-pattern>
		<http-method>POST</http-method>
		<http-method>GET</http-method>
	</web-resource-collection>
	<auth-constraint>
		<role-name>admin</role-name>
	</auth-constraint>
</security-constraint>
<security-role>
	<role-name>admin</role-name>
</security-role>

We will need two pages – login.jsp and parentReload.jsp. The first one goes to J2EE login-config config in web.xml, so that it would show up if a request is made to a secure context:


<login-config>
	<auth-method>FORM</auth-method>
	<form-login-config>
		<form-login-page>/login.jsp</form-login-page>
		<form-error-page>/login.jsp?invalid=true</form-error-page>
	</form-login-config>
</login-config>

The login.jsp itself should look something like this:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<%
	if (request.getParameter("invalid")!=null) {
%>
Incorrect login/password, try again:
<%
	}
%>
<form action="j_security_check" method="post">
	user name: <input type="text" name="j_username"/>

	password: <input type="password" name="j_password"/><br>
	<input type="submit">
</form>
</body>
</html>

The parentReload.jsp goes to the /secure folder, probably becoming its the only inhibitant. The JSP content is pretty simple, can you guess what it does?


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
	<script type="text/javascript">
		parent.location.reload();
	</script>
</head>

Yes, it reloads the parent window! Now, on each page that is supposed to be rendered differently for different types of users you can put this nice code on the top of page:


<%
final java.security.Principal userPrincipal = request.getUserPrincipal();
if(userPrincipal==null) {
%>
<iframe src="secure/parentReload.jsp" frameborder="0"></iframe>
<%
}
%>

This is how it works, if you haven’t guessed it by now: if the current user is not authenticated yet an iframe is rendered on the page. This iframe’s src ‘secure/parentReload.jsp’ is located in the protected area, so, instead of displaying the original parentReload.jsp J2EE container intercepts this request and renders the login.jsp page inside the frame, which results in a little user/password widget on the top of each page, which is pretty neat. Once the user decides to login the iframe form is submitted without reloading the main page. If user credentials were valid J2EE container renders the parentReload.jsp in the iframe. Once rendered inside the iframe it will cause the parent window (the main page) to reload. Upon reload it will no longer try to render the iframe anymore, and you are free to render the protected content. This has been tested and workd great on Tomcat, and supposed to work with any J2EE container. Enjoy.