views:

474

answers:

4

I'm experimenting with creating a simple AJAX Java webapp.

I'd like to use the container managed security provided by the Servlet container, but having investigated it have a feeling that it isn't going to work how I'd like it to. Basically I'd like to be able to have a login prompt on the main page, without the user having to navigate away to a login form.

As an example imagine a simple message board application and a user who wants to post a new message enters the text directly into a form on the screen, when it comes to pressing the submit button I would like be able to make an ajax call to determine if the user is already logged in, if not then I'd like to display a login div on the same page to allow the user to log in without navigating away to a separate login page.

The form based login provided by the servlet container seems to be based on the assumption that the user will be redirected to a separate login page at the point where they try to access something that is "secured", which isn't what I want to happen.

So I suppose what I'd like to know is if there is a standard way of allowing users to login within a single page ajax application using the container managed security, or some 3rd party library? I'm going to have a look at Spring security, but at first glance it seems to have the same problem that I'm having with the standard security.

EDIT:Found this very useful, think it may be the basis of my solution http://www.jroller.com/sjivan/entry/ajax%5Fbased%5Flogin%5Fusing%5Faceci

A: 

I've used Spring Security in the past, and while I didn't use it to do this specifically, I remember it was very pluggable. While the classic action to take if a user was unauthenticated is issue a redirect to a login form page, you can use one of several classes provided to change the behaviour in this case, or it's quite easy to write your own which will do whatever you want (in this case return an appropriate AJAX response by the looks of it).

The logic I ended up having to implement was pretty horrible, for legacy reasons, and I was still able to do it without any specific hassles. I don't doubt that you could get Spring Security to work in this respect too (and I wouldn't be surprised if they already have the specific classes for your requirements).

Andrzej Doyle
ok - thanks for quick reply, I will investigate and report back
Mike Warren
A: 

Hey Mike, I'm going thru the same process- trying to figure out best practice for integrating security packages like Spring Security, Apache Shiro, etc into ajax world.

From what I understand so far, at the end of the day (regardless of which security package you're using to implement the authorization and authentication), the ajax call that you make to check whether a user is authenticated has to call a servlet that renders a response (such as json or xml) that the javascript on the client can then handle and react to appropriately (display a login form inline, etc).

Here's the flow as I understand it:

  1. Initial browser request, example: http://mysite/homepage
  2. Server renders page (using any of the plethora of java frameworks available, for example, simple servlet, jsp, jsf, etc, etc)
  3. Rendered Page includes some sort of javascript library (gwt, jquery, prototype, etc)
  4. javascript library makes async request. This request must be made to a url where the java servlet container knows to respond with json and/or xml rather than html. For example, http://mysite/ajax/isAuthenticated
  5. javascript on client listens for response.
  6. javascript on client parses json/xml response and either displays login page, or continues on to next thing.

There are probably hundreds of combinations of server side + client side frameworks to help with this. So far, I've tried grails + prototype, grails + jquery, grails + gwt, simple servlets + gwt, and currently looking into using Spring MVC + Gwt. Also, outside of java world, I just started reading about Ruby on Rails (which, as I understand was basically created to make this ajax communication between client and server easy). I haven't found the one that really works for me yet, so if you have any luck, please let me know your results!

Dave Paroulek
A: 

Found a similar question has been answered on the Spring security forum

http://forum.springsource.org/showthread.php?t=80549

Not as straighforward as I hoped, but looks like a good suggestion once you've got up to speed with Spring Security - I may leave getting the logon for now and concentrate on other functionality. Will update here if I get as far as implementing a solution.

Mike Warren
A: 

OK - have got a basic solution, I'm not saying its the best, but looks like it will do the job.

Its based on a blog post by Sanjiv Jivan

http://www.jroller.com/sjivan/entry/ajax%5Fbased%5Flogin%5Fusing%5Faceci

EDIT: Having just read the comments on that post it looks like there may be another way to do it, also the post is 3+ years old, so wouldn't be surprised if there's better solutions out there, maybe using new features in Spring or J2EE. But I'm going to stick with this for now.

He's done a very good job of documenting it there, so I'll just comment here that I've got a basic example going by starting with copying Spring Security sample app., then adding the ServletFilter as described by Sanjiv.

As he was using an earlier version of Acegi Security (now called Spring Security) there were one or two changes required:

The url pattern is now "/j_spring_security_check" (not "/j_acegi_security_check"), and I found I had to add an input named "ajax" to get the isAjaxRequest method to return true - guessing I missed something in the javascript for that.

Had to change one line in the filter to check for "login_error" instead of "login_error=1", guessing that's something thats changed in newer versions of SpringSecurity. I.E.:

               if (redirectURL.indexOf("login_error") == -1) {

Also as I'm using jquery not prototype I created a basic html page with javascript to test using jquery.

Its rough and ready at the moment, the status that gets displayed is just "url:/msgbrd/" or "error:Bad credentials", but can tidy that up easily enough.

In case it helps here's my example index.html:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
<script type="text/javascript" src="jquery.form.js"></script>
<script type="text/javascript">

var loginOptions = { 
beforeSubmit:  postingLogin,  // pre-submit callback 
success:       showResponse,  // post-submit callback 
    type: 'post',
    url: '/msgbrd/j_spring_security_check'  ,
    clearForm: true
}; 


$(document).ready(function(){
    $('#loginForm').ajaxForm( loginOptions );   
     });


function postingLogin() {
    console.log("Login posting: ");

}
function doneLogin() {

    console.log("Login posted ");
}
function showResponse(responseText, statusText)  { 
    $("#statusMessage").empty();
    $("#statusMessage").append( responseText); 
} 

</script>


</head>
<body>
<h1>msgbrd</h1>
<div>
<form id="loginForm" action="" method="POST">
<p><label for="username"> User Name: </label> <input id="username"
    type="text" name="j_username" class="loginText"></p>

<p><input id="ajax" name="ajax" value="ajax"></input></p>
<p><label for="password"> Password: </label> <input id="password"
    type="password" name="j_password" class="loginText"
    onkeydown="loginOnEnter(event);"></p>

<p><label for="remember_me"> <input id="remember_me"
    type="checkbox" name="_acegi_security_remember_me">Remember Me</label>
</p>


<p><input type="submit" value="Go"></input></p>
<p id="statusMessage"></p>
</form>
</div>
</body>
</html>
Mike Warren