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.