Skip to content

Commit

Permalink
Merge pull request from GHSA-269g-pwp5-87pp
Browse files Browse the repository at this point in the history
When running on Java 7 or later, temporary directories are now created
Using Java’s NIO API which restricts permissions to owner-only by
default.
  • Loading branch information
marcphilipp authored Oct 11, 2020
1 parent b6cfd1e commit 610155b
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 2 deletions.
43 changes: 42 additions & 1 deletion src/main/java/org/junit/rules/TemporaryFolder.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.Rule;

Expand Down Expand Up @@ -229,7 +232,45 @@ public File newFolder() throws IOException {
return createTemporaryFolderIn(getRoot());
}

private File createTemporaryFolderIn(File parentFolder) throws IOException {
private static File createTemporaryFolderIn(File parentFolder) throws IOException {
try {
return createTemporaryFolderWithNioApi(parentFolder);
} catch (ClassNotFoundException ignore) {
// Fallback for Java 5 and 6
return createTemporaryFolderWithFileApi(parentFolder);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
}
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
IOException exception = new IOException("Failed to create temporary folder in " + parentFolder);
exception.initCause(cause);
throw exception;
} catch (Exception e) {
throw new RuntimeException("Failed to create temporary folder in " + parentFolder, e);
}
}

private static File createTemporaryFolderWithNioApi(File parentFolder) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

This comment has been minimized.

Copy link
@ArvinDevel

ArvinDevel Aug 7, 2022

hi @marcphilipp , may I know the reason to use reflection, IMO the direct class and method call has higher performance.

This comment has been minimized.

Copy link
@marcphilipp

marcphilipp Aug 8, 2022

Author Member

The reason is that JUnit 4 is compatible with Java 1.5 and these classes were introduced in 1.7.

This comment has been minimized.

Copy link
@ArvinDevel

ArvinDevel Aug 23, 2022

got it, thank you a lot.

Class<?> filesClass = Class.forName("java.nio.file.Files");
Object fileAttributeArray = Array.newInstance(Class.forName("java.nio.file.attribute.FileAttribute"), 0);
Class<?> pathClass = Class.forName("java.nio.file.Path");
Object tempDir;
if (parentFolder != null) {
Method createTempDirectoryMethod = filesClass.getDeclaredMethod("createTempDirectory", pathClass, String.class, fileAttributeArray.getClass());
Object parentPath = File.class.getDeclaredMethod("toPath").invoke(parentFolder);
tempDir = createTempDirectoryMethod.invoke(null, parentPath, TMP_PREFIX, fileAttributeArray);
} else {
Method createTempDirectoryMethod = filesClass.getDeclaredMethod("createTempDirectory", String.class, fileAttributeArray.getClass());
tempDir = createTempDirectoryMethod.invoke(null, TMP_PREFIX, fileAttributeArray);
}
return (File) pathClass.getDeclaredMethod("toFile").invoke(tempDir);
}

private static File createTemporaryFolderWithFileApi(File parentFolder) throws IOException {
File createdFolder = null;
for (int i = 0; i < TEMP_DIR_ATTEMPTS; ++i) {
// Use createTempFile to get a suitable folder name.
Expand Down
37 changes: 36 additions & 1 deletion src/test/java/org/junit/rules/TempFolderRuleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,28 @@
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.junit.experimental.results.PrintableResult.testResult;
import static org.junit.experimental.results.ResultMatchers.failureCountIs;
import static org.junit.experimental.results.ResultMatchers.isSuccessful;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.junit.After;
import org.junit.AssumptionViolatedException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class TempFolderRuleTest {
private static File[] createdFiles = new File[20];
Expand Down Expand Up @@ -182,6 +189,34 @@ public void recursiveDeleteFolderWithZeroElements() throws IOException {
assertFalse(folder.getRoot().exists());
}

@Test
public void tempFolderIsOnlyAccessibleByOwner() throws IOException {
TemporaryFolder folder = new TemporaryFolder();
folder.create();

Set<String> expectedPermissions = new TreeSet<String>(Arrays.asList("OWNER_READ", "OWNER_WRITE", "OWNER_EXECUTE"));
Set<String> actualPermissions = getPosixFilePermissions(folder.getRoot());
assertEquals(expectedPermissions, actualPermissions);
}

private Set<String> getPosixFilePermissions(File root) {
try {
Class<?> pathClass = Class.forName("java.nio.file.Path");
Object linkOptionArray = Array.newInstance(Class.forName("java.nio.file.LinkOption"), 0);
Class<?> filesClass = Class.forName("java.nio.file.Files");
Object path = File.class.getDeclaredMethod("toPath").invoke(root);
Method posixFilePermissionsMethod = filesClass.getDeclaredMethod("getPosixFilePermissions", pathClass, linkOptionArray.getClass());
Set<?> permissions = (Set<?>) posixFilePermissionsMethod.invoke(null, path, linkOptionArray);
SortedSet<String> convertedPermissions = new TreeSet<String>();
for (Object item : permissions) {
convertedPermissions.add(item.toString());
}
return convertedPermissions;
} catch (Exception e) {
throw new AssumptionViolatedException("Test requires at least Java 1.7", e);
}
}

public static class NameClashes {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
Expand Down

0 comments on commit 610155b

Please # to comment.