blob: 09c1f38eaf043f9b181fea577d42dd93e7afde9d [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package groovy.lang;
import groovy.security.GroovyCodeSourcePermission;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.cert.Certificate;
/**
* CodeSource wrapper class that allows specific security policies to be associated with a class
* compiled from groovy source.
*
* @author Steve Goetze
*/
public class GroovyCodeSource {
/**
* The codeSource to be given the generated class. This can be used by policy file
* grants to administer security.
*/
private CodeSource codeSource;
/** The name given to the generated class */
private String name;
/** The groovy source to be compiled and turned into a class */
private InputStream inputStream;
/** The certificates used to sign the items from the codesource */
Certificate[] certs;
private boolean cachable;
private File file;
public GroovyCodeSource(String script, String name, String codeBase) {
this(new ByteArrayInputStream(script.getBytes()), name, codeBase);
}
/**
* Construct a GroovyCodeSource for an inputStream of groovyCode that has an
* unknown provenance -- meaning it didn't come from a File or a URL (e.g. a String).
* The supplied codeBase will be used to construct a File URL that should match up
* with a java Policy entry that determines the grants to be associated with the
* class that will be built from the InputStream.
*
* The permission groovy.security.GroovyCodeSourcePermission will be used to determine if the given codeBase
* may be specified. That is, the current Policy set must have a GroovyCodeSourcePermission that implies
* the codeBase, or an exception will be thrown. This is to prevent callers from hijacking
* existing codeBase policy entries unless explicitly authorized by the user.
*/
public GroovyCodeSource(InputStream inputStream, String name, String codeBase) {
this.inputStream = inputStream;
this.name = name;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new GroovyCodeSourcePermission(codeBase));
}
try {
this.codeSource = new CodeSource(new URL("file", "", codeBase), (java.security.cert.Certificate[])null);
} catch (MalformedURLException murle) {
throw new RuntimeException("A CodeSource file URL cannot be constructed from the supplied codeBase: " + codeBase);
}
}
public GroovyCodeSource(final File file) throws FileNotFoundException {
if (!file.exists())
throw new FileNotFoundException(file.toString() + " (" + file.getAbsolutePath() + ")");
else {
try {
if (!file.canRead())
throw new RuntimeException(file.toString() + " can not be read. Check the read permisson of the file \"" + file.toString() + "\" (" + file.getAbsolutePath() + ").");
}
catch (SecurityException e) {
throw e;
}
}
//this.inputStream = new FileInputStream(file);
this.file = file;
this.inputStream = null;
this.cachable = true;
//The calls below require access to user.dir - allow here since getName() and getCodeSource() are
//package private and used only by the GroovyClassLoader.
try {
Object[] info = (Object[]) AccessController.doPrivileged( new PrivilegedExceptionAction() {
public Object run() throws MalformedURLException {
Object[] info = new Object[2];
URL url = file.toURI().toURL();
info[0] = url.toExternalForm();
//toURI().toURL() will encode, but toURL() will not.
info[1] = new CodeSource(url, (Certificate[]) null);
return info;
}
});
this.name = (String) info[0];
this.codeSource = (CodeSource) info[1];
} catch (PrivilegedActionException pae) {
throw new RuntimeException("Could not construct a URL from: " + file);
}
}
public GroovyCodeSource(URL url) throws IOException {
if (url == null) {
throw new RuntimeException("Could not construct a GroovyCodeSource from a null URL");
}
this.inputStream = url.openStream();
this.name = url.toExternalForm();
this.codeSource = new CodeSource(url, (java.security.cert.Certificate[])null);
}
CodeSource getCodeSource() {
return codeSource;
}
public InputStream getInputStream() {
if(this.inputStream != null) {
return this.inputStream;
}
else {
try {
if (file!=null) return new FileInputStream(file);
} catch (FileNotFoundException fnfe) {
// IGNORE
}
return inputStream;
}
}
public String getName() {
return name;
}
public File getFile() {
return file;
}
public void setCachable(boolean b) {
cachable = b;
}
public boolean isCachable() {
return cachable;
}
}