Announcement Announcement Module
Collapse
No announcement yet.
Security checks Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Security checks

    I was wondering what would be a good way to handle security checks based on the user associated with a request. Currently I have

    Code:
    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&#58;[email protected]">Cameron Zemek</a>
     */
    public class ViewOrderController implements Controller &#123;
        private WebStoreFacade webstore;
        
        public void setWebStore&#40;WebStoreFacade webstore&#41; &#123;
            this.webstore = webstore;
        &#125;
        
        public ModelAndView handleRequest&#40;
                HttpServletRequest request,
                HttpServletResponse response&#41; throws Exception &#123;
            int orderId = Integer.parseInt&#40;request.getParameter&#40;"orderId"&#41;&#41;;        
            Order order = webstore.getOrder&#40;new PrimaryKey&#40;orderId&#41;&#41;;
            
            // TODO Move this authorization check into the application layer
            // Check user is authorized to view this order
            Customer customer = &#40;Customer&#41; WebUtils.getSessionAttribute&#40;
                    request, "sessionCustomer"&#41;;
            if &#40;! order.getUserName&#40;&#41;.equals&#40;customer.getUserName&#40;&#41;&#41;&#41; &#123;
            	return new ModelAndView&#40;"Error", "message",
            			"You are not authorized to view this order!"&#41;;
            &#125;
            
            return new ModelAndView&#40;"Order", "order", order&#41;;
        &#125;
    &#125;
    I should move the security check into the application layer but I don't want to pass the customer around. Any ideas?

  • #2
    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.

    Comment


    • #3
      In case you want some sample code, I've just done something similar myself anyway...

      Your HandlerIntercepter would look something like:
      Code:
      public class WebInterceptor extends HandlerInterceptorAdapter &#123;
          public boolean preHandle&#40;
                  HttpServletRequest request,
                  HttpServletResponse response,
                  Object handler&#41;
                  throws Exception &#123;
              CurrentThread.setCustomer&#40;&#40;Customer&#41;request.getSession&#40;&#41;.getAttribute&#40;"sessionCustomer"&#41;&#41;;
              return true;
          &#125;
      &#125;
      And where ever you access it like (which can be done using AOP):
      Code:
      CurrentThread.getCustomer&#40;&#41;;
      And the ThreadLocal:
      Code:
      public class CurrentThread &#123;
      
          private static ThreadLocal customer = new ThreadLocal&#40;&#41;;
      
          public static Customer getCustomer&#40;&#41; &#123;
              if &#40;customer.get&#40;&#41;==null&#41; &#123;
                  return null;
              &#125;
              return &#40;Customer&#41; customer.get&#40;&#41;;
          &#125;
      
          public static void setCustomer&#40;Customer customerIn&#41; &#123;
              customer.set&#40;customerIn&#41;;
          &#125;
      
      &#125;

      Comment


      • #4
        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.

        Comment


        • #5
          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.
          Code:
          public class CustomDispatcherServlet extends DispatcherServlet &#123;
          
              public CustomDispatcherServlet&#40;&#41; &#123;
                  super&#40;&#41;;
              &#125;
          
              protected void doService&#40;HttpServletRequest request, HttpServletResponse response&#41; throws Exception &#123;
                  CurrentThread.setCustomer&#40;&#40;Customer&#41;request.getSession&#40;&#41;.getAttribute&#40;"sessionCustomer"&#41;&#41;;
                  super.doService&#40;request, response&#41;;
                  CurrentThread.cleanUp&#40;&#41;;
              &#125;
          &#125;

          Comment

          Working...
          X