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      private boolean cachable = false;
    39
    40  	private File file;
    41
    42  	public GroovyCodeSource(String script, String name, String codeBase) {
    43  		this(new ByteArrayInputStream(script.getBytes()), name, codeBase);
    44  	}
    45
    46  	/***
    47  	 * Construct a GroovyCodeSource for an inputStream of groovyCode that has an
    48  	 * unknown provenance -- meaning it didn't come from a File or a URL (e.g. a String).
    49  	 * The supplied codeBase will be used to construct a File URL that should match up
    50  	 * with a java Policy entry that determines the grants to be associated with the
    51  	 * class that will be built from the InputStream.
    52  	 *
    53  	 * The permission groovy.security.GroovyCodeSourcePermission will be used to determine if the given codeBase
    54  	 * may be specified.  That is, the current Policy set must have a GroovyCodeSourcePermission that implies
    55  	 * the codeBase, or an exception will be thrown.  This is to prevent callers from hijacking
    56  	 * existing codeBase policy entries unless explicitly authorized by the user.
    57  	 */
    58  	public GroovyCodeSource(InputStream inputStream, String name, String codeBase) {
    59  		this.inputStream = inputStream;
    60  		this.name = name;
    61  		SecurityManager sm = System.getSecurityManager();
    62  		if (sm != null) {
    63  		    sm.checkPermission(new GroovyCodeSourcePermission(codeBase));
    64  		}
    65  		try {
    66  			this.codeSource = new CodeSource(new URL("file", "", codeBase), (java.security.cert.Certificate[])null);
    67  		} catch (MalformedURLException murle) {
    68  			throw new RuntimeException("A CodeSource file URL cannot be constructed from the supplied codeBase: " + codeBase);
    69  		}
    70  	}
    71
    72  	/***
    73  	 * Package private constructor called by GroovyClassLoader for signed jar entries
    74  	 */
    75  	GroovyCodeSource(InputStream inputStream, String name, final File path, final Certificate[] certs) {
    76  		this.inputStream = inputStream;
    77  		this.name = name;
    78  		try {
    79  			this.codeSource = (CodeSource) AccessController.doPrivileged( new PrivilegedExceptionAction() {
    80  				public Object run() throws MalformedURLException {
    81  					//toURI().toURL() will encode, but toURL() will not.
    82  					return new CodeSource(path.toURI().toURL(), certs);
    83  				}
    84  			});
    85  		} catch (PrivilegedActionException pae) {
    86  			//shouldn't happen
    87  			throw new RuntimeException("Could not construct a URL from: " + path);
    88  		}
    89  	}
    90
    91  	public GroovyCodeSource(final File file) throws FileNotFoundException {
    92  		if (!file.exists())
    93  		    throw new FileNotFoundException(file.toString() + " (" +  file.getAbsolutePath() +  ")");
    94  		else {
    95  		   try {
    96  		       if (!file.canRead())
    97  		           throw new RuntimeException(file.toString() + " can not be read. Check the read permisson of the file \"" + file.toString() + "\" (" +  file.getAbsolutePath() +  ").");
    98  		   }
    99  		   catch (SecurityException e) {
    100 		        throw e;
    101 		    }
    102 		}
    103
    104 		//this.inputStream = new FileInputStream(file);
    105 		this.file = file;
    106 		this.inputStream = null;
    107         this.cachable = true;
    108 		//The calls below require access to user.dir - allow here since getName() and getCodeSource() are
    109 		//package private and used only by the GroovyClassLoader.
    110 		try {
    111             Object[] info = (Object[]) AccessController.doPrivileged( new PrivilegedExceptionAction() {
    112 				public Object run() throws MalformedURLException {
    113                     Object[] info = new Object[2];
    114                     URL url = file.toURI().toURL();
    115                     info[0] = url.toExternalForm();
    116 					//toURI().toURL() will encode, but toURL() will not.
    117 					info[1] = new CodeSource(url, (Certificate[]) null);
    118                     return info;
    119 				}
    120 			});
    121 			this.name = (String) info[0];
    122             this.codeSource = (CodeSource) info[1];
    123 		} catch (PrivilegedActionException pae) {
    124 			throw new RuntimeException("Could not construct a URL from: " + file);
    125 		}
    126 	}
    127
    128 	public GroovyCodeSource(URL url) throws IOException {
    129 		if (url == null) {
    130 			throw new RuntimeException("Could not construct a GroovyCodeSource from a null URL");
    131 		}
    132 		this.inputStream = url.openStream();
    133 		this.name = url.toExternalForm();
    134 		this.codeSource = new CodeSource(url, (java.security.cert.Certificate[])null);
    135 	}
    136
    137 	CodeSource getCodeSource() {
    138 		return codeSource;
    139 	}
    140
    141 	public InputStream getInputStream() {
    142         try {
    143             if (file!=null) return new FileInputStream(file);
    144         } catch (FileNotFoundException fnfe) {}
    145 		return inputStream;
    146 	}
    147
    148 	public String getName() {
    149 		return name;
    150 	}
    151
    152     public File getFile() {
    153         return file;
    154     }
    155
    156     public void setCachable(boolean b) {
    157         cachable = b;
    158     }
    159
    160     public boolean isCachable() {
    161         return cachable;
    162     }
    163 }