The following class, isolates a proxy on it's own thread and using reflection, isolates it completely from the rest of the executing environment, by passing method calls as tasks.

Forgive the tab formatting.

Cheers,

Peter.

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.river.impl.security.dos;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import net.jini.io.MarshalledInstance;

/**
* A preliminary experiment into Isolating a Smart Proxy.
*
* I think I'll investigate creating a Permission for additional threads
* for improved performance and also creating an event model so clients
* don't need to wait for remote method returns. I'll create a new interface
* for this, that can be implemented by services directly too.
*
* Alternative, only maintain this data structure for as long as it takes
* to verify proxy trust, then return proxy to the client or have the client
* thread call the smart proxy via the reflection proxy directly.
*
* REMIND: Investigate subclass method returns, this would be simple, if the
* smart proxy is confined to it's own ClassLoader, we just check the class
* of the object returned isn't from that ClassLoader, unless the smart proxy
* has a ServiceAPISubclassPermission or something like that.
*
* @author Peter Firmstone
*/
public class ProxyIsolate implements InvocationHandler {
   private volatile Object smartProxy;
   private volatile ExecutorService proxyExecutor;
   private volatile Throwable thrown;
   private final long timeout;
   private final TimeUnit unit;
@SuppressWarnings("unchecked")
   public ProxyIsolate(MarshalledInstance proxy,
               ClassLoader defaultLoader,
               boolean verifyCodebaseIntegrity,
               ClassLoader verifierLoader,
               Collection context,
                           long timeout,
                           TimeUnit timeUnit
       ) throws TimeoutException, InterruptedException, ExecutionException{
   this.timeout = timeout;
       unit = timeUnit;
   thrown = null;
   proxyExecutor = Executors.newSingleThreadExecutor(new Factory(this));
   UnmarshallProxyTask task =
       new UnmarshallProxyTask(proxy, defaultLoader,
       verifyCodebaseIntegrity, verifierLoader, context);
       smartProxy = proxyExecutor.submit(task).get(timeout, timeUnit);
   }
private Object taskInvoke(Object proxy, Method method, Object[] args) throws
       Exception {
   String methodName = method.getName();
   if (method.getDeclaringClass() == Object.class)  {
       // Handle the Object public methods.
       if (methodName.equals("hashCode"))  {
return new Integer(System.identityHashCode(proxy)); } else if (methodName.equals("equals")) {
       return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
       } else if (methodName.equals("toString")) {
return proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode());
       }
   }
return method.invoke(smartProxy, args); } @SuppressWarnings("unchecked") public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   if (isTerminated()) throw new IOException(thrown);
   Callable task = new MethodInvocationTask(this, proxy, method, args);
   return proxyExecutor.submit(task).get(timeout, unit);
   }
private void terminate(Throwable e){
   thrown = e;
   smartProxy = null;
proxyExecutor.shutdown(); } private boolean isTerminated(){
   if (smartProxy == null) return true;
   return false;
   }
private static class Factory implements ThreadFactory{
   private static final ThreadGroup tg = new ThreadGroup("IsolatedProxy");
   {
       tg.setDaemon(true);
       tg.setMaxPriority(4);
   }
   private final ProxyIsolate proxy;
   Factory(ProxyIsolate spi){
       proxy = spi;
   }

   public Thread newThread(Runnable r) {
       Thread t = new Thread(tg, r);
       t.setUncaughtExceptionHandler(new ExceptionHandler(proxy));
       return t;
} } private static class ExceptionHandler implements Thread.UncaughtExceptionHandler{
   private final ProxyIsolate proxy;
ExceptionHandler(ProxyIsolate spi){
       proxy = spi;
   }

   public void uncaughtException(Thread t, Throwable e) {
       // For all other Exceptions we let the ExecutorService handle it.
       if ( e instanceof Error){
       // Do we want to take different actions based on the error?
       proxy.terminate(e);
       }
   }
} private static class UnmarshallProxyTask implements Callable{
   private final MarshalledInstance mi;
   private final ClassLoader defaultLoader;
   private final boolean verifyCodebaseIntegrity;
   private final ClassLoader verifierLoader;
   private final Collection context;
UnmarshallProxyTask(MarshalledInstance proxy,
       ClassLoader defaultLoader,
       boolean verifyCodebaseIntegrity,
       ClassLoader verifierLoader,
       Collection context)
   {
       mi = proxy;
       this.defaultLoader = defaultLoader;
       this.verifyCodebaseIntegrity = verifyCodebaseIntegrity;
       this.verifierLoader = verifierLoader;
       this.context = context;
}
   public Object call() throws Exception {
       return mi.get(defaultLoader, verifyCodebaseIntegrity,
           verifierLoader, context);
   }
} private static class MethodInvocationTask implements Callable {
   private final ProxyIsolate smartProxy;
   private final Object proxy;
   private final Method method;
   private final Object[] args;
MethodInvocationTask(ProxyIsolate target, Object proxy, Method method, Object[] args){
       smartProxy = target;
       this.proxy = proxy;
       this.method = method;
this.args = args; }
   public Object call() throws Exception {
       return smartProxy.taskInvoke(proxy, method, args);
   }
}

}

Reply via email to