river-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From peter_firmst...@apache.org
Subject svn commit: r1067602 - in /incubator/river/jtsk/skunk/pepe: src/org/apache/river/impl/security/dos/ test/src/org/apache/river/impl/security/dos/ test/src/tests/support/
Date Sun, 06 Feb 2011 06:39:59 GMT
Author: peter_firmstone
Date: Sun Feb  6 06:39:58 2011
New Revision: 1067602

URL: http://svn.apache.org/viewvc?rev=1067602&view=rev
Log:
Proxy Isolation refactoring

Added:
    incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/DiscoveryV2ReadUncastResponseTask.java
  (with props)
    incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolatedExecutor.java
  (with props)
    incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolationException.java
  (with props)
    incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/ProxyIsolationHandler.java
  (with props)
    incubator/river/jtsk/skunk/pepe/test/src/org/apache/river/impl/security/dos/
    incubator/river/jtsk/skunk/pepe/test/src/org/apache/river/impl/security/dos/IsolateTest.java
  (with props)
    incubator/river/jtsk/skunk/pepe/test/src/tests/support/EndlessLoopTask.java   (with props)
Removed:
    incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/ProxyIsolate.java

Added: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/DiscoveryV2ReadUncastResponseTask.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/DiscoveryV2ReadUncastResponseTask.java?rev=1067602&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/DiscoveryV2ReadUncastResponseTask.java
(added)
+++ incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/DiscoveryV2ReadUncastResponseTask.java
Sun Feb  6 06:39:58 2011
@@ -0,0 +1,73 @@
+/*
+ * 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 com.sun.jini.discovery.DiscoveryProtocolException;
+import com.sun.jini.discovery.UnicastResponse;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import net.jini.core.lookup.ServiceRegistrar;
+import net.jini.io.MarshalledInstance;
+
+class DiscoveryV2ReadUncastResponseTask implements Callable<UnicastResponse> {
+
+    private final InputStream in;
+    private final ClassLoader defaultLoader;
+    private final boolean verifyCodebaseIntegrity;
+    private final ClassLoader verifierLoader;
+    private final Collection context;
+
+    DiscoveryV2ReadUncastResponseTask(InputStream in,
+            ClassLoader defaultLoader,
+            boolean verifyCodebaseIntegrity,
+            ClassLoader verifierLoader, 
+            Collection context) 
+    {
+        this.in = in;
+        this.defaultLoader = defaultLoader;
+        this.verifyCodebaseIntegrity = verifyCodebaseIntegrity;
+        this.verifierLoader = verifierLoader;
+        this.context = context;
+    }
+
+    public UnicastResponse call() throws Exception {
+        try {
+            DataInput din = new DataInputStream(in);
+            String host = din.readUTF();
+
+            // read LUS port
+            int port = din.readUnsignedShort();
+            String[] groups = new String[din.readInt()];
+            for (int i = 0; i < groups.length; i++) {
+                groups[i] = din.readUTF();
+            }
+            MarshalledInstance mi = (MarshalledInstance) new ObjectInputStream(in).readObject();
+            ServiceRegistrar reg = 
+                    (ServiceRegistrar) mi.get(defaultLoader, 
+                    verifyCodebaseIntegrity, verifierLoader, context);
+            return new UnicastResponse(host, port, groups, reg);
+        } catch (RuntimeException e) {
+            throw new DiscoveryProtocolException(null, e);
+        }
+    }
+}

Propchange: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/DiscoveryV2ReadUncastResponseTask.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolatedExecutor.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolatedExecutor.java?rev=1067602&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolatedExecutor.java
(added)
+++ incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolatedExecutor.java
Sun Feb  6 06:39:58 2011
@@ -0,0 +1,114 @@
+/*
+ * 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.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;
+
+/**
+ * Performs Callable tasks in an isolated thread, which is terminated
+ * if any Errors are experienced.  This may take some time to terminate the thread
+ * as it is not forcibly stopped.  The thread priority is minimal and a daemon
+ * thread so it would take a number of unterminated threads to cause problems.
+ * 
+ * The caller can give up on the execution of the task by setting a timeout.
+ * 
+ * @param T 
+ * @author peter
+ */
+public class IsolatedExecutor<T> {
+    private volatile ExecutorService isolateExecutor;
+    private volatile Throwable thrown;
+    
+    public IsolatedExecutor()
+    {
+        thrown = null;
+	isolateExecutor = Executors.newSingleThreadExecutor(new Factory(this));
+    }
+    
+    /**
+     * Process Callable tasks in isolation.
+     * If an ExecutionException has been thrown, the task should be abandoned.
+     * If an IsolationException has been thrown, an Error has occurred with
+     * the IsolatedExecutor and a new object should be created.
+     * 
+     * @param task
+     * @param timeout 
+     * @param timeUnit 
+     * @return
+     * @throws org.apache.river.impl.security.dos.IsolatedExecutor.IsolationException
+     * @throws java.util.concurrent.ExecutionException
+     */
+    public T process(Callable<T> task, long timeout, TimeUnit timeUnit) throws 
+            IsolationException, ExecutionException, InterruptedException, 
+            TimeoutException {
+        if ( thrown != null){
+            throw new IsolationException ("Isolate has" +
+                  "experienced an error during processing and " +
+                  "cannot perform further " +
+                  "tasks", thrown);
+        }
+        return isolateExecutor.submit(task).get(timeout, timeUnit);
+    }
+    
+    private void terminate(Throwable e){
+	thrown = e;
+	isolateExecutor.shutdownNow();	
+    }
+    
+    private static class Factory implements ThreadFactory{
+	private static final ThreadGroup tg = new ThreadGroup("Isolated");
+	{
+	    tg.setDaemon(true);
+	    tg.setMaxPriority(4);
+	}
+	private final IsolatedExecutor isolate;
+	Factory(IsolatedExecutor uri){
+	    isolate = uri;
+	}
+
+	public Thread newThread(Runnable r) {
+	    Thread t = new Thread(tg, r);
+	    t.setUncaughtExceptionHandler(new ExceptionHandler(isolate));
+	    return t;
+	}	
+    }
+    
+    private static class ExceptionHandler implements Thread.UncaughtExceptionHandler{
+	private final IsolatedExecutor isolate;
+	
+	ExceptionHandler(IsolatedExecutor uri){
+	    isolate = uri;
+	}
+
+	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?
+		isolate.terminate(e);
+	    }
+	}
+	
+    }
+}

Propchange: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolatedExecutor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolationException.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolationException.java?rev=1067602&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolationException.java
(added)
+++ incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolationException.java
Sun Feb  6 06:39:58 2011
@@ -0,0 +1,22 @@
+package org.apache.river.impl.security.dos;
+
+public class IsolationException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    public IsolationException() {
+        super();
+    }
+
+    public IsolationException(String message) {
+        super(message);
+    }
+
+    public IsolationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public IsolationException(Throwable cause) {
+        super(cause);
+    }
+}

Propchange: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/IsolationException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/ProxyIsolationHandler.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/ProxyIsolationHandler.java?rev=1067602&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/ProxyIsolationHandler.java
(added)
+++ incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/ProxyIsolationHandler.java
Sun Feb  6 06:39:58 2011
@@ -0,0 +1,174 @@
+/*
+ * 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.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+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 subclassed return values, this is 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.  The reason for 
+ * checking that remote code hasn't escaped the IsolatedExecutor, is that we want to
+ * ensure it cannot harm the application threads.
+ * 
+ * @author Peter Firmstone
+ */
+public class ProxyIsolationHandler implements InvocationHandler {
+    private volatile Object smartProxy;
+    private final IsolatedExecutor isolate;
+    private final long timeout;
+    private final TimeUnit unit;
+    private final ClassLoader proxyLoader;
+    
+    @SuppressWarnings("unchecked")
+    public ProxyIsolationHandler(MarshalledInstance proxy, 
+			    ClassLoader defaultLoader,
+			    boolean verifyCodebaseIntegrity, 
+			    ClassLoader verifierLoader,
+			    Collection context,
+                            long timeout,
+                            TimeUnit timeUnit
+	    ) throws TimeoutException, InterruptedException, ExecutionException, IsolationException{
+        if (defaultLoader == null) throw new IsolationException("A default " +
+                "ClassLoader must be defined for effective isolation");
+        isolate = new IsolatedExecutor();
+	this.timeout = timeout;
+        unit = timeUnit;
+	UnmarshallProxyTask task = 
+		new UnmarshallProxyTask(proxy, defaultLoader,
+		verifyCodebaseIntegrity, verifierLoader, context);
+        smartProxy = isolate.process(task, timeout, timeUnit);
+        proxyLoader = defaultLoader;
+    }
+    
+    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 {
+	Callable task = new MethodInvocationTask(this, proxy, method, args);
+        Object result = isolate.process(task, timeout, unit);
+        CheckReturn cr = new CheckReturn(result, proxyLoader);
+        return AccessController.doPrivileged(cr);
+    }
+    
+    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 ProxyIsolationHandler smartProxy;
+	private final Object proxy;
+	private final Method method;
+	private final Object[] args;
+	MethodInvocationTask(ProxyIsolationHandler 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);
+	}
+	    
+    }
+    
+    private static class CheckReturn implements PrivilegedExceptionAction{
+        private final Object checked;
+        private final ClassLoader loader;
+        CheckReturn (Object check, ClassLoader loader){
+            checked = check;
+            this.loader = loader;
+        }
+        public Object run() throws Exception {
+            Class clazz = checked.getClass();
+            Class[] classes = clazz.getDeclaredClasses();
+            Set<ClassLoader> loaders = new HashSet<ClassLoader>();
+            loaders.add(clazz.getClassLoader());
+            int l = classes.length;
+            for (int i = 0; i < l; i++){
+                loaders.add(classes[i].getClassLoader());
+            }
+            if (loaders.contains(loader)) throw new IsolationException("Attempt" +
+                    " to return isolated code from isolation classloader");
+            return checked;
+        }
+        
+    }
+
+}

Propchange: incubator/river/jtsk/skunk/pepe/src/org/apache/river/impl/security/dos/ProxyIsolationHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/skunk/pepe/test/src/org/apache/river/impl/security/dos/IsolateTest.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/pepe/test/src/org/apache/river/impl/security/dos/IsolateTest.java?rev=1067602&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/pepe/test/src/org/apache/river/impl/security/dos/IsolateTest.java
(added)
+++ incubator/river/jtsk/skunk/pepe/test/src/org/apache/river/impl/security/dos/IsolateTest.java
Sun Feb  6 06:39:58 2011
@@ -0,0 +1,72 @@
+/*
+ * 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.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import tests.support.EndlessLoopTask;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author peter
+ */
+public class IsolateTest {
+
+    public IsolateTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    /**
+     * Test of process method, of class IsolatedExecutor.
+     */
+    @Test
+    public void timeout() throws Exception {
+        System.out.println("process");
+        Callable<Object> task = new EndlessLoopTask();
+        long timeout = 10L;
+        IsolatedExecutor instance = new IsolatedExecutor();
+        Exception e = null;
+        try {
+            instance.process(task, timeout, TimeUnit.SECONDS);
+        } catch ( TimeoutException ex ){
+            e = ex;
+            System.out.println(ex);
+        }
+        assertTrue((e instanceof TimeoutException));
+        // TODO review the generated test code and remove the default call to fail.
+    }
+
+}
\ No newline at end of file

Propchange: incubator/river/jtsk/skunk/pepe/test/src/org/apache/river/impl/security/dos/IsolateTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/skunk/pepe/test/src/tests/support/EndlessLoopTask.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/pepe/test/src/tests/support/EndlessLoopTask.java?rev=1067602&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/pepe/test/src/tests/support/EndlessLoopTask.java (added)
+++ incubator/river/jtsk/skunk/pepe/test/src/tests/support/EndlessLoopTask.java Sun Feb  6
06:39:58 2011
@@ -0,0 +1,36 @@
+/*
+ * 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 tests.support;
+
+import java.util.concurrent.Callable;
+
+/**
+ *
+ * @author peter
+ */
+public class EndlessLoopTask implements Callable {
+
+    public Object call() throws Exception {
+        long count = 0;
+        while (true){
+            count++;
+        }
+    }
+
+}

Propchange: incubator/river/jtsk/skunk/pepe/test/src/tests/support/EndlessLoopTask.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message