6

I have some complicated access restrictions in my application which basically require looking at a combination of the user's roles, as well as some deep properties of the domain objects, to make access decisions.

For some of my methods (specifically things like getItem(Integer id) and updateItem(Integer id, FormBean form)), I can't really know ahead of time if they're allowed to access that item, as I don't have it yet, so I had been using @PostAuthorize.

However, that latter example, updateItem(id, form) presents a challenge. I only want to allow them to update the form in certain specific cases. Right now, I do see the @PostAuthorize causing them to get an HTTP 403 response when they do something they shouldn't, but the database changes aren't rolled back.

Is it possible to get @PreAuthorize, @Transactional and @PostAuthorize to all play nicely together in this case? (I think maybe by adjusting the order of some advice on them... but I'm not totally clear on how that ordering should be done).

Or, has my system gotten complex enough that I should really bite the bullet on Domain ACLs? Unfortunately, the documentation on those feels rather thin...

pioto
  • 2,472
  • 23
  • 37

2 Answers2

6

Spring framework used Ordered to define the ordering of beans. The easiest way to explicit define the order for @Transactional and @PostAuthorize are through the annotations:

@EnableTransactionManagement(order = 0)
@EnableGlobalMethodSecurity(prePostEnabled = true, order = 1)
Andrii Ofim
  • 151
  • 2
  • 4
-2

Why not use @PreAuthorize("hasPermission(#id, 'read')") and @PreAuthorize("hasPermission(#id, 'update')") and implement your own version of PermissionEvaluator?

But if you really do wish to use @PostAuthorize then you could try fiddling with the ordering of security and transactional aspects, as is described here.

My guess would be:

// perform security check first, will throw exception if bad
@EnableGlobalMethodSecurity(prePostEnabled = true, order = 0)

// apply tm around security check and update, allowing for rollback
@EnableTransactionManagement(order = 1) 
Miloš Milivojević
  • 5,219
  • 3
  • 26
  • 39
  • Thanks, I agree this is probably the way to go. Unfortunately, that interface feels like it could lead to some messy code once I start to manage multiple domain classes with it. Do you have any suggested patterns for handling that? (I think I'd like to have one class registered to handle hasPermission for each domain class; each of these is going to need to `@Autowire` a `FooRepository` class and what not) – pioto Jul 30 '16 at 13:40
  • You can have a generic base class where the type parameter would be the entity type and you'd also have a repository field let which you'd let Spring autowire for you. The base class would have an abstract method that would return a set of privileges for a given ID and authentication and subclasses would then implement that method. The base class would fetch that set and check if it contains the required privilege. – Miloš Milivojević Jul 30 '16 at 14:07