1 package groovy.lang;
2
3 import groovy.security.GroovyCodeSourcePermission;
4
5 import java.io.ByteArrayInputStream;
6 import java.io.File;
7 import java.io.FileInputStream;
8 import java.io.FileNotFoundException;
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.net.MalformedURLException;
12 import java.net.URL;
13 import java.security.AccessController;
14 import java.security.CodeSource;
15 import java.security.PrivilegedActionException;
16 import java.security.PrivilegedExceptionAction;
17 import java.security.cert.Certificate;
18
19 /***
20 * CodeSource wrapper class that allows specific security policies to be associated with a class
21 * compiled from groovy source.
22 *
23 * @author Steve Goetze
24 */
25 public class GroovyCodeSource {
26
27 /***
28 * The codeSource to be given the generated class. This can be used by policy file
29 * grants to administer security.
30 */
31 private CodeSource codeSource;
32 /*** The name given to the generated class */
33 private String name;
34 /*** The groovy source to be compiled and turned into a class */
35 private InputStream inputStream;
36 /*** The certificates used to sign the items from the codesource */
37 Certificate[] certs;
38
39 public GroovyCodeSource(String script, String name, String codeBase) {
40 this(new ByteArrayInputStream(script.getBytes()), name, codeBase);
41 }
42
43 /***
44 * Construct a GroovyCodeSource for an inputStream of groovyCode that has an
45 * unknown provenance -- meaning it didn't come from a File or a URL (e.g. a String).
46 * The supplied codeBase will be used to construct a File URL that should match up
47 * with a java Policy entry that determines the grants to be associated with the
48 * class that will be built from the InputStream.
49 *
50 * The permission groovy.security.GroovyCodeSourcePermission will be used to determine if the given codeBase
51 * may be specified. That is, the current Policy set must have a GroovyCodeSourcePermission that implies
52 * the codeBase, or an exception will be thrown. This is to prevent callers from hijacking
53 * existing codeBase policy entries unless explicitly authorized by the user.
54 */
55 public GroovyCodeSource(InputStream inputStream, String name, String codeBase) {
56 this.inputStream = inputStream;
57 this.name = name;
58 SecurityManager sm = System.getSecurityManager();
59 if (sm != null) {
60 sm.checkPermission(new GroovyCodeSourcePermission(codeBase));
61 }
62 try {
63 this.codeSource = new CodeSource(new URL("file", "", codeBase), (java.security.cert.Certificate[])null);
64 } catch (MalformedURLException murle) {
65 throw new RuntimeException("A CodeSource file URL cannot be constructed from the supplied codeBase: " + codeBase);
66 }
67 }
68
69 /***
70 * Package private constructor called by GroovyClassLoader for signed jar entries
71 */
72 GroovyCodeSource(InputStream inputStream, String name, final File path, final Certificate[] certs) {
73 this.inputStream = inputStream;
74 this.name = name;
75 try {
76 this.codeSource = (CodeSource) AccessController.doPrivileged( new PrivilegedExceptionAction() {
77 public Object run() throws MalformedURLException {
78
79 return new CodeSource(path.toURI().toURL(), certs);
80 }
81 });
82 } catch (PrivilegedActionException pae) {
83
84 throw new RuntimeException("Could not construct a URL from: " + path);
85 }
86 }
87
88 public GroovyCodeSource(final File file) throws FileNotFoundException {
89 this.inputStream = new FileInputStream(file);
90
91
92 try {
93 Object[] info = (Object[]) AccessController.doPrivileged( new PrivilegedExceptionAction() {
94 public Object run() throws MalformedURLException {
95 Object[] info = new Object[2];
96 info[0] = file.getAbsolutePath();
97
98 info[1] = new CodeSource(file.toURI().toURL(), (Certificate[]) null);
99 return info;
100 }
101 });
102 this.name = (String) info[0];
103 this.codeSource = (CodeSource) info[1];
104 } catch (PrivilegedActionException pae) {
105 throw new RuntimeException("Could not construct a URL from: " + file);
106 }
107 }
108
109 public GroovyCodeSource(URL url) throws IOException {
110 if (url == null) {
111 throw new RuntimeException("Could not construct a GroovyCodeSource from a null URL");
112 }
113 this.inputStream = url.openStream();
114 this.name = url.toExternalForm();
115 this.codeSource = new CodeSource(url, (java.security.cert.Certificate[])null);
116 }
117
118 CodeSource getCodeSource() {
119 return codeSource;
120 }
121
122 public InputStream getInputStream() {
123 return inputStream;
124 }
125
126 public String getName() {
127 return name;
128 }
129 }