securitytestsupport.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 286 行

JAVA
286
字号
package groovy.security;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyCodeSource;
import groovy.lang.Script;
import groovy.util.GroovyTestCase;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.Permission;
import java.security.Policy;
import java.security.PrivilegedAction;
import java.util.Enumeration;

import junit.framework.TestCase;
import junit.framework.TestFailure;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import junit.textui.ResultPrinter;

import org.codehaus.groovy.runtime.InvokerHelper;

/**
 * @author Steve Goetze
 */
public class SecurityTestSupport extends GroovyTestCase {

	private static int counter = 0;
	private static boolean securityDisabled; 
	private static boolean securityAvailable;
	private static boolean securityChecked = false;

	static {
		if (System.getProperty("groovy.security.disabled") != null) {
			securityAvailable = false;
			securityDisabled = true;
		} else {
			securityDisabled = false;
			String groovyLibDir = System.getProperty("groovy.lib");
			if (groovyLibDir == null) {
				//Try to find maven repository in the default user.home location
				groovyLibDir = System.getProperty("user.home") + "/" + ".maven/repository";
			}
			if (groovyLibDir == null) {
				//Try at user.dir/lib
				groovyLibDir = "lib";
			}
			if (new File(groovyLibDir).exists()) {
				securityAvailable = true;
				System.setProperty("groovy.lib", groovyLibDir);
				System.setProperty("java.security.policy", "=security/groovy.policy");
			} else {
				securityAvailable = false;
			}
		}
	}

	public static boolean isSecurityAvailable() {
		return securityAvailable;
	}

	public static boolean isSecurityDisabled() {
		return securityDisabled;
	}

	public static void resetSecurityPolicy(String policyFileURL) {
		System.setProperty("java.security.policy", policyFileURL);
		Policy.getPolicy().refresh();
	}
	
	protected class SecurityTestResultPrinter extends ResultPrinter {
		
		public SecurityTestResultPrinter(PrintStream stream) {
			super(stream);
		}
		public void print(TestResult result) {
			getWriter().println("Security testing on a groovy test failed:");
		    printErrors(result);
		    printFailures(result);
		    printFooter(result);
		}
	}

    protected GroovyClassLoader loader = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
		public Object run() {
			return new GroovyClassLoader(SecurityTestSupport.class.getClassLoader()); 
		}
	});
    
	private SecurityManager securityManager;
    private ClassLoader currentClassLoader;

	public SecurityTestSupport() {
	}
	
	/*
	 * Check SecuritySupport to see if security is properly configured.  If not, fail the first
	 * test that runs.  All remaining tests will run, but not do any security checking.
	 */
	private boolean checkSecurity() {
		if (!securityChecked) {
			securityChecked = true;
			if (!isSecurityAvailable()) {
				fail("Security is not available - skipping security tests.  Ensure that groovy.lib is set and points to the groovy dependency jars.");
			}
		}
		return isSecurityAvailable();
	}

	//Prepare for each security test.  First, check to see if groovy.lib can be determined via
	//a call to checkSecurity().  If not, fail() the first test.  Establish a security manager
	//and make the GroovyClassLoader the initiating class loader (ala GroovyShell) to compile AND
	//invoke the test scripts.  This handles cases where multiple .groovy scripts are involved in a
	//test case: a.groovy depends on b.groovy; a.groovy is parsed (and in the process the gcl
	//loads b.groovy via findClass).  Note that b.groovy is only available in the groovy class loader.
	//See 
	protected void setUp() {
		if (checkSecurity()) {
			securityManager = System.getSecurityManager();
			if (securityManager == null) {
	    		System.setSecurityManager(new SecurityManager());
			}
		}
		currentClassLoader = Thread.currentThread().getContextClassLoader();
		AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                Thread.currentThread().setContextClassLoader(loader);
                return null;
            }
        });
    }

	protected void tearDown() {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                System.setSecurityManager(securityManager);
                Thread.currentThread().setContextClassLoader(currentClassLoader);
                return null;
            }
        });
	}

    protected synchronized String generateClassName() {
        return "testSecurity" + (++counter);
    }

	/*
	 * Execute the groovy script contained in file.  If missingPermission
	 * is non-null, then this invocation expects an AccessControlException with missingPermission
	 * as the reason.  If missingPermission is null, the script is expected to execute successfully.
	 */
	protected Class parseClass(File file) {
		GroovyCodeSource gcs = null;
		try {
			gcs = new GroovyCodeSource(file);
		} catch (FileNotFoundException fnfe) {
			fail(fnfe.toString());
		}
		return parseClass(gcs);
	}

    /*
	 * Parse the Groovy code contained in the GroovyCodeSource as a privileged operation (i.e. do not
	 * require the code source to have specific compile time permissions) and return the resulting class.
	 */
	protected Class parseClass(final GroovyCodeSource gcs) {
		Class clazz = null;
		try {
			clazz = loader.parseClass(gcs);
		} catch (Exception e) {
			fail(e.toString());
		}
		return clazz;
	}
    
    /*
	 * Parse the script contained in the GroovyCodeSource as a privileged operation (i.e. do not
	 * require the code source to have specific compile time permissions).  If the class produced is a
	 * TestCase, run the test in a suite and evaluate against the missingPermission.
	 * Otherwise, run the class as a groovy script and evaluate against the missingPermission.
	 */
	private void parseAndExecute(final GroovyCodeSource gcs, Permission missingPermission) {
		Class clazz = null;
		try {
			clazz = loader.parseClass(gcs);
		} catch (Exception e) {
			fail(e.toString());
		}
		if (TestCase.class.isAssignableFrom(clazz)) {
			executeTest(clazz, missingPermission);
		} else {
			executeScript(clazz, missingPermission);
		}
	}

	protected void executeTest(Class test, Permission missingPermission) {
		TestSuite suite = new TestSuite();
		suite.addTestSuite(test);
        TestResult result = new TestResult();
        suite.run(result);
        if (result.wasSuccessful()) {
        	if (missingPermission == null) {
        		return;
        	} else {
        		fail("Security test expected an AccessControlException on " + missingPermission + ", but did not receive one");
        	}
        } else {
        	if (missingPermission == null) {
        		new SecurityTestResultPrinter(System.out).print(result);
        		fail("Security test was expected to run successfully, but failed (results on System.out)");
        	} else {
        		//There may be more than 1 failure:  iterate to ensure that they all match the missingPermission.
        		boolean otherFailure = false;
        		for (Enumeration e = result.errors(); e.hasMoreElements(); ) {
        			TestFailure failure = (TestFailure) e.nextElement();
        			if (failure.thrownException() instanceof AccessControlException) {
        				AccessControlException ace = (AccessControlException) failure.thrownException();
        				if (missingPermission.implies(ace.getPermission())) {
        					continue;
        				}
        			}
        			otherFailure = true;        			
        		}
        		if (otherFailure) {
        			new SecurityTestResultPrinter(System.out).print(result);
        			fail("Security test expected an AccessControlException on " + missingPermission + ", but  failed for other reasons (results on System.out)");
        		}
        	}
        }
    }

	protected void executeScript(Class scriptClass, Permission missingPermission) {
		try {
			Script script = InvokerHelper.createScript(scriptClass, new Binding());
			script.run();
			//InvokerHelper.runScript(scriptClass, null);
		} catch (AccessControlException ace) {
			if (missingPermission != null && missingPermission.implies(ace.getPermission())) {
				return;
			} else {
				fail(ace.toString());
			}
		}
		if (missingPermission != null) {
			fail("Should catch an AccessControlException");
		}
	}
	
	/*
	 * Execute the groovy script contained in file.  If missingPermission
	 * is non-null, then this invocation expects an AccessControlException with missingPermission
	 * as the reason.  If missingPermission is null, the script is expected to execute successfully.
	 */
	protected void assertExecute(File file, Permission missingPermission) {
		if (!isSecurityAvailable()) {
			return;
		}
		GroovyCodeSource gcs = null;
		try {
			gcs = new GroovyCodeSource(file);
		} catch (FileNotFoundException fnfe) {
			fail(fnfe.toString());
		}
		parseAndExecute(gcs, missingPermission);
	}
	
	/*
	 * Execute the script represented by scriptStr using the supplied codebase.  If missingPermission
	 * is non-null, then this invocation expects an AccessControlException with missingPermission
	 * as the reason.  If missingPermission is null, the script is expected to execute successfully.
	 */
	protected void assertExecute(String scriptStr, String codeBase, Permission missingPermission) {
		if (!isSecurityAvailable()) {
			return;
		}
		if (codeBase == null) {
			codeBase = "/groovy/security/test";
		}
		parseAndExecute(new GroovyCodeSource(scriptStr, generateClassName(), codeBase), missingPermission);
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?