Author: bodewig
Date: Wed Jul 22 13:17:16 2009
New Revision: 796702
URL: http://svn.apache.org/viewvc?rev=796702&view=rev
Log:
properly set CodeSource when loading classes. PR 20174
Modified:
ant/core/trunk/WHATSNEW
ant/core/trunk/src/etc/testcases/core/antclassloader.xml
ant/core/trunk/src/main/org/apache/tools/ant/AntClassLoader.java
ant/core/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java
Modified: ant/core/trunk/WHATSNEW
URL:
http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=796702&r1=796701&r2=796702&view=diff
==============================================================================
--- ant/core/trunk/WHATSNEW (original)
+++ ant/core/trunk/WHATSNEW Wed Jul 22 13:17:16 2009
@@ -410,7 +410,10 @@
* The default stylesheets for <junitreport> failed to properly escape
XML content in exception stack traces.
- Bugzilla Report 39492
+ Bugzilla Report 39492.
+
+ * AntClassLoader didn't set the proper CodeSource for loaded classes.
+ Bugzilla Report 20174.
Other changes:
--------------
Modified: ant/core/trunk/src/etc/testcases/core/antclassloader.xml
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/etc/testcases/core/antclassloader.xml?rev=796702&r1=796701&r2=796702&view=diff
==============================================================================
--- ant/core/trunk/src/etc/testcases/core/antclassloader.xml (original)
+++ ant/core/trunk/src/etc/testcases/core/antclassloader.xml Wed Jul 22
13:17:16 2009
@@ -67,4 +67,9 @@
</jar>
</target>
+ <target name="signTestJar" depends="prepareGetPackageTest">
+ <signjar alias="testonly" keystore="../testkeystore"
+ storepass="apacheant" jar="${tmp.dir}/test.jar"/>
+ </target>
+
</project>
Modified: ant/core/trunk/src/main/org/apache/tools/ant/AntClassLoader.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/AntClassLoader.java?rev=796702&r1=796701&r2=796702&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/AntClassLoader.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/AntClassLoader.java Wed Jul 22
13:17:16 2009
@@ -27,6 +27,9 @@
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.security.cert.Certificate;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
@@ -37,6 +40,7 @@
import java.util.Locale;
import java.util.jar.Attributes;
import java.util.jar.Attributes.Name;
+import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
@@ -1116,11 +1120,17 @@
protected Class defineClassFromData(File container, byte[] classData,
String classname)
throws IOException {
definePackage(container, classname);
- // XXX should instead make a new ProtectionDomain with a CodeSource
- // corresponding to container.toURI().toURL() and the same
- // PermissionCollection as Project.class.protectionDomain had
- return defineClass(classname, classData, 0, classData.length,
Project.class
- .getProtectionDomain());
+ ProtectionDomain currentPd = Project.class.getProtectionDomain();
+ String classResource = getClassFilename(classname);
+ CodeSource src = new CodeSource(FILE_UTILS.getFileURL(container),
+ getCertificates(container,
+ classResource));
+ ProtectionDomain classesPd =
+ new ProtectionDomain(src, currentPd.getPermissions(),
+ this,
+ currentPd.getPrincipals());
+ return defineClass(classname, classData, 0, classData.length,
+ classesPd);
}
/**
@@ -1180,6 +1190,41 @@
}
/**
+ * Get the certificates for a given jar entry, if it is indeed a jar.
+ *
+ * @param container the File from which to read the entry
+ * @param entry the entry of which the certificates are requested
+ *
+ * @return the entry's certificates or null is the container is
+ * not a jar or it has no certificates.
+ *
+ * @exception IOException if the manifest cannot be read.
+ */
+ private Certificate[] getCertificates(File container, String entry)
+ throws IOException {
+ if (container.isDirectory()) {
+ return null;
+ }
+ JarFile jarFile = null;
+ InputStream is = null;
+ try {
+ jarFile = new JarFile(container);
+ JarEntry ent = jarFile.getJarEntry(entry);
+ if (ent != null) {
+ // must read the input in order to obtain certificates
+ is = jarFile.getInputStream(ent);
+ while (is.read() >= 0);
+ }
+ return ent == null ? null : ent.getCertificates();
+ } finally {
+ FileUtils.close(is);
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ }
+ }
+
+ /**
* Define the package information when the class comes from a
* jar with a manifest
*
Modified:
ant/core/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java?rev=796702&r1=796701&r2=796702&view=diff
==============================================================================
--- ant/core/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java
(original)
+++ ant/core/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java
Wed Jul 22 13:17:16 2009
@@ -28,6 +28,7 @@
public class AntClassLoaderTest extends BuildFileTest {
private Project p;
+ private AntClassLoader loader;
public AntClassLoaderTest(String name) {
super(name);
@@ -41,6 +42,9 @@
}
public void tearDown() {
+ if (loader != null) {
+ loader.cleanup();
+ }
getProject().executeTarget("cleanup");
}
//test inspired by bug report 37085
@@ -50,8 +54,8 @@
Path myPath = new Path(getProject());
myPath.setLocation(new File(mainjarstring));
getProject().setUserProperty("build.sysclasspath","ignore");
- AntClassLoader myLoader = getProject().createClassLoader(myPath);
- String path = myLoader.getClasspath();
+ loader = getProject().createClassLoader(myPath);
+ String path = loader.getClasspath();
assertEquals(mainjarstring + File.pathSeparator + extjarstring, path);
}
public void testJarWithManifestInNonAsciiDir() {
@@ -60,13 +64,13 @@
Path myPath = new Path(getProject());
myPath.setLocation(new File(mainjarstring));
getProject().setUserProperty("build.sysclasspath","ignore");
- AntClassLoader myLoader = getProject().createClassLoader(myPath);
- String path = myLoader.getClasspath();
+ loader = getProject().createClassLoader(myPath);
+ String path = loader.getClasspath();
assertEquals(mainjarstring + File.pathSeparator + extjarstring, path);
}
public void testCleanup() throws BuildException {
Path path = new Path(p, ".");
- AntClassLoader loader = p.createClassLoader(path);
+ loader = p.createClassLoader(path);
try {
// we don't expect to find this
loader.findClass("fubar");
@@ -105,12 +109,44 @@
myPath.setLocation(new File(getProject().getProperty("tmp.dir")
+ "/test.jar"));
getProject().setUserProperty("build.sysclasspath","ignore");
- AntClassLoader loader = getProject().createClassLoader(myPath);
+ loader = getProject().createClassLoader(myPath);
assertNotNull("should find class",
loader.findClass("org.example.Foo"));
assertNotNull("should find package",
new GetPackageWrapper(loader).getPackage("org.example"));
}
+ public void testCodeSource() throws Exception {
+ executeTarget("prepareGetPackageTest");
+ Path myPath = new Path(getProject());
+ myPath.setLocation(new File(getProject().getProperty("tmp.dir")
+ + "/test.jar"));
+ getProject().setUserProperty("build.sysclasspath","ignore");
+ loader = getProject().createClassLoader(myPath);
+ Class foo = loader.findClass("org.example.Foo");
+ String codeSourceLocation =
+ foo.getProtectionDomain().getCodeSource().getLocation().toString();
+ assertTrue(codeSourceLocation + " should point to test.jar",
+ codeSourceLocation.endsWith("test.jar"));
+ }
+
+ public void testSignedJar() throws Exception {
+ executeTarget("signTestJar");
+ File jar = new File(getProject().getProperty("tmp.dir")
+ + "/test.jar");
+
+ Path myPath = new Path(getProject());
+ myPath.setLocation(jar);
+ getProject().setUserProperty("build.sysclasspath","ignore");
+ loader = getProject().createClassLoader(myPath);
+ Class foo = loader.findClass("org.example.Foo");
+
+ assertNotNull("should find class", foo);
+ assertNotNull("should have certificates",
+ foo.getProtectionDomain().getCodeSource()
+ .getCertificates());
+ assertNotNull("should be signed", foo.getSigners());
+ }
+
private static class GetPackageWrapper extends ClassLoader {
GetPackageWrapper(ClassLoader parent) {
super(parent);