View Javadoc

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  					//toURI().toURL() will encode, but toURL() will not.
79  					return new CodeSource(path.toURI().toURL(), certs);
80  				}
81  			});
82  		} catch (PrivilegedActionException pae) {
83  			//shouldn't happen
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  		//The calls below require access to user.dir - allow here since getName() and getCodeSource() are
91  		//package private and used only by the GroovyClassLoader.
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  					//toURI().toURL() will encode, but toURL() will not.
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 }