When investigating the above jira issue, I realised that there wasn't much that could be done for concurrency for the existing implementation without using Java 5 concurrency libraries, at the time we still supported Java 1.4.

A java Policy is heavily contented because every protection domain on the stack must be checked every time a security check is made, so if you have multiple threads making permission checks, pretty soon all those synchronized calls result in heavy contention.

Some time ago, I set about writing a replacement for DynamicPolicyProvider, named DynamicConcurrentPolicyProvider, I chose leave the existing implementation of DynamicPolicyProvider as it was for Java 1.4 support. However now we no longer support Java 1.4, so potentially DynamicPolicyProvider can be completely replaced.

DynamicConcurrentPolicyProvider has the following advantages:

  1. Uses ConcurrentHashMap to map ProtectionDomain's to Permissions,
     mostly avoiding locking.
  2. Replaces the heterogeneous PermissionCollection
     java.security.Permissions with a new implementation called
     ConcurrentPermissions, it also uses ConcurrentHashMap for
     uncontended implies checks.
  3. ReadWritePermissionCollection - for existing Permission classes
     that don't provide their own PermissionCollection, this allows
     multiple read, single write and protects allows enumeration
     without throwing ConcurrentModification exception by taking
     snapshots.  Most PermissionCollection's are not written very
     often, so this is also a big gain.

Concurrency is very important when using Subject's as all the ProtectionDomain's on the stack are replaced with new ProtectionDomains containing the Subject's Principals. ProtectionDomain doesn't override equals, so every time the AccessControlContext changes, new ProtectionDomains are created requiring the underlying file policies to be re-read and DynamicGrant's GrantPermission's to be checked and new Permissions, PermissionCollection and Permission classes to be constructed.

Going one step further, there's a new InternetSecurityManager to replace the aging RMISecurityManager.

InternetSecurityManager caches the results of AccessControlContext security checks, again in a ConcurrentMap, so repeat security checks don't even go to the policy for checking, they're returned immediately. Of course when we invoke Subject.doAs, the cache won't have the new AccessControlContext due to the new ProtectionDomain created as a result of SubjectDomainCombiner.

I've also got some ConcurrentWeakMap implementations to assist with garbage collection.

These concurrency improvements, result in massive improvements in scalability for Security checks, I've hammered this with as many threads as my poor little UltraSparc can muster, what I'd really like is someone with some serious compute power to see how far it scales.

But before I go and replace the existing implementation there are some extensions to the existing security model which need to be reviewed and finalised or removed.

These extensions relate to Permission revocation, where Permission guards that don't let objects escape can be revoked or removed. Not all Permission's once granted can be revoked, since they let the reference to the objects they protect, escape.

To prevent object references escaping, while allowing temporary access, another class called DelegatePermission encapsulates an existing Permission (which would normally allow object references to escape), when combined with a Delegate Object wrapper containing method guards (A guard object is created upon construction and checked on every method call), provides access to the encapsulated object until the DelegatePermission is revoked.

This allows Permission revocation protection for Sockets, Streams etc in the event of a Policy change or detected threat.

The tricky part is I haven't finalised how permission revocation should work. In the coming months, after the next release I'm going to create a new Branch, to focus on finalising it, I'll need your help, I don't want to make api mistakes that we'd have to live with long term.

The existing code is in org.apache.river at http://svn.apache.org/viewvc/river/jtsk/skunk/pepe/?pathrev=1137269

There's some other cruft in there too that needs cleaning up.

Revocation can be performed by granting Permissions to Principals or by removing existing PermissionGrant's from the policy or by a combination of both.

PermissionGrant's would also enable a SecurityService that provides advise on PermissionGrant's to be added or removed from a local Policy, to enable a centralised security service or policy for all nodes in a group. Such a SecurityService would be subject to strict InvocationConstraints over secure connections, but would enable grants to Codebase certificates, Principals, CodeSources or combinations of all three, or revoking particular CodeSource's known to be vulnerable, or certificates known to be compromised, or when certificate strength is determined inadequate etc, it could potentially simplify deployment in a secure environment. Such a service would probably be event based, and have only a reflective proxy locally with no download permission's and serialize builders rather than the PermissionGrant's themselves.

Cheers,

Peter.

Reply via email to