You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Peter Firmstone <ji...@zeus.net.au> on 2010/08/25 10:24:15 UTC

Security Delegates & a Revocable Dynamic Policy, Thoughts & Questions

Well, I'm wondering what the best solution might be for granting 
Permission's to proxy's that we'd later want to revoke.  In effect we 
haven't decided to trust the proxy code. The concept is, to provide 
supervised access to privileged functions for proxy's, not unsupervised 
trusted access.

Summary of observations so far:

    * References to sensitive objects, must not be allowed to escape
      into untrusted proxy code.
    * Existing JVM Permission's like SocketPermission cannot be granted
      to untrusted proxy code, they let references escape.
    * Security Delegates, provide a means to encapsulate sensitive
      objects, every method invocation must be checked.  Micro Managed
      ;)  This can have some obvious performance implications.
    * The delegate must hold any required JVM permission's. 
    * The delegate holds a reference to a sensitive object, and controls
      access to it's methods.
    * Delegates may be nested, eg: a Socket Delegate, wraps an
      OuputStream in another delegate when returning it to a caller.
    * A fine grained Permission, is very specific, eg: only grant
      permission to contact a particular network address.  Fined grained
      permission's have a  performance cost as well as increased
      application developer complexity cost.
    * A broad, coarse grained Permission is simple, eg: you either have
      permission to use the network or you don't.
    * A delegate can close and release all resources held, when
      permission checks fail, if it catches the AccessControlException,
      otherwise it must let the AccessControlException bubble up the
      call stack, which still allows other calling threads to continue
      to utilise the delegate.  EG an OutputStream or Channel must
      close, while a Socket may remain open.

I can see there are two choices, using networking as an example (The 
Permissions below exclude JVM Permission's unless otherwise stated):

    * For reasonable performance, a delegate's permission check has to
      be non blocking and fast for the majority of invocations.
    * OPTION 1: To use fine grained Permission's, that duplicate
      existing JVM permissions, for grants to untrusted proxy's. Because
      this approach uses more resources and takes longer to check, we
      must cache the result for each AccessControlContext and don't
      check it again until revocation occurs.  An
      ExecutionContextManager looks after the permission check on behalf
      of the delegate, while the delegate (our micro manager) thinks
      it's checking the permission on every invocation.OR
    * OPTION 2: Use fine grained JVM Permission grant's for delegates
      only, and new course grained permissions for proxy's, which the
      delegate uses to supervise access.  The delegates are responsible
      for preventing references from escaping and checking Proxy
      Permission's on every method invocation.
          o EG: Grant a SocketPermission to the DELEGATE'S CodeSource,
            restricting construction of sockets, to particular address
            ranges, because the socket won't change it's connection
            after construction.  (If we limit the permission's we give
            to our micro manager, he can't give a proxy something he
            doesn't have).
          o The delegate controls access to OutputStream and InputStream
            methods, using a fast and simple course grained network
            Permission check.
          o To stop access to the network, I revoke the network
            permission on that proxy.
          o If I'm a proxy that doesn't have network permission, I can't
            access the network at all.
          o If I'm a proxy with network permission, I can only do what
            the delegates are allowed to do.

OPTION 1 is the most pedantic and perhaps more flexibile, since it fully 
controls and restricts access with  finely grained permissions, however 
it increases complexity on behalf of the application developer, who has 
to understand and know all the new permissions.

OPTION 2, allows simplicity on the part of the application developer: 
"My proxy needs network access permission."  The permission check 
executes very quickly on every invocation, (non blocking 
PermissionCollection required), so the result doesn't need to be cached 
for the AccessControlContext and we can simply use 
AccessController.checkPermission calls. The policy's, by limiting the 
the Permission's delegates have with traditional JVM Permissions, can 
control what networks can be accessed by proxy's. A default security 
policy for delegates can be provided with River.

I've given both options quite a lot of thought, but find myself drawn to 
option 2.

Option 2 requires a new class, ProxyPermission extends Permission.

So for another example, disk access, we can limit the disk area the 
proxy's can read and write, via the delegates, so these untrusted 
proxy's could have a public shared writeable disk area, on a particular 
hard drive partition, or capacity restricted file system directory, so 
they can't take down the system.  The ProxyPermission would simply be, 
new ProxyPermission("File").  These proxy's could read each others files 
and do some nasty stuff to each other.  But then if we're clever with 
our delegates implementations, each could create and assign specific 
directories for files on that filesystem, so if each proxy has it's own 
file handle delegate instances, the proxy itself can decide who else it 
does or doesn't share disk access with, by not sharing it's file handle 
delegate references.  A file delegate could place some restrictions on 
the total number of writes, this might be system wide configurable, so 
one proxy can't fill up the filesystem.  There are other things we'd 
need to consider, such as clean up remove files, freeing up resources etc.

Option 2 also requires a River jar archive called delegates.jar, 
containing all our delegate classes, which is then used to define any 
policy restrictions imposed on security delegates, which will restrict 
what untrusted, but supervised smart proxy's can do.

Then an application developer only has to think about, disk, network, 
etc, whatever simple permission the service's proxy requires and this is 
only granted while the proxy is in use.  The administrator controls what 
untrusted proxy's have access to, with a policy file for the 
delegate.jar codesource.  Delegate implementations can be hidden from 
application developers, via River's existing API's such as JERI.

These ProxyPermission's are then used to ensure revocation of other 
Permission's.  Other permission's can be dynamically added and removed 
from the policy, but only a ProxyPermission removal, can effect full 
revocation.

But what if we want the greater flexibility that fine grained JVM 
permissions offer?

We can add Principals to the permission grants for the delegate.jar 
codesource, these can also be dynamically added and removed, so in 
effect we can control what we allow the proxy's to do, by what we grant 
to our delegates, delegates prevent the references from escaping and 
perform coarse grained method access permission checks, to ensure full 
revocation occurs when we want it to.

So if the application developer wants to:

   1. Perform Authentication of service and client
   2. Authorise, by granting delegates with specific Principal[], any
      Permission's requested via proxy constraints (excluding
      ProxyPermission's), to delegates.jar.
   3. Verify Proxy
   4. Grant ProxyPermission, "network", "file", etc to the proxy.
   5. Execute methods on proxy as a Subject.
   6. Revoke ProxyPermissions "network", "file", etc from proxy (dispose
      of proxy)
   7. We can also revoke the Principal and CodeSource delegate.jar
      permission grant, if we want, no references these permissions
      guard, have escaped into untrusted proxy code, the delegates
      prevented it, so they too are effectively fully revoked.
   8. We can now keep any objects we obtained from the service, knowing
      full well that a trojan cannot perform some action when a thread
      access the object, because it has no permissions.

But we're not restricted to using JAAS, you can utilise whatever user 
authentication system you like, the Delegates just ensure we don't give 
out references for security sensitive objects to untrusted code.

So if we manage to do this properly, we have the basis for cooperation 
between different companies or entities with disparate systems, where 
trust is based around authentication, authorisation, privacy and agreed 
common ServiceAPI, but doesn't extend to codebase trust.

If we can eliminate protocols as the required means of communication 
between disparate systems, we can open up new found abilities for 
communication.

How's that sound?

Anyone willing to assist?

Regards,

Peter.