git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@796702 13f79535-47bb-0310-9956-ffa450edef68master
@@ -410,7 +410,10 @@ Fixed bugs: | |||
* 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: | |||
-------------- | |||
@@ -67,4 +67,9 @@ public class Foo {} | |||
</jar> | |||
</target> | |||
<target name="signTestJar" depends="prepareGetPackageTest"> | |||
<signjar alias="testonly" keystore="../testkeystore" | |||
storepass="apacheant" jar="${tmp.dir}/test.jar"/> | |||
</target> | |||
</project> |
@@ -27,6 +27,9 @@ import java.io.Reader; | |||
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.Vector; | |||
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 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||
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); | |||
} | |||
/** | |||
@@ -1179,6 +1189,41 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||
} | |||
} | |||
/** | |||
* 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 | |||
@@ -28,6 +28,7 @@ import org.apache.tools.ant.types.Path; | |||
public class AntClassLoaderTest extends BuildFileTest { | |||
private Project p; | |||
private AntClassLoader loader; | |||
public AntClassLoaderTest(String name) { | |||
super(name); | |||
@@ -41,6 +42,9 @@ public class AntClassLoaderTest extends BuildFileTest { | |||
} | |||
public void tearDown() { | |||
if (loader != null) { | |||
loader.cleanup(); | |||
} | |||
getProject().executeTarget("cleanup"); | |||
} | |||
//test inspired by bug report 37085 | |||
@@ -50,8 +54,8 @@ public class AntClassLoaderTest extends BuildFileTest { | |||
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 @@ public class AntClassLoaderTest extends BuildFileTest { | |||
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 @@ public class AntClassLoaderTest extends BuildFileTest { | |||
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); | |||