A Brief evolution of java.security.Policy providers and Jini Security,
please correct me where necessary.
Prior to Jini 2.0 security was left up to implementing developers, the
standard tools available in Java 1.2 were insufficient. You had to
implement your own SecurityManager. Or you could define Security
policy's in policy files. The AccessController still consulted the
ProtectionDomain, but the ProtectionDomain Permission's were static and
unchanging. You could implement your own policy provider for
java.security.Policy, by there was no way you could guarantee updates to
the ProtectionDomain with any changes, the ProtectionDomain used the
Policy.getPermissions(ProtectionDomain) call to obtain the
PermissionCollection from the Policy.
To enable the Jini 2.0 Security infrastructure, Sun made changes to Java
itself, in Java 1.4 ProtectionDomain's were given a new constructor
that enabled the ProtectionDomain to consult an external Policy
Provider, and the java.security.Policy gained the
implies(ProtectionDomain, Permission) method, allowing the
ProtectionDomain to consult the Policy, Jini 2.0 took advantage of this
with the DynamicPolicyProvider. This Policy system is a permissive
system, that is security was only ever relaxed, it cannot be tightened
without restarting the JVM.
Now we have taken a new evolutionary step, inspired by Sun's Neuromancer
Research Project's additional security needs, for a distributed object
registry, we now have a RevokeableDynamicPolicy interface.
RevokeableDynamicPolicy wouldn't be possible to implement without the
changes to Java 1.4 Security that were prompted by Jini 2.0.
A RevokeableDynamicPolicy relies on the following features inherent in Java:
* ProtectionDomain's new dynamic 4 parameter constructor support for
dynamic Policy's, supplied with a null PermissionCollection. Added
in Java 1.4
* Not returning any PermissionCollection's belonging to dynamic
grants via either of Policy.getPermissions(*) methods. Only those
belonging to underlying static Policy providers will be returned.
* Total reliance on Policy.implies(ProtectionDomain, Permission)
added in Java 1.4
A RevokeableDynamicPolicy supports the addition or removal of
PermissionGrant's
* PermissionGrant.implies(ProtectionDomain), is the main feature of
the RevokeableDynamicPolicy.
* PermissionGrant is an interface.
* A PermissionGrant can be implemented by anyone, but the
implementing codebase must have a RuntimePermission for
"getProtectionDomain" and GrantPermission for the Permission's it
will grant.
* A PermissionGrant can use any means it can to determine if it
implies a ProtectionDomain, if it does the RevokeableDynamicPolicy
will add Permission's to the PermissionCollection cached for that
ProtectionDomain by calling PermissionGrant.getPermissions();
* To remove a PermissionGrant, you must have RevokePermission.
What I discovered when implementing a Concurrent version of
RevokeableDynamicPolicy:
* PermissionCollection.elements() returned an
Enumeration<Permission> that would throw a
ConcurrentModificationException, when Permission's were added to
the backing PermissionCollection.
* java.security.Permissions is a heterogeneous PermissionCollection
implementation, it's a point of contention for threads. It needed
a concurrent replacement.
* The replacement,
org.apache.river.imp.security.policy.ConcurrentPermissions
implements a threadsafe alternative for Permissions that prevents
Enumeration<Permission> from throwing
ConcurrentModificationException by caching.
* Now it is possible for Policy.implies(ProtectionDomain,
Permission) calls to occur concurrently during adding or removal
of PermissionGrant's. Policy.elements() Enumeration<Permission>
can also be enumerated during adding or removal of
PermissionGrant's or implies() calls.
* UmbrellaGrantPermission's have been added to
org.apache.river.imp.security.policy.DynamicConcurrentPolicyProvider,
so you can minimise the size of Policy files for GrantPermission's.
* This implementation passes all the existing qa harness and jtreg
tests for DynamicPolicy.
* Please feel free to assist by creating new tests for Concurrency
(many threads, hammer all methods).
What's next:
* Adding new methods to net.jini.security.Security to provide
support for PermissionGrant's and RevokeableDynamicPolicy.
* Creating an Entry that provides PermissionGrantBuilder's to assist
the client to restrict the Permission's to those that are
acceptable to the client and only those needed by the Service.
* Utilising the new org.apache.river.imp.util.PolicyParser interface
(this may be added to the api at a later date), standard java
policy file syntax can be parsed by the provided
DefaultPolicyParser (courtesy Apache Harmony) and will return
PermissionGrant's, the PermissionGrant's can return
PermissionGrantBuilder's that can be used in Entry's
* We can add standard java policy files to our downloadable jar
archives, we just need a utility class that generates the
PermissionGrantBuilder Entry's for us.
* The new PolicyParser allows parsing of URL based policy files.
* A Distributed Object Registry, inspired by Project Neuromancer,
utilising distributed hash tables to track the location of objects.
The bigger picture, A Future Roadmap:
* Standardise the use of a Parent ClassLoader in the ClassLoader
hierarchy (tree) above all client and service implementation and
proxy ClassLoader's so that the implementations can all
communicate using COMMON SERVICE INTERFACES.
* Standardise jar file naming to assist ClassLoader layout, see
https://issues.apache.org/jira/browse/RIVER-341
* Create a new ServiceStarter / ClientStarter to setup the
ClassLoader tree based on the new naming scheme.
* Codebase Entry's and Client Codebase Provisioning.
* jeri Endpoint implementations to traverse firewalls.
* DNS-SD for Internet Unicast Discovery.
* StreamServiceRegistrar - for the Internet with delayed
Unmarshalling of Service Proxy's
* A new URL Handler for CodeBase's with Version information for
Provisioning.
RevokeableDynamicPolicy and StreamServiceRegistrar lookup filter
chaining makes it possible to:
* Lookup Services by common Codebase Entry's
* Process ResultStream using chained and nested ServiceItemFilters:
1. ServiceItemFilter at the client by comparison of Entry
contents < > =.
2. ServiceItemFilter to Unmarshall Proxy, Provision CodeSource
3. ServiceItemFilter to check Method Constraints
4. ServiceItemFilter to Dynamically Grant Permission's based on
Entry as deemed acceptable.
5. ServiceItemFilter to Perform operation on Proxy
6. ServiceItemFilter to Dynamically Revoke Permission's based.
7. ServiceItemFilter to Throw away Proxy reference
8. While next, Goto 2 repeat process, can utilise same
ClassLoader as previous Service Proxy for speed, no need to
downlaod, reload and re verify bytecodes for CodeSource.
* ResultStream's are like an Enumeration, but are concurrent, used
like a stream, a null result indicates end of ResultStream.
Best Regards,
Peter Firmstone.