1 package groovy.security;
2
3 import groovy.lang.Binding;
4 import groovy.lang.GroovyClassLoader;
5 import groovy.lang.GroovyCodeSource;
6 import groovy.lang.Script;
7 import groovy.util.GroovyTestCase;
8
9 import java.io.File;
10 import java.io.FileNotFoundException;
11 import java.io.PrintStream;
12 import java.security.AccessControlException;
13 import java.security.AccessController;
14 import java.security.Permission;
15 import java.security.Policy;
16 import java.security.PrivilegedAction;
17 import java.util.Enumeration;
18
19 import junit.framework.TestCase;
20 import junit.framework.TestFailure;
21 import junit.framework.TestResult;
22 import junit.framework.TestSuite;
23 import junit.textui.ResultPrinter;
24
25 import org.codehaus.groovy.runtime.InvokerHelper;
26
27 /***
28 * @author Steve Goetze
29 */
30 public class SecurityTestSupport extends GroovyTestCase {
31
32 private static int counter = 0;
33 private static boolean securityDisabled;
34 private static boolean securityAvailable;
35 private static boolean securityChecked = false;
36
37 static {
38 if (System.getProperty("groovy.security.disabled") != null) {
39 securityAvailable = false;
40 securityDisabled = true;
41 } else {
42 securityDisabled = false;
43 String groovyLibDir = System.getProperty("groovy.lib");
44 if (groovyLibDir == null) {
45
46 groovyLibDir = System.getProperty("user.home") + "/" + ".maven/repository";
47 }
48 if (groovyLibDir == null) {
49
50 groovyLibDir = "lib";
51 }
52 if (new File(groovyLibDir).exists()) {
53 securityAvailable = true;
54 System.setProperty("groovy.lib", groovyLibDir);
55 System.setProperty("java.security.policy", "=security/groovy.policy");
56 } else {
57 securityAvailable = false;
58 }
59 }
60 }
61
62 public static boolean isSecurityAvailable() {
63 return securityAvailable;
64 }
65
66 public static boolean isSecurityDisabled() {
67 return securityDisabled;
68 }
69
70 public static void resetSecurityPolicy(String policyFileURL) {
71 System.setProperty("java.security.policy", policyFileURL);
72 Policy.getPolicy().refresh();
73 }
74
75 protected class SecurityTestResultPrinter extends ResultPrinter {
76
77 public SecurityTestResultPrinter(PrintStream stream) {
78 super(stream);
79 }
80 public void print(TestResult result) {
81 getWriter().println("Security testing on a groovy test failed:");
82 printErrors(result);
83 printFailures(result);
84 printFooter(result);
85 }
86 }
87
88 protected GroovyClassLoader loader = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
89 public Object run() {
90 return new GroovyClassLoader(SecurityTestSupport.class.getClassLoader());
91 }
92 });
93
94 private SecurityManager securityManager;
95 private ClassLoader currentClassLoader;
96
97 public SecurityTestSupport() {
98 }
99
100
101
102
103
104 private boolean checkSecurity() {
105 if (!securityChecked) {
106 securityChecked = true;
107 if (!isSecurityAvailable()) {
108 fail("Security is not available - skipping security tests. Ensure that groovy.lib is set and points to the groovy dependency jars.");
109 }
110 }
111 return isSecurityAvailable();
112 }
113
114
115
116
117
118
119
120
121 protected void setUp() {
122 if (checkSecurity()) {
123 securityManager = System.getSecurityManager();
124 if (securityManager == null) {
125 System.setSecurityManager(new SecurityManager());
126 }
127 }
128 currentClassLoader = Thread.currentThread().getContextClassLoader();
129 AccessController.doPrivileged(new PrivilegedAction() {
130 public Object run() {
131 Thread.currentThread().setContextClassLoader(loader);
132 return null;
133 }
134 });
135 }
136
137 protected void tearDown() {
138 AccessController.doPrivileged(new PrivilegedAction() {
139 public Object run() {
140 System.setSecurityManager(securityManager);
141 Thread.currentThread().setContextClassLoader(currentClassLoader);
142 return null;
143 }
144 });
145 }
146
147 protected synchronized String generateClassName() {
148 return "testSecurity" + (++counter);
149 }
150
151
152
153
154
155
156 protected Class parseClass(File file) {
157 GroovyCodeSource gcs = null;
158 try {
159 gcs = new GroovyCodeSource(file);
160 } catch (FileNotFoundException fnfe) {
161 fail(fnfe.toString());
162 }
163 return parseClass(gcs);
164 }
165
166
167
168
169
170 protected Class parseClass(final GroovyCodeSource gcs) {
171 Class clazz = null;
172 try {
173 clazz = loader.parseClass(gcs);
174 } catch (Exception e) {
175 fail(e.toString());
176 }
177 return clazz;
178 }
179
180
181
182
183
184
185
186 private void parseAndExecute(final GroovyCodeSource gcs, Permission missingPermission) {
187 Class clazz = null;
188 try {
189 clazz = loader.parseClass(gcs);
190 } catch (Exception e) {
191 fail(e.toString());
192 }
193 if (TestCase.class.isAssignableFrom(clazz)) {
194 executeTest(clazz, missingPermission);
195 } else {
196 executeScript(clazz, missingPermission);
197 }
198 }
199
200 protected void executeTest(Class test, Permission missingPermission) {
201 TestSuite suite = new TestSuite();
202 suite.addTestSuite(test);
203 TestResult result = new TestResult();
204 suite.run(result);
205 if (result.wasSuccessful()) {
206 if (missingPermission == null) {
207 return;
208 } else {
209 fail("Security test expected an AccessControlException on " + missingPermission + ", but did not receive one");
210 }
211 } else {
212 if (missingPermission == null) {
213 new SecurityTestResultPrinter(System.out).print(result);
214 fail("Security test was expected to run successfully, but failed (results on System.out)");
215 } else {
216
217 boolean otherFailure = false;
218 for (Enumeration e = result.errors(); e.hasMoreElements(); ) {
219 TestFailure failure = (TestFailure) e.nextElement();
220 if (failure.thrownException() instanceof AccessControlException) {
221 AccessControlException ace = (AccessControlException) failure.thrownException();
222 if (missingPermission.implies(ace.getPermission())) {
223 continue;
224 }
225 }
226 otherFailure = true;
227 }
228 if (otherFailure) {
229 new SecurityTestResultPrinter(System.out).print(result);
230 fail("Security test expected an AccessControlException on " + missingPermission + ", but failed for other reasons (results on System.out)");
231 }
232 }
233 }
234 }
235
236 protected void executeScript(Class scriptClass, Permission missingPermission) {
237 try {
238 Script script = InvokerHelper.createScript(scriptClass, new Binding());
239 script.run();
240
241 } catch (AccessControlException ace) {
242 if (missingPermission != null && missingPermission.implies(ace.getPermission())) {
243 return;
244 } else {
245 fail(ace.toString());
246 }
247 }
248 if (missingPermission != null) {
249 fail("Should catch an AccessControlException");
250 }
251 }
252
253
254
255
256
257
258 protected void assertExecute(File file, Permission missingPermission) {
259 if (!isSecurityAvailable()) {
260 return;
261 }
262 GroovyCodeSource gcs = null;
263 try {
264 gcs = new GroovyCodeSource(file);
265 } catch (FileNotFoundException fnfe) {
266 fail(fnfe.toString());
267 }
268 parseAndExecute(gcs, missingPermission);
269 }
270
271
272
273
274
275
276 protected void assertExecute(String scriptStr, String codeBase, Permission missingPermission) {
277 if (!isSecurityAvailable()) {
278 return;
279 }
280 if (codeBase == null) {
281 codeBase = "/groovy/security/test";
282 }
283 parseAndExecute(new GroovyCodeSource(scriptStr, generateClassName(), codeBase), missingPermission);
284 }
285 }