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 }