001: package groovy.lang;
002:
003: import groovy.security.GroovyCodeSourcePermission;
004:
005: import java.io.ByteArrayInputStream;
006: import java.io.File;
007: import java.io.FileInputStream;
008: import java.io.FileNotFoundException;
009: import java.io.IOException;
010: import java.io.InputStream;
011: import java.net.MalformedURLException;
012: import java.net.URL;
013: import java.security.AccessController;
014: import java.security.CodeSource;
015: import java.security.PrivilegedActionException;
016: import java.security.PrivilegedExceptionAction;
017: import java.security.cert.Certificate;
018:
019: /**
020: * CodeSource wrapper class that allows specific security policies to be associated with a class
021: * compiled from groovy source.
022: *
023: * @author Steve Goetze
024: */
025: public class GroovyCodeSource {
026:
027: /**
028: * The codeSource to be given the generated class. This can be used by policy file
029: * grants to administer security.
030: */
031: private CodeSource codeSource;
032: /** The name given to the generated class */
033: private String name;
034: /** The groovy source to be compiled and turned into a class */
035: private InputStream inputStream;
036: /** The certificates used to sign the items from the codesource */
037: Certificate[] certs;
038: private boolean cachable = false;
039:
040: private File file;
041:
042: public GroovyCodeSource(String script, String name, String codeBase) {
043: this (new ByteArrayInputStream(script.getBytes()), name,
044: codeBase);
045: }
046:
047: /**
048: * Construct a GroovyCodeSource for an inputStream of groovyCode that has an
049: * unknown provenance -- meaning it didn't come from a File or a URL (e.g. a String).
050: * The supplied codeBase will be used to construct a File URL that should match up
051: * with a java Policy entry that determines the grants to be associated with the
052: * class that will be built from the InputStream.
053: *
054: * The permission groovy.security.GroovyCodeSourcePermission will be used to determine if the given codeBase
055: * may be specified. That is, the current Policy set must have a GroovyCodeSourcePermission that implies
056: * the codeBase, or an exception will be thrown. This is to prevent callers from hijacking
057: * existing codeBase policy entries unless explicitly authorized by the user.
058: */
059: public GroovyCodeSource(InputStream inputStream, String name,
060: String codeBase) {
061: this .inputStream = inputStream;
062: this .name = name;
063: SecurityManager sm = System.getSecurityManager();
064: if (sm != null) {
065: sm
066: .checkPermission(new GroovyCodeSourcePermission(
067: codeBase));
068: }
069: try {
070: this .codeSource = new CodeSource(new URL("file", "",
071: codeBase), (java.security.cert.Certificate[]) null);
072: } catch (MalformedURLException murle) {
073: throw new RuntimeException(
074: "A CodeSource file URL cannot be constructed from the supplied codeBase: "
075: + codeBase);
076: }
077: }
078:
079: /**
080: * Package private constructor called by GroovyClassLoader for signed jar entries
081: */
082: GroovyCodeSource(InputStream inputStream, String name,
083: final File path, final Certificate[] certs) {
084: this .inputStream = inputStream;
085: this .name = name;
086: try {
087: this .codeSource = (CodeSource) AccessController
088: .doPrivileged(new PrivilegedExceptionAction() {
089: public Object run()
090: throws MalformedURLException {
091: //toURI().toURL() will encode, but toURL() will not.
092: return new CodeSource(path.toURI().toURL(),
093: certs);
094: }
095: });
096: } catch (PrivilegedActionException pae) {
097: //shouldn't happen
098: throw new RuntimeException(
099: "Could not construct a URL from: " + path);
100: }
101: }
102:
103: public GroovyCodeSource(final File file)
104: throws FileNotFoundException {
105: if (!file.exists())
106: throw new FileNotFoundException(file.toString() + " ("
107: + file.getAbsolutePath() + ")");
108: else {
109: try {
110: if (!file.canRead())
111: throw new RuntimeException(
112: file.toString()
113: + " can not be read. Check the read permisson of the file \""
114: + file.toString() + "\" ("
115: + file.getAbsolutePath() + ").");
116: } catch (SecurityException e) {
117: throw e;
118: }
119: }
120:
121: //this.inputStream = new FileInputStream(file);
122: this .file = file;
123: this .inputStream = null;
124: this .cachable = true;
125: //The calls below require access to user.dir - allow here since getName() and getCodeSource() are
126: //package private and used only by the GroovyClassLoader.
127: try {
128: Object[] info = (Object[]) AccessController
129: .doPrivileged(new PrivilegedExceptionAction() {
130: public Object run()
131: throws MalformedURLException {
132: Object[] info = new Object[2];
133: URL url = file.toURI().toURL();
134: info[0] = url.toExternalForm();
135: //toURI().toURL() will encode, but toURL() will not.
136: info[1] = new CodeSource(url,
137: (Certificate[]) null);
138: return info;
139: }
140: });
141: this .name = (String) info[0];
142: this .codeSource = (CodeSource) info[1];
143: } catch (PrivilegedActionException pae) {
144: throw new RuntimeException(
145: "Could not construct a URL from: " + file);
146: }
147: }
148:
149: public GroovyCodeSource(URL url) throws IOException {
150: if (url == null) {
151: throw new RuntimeException(
152: "Could not construct a GroovyCodeSource from a null URL");
153: }
154: this .inputStream = url.openStream();
155: this .name = url.toExternalForm();
156: this .codeSource = new CodeSource(url,
157: (java.security.cert.Certificate[]) null);
158: }
159:
160: CodeSource getCodeSource() {
161: return codeSource;
162: }
163:
164: public InputStream getInputStream() {
165: try {
166: if (file != null)
167: return new FileInputStream(file);
168: } catch (FileNotFoundException fnfe) {
169: }
170: return inputStream;
171: }
172:
173: public String getName() {
174: return name;
175: }
176:
177: public File getFile() {
178: return file;
179: }
180:
181: public void setCachable(boolean b) {
182: cachable = b;
183: }
184:
185: public boolean isCachable() {
186: return cachable;
187: }
188: }
|