Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,15 @@ private Set<ClassPathManifestEntry> getClassPathManifestEntriesFromJar(File jar)
// See jdk.internal.loader.URLClassPath.JarLoader.tryResolveFile(URL, String)
continue;
}
File candidate = new File(parent, path);
if (candidate.isFile() && candidate.getCanonicalPath().contains(parent.getCanonicalPath())) {

// Handle absolute paths correctly - don't use parent for absolute paths
File pathFile = new File(path);
File candidate = pathFile.isAbsolute() ? pathFile : new File(parent, path);

// For relative paths, enforce security check (must be under parent)
// For absolute paths, just verify file exists (matching JVM behavior)
if (candidate.isFile() &&
(pathFile.isAbsolute() || candidate.getCanonicalPath().contains(parent.getCanonicalPath()))) {
manifestEntries.add(ClassPathManifestEntry.of(candidate, this.useCaches));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,21 @@ void javaDashJarFindsClassPathManifestEntries() throws Exception {
assertThat(result.replace("\\", "/")).contains("!!!!").contains("/lib/asset.jar!/assets/file.txt");
}

@Test
void javaDashJarFindsAbsoluteClassPathManifestEntries() throws Exception {
Path assetJar = this.temp.resolve("dependency").resolve("asset.jar");
Files.createDirectories(assetJar.getParent());
writeAssetJar(assetJar);
writeApplicationJarWithAbsolutePath(this.temp.resolve("app.jar"), assetJar);
String java = ProcessHandle.current().info().command().get();
Process process = new ProcessBuilder(java, "-jar", "app.jar")
.directory(this.temp.toFile())
.start();
assertThat(process.waitFor()).isZero();
String result = StreamUtils.copyToString(process.getInputStream(), StandardCharsets.UTF_8);
assertThat(result.replace("\\", "/")).contains("!!!!").contains("asset.jar!/assets/file.txt");
}

private void writeAssetJar(Path path) throws Exception {
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(path.toFile()))) {
jar.putNextEntry(new ZipEntry("assets/"));
Expand Down Expand Up @@ -392,6 +407,35 @@ private void writeApplicationJar(Path path) throws Exception {
assertThat(new UrlResource(ResourceUtils.JAR_URL_PREFIX + ResourceUtils.FILE_URL_PREFIX + path + ResourceUtils.JAR_URL_SEPARATOR).exists()).isTrue();
}

private void writeApplicationJarWithAbsolutePath(Path path, Path assetJar) throws Exception {
Manifest manifest = new Manifest();
Attributes mainAttributes = manifest.getMainAttributes();
mainAttributes.put(Name.CLASS_PATH, buildSpringClassPath() + assetJar.toAbsolutePath());
mainAttributes.put(Name.MAIN_CLASS, ClassPathManifestEntriesTestApplication.class.getName());
mainAttributes.put(Name.MANIFEST_VERSION, "1.0");
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(path.toFile()), manifest)) {
String appClassResource = ClassUtils.convertClassNameToResourcePath(
ClassPathManifestEntriesTestApplication.class.getName()) + ClassUtils.CLASS_FILE_SUFFIX;
String folder = "";
for (String name : appClassResource.split("/")) {
if (!name.endsWith(ClassUtils.CLASS_FILE_SUFFIX)) {
folder += name + "/";
jar.putNextEntry(new ZipEntry(folder));
jar.closeEntry();
}
else {
jar.putNextEntry(new ZipEntry(folder + name));
try (InputStream in = getClass().getResourceAsStream(name)) {
in.transferTo(jar);
}
jar.closeEntry();
}
}
}
assertThat(new FileSystemResource(path).exists()).isTrue();
assertThat(new UrlResource(ResourceUtils.JAR_URL_PREFIX + ResourceUtils.FILE_URL_PREFIX + path + ResourceUtils.JAR_URL_SEPARATOR).exists()).isTrue();
}

private String buildSpringClassPath() throws Exception {
return copyClasses(PathMatchingResourcePatternResolver.class, "spring-core") +
copyClasses(LogFactory.class, "commons-logging");
Expand Down