Thanks Dan & Gregg,

I've been working on the overhead problem, here's a summary (will commit the latest after tests finish):

  1. Removed calls to CodeSource.implies (this causes a DNS lookup)
  2. Replaced URL with URI in Policy providers (URL requires DNS lookup
     and File system access)
  3. Removed calls to SocketPermission.hashCode and equals (this causes
     a reverse DNS lookup)
  4. Replaced URL with URI in maps inside PreferredClassLoader and
     PreferredClassProvider
  5. Changed the behaviour of Reference Collections to avoid calling
     hashCode during initialisation of temporary and timed referrers.
     (to avoid calling SocketPermission.hashCode).
  6. Created a PermissionComparator to avoid broken equals and hashCode
     implementations in Permission classes.
  7. Optimise the order of Permission checks (further optimisation is
     possible).
  8. Added dnsjava nameservice provider - a local dns server written
     entirely in java that supports multi threading and reverse DNS
     lookup, so many SocketPermission.implies instances can execute in
     parallel and avoid long timeouts (dnsjava has had 13 years of
     development and is relatively stable).  This requires a system
     property to be set.
  9. CachingSecurityManager uses Cliff Click's high scaling hash map
     implementation, proven to scale linearly to over 500 threads and
     Doug Lee's ConcurrentSkipListSet which is also concurrent.  This
     caches permission checks for each AccessControlContext and uses
the PermissionComparator to avoid calling equals or hashCode. Timed references reap permissions from the cache after about 10
     minutes of non use using a background thread.  Soft Permissions
     were not suitable.
 10. Immutable PermissionGrant's; the Policy uses these to make policy
decisions, these are shared among many threads without blocking. PermissionCollection instances are created on demand then
     discarded, since PermissionCollection is typically single threaded
     and synchronized.  Permission objects are meant to be immutable so
     they should be non blocking, some like SocketPermission aren't
     (they wait for dns lookup results if other threads are executing
     the same lookup) but with dnsjava they are much better.

So I hope I'm fixing security enough to stop people switching it off altogether. River is more exposed to Java 2 security kinks than other software because it is so network orientated, but I haven't really gone outside the original Java 2 security model, I've created completely new file policy, dynamic policy and security manager implementations, java 2 security was designed with this flexibility in mind.

I think we've got the only scalable java security infrastructure, I'm hoping future deployment will bring more patches and further improvements.

Code needs to access more resources than users like ProtectionDomains, ClassLoaders and system properties, however users are more concerned with access to files and network. In Unix, everything is a file reduces access control complexity. Plan9 was designed as a distributed network os also based on the everything is a file concept. The protection domain concept that Java uses was inspired by Multix.

The intersection of permissions contained by protection domains on the stack at any point in time determine the available permissions.

I've found that each time we've changed our java platform dependencies and compiler options, I've had to modify the test policy files, simply because code follows different execution paths and different domains are on the stack at the time the permission check is called.

Now here is where it gets interesting, as Dan pointed out, most administrators are happy to just allow a user all network access and restrict it using a firewall. But if it enables smart proxy's from behind the firewall to serve clients beyond the firewall (lets imagine for a moment that UDT Sockets have solved that problem), that could be seen as circumvention by an administrator. However if user Principals are not injected into every domain on the stack, and there is less trusted code on the stack, the user will only have the permissions of the less trusted code while it remains on the stack.

So in the presence of trusted code, user polices are relatively simple, but in the presence of less trusted code, the code doesn't gain the full permissions of the user and user privileges can be much more relaxed and remain simple. Principals and code become separate concerns.

This is why I think that the design of SubjectDomainCombiner is not suited to River, without some subtle modifications to add a Subject ProtectionDomain to the stack rather than injecting the Subject's principals into every ProtectionDomain on the stack.

Then as Dan has suggested, services can expose the permissions they require, this then drops the users privileges to that of the less trusted code, while that code remains on the call stack (it will be removed after method calls have returned).

In fact codesources can expose the permissions they require through permissions.perms files similar to OSGi, then we have to decide whether we trust the code enough to grant permission and that usually requires someone to vouch for it, like the server Subject or a code signer. So we need a different way to contact the server in an entry or something prior to class loading and unmarshalling.

If we create an Entry specifically for Identity Certificates, an entry containing the permissions and a service with a reflective proxy used for obtaining authority certificates, then provided that delayed unmarshalling of the smart proxy is used, we are in a situation where we can grant DownloadPermission to the smart proxy, perform proxy verification then grant all remaining permissions to it. We could even have MarshalledInstance heavily restrict the Permission available during unmarshalling, even when the stack contains only privileged code so ClassLoaders cannot be created by untrusted code (requiring no administration). There is a small period during class loading when the class's ProtectionDomain isn't on the call stack, when static initialisers and so forth can get up to mischief and wreak havoc. We must ensure that something unprivileged is on the stack during unmarshalling. When the MarshalledInstance has returned it is removed from the stack, but the new untrusted smart proxy PD is now on the stack, so there is nothing to worry about. A ProtectionDomain isn't assigned to a Class until the Class object has been instantiated.

Then I think we should be able to abstract it all using something along the lines of what Gregg is describing, especially if we've simplified the user model, so we don't have to be as concerned about untrusted code.

I'm not saying it's easy, nor do I have a specific abstraction model in mind, I'm very flexible and open to suggestion.

I think the untrusted code complexity issues are solvable (rather than require only trusted code, because this spoils the dynamic flexibility of Jini) we could provide a tool to perform runtime permission auditing developers can expose the permissions required by their services, if you have a look at CombinerSecurityManager there is a method:

protected boolean checkPermission(ProtectionDomain pd, Permission p){
       return pd.implies(p);
   }

Just override this and create a Map that collects all the permissions required by each ProtectionDomain and dump it to a file.

An administrator could determine in advance the permissions that users can grant to downloaded code with GrantPermission, effectively sandboxing code in, because you can't always trust users not to grant permission they don't understand to dancing pigs.

Administrators obviously get to grant more.

Thanks for the comments, much appreciated.

Cheers,

Peter.



Gregg Wonderly wrote:
On Jun 30, 2012, at 2:39 AM, Dan Creswell wrote:

I'd also suggest that too much permission is granted because the current
Java security infrastructure inevitably works on a highly granular level
with long lists of detailed security options for this or that. That brings
a lot of overhead and complexity. Unix filesystems essentially reduce the
problem to user, group, other that classification whilst sometimes unwieldy
also makes for a level of sanity in terms of the number of permissions that
need playing with or expressing.

It seems to me that we should be looking at similar tactics for
grouping/abstracting that take out the need to hit a long list of very
granular permissions.

This is the whole, complete and total issue from my perspective.  For me, Java permissions 
represent the totality of exposure you want to give the system, to your software.  It has nothing 
to do with what "roles" or "users" need, it's just a ton of detail, which 
practically might be different from day to day, deployment to deployment and otherwise creates 
tedium which, turns people off.

For me, the services "features" are what I want the user to be controlled with.  At the method 
level, I want to be able to say "which role" gets to use "which arguments".  This can 
turn into a lot of tedium too though.

However, I really feel it makes more sense to say things like the following which 
enumerate "functions" which certain roles can perform.

admins -> browse,add,edit,delete,admin
techs ->browse, edit
viewers->browse
managers->browse,add,edit,delete

If you create this kind of role mapping, and then take each of the services 
methods, and lump them into one of the functions, you've mapped out a decently 
concise view of what you need to happen.

My http://java.net/projects/authlib project provides a complete mechanism which allows you to formulate XML descriptions of this type, and from that XML, generate delegating service classes, which then use a JDBC database, to load/maintain an in memory view of the security model. There is an admin ServiceUI which lets you create all the roles and permissions etc.
I suspect that this seems quite complicated, compared to managing permissions, 
but, it actually allows you to configure security using what I feel is the 
right domain of details, which then makes it a lot easier to actually use 
security.

Gregg Wonderly

Reply via email to