We developed our current ACL type system before Acegi had its ACL system, and 
planned for this behavior from the beginning (we work with Hibernate as 
well).  Our system has these abilities:
1. Property level ACLs.  If the user does not have read access for a property, 
then somehow blank it out so that sensitive data is not transmitted on the 
wire.  If the user does not have write access to a property and the client 
attempts to change a value on the property, then throw a security exception 
when they attempt to persist the object.
2. Instance level ACLs.  If the user does not have read access to an instance, 
then filter that instance out:
  a. If the instance is the return value of a service method, throw access 
denied exception.
  b. If the instance appears in a collection, remove it from the collection.
  c. If the instance appears as the value of a property, secure the property 
(via the same process used in #1).

Apply these symantecs to all returned objects wherever they appear in an 
object graph, which, of course, implies recursion.  Now consider the typical 
usage pattern for our rich client application:
1. Rich client makes remote invocation to server side service via service 
interface.  The interface is a proxy that calls the remote service via 
HttpInvoker.
2. Enter server side:
  a. We first encounter the general security proxy that does basic role based 
security checks against the service method itself.
  b. Next, we encounter the transaction proxy which establishes a transaction 
context for the remainder of the method invocation.
  c. Invoke the actual service method.
  d. Service method returns object graph.
  e. Leave transaction proxy, meaning the transaction is committed (or rolled 
back in case of error/exception).
  f. If there was no error or exception, then we return back to the security 
proxy which now performs ACL security on the returned graph (note that this 
is outside of the transaction).  The object graph may be mutated during this 
securing phase.

As you can imagine, this gets real complicated when using POJOs and Hibernate 
(and your Hibernate model doubles as your DTOs), which is exactly what we 
use.  If you retrieve an object graph from one service method, make 
modifications, and then persist those changes via another service method 
invocation you are dealing with two totally separate transactions and 
Hibernate Sessions.  The ACL mechanism performs actual modifications to the 
POJOs in order to "secure" them, but you do not want these modifications 
persisted back to the DB as they were temporary and specific to the purpose 
of securing transmission of data.  This is about when you start longing for 
the more dynamic nature of some other languages - it would be so much easier 
if I could set dynamic metadata against a property (a property property), or 
remove a property altogether.  Anyway, you somehow have to merge the 
allowable mutations made by the client with the original object state before 
persisting to Hibernate.  The version of Hibernate we use (< 3.0) does not 
make this any easier, though it is possible.  There are a lot of various 
interactions that can bite you if you aren't very careful with your 
implementation.  I don't have time now to elaborate on how we solved these 
various issues.  For now, I'll say that we used a combination of AOP, 
Hibernate Interceptor, and special "secured" placeholders for objects.  The 
solution is not optimal at the moment.  Our version of Hibernate just does 
not provide any easy way to optimize things, so we end up reading each and 
every object from the DB before updating it.  This means at the time of 
update we have two copies of each object: the one passed in from the client 
(which is mutilated, so to speak, because of the ACL mods), and one we just 
reloaded from the DB via Hibernate.  We end up applying an algorithm to 
determine what allowable mutations were made by the client and then making 
those same mutations on the "real" object loaded from Hibernate.  There are 
other ways to approach the solution, of course (such as proxying every object 
in the graph and recording deltas as the client changes things) - but each 
solution has its own set of advantages and disadvantages.  The proxy solution 
gets harder to deal with when exposing your service as a web service to other 
types of clients.

  - Andy

On Wednesday 09 February 2005 02:40 pm, Tim Kettering wrote:
> Hi everyone,
>
>
>
> I've started work on implementing acegi's post-invocation security w/ ACLs.
> I am also using Spring/Hibernate to handle the data, and tx layer.
>
>
>
> What I am attempting to do is have the post-invocation "scrub" an domain
> object (which will have nested domain objects that need to be checked).
> Making up an example, we have a Store object which can contain a collection
> of Item objects.  So when a service call is made load a store #233, the
> post invocation chain would first check to see if the user has permission
> to view the Store itself.  Once that is allowed, the check goes deeper into
> the Store itself, and checks each Item in turn to ensure the proper
> permissions. So far it seems to work well.
>
>
>
> But however, since I am using Spring/Hibernate's session/tx management, I
> found out that when Acegi was scrubbing the Store object, the "changes"
> would be written back to the database by hibernate at the end of the
> session (due to the automatic flush).  Which in hindsight, is quite obvious
> that would happen, and is indeed correct behavior by Hibernate/Spring.
>
>
>
> My next thought was to move the post-invocation stuff outside the
> Hibernate/Spring transaction boundary, but then as a co-worker pointed out,
> I would lose the benefit of having the proper version of data within the
> transaction when doing the ACL checks against those items.  Nested
> transactions is an option, but I thought I'd write a email to the list and
> inquire if anyone else here has run into this situation and perhaps be
> willing to share a good solution?  Or if there is none, we could discuss
> this, and contribute to the knowledge base of good Acegi practices, since
> this issue is likely to come up again when people start to adopt
> post-invocation more widely.
>
>
>
> Some options that I thought of.
>
>
>
> 1.    Nested Transactions.
> 2.    Force an hibernate eviction of object at start of post-invocation
> chain (clunky though.. we have some straight jdbc calls too so I hate to
> pollute chain w/ hibernate specific calls).
>
>
>
> Im hoping others might have ideas as well.
>
>
>
> -tim


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Home: http://acegisecurity.sourceforge.net
Acegisecurity-developer mailing list
Acegisecurity-developer@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/acegisecurity-developer

Reply via email to