pfirmstone / JGDMS

Infrastructure for providing secured micro services, that are dynamically discoverable and searchable over ipv6 networks
https://pfirmstone.github.io/JGDMS/
Apache License 2.0
14 stars 4 forks source link

OSGi bundles and proxy identity - allow more than once service proxy to utilise a specific bundle version? #150

Open pfirmstone opened 2 years ago

pfirmstone commented 2 years ago

Describe the bug Currently ProxyBundleProvider doesn't allow more than one services to use a specific proxy bundle version, currently this represents a major restriction placed on the use of OSGi services.

The reason this occurs is a mismatch between OSGi bundle loading and service proxy identity.

There is a many to one relationship between proxy identity and bundles. OSGi doesn't allow loading duplicate bundles.

Options and thoughts on how to handle this, all suggestions are welcome:

  1. Allow different services to share the same classes, consequences; loss of service proxy identity, unwanted permissions granted to less trusted services.
  2. Encapsulate the service proxy with another proxy, unfortunately this wont work with RemoteMethodControl, which would return a new instance.
  3. Create a shim InvocationHandler, who's class is loaded directly by BundleDelegatingClassLoader, so that whenever remote method calls are made, the permissions granted are granted to this particular ClassLoader and ProtectionDomain. Then only one bundle would need to be loaded, but the presence of the InvocationHandler on the call stack would reduce permission to the intersection of the sets of permissions on the call stack. We would need to make BundleDelegatingClassLoader override preferred ClassLoader and prefer the class of the InvocationHandler. It would be best if the InvocationHander is in its own package, in the JERI bundle. During marshalling this InvocationHandler would need to replace itself with the encapsulated InvocationHandler, however that may create problems with equality, with the CodebaseAccessor InvocationHandler. Since we know the InvocationHandler will be an instance of AtoimcInvocationHandler, we can extend it instead, with a stateless child class that only has an @AtomicSerial constructor and replaces itself with the superclass when serialized. This class wouldn't be exported from the package, and CodeSource could be used to find the URL of the bundle.
pfirmstone commented 2 years ago

Item 3.

I think it would be easiest to use preferred class loading to load AtoimcInvocationHandler into the BundleDelegatingClassLoader. However this presents a problem with BasicJeriTrustVerifier.

Perhaps we should inject a token into AtomicInvocationHandler instead, that is loaded by the BundleDelegationClassLoader, to ensure that a ProtectionDomain representing the service is present on the call stack, then we need to invoke a method on the token every time that InvocationHandler::invoke is called. This could of course be in-lined as a no-op, this needs further investigation.

The problem with the token approach is that permissions are granted by the client during proxy preparation to the ClassLoader of the smart proxy. The BundleDelegatingClassLoader, although the ClassLoader of the Endpoint, is not the actual ClassLoader used to load Bundle classes. Further complicating the situation, any dependencies that are resolved for the proxy, may not have required permissions.

Should we consider allowing smart proxies to share Bundles?

What are the consequences?

pfirmstone commented 2 years ago

Example: different lookup services would share static fields:

https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/services/reggie/reggie-dl/src/main/java/org/apache/river/reggie/proxy/ClassMapper.java

pfirmstone commented 2 years ago

Is this an option?

In an answer no, while it would work, it's a hack.

pfirmstone commented 2 years ago

Investigate OSGi subsystems or OSGi Framework Bundle Collision Hook Service.

My current thinking is we need to consider Apache Aries OSGi subsystems.