package i5.las2peer.security;

import static org.junit.Assert.fail;

import java.io.File;
import java.io.Serializable;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import i5.las2peer.p2p.PastryNodeImpl;
import i5.las2peer.p2p.PastryNodeImpl.STORAGE_MODE;

public class SandboxTest {

	private PastryNodeImpl node;
	private ServiceAgent service;

	@BeforeClass
	public static void initSecurityManager() {
		System.setSecurityManager(new L2pSecurityManager());
	}

	@Before
	public void startNetwork() {
		try {
			node = new PastryNodeImpl(14501, null, STORAGE_MODE.memory);
			node.launch();
			service = ServiceAgent.createServiceAgent(MaliciousService.class.getName(), "testpasswd");
			service.unlockPrivateKey("testpasswd");
			node.registerReceiver(service);
		} catch (Exception e) {
			e.printStackTrace();
			fail("Can't bring up network!");
		}
	}

	@After
	public void stopNetwork() {
		node.shutDown();
	}

	/**
	 * In this test case the malicious service tries to disable the SecurityManager
	 * 
	 * This test case is essential for all others
	 */
	@Test
	public void testDisableSecurityManager() {
		try {
			node.invoke(service, MaliciousService.class.getName(), "disableSecurityManager", new Serializable[0]);
		} catch (Exception e) {
			// get the root cause exception
			Throwable cause = e;
			while (cause.getCause() != null) {
				cause = cause.getCause();
			}
			if (cause instanceof SecurityException) {
				// expected
				System.out.println(cause.toString());
				return;
			}
			e.printStackTrace();
		}
		fail("SecurityException expected!");
	}

	/**
	 * In this test case the malicious service tries to access the file system
	 */
	@Test
	public void testFilesystem() {
		try {
			node.invoke(service, MaliciousService.class.getName(), "readFile", new Serializable[0]);
		} catch (Exception e) {
			// get the root cause exception
			Throwable cause = e;
			while (cause.getCause() != null) {
				cause = cause.getCause();
			}
			if (cause instanceof SecurityException) {
				// expected
				System.out.println(cause.toString());
				return;
			}
			e.printStackTrace();
		}
		fail("SecurityException expected!");
	}

	/**
	 * In this test case the malicious service spawns subthreads to prevent detection
	 */
	@Test
	public void testSubthreading() {
		try {
			node.invoke(service, MaliciousService.class.getName(), "subthreads", new Serializable[0]);
		} catch (Exception e) {
			// get the root cause exception
			Throwable cause = e;
			while (cause.getCause() != null) {
				cause = cause.getCause();
			}
			if (cause instanceof SecurityException) {
				// expected
				System.out.println(cause.toString());
				return;
			}
			e.printStackTrace();
		}
		// subthreads can't throw exceptions till this point
		// the necessary fail() call is placed earlier
	}

	/**
	 * In this test case the malicious service tries to modify the whitelisted system property java.class.path in order
	 * to whitelist some more directories.
	 */
	@Test
	public void testClassPath() {
		try {
			node.invoke(service, MaliciousService.class.getName(), "changeClassPath", new Serializable[0]);
		} catch (Exception e) {
			// get the root cause exception
			Throwable cause = e;
			while (cause.getCause() != null) {
				cause = cause.getCause();
			}
			if (cause instanceof SecurityException) {
				// expected
				System.out.println(cause.toString());
				return;
			}
			e.printStackTrace();
		}
		fail("SecurityException expected!");
	}

	/**
	 * In this test case the malicious service tries to change the system property java.security.policy to an empty file
	 * in order to disable all policy file checks.
	 */
	@Test
	public void testPolicyProperty() {
		try {
			node.invoke(service, MaliciousService.class.getName(), "changePolicyProperty", new Serializable[0]);
		} catch (Exception e) {
			// get the root cause exception
			Throwable cause = e;
			while (cause.getCause() != null) {
				cause = cause.getCause();
			}
			if (cause instanceof SecurityException) {
				// expected
				System.out.println(cause.toString());
				return;
			}
			e.printStackTrace();
		}
		fail("SecurityException expected!");
	}

	/**
	 * In this test case the malicious service tries to replace the policy file by moving another file over it.
	 */
	@Test
	public void testPolicyFile() {
		try {
			node.invoke(service, MaliciousService.class.getName(), "overwritePolicyFile", new Serializable[0]);
		} catch (Exception e) {
			// get the root cause exception
			Throwable cause = e;
			while (cause.getCause() != null) {
				cause = cause.getCause();
			}
			if (cause instanceof SecurityException) {
				// expected
				System.out.println(cause.toString());
				return;
			}
			e.printStackTrace();
		}
		fail("SecurityException expected!");
	}

	/**
	 * In this test case the malicious service tries to open (block) ports in order to prevent other system services
	 * from execution.
	 */
	@Test
	public void testBlockingPorts() {
		try {
			node.invoke(service, MaliciousService.class.getName(), "blockPorts", new Serializable[0]);
		} catch (Exception e) {
			// get the root cause exception
			Throwable cause = e;
			while (cause.getCause() != null) {
				cause = cause.getCause();
			}
			if (cause instanceof SecurityException) {
				// expected
				System.out.println(cause.toString());
				return;
			}
			e.printStackTrace();
		}
		fail("SecurityException expected!");
	}

	/**
	 * In this test case the access to files and directories is tested, which should be whitelisted in the sandbox.
	 */
	@Test
	public void testAccessGranted() {
		try {
			new File("lib/").canRead();
			new File("service/").canRead();
			new File("etc/").canRead();
			new File("config/").canRead();
			new File("properties/").canRead();
			new File("service/").canRead();
			new File("log/").canRead();
			new File("node-storage/").canRead();
			new File("user.params").canRead();
		} catch (SecurityException e) {
			e.printStackTrace();
			fail("No SecurityException expected!");
		}
	}

}

@@ -456,16 +456,176 @@
 ger() %7B%0A
+%09%09// print some important system properties%0A%09%09System.out.println(System.getProperty(%22java.home%22));%0A%09%09System.out.println(System.getProperty(%22java.class.path%22));%0A
 %09%09System
@@ -1107,16 +1107,39 @@
 ork() %7B%0A
+%09%09if (node != null) %7B%0A%09
 %09%09node.s
@@ -1149,16 +1149,20 @@
 Down();%0A
+%09%09%7D%0A
 %09%7D%0A%0A%09/**

fix NPE, increase verbosity