river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: Jini and OSGI revisited
Date Sat, 09 Oct 2010 11:34:37 GMT
Ok, this is difficult for me because I haven't fully digested the Module 
code yet.

An OSGi / Jini client would already know the Service API it wanted to 
find. So the Service API Bundle the client depends on would already be 
installed in the client node. It would just be a matter of discovering 
the correct service and Reggie does discriminate between API with 
different versions.

The really tricky part is finding the correct ClassLoader to unmarshall 
your classes into and the right ClassLoader to put your reflective 
proxy. Hint: It has to go into the Service API interface ClassLoader, 
otherwise there are issues with visibility.  Java has the Package 
version spec, which might be used to assist, since a client could 
potentially have multiple versions of a Service API, but different 
bundles can have identical packages.

OSGi has some nice features like Permissions required by a bundle being 
packaged in the bundle. OSGi's Security Infrastructure predates the Java 
1.4 dynamic permission security model, since it supported the various 
flavours of embedded java and personal profile, which is now simply Java 
CDC.

OSGi's security differs from the Java 1.4 Permission model in it's 
BundleClassLoader and PermissionCollectionWrapper, which enables 
Permission's to be dynamically added or removed.  
PermissionCollectionWrapper is passed to the static (pre Java 1.4) 
constructor of the ProtectionDomain.  PermissionCollectionWrapper 
remains mutable after the ProtectionDomain's construction.  It can't be 
used in the ProtectionDomain dynamic constructor, since this would cause 
it to be replaced by a Permissions instance when performing a policy merge.

It's important to remember that while Permission's can be added and 
removed from OSGi's ProtectionDomain's, true revocation of permission's 
doesn't occur, client code having obtained security sensitive object 
references still have them after permission has been removed, so can 
continue performing privileged actions, although it can't perform any 
new privileged actions.  I believe the dynamic Permission's in OSGi were 
made dynamic to allow remote policy updates.

OSGi has a ConditionalPermissionAdmin service which allows permission 
checks to be delayed, in the case where a number of checks are performed.

I've done some work on an InternetSecurityManager, I've made sure that 
the DelegatePermission's work with OSGi ProtectionDomains as well, so 
the OSGi ProtectionDomains can be intermingled with the Dynamic Java 1.4 
style ProtectionDomain's that Jini utilises to enable DynamicPolicy's.  
The catch is that the ConditionalPermissionAdmin delayed permission 
checks won't work, since that requires OSGi's SecurityManager.

I had given this some serious thought, but had concluded that it would 
be easier to treat Service API as fixed and non changing, this would not 
prevent OSGi from being a Jini client or service, however it wouldn't 
force others to adopt OSGi either.  I proposed Extended Service API to 
enable evolution of Service API similar to the practice of extending 
java Interfaces.  This is suitable when one party wants to extend the 
Service API but doesn't control the spec.

I'd figured that the proxy can install as many dependency's as it wants 
in its own ClassLoader, provided we minimise the classes visible in 
parent class loaders to the Service API, Jini and Java Platforms.

Since all implementations communicate using the Service API, Jini and 
Java platform classes, this makes it possible to isolate all the library 
and package versions of all the implementations, each to their own child 
ClassLoader visibility.

So clients can still be implemented in OSGi, and updated dynamically, 
but OSGi isn't concerned with the classes in proxy ClassLoaders, since 
the client and proxy only cooperate using the Service API and can't see 
each other.  To add Service API in a client node, we would need a way to 
add new Service API to the Service API ClassLoader, with potentially 
many ProtectionDomains for many CodeSources containing Service API.
 
I thought the lost codebase problem could be solved by cooperative 
CodeSource caching or something similar, based on the jar file message 
digest.

Cheers,

Peter.

Michal Kleczek wrote:
> Folks,
>
> The discussion about trust and solving deserialization DoS issues brought me 
> to the idea of annotating classes with Modules.
>
> On the other hand Peter is working on ClassLoader / class identity issues.
> I tried to think about it and came up with an idea that a Module can express 
> that it depends on other Modules so that if there is a dependency that is 
> shared between two modules classes loaded from this dependency preserve their 
> ClassLoader:
>
> interface Module {
>   Module[] getDependencies();
>   //... class loading methods
> }
>
> We would have to implement a ClassLoader structure that is not hierarchical 
> but allows loading classes from dependencies.
>
> BUT IT IS ALREADY DONE!!! And it is done well. It is called OSGI.
> How can we leverage this?
>
> 1. Let's annotate classes with objects implementing:
> interface BundleSource extends ReferentUuid {
>   Iterable<? extends BundleSource> getDependencies();
>
>   //no more multiple urls - we are a bundle
>   //we can either provide everything in our bundle
>   //or require dependencies to be installed
>   InputStream open();
> }
>
> 2. As in my original idea - we prepare BundleSources with a ProxyPreparer so 
> that we know BundleSource is trusted before.
>
> 3. Let's implement a JiniBundle:
> public class JiniBundle implements BundleActivator {
>
>   //our context
>   private static BundleContext bundleContext;
>
>   //we need a package admin instance to find Bundles that
>   //were used to load classes
>   //have to check if it is really needed or we can safely assume
>   //that ClassLoaders implement BundleReference
>   private PackageAdmin packageAdmin;
>
>   //our cache of BundleSources
>   private static Map<Bundle, BundleSource> bundleSourceCache =
>     new WeakHashMap();
>
>   //used by MarshalOutputStream to annotate classes
>   //will return null if we don't know the BundleSource
>   public static BundleSource getSourceOf(Class c) {
>     return bundleSourceCache.get(
>       packageAdmin.getExportedPackage(class.getPackage().getName()).getExportingBundle());
>   }
>
>   //now the difficult part :)
>   
>   //cache of installed BundleSources
>   private static Map<BundleSource, Reference<? extends Bundle>>
>     installedBundles = new WeakHashMap();
>
>   //used by MarshalInputStream to resolve classes
>   //
>   public static Class loadClass(
>     BundleSource source, String name, ClassLoader defaultLoader) {
>     if (source == null) {
>       return defaultLoader.loadClass(name);
>     }
>     try {
>       makeSureInstalled(source).loadClass(name);
>     }
>     catch (RuntimeException e) {
>       throw e;
>     }
>     catch (Exception e) {
>       throw new ClassNotFoundException();
>     }
>   }
>
>   private static Bundle makeSureInstalled(BundleSource source) {
>       Bundle b = installedBundles.get(source);
>       if (b == null) {
>
>         //prepare
>         source = bundleSourcePreparer.prepare(source);
>
>         //make sure dependencies are installed
>         for (final BundleSource dependency : source.getDependencies()) {
>           makeSureInstalled(dependency);
>         }
>         
>         //install
>         Bundle b = bundleContext.installBundle(
>           source.getReferentUuid().toString(), source.open());
>         
>         //cache
>         bundleSourceCache.put(b, source);
>         installedBundles.put(source, new WeakReference(b));
>       }
>       return b;
>   }
>
>   //osgi activation follows...
>
> }
>
> Further details to be thought out:
> 1. Especially important is handling of lost codebase problem. OSGI implicitly 
> imports exported packages so it can happen that the service interface is 
> loaded from a bundle that was not installed by JiniBundle - so there is no 
> BundleSource associated with it.
> 2. Similar to lost codebase problem is that OSGI container can load a class 
> from a different bundle than the one we would want to so the codebase will not 
> be lost but will be different than the original one.
> 3. Sure there are many more - and the question is whether OSGI is the best 
> choice (maybe classworlds or NetBeans platform is better)
>
> But in the end - would it be a nirvana? :)
>
> Michal
>
>   


Mime
View raw message