Announcement Announcement Module
No announcement yet.
Method Invocation & Data Access Security Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Method Invocation & Data Access Security

    I continue finding myself coming back to Spring Security to bridge a security need I have in an application that is currently going into development. This web application leverages Hibernate, JPA, Struts 2, and already leverages the Spring libraries for dependency injection.

    The security model needs of this application are somewhat dynamic. We need to be able to test whether a particular user can invoke a method within our service layer and once that decision has been made and allowed for said user, the data that which the user can operate against or retrieve must also be filtered based on their rights.

    As I am a newbie to Spring Security and I find a number of the documents that describe it's flexibility a tad daunting at times; I hope that others who have a better grasp maybe can simplify it for me and illustrate some examples that can help me get started.

    Lets assume we have a user community that contains those who can perform actions on purchase order. Some of these users are capable of creating this PO document while others are only capable of canceling, denying, or approving the purchase order. Taking this to the next level, all of these users are only capable of doing these purchase order operations within a specific company code and for a specific list of items.

    How would I drive my authorizations from the database to restrict the invocation of the service layer methods and check the create, cancel, approve, deny portion and then only allow the operations to succeed if the item in question is within a specific company code or inventory associated to a company?

  • #2
    Take a look at the contacts sample application. You might also want to look at Mike's SpringOne presentation.


    • #3
      After having watched the presentation, followed along by setting up a sample Spring Security application with the presenter, I am still left with one underlining problem and that is how to handle the granular security requirements of my original post.

      I can easily write my own service that handles returning my own custom UserDetails object and generating a list of rights based on the roles assigned within my system. What I have to be careful though is that these rights reflect the right domain object they refer to because users will be able to perform different operations on different domain objects.

      For example, user crancran has the rights of create, display, and search however I don't have the right to cancel a purchase order. Then in my service, I could easily annotate my methods like:

      public class PurchaseOrderService {
        @PreAuthorize("hasPermission(#po, 'create')")
        public PurchaseOrder create(PurchaseOrder po) {
          // business logic
        @PreAuthorize("hasPermission(#po, 'display')")
        public PurchaseOrder lookup(Long poNumber) {
          // business logic
        @PreAuthorize("hasPermission(#po, 'cancel')")
        public void cancel(PurchaseOrder po) {
          // business logic
        @PreAuthorize("hasPermission(#pocriteria, 'search')")
        public List<PurchaseOrder> search(PoSearchCriteria pocriteria) {
          // business logic
      The permissions evaluator would do a check on the target object for its instanceof type, then based on the permission object value, I would need to filter my user's granted authorizations by the module or domain object type to see whether the user can perform the requested operation of create, display, cancel, or search.

      But the security requirements go a step farther and imply a restriction that I can only perform these operations on purchase order documents within a specific company or division of my organization. So I can only search for purchase orders, create, or display those within division A; however another user may have the same roles but they can do the same operations but for a different division or a combination of division A and division B.

      For create, display, and cancel, it would be as simple as checking to see whether the division on the purchase order was within the allowed divisions from my role. If not, I return false.

      The search portion is what throws me ...

      The search form allows the user to specify a global range view against domain objects, in this case the purchase order. The user can select to have the results search across their entire organization or within a specific division, region or even at a specific facility level. But when the role specifies that I can only search purchase orders within division A; how can I handle this?

      One option is to use the @PostFilter annotation and when the results are returned, I check the division for each and if its not within division A; then I remove it from the collection. But this is highly inefficient.

      Is there a better way that I can force this restriction check ahead of time so that when my Hibernate query fires, it would only return objects within that division? if the user chose region or facility, the results would be even more granular based on those values; however if the user choose across entire organization but their visibility was only for division A; then only division A records would be queried.

      What I don't want to see however, is that I have placed my security checks inside this Permissions evaluator class and yet in my service, I must impose this additional granular check. If there is a way I could put it inside the permissions evaluator or within a security class rather than the service, this would be ideal. I want to keep my security stuff out if the service and self contained if at all possible.

      Last edited by crancran; Jan 30th, 2011, 03:41 AM.


      • #4
        Optimizing queries would really have to be part of your business logic. You can separate the code that determines the allowed divisions from the current principal, but you'd still have to call it from your service in order to adjust the query criteria.