PDA

View Full Version : Security checks


grom358
Oct 8th, 2004, 05:55 AM
I was wondering what would be a good way to handle security checks based on the user associated with a request. Currently I have


package presentation.web.shop;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.util.WebUtils;

import application.WebStoreFacade;
import domain.PrimaryKey;
import domain.Order;
import domain.Customer;

/**
* @author <a href="mailto:grom@capsicumcorp.com">Cameron Zemek</a>
*/
public class ViewOrderController implements Controller {
private WebStoreFacade webstore;

public void setWebStore(WebStoreFacade webstore) {
this.webstore = webstore;
}

public ModelAndView handleRequest(
HttpServletRequest request,
HttpServletResponse response) throws Exception {
int orderId = Integer.parseInt(request.getParameter("orderId"));
Order order = webstore.getOrder(new PrimaryKey(orderId));

// TODO Move this authorization check into the application layer
// Check user is authorized to view this order
Customer customer = (Customer) WebUtils.getSessionAttribute(
request, "sessionCustomer");
if (! order.getUserName().equals(customer.getUserName()) ) {
return new ModelAndView("Error", "message",
"You are not authorized to view this order!");
}

return new ModelAndView("Order", "order", order);
}
}


I should move the security check into the application layer but I don't want to pass the customer around. Any ideas?

Alef Arendsen
Oct 8th, 2004, 06:02 AM
You don't have to pass the customer around! Bind it to a ThreadLocal at the point you first determine the customer (for example in a HandlerInterceptor) and pick the ThreadLocal up again at the point where you need to check it (for example in in Advice attached to you business object).

Acegi security uses this principle a lot as well to bind the security context.

katentim
Oct 8th, 2004, 09:10 AM
In case you want some sample code, I've just done something similar myself anyway...

Your HandlerIntercepter would look something like:
public class WebInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
CurrentThread.setCustomer((Customer)request.getSes sion().getAttribute("sessionCustomer"));
return true;
}
}

And where ever you access it like (which can be done using AOP):
CurrentThread.getCustomer();

And the ThreadLocal:
public class CurrentThread {

private static ThreadLocal customer = new ThreadLocal();

public static Customer getCustomer() {
if (customer.get()==null) {
return null;
}
return (Customer) customer.get();
}

public static void setCustomer(Customer customerIn) {
customer.set(customerIn);
}

}

Ben Alex
Oct 8th, 2004, 08:20 PM
Don't forget to unbind (set to null) your ThreadLocal at the end of each web request. Acegi Security uses filters for this, to achieve portability between web frameworks. I also use filters in my own apps for other ThreadLocal purposes (ie an ActiveSubscriber so we know which application licensee owns the data).

If using filters, check out net.sf.acegisecurity.util.FilterToBeanProxy as it allows your filter to be obtained from the application context, meaning you can take advantage of its wiring, resource bundle, event notification and lifecycle capabilities.

katentim
Oct 8th, 2004, 11:00 PM
Don't forget to unbind (set to null) your ThreadLocal
Yes, in servers the thread is likely to be re-used.

If you are using advice, you can dispense with the ThreadLocal as soon as you've finished checking it. If you want the Web-related ThreadLocal variables for the entire request/response, you could sub-class the DispatcherServlet and set/clear them there (see below), but filters (as suggested in the previous post) are a neat approach.
public class CustomDispatcherServlet extends DispatcherServlet {

public CustomDispatcherServlet() {
super();
}

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
CurrentThread.setCustomer((Customer)request.getSes sion().getAttribute("sessionCustomer"));
super.doService(request, response);
CurrentThread.cleanUp();
}
}