diff --git a/pom.xml b/pom.xml index 105e212f..fb67f471 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.dataone hashstore - 1.0-SNAPSHOT + 1.1.0 hashstore https://github.com/DataONEorg/hashstore-java diff --git a/src/main/java/org/dataone/hashstore/filehashstore/FileHashStoreUtility.java b/src/main/java/org/dataone/hashstore/filehashstore/FileHashStoreUtility.java index b180b050..5c15c769 100644 --- a/src/main/java/org/dataone/hashstore/filehashstore/FileHashStoreUtility.java +++ b/src/main/java/org/dataone/hashstore/filehashstore/FileHashStoreUtility.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.attribute.PosixFilePermission; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; @@ -16,9 +17,11 @@ import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Random; +import java.util.Set; import java.util.stream.Stream; import javax.xml.bind.DatatypeConverter; @@ -321,8 +324,9 @@ public static String getHierarchicalPathString(int depth, int width, String dige } /** - * Creates an empty/temporary file in a given location. If this file is not moved, it will be - * deleted upon JVM gracefully exiting or shutting down. + * Creates an empty/temporary file in a given location. This temporary file has the default + * permissions of 'rw- r-- ---' (owner read/write, and group read). If this file is not + * moved, it will be deleted upon JVM gracefully exiting or shutting down. * * @param prefix string to prepend before tmp file * @param directory location to create tmp file @@ -336,10 +340,19 @@ public static File generateTmpFile(String prefix, Path directory) int randomNumber = rand.nextInt(1000000); String newPrefix = prefix + "-" + System.currentTimeMillis() + randomNumber; - Path newPath = Files.createTempFile(directory, newPrefix, null); - File newFile = newPath.toFile(); - newFile.deleteOnExit(); - return newFile; + Path newTmpPath = Files.createTempFile(directory, newPrefix, null); + File newTmpFile = newTmpPath.toFile(); + + // Set default file permissions 'rw- r-- ---' + final Set permissions = new HashSet<>(); + permissions.add(PosixFilePermission.OWNER_READ); + permissions.add(PosixFilePermission.OWNER_WRITE); + permissions.add(PosixFilePermission.GROUP_READ); + Files.setPosixFilePermissions(newTmpPath, permissions); + // Mark tmp file to be cleaned up if it runs into an issue + newTmpFile.deleteOnExit(); + + return newTmpFile; } /** diff --git a/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreInterfaceTest.java b/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreInterfaceTest.java index 303af320..7bc157fb 100644 --- a/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreInterfaceTest.java +++ b/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreInterfaceTest.java @@ -17,6 +17,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermission; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -26,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -163,6 +165,39 @@ public void storeObject_hexDigests() throws Exception { } } + /** + * Check that data object stored contains the correct permission settings 'rw- r-- ---' + */ + @Test + public void storeObject_filePermissions() throws Exception { + for (String pid : testData.pidList) { + String pidFormatted = pid.replace("/", "_"); + Path testDataFile = testData.getTestFile(pidFormatted); + + try (InputStream dataStream = Files.newInputStream(testDataFile)) { + fileHashStore.storeObject(dataStream, pid, null, null, null, -1); + + Path objRealPath = fileHashStore.getHashStoreDataObjectPath(pid); + + Collection expectedPermissions = new HashSet<>(); + expectedPermissions.add(PosixFilePermission.OWNER_READ); + expectedPermissions.add(PosixFilePermission.OWNER_WRITE); + expectedPermissions.add(PosixFilePermission.GROUP_READ); + + Set actualPermissions = + Files.getPosixFilePermissions(objRealPath); + + assertEquals(expectedPermissions, actualPermissions); + assertFalse(actualPermissions.contains(PosixFilePermission.OWNER_EXECUTE)); + assertFalse(actualPermissions.contains(PosixFilePermission.GROUP_WRITE)); + assertFalse(actualPermissions.contains(PosixFilePermission.GROUP_EXECUTE)); + assertFalse(actualPermissions.contains(PosixFilePermission.OTHERS_READ)); + assertFalse(actualPermissions.contains(PosixFilePermission.OTHERS_WRITE)); + assertFalse(actualPermissions.contains(PosixFilePermission.OTHERS_EXECUTE)); + } + } + } + /** * Check that store object throws exception when object is null */ diff --git a/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreProtectedTest.java b/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreProtectedTest.java index f5a3c486..64522145 100644 --- a/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreProtectedTest.java +++ b/src/test/java/org/dataone/hashstore/filehashstore/FileHashStoreProtectedTest.java @@ -15,15 +15,18 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermission; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; +import java.util.Set; import javax.xml.bind.DatatypeConverter; @@ -2421,4 +2424,31 @@ public void fileHashStoreUtility_renamePathForRestoration() throws Exception { } } } + + + /** + * Confirm that generateTemporaryFile creates tmpFile with expected permissions + */ + @Test + public void fileHashStoreUtility_generateTmpFile_permissions() throws Exception { + Path directory = tempFolder.resolve("hashstore"); + // newFile + File tmpFile = FileHashStoreUtility.generateTmpFile("testfile", directory); + + Collection expectedPermissions = new HashSet<>(); + expectedPermissions.add(PosixFilePermission.OWNER_READ); + expectedPermissions.add(PosixFilePermission.OWNER_WRITE); + expectedPermissions.add(PosixFilePermission.GROUP_READ); + + Set actualPermissions = + Files.getPosixFilePermissions(tmpFile.toPath()); + + assertEquals(expectedPermissions, actualPermissions); + assertFalse(actualPermissions.contains(PosixFilePermission.OWNER_EXECUTE)); + assertFalse(actualPermissions.contains(PosixFilePermission.GROUP_WRITE)); + assertFalse(actualPermissions.contains(PosixFilePermission.GROUP_EXECUTE)); + assertFalse(actualPermissions.contains(PosixFilePermission.OTHERS_READ)); + assertFalse(actualPermissions.contains(PosixFilePermission.OTHERS_WRITE)); + assertFalse(actualPermissions.contains(PosixFilePermission.OTHERS_EXECUTE)); + } }