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.