This is an automated email from the ASF dual-hosted git repository.
vavrtom pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git
The following commit(s) were added to refs/heads/main by this push:
new f227730daa QPID-8753: [Broker-J] Clean up protected test key files
(#425)
f227730daa is described below
commit f227730daae61e055259497af91324bf39626260
Author: Daniil Kirilyuk <[email protected]>
AuthorDate: Fri Aug 28 10:41:07 2026 +0200
QPID-8753: [Broker-J] Clean up protected test key files (#425)
---
.../encryption/AESGCMKeyFileEncrypterTest.java | 22 ++--
.../AbstractAESKeyFileEncrypterFactoryTest.java | 7 +-
.../qpid/server/store/BrokerRecovererTest.java | 105 +++++--------------
.../org/apache/qpid/test/utils/TestFileUtils.java | 114 ++++++++++++++++++++-
.../apache/qpid/test/utils/TestFileUtilsTest.java | 113 ++++++++++++++++++++
5 files changed, 268 insertions(+), 93 deletions(-)
diff --git
a/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESGCMKeyFileEncrypterTest.java
b/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESGCMKeyFileEncrypterTest.java
index 9163bdb8e7..a72ea00975 100644
---
a/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESGCMKeyFileEncrypterTest.java
+++
b/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESGCMKeyFileEncrypterTest.java
@@ -63,7 +63,7 @@ import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.JsonSystemConfigImpl;
import org.apache.qpid.server.model.SystemConfig;
import org.apache.qpid.server.model.User;
-import org.apache.qpid.server.util.FileUtils;
+import org.apache.qpid.test.utils.TestFileUtils;
import org.apache.qpid.test.utils.UnitTestBase;
public class AESGCMKeyFileEncrypterTest extends UnitTestBase
@@ -91,13 +91,19 @@ public class AESGCMKeyFileEncrypterTest extends UnitTestBase
@AfterEach
public void tearDown() throws Exception
{
- if (_systemLauncher != null)
+ try
{
- _systemLauncher.shutdown();
+ if (_systemLauncher != null)
+ {
+ _systemLauncher.shutdown();
+ }
}
- if (_workDir != null)
+ finally
{
- FileUtils.deleteDirectory(_workDir.toFile().getAbsolutePath());
+ if (_workDir != null)
+ {
+ TestFileUtils.deleteRecursively(_workDir);
+ }
}
}
@@ -205,14 +211,14 @@ public class AESGCMKeyFileEncrypterTest extends
UnitTestBase
@Test
public void testSetKeyLocationAsExpression() throws Exception
{
- final Path workDir = Files.createTempDirectory("qpid_work_dir");
- final File keyFile = new File(workDir.toFile(), "test.key");
+ _workDir = Files.createTempDirectory("qpid_work_dir");
+ final File keyFile = new File(_workDir.toFile(), "test.key");
AbstractAESKeyFileEncrypterFactory.createAndPopulateKeyFile(keyFile);
final Map<String, String> context = Map.of(
AbstractAESKeyFileEncrypterFactory.ENCRYPTER_KEY_FILE,
"${qpid.work_dir}" + File.separator + keyFile.getName());
createBrokerAndAuthenticationProviderWithEncrypterPassword(AESGCMKeyFileEncrypterFactory.TYPE,
- workDir,
+ _workDir,
context);
final String encryptedPassword = getEncryptedPasswordFromConfig();
final SecretKeySpec aesSecretKey = new
SecretKeySpec(Files.readAllBytes(keyFile.toPath()), "AES");
diff --git
a/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AbstractAESKeyFileEncrypterFactoryTest.java
b/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AbstractAESKeyFileEncrypterFactoryTest.java
index b03585ed8a..e21fb75668 100644
---
a/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AbstractAESKeyFileEncrypterFactoryTest.java
+++
b/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AbstractAESKeyFileEncrypterFactoryTest.java
@@ -43,11 +43,9 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.security.NoSuchAlgorithmException;
-import java.util.Comparator;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Stream;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
@@ -62,6 +60,7 @@ import org.mockito.stubbing.Answer;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.SystemConfig;
+import org.apache.qpid.test.utils.TestFileUtils;
import org.apache.qpid.test.utils.UnitTestBase;
@SuppressWarnings({"rawtypes", "unchecked"})
@@ -240,9 +239,9 @@ public class AbstractAESKeyFileEncrypterFactoryTest extends
UnitTestBase
@AfterEach
public void tearDown() throws Exception
{
- try (final Stream<Path> stream = Files.walk(_tmpDir))
+ if (_tmpDir != null)
{
-
stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+ TestFileUtils.deleteRecursively(_tmpDir);
}
}
diff --git
a/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java
b/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java
index 622763131f..8009bf54a0 100644
---
a/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java
+++
b/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java
@@ -25,36 +25,19 @@ import static
org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.io.File;
-import java.io.IOException;
import java.lang.reflect.Method;
-import java.nio.file.FileSystems;
-import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.attribute.AclEntry;
-import java.nio.file.attribute.AclEntryPermission;
-import java.nio.file.attribute.AclEntryType;
-import java.nio.file.attribute.AclFileAttributeView;
-import java.nio.file.attribute.PosixFileAttributeView;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.UserPrincipal;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.logging.EventLogger;
@@ -70,6 +53,7 @@ import org.apache.qpid.server.model.SystemConfig;
import
org.apache.qpid.server.security.auth.manager.SimpleLDAPAuthenticationManager;
import
org.apache.qpid.server.security.encryption.AESGCMKeyFileEncrypterFactory;
import org.apache.qpid.server.security.encryption.ConfigurationSecretEncrypter;
+import org.apache.qpid.test.utils.TestFileUtils;
import org.apache.qpid.test.utils.UnitTestBase;
public class BrokerRecovererTest extends UnitTestBase
@@ -80,17 +64,23 @@ public class BrokerRecovererTest extends UnitTestBase
private SystemConfig<?> _systemConfig;
private TaskExecutor _taskExecutor;
+ private Path _workDir;
@BeforeEach
public void setUp() throws Exception
{
+ cleanUp();
+ _workDir = Files.createTempDirectory(getTestName());
_taskExecutor = CurrentThreadTaskExecutor.newStartedInstance();
- _systemConfig = new JsonSystemConfigImpl(_taskExecutor,
mock(EventLogger.class),null, Map.of())
+ _systemConfig = new JsonSystemConfigImpl(_taskExecutor,
mock(EventLogger.class), null, Map.of())
{
{
updateModel(BrokerModel.getInstance());
}
};
+ _systemConfig.setContextVariable(SystemConfig.QPID_WORK_DIR,
_workDir.toString());
+ assertEquals(_workDir.toString(),
_systemConfig.getContextValue(String.class, SystemConfig.QPID_WORK_DIR),
+ "Unexpected test work directory");
when(_brokerEntry.getId()).thenReturn(_brokerId);
when(_brokerEntry.getType()).thenReturn(Broker.class.getSimpleName());
@@ -111,42 +101,7 @@ public class BrokerRecovererTest extends UnitTestBase
@AfterEach
public void tearDown() throws Exception
{
- _taskExecutor.stop();
- final Path path = Path.of(_systemConfig.getContextValue(String.class,
SystemConfig.QPID_WORK_DIR));
- if (path.toFile().exists())
- {
- try
- {
- Files.walkFileTree(path, new SimpleFileVisitor<>()
- {
- @Override
- public FileVisitResult visitFile(final Path file, final
BasicFileAttributes attrs) throws IOException
- {
- makeFileDeletable(file.toFile());
- Files.deleteIfExists(file);
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult postVisitDirectory(final Path dir,
final IOException exc) throws IOException
- {
- makeFileDeletable(dir.toFile());
- Files.deleteIfExists(dir);
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFileFailed(final Path file,
final IOException exc)
- {
- return FileVisitResult.CONTINUE;
- }
- });
- }
- catch (IOException e)
- {
- // ignore cleanup issues in tests
- }
- }
+ cleanUp();
}
@Test
@@ -387,38 +342,30 @@ public class BrokerRecovererTest extends UnitTestBase
recoverer.recover(Arrays.asList(records), false);
}
- private void makeFileDeletable(File file)
+ private void cleanUp() throws Exception
{
try
{
- if (Files.getFileAttributeView(file.toPath(),
PosixFileAttributeView.class) != null)
+ if (_taskExecutor != null)
{
- Files.setPosixFilePermissions(file.toPath(),
EnumSet.of(PosixFilePermission.OTHERS_WRITE));
- }
- else if (Files.getFileAttributeView(file.toPath(),
AclFileAttributeView.class) != null)
- {
- file.setWritable(true);
- final AclFileAttributeView attributeView =
- Files.getFileAttributeView(file.toPath(),
AclFileAttributeView.class);
- final ArrayList<AclEntry> acls = new
ArrayList<>(attributeView.getAcl());
-
- final AclEntry.Builder builder = AclEntry.newBuilder();
- final UserPrincipal everyone =
FileSystems.getDefault().getUserPrincipalLookupService()
- .lookupPrincipalByName("Everyone");
- builder.setPrincipal(everyone);
- builder.setType(AclEntryType.ALLOW);
-
builder.setPermissions(Stream.of(AclEntryPermission.values()).collect(Collectors.toSet()));
- acls.add(builder.build());
- attributeView.setAcl(acls);
- }
- else
- {
- throw new IllegalConfigurationException("Failed to change file
permissions");
+ _taskExecutor.stop();
}
}
- catch (IOException e)
+ finally
{
- throw new IllegalConfigurationException("Failed to change file
permissions", e);
+ _taskExecutor = null;
+ _systemConfig = null;
+ if (_workDir != null)
+ {
+ try
+ {
+ TestFileUtils.deleteRecursively(_workDir);
+ }
+ finally
+ {
+ _workDir = null;
+ }
+ }
}
}
}
diff --git
a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java
b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java
index 24685d2361..f33ebf136b 100644
---
a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java
+++
b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java
@@ -21,11 +21,28 @@
package org.apache.qpid.test.utils;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-
-import java.io.FileOutputStream;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.attribute.AclEntry;
+import java.nio.file.attribute.AclEntryPermission;
+import java.nio.file.attribute.AclEntryType;
+import java.nio.file.attribute.AclFileAttributeView;
+import java.nio.file.attribute.DosFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
import org.junit.jupiter.api.TestInfo;
@@ -241,6 +258,99 @@ public class TestFileUtils
return file.delete();
}
+ /**
+ * Recursively deletes a test file tree whose owner permissions may have
been restricted.
+ * Symbolic links are deleted without following them.
+ *
+ * @param path root of the test file tree
+ * @throws IOException if owner permissions cannot be restored or a file
cannot be deleted
+ */
+ public static void deleteRecursively(final Path path) throws IOException
+ {
+ if (Files.isSymbolicLink(path))
+ {
+ Files.deleteIfExists(path);
+ return;
+ }
+
+ try
+ {
+ restoreOwnerPermissions(path);
+ }
+ catch (NoSuchFileException e)
+ {
+ return;
+ }
+
+ if (Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS))
+ {
+ try (final DirectoryStream<Path> children =
Files.newDirectoryStream(path))
+ {
+ for (final Path child : children)
+ {
+ deleteRecursively(child);
+ }
+ }
+ }
+ Files.deleteIfExists(path);
+ }
+
+ private static void restoreOwnerPermissions(final Path path) throws
IOException
+ {
+ final PosixFileAttributeView posixView =
Files.getFileAttributeView(path, PosixFileAttributeView.class,
+ LinkOption.NOFOLLOW_LINKS);
+
+ if (posixView != null)
+ {
+ final Set<PosixFilePermission> permissions =
EnumSet.noneOf(PosixFilePermission.class);
+ permissions.addAll(posixView.readAttributes().permissions());
+ permissions.add(PosixFilePermission.OWNER_READ);
+ permissions.add(PosixFilePermission.OWNER_WRITE);
+ permissions.add(PosixFilePermission.OWNER_EXECUTE);
+ posixView.setPermissions(permissions);
+ }
+ else
+ {
+ final AclFileAttributeView aclView =
Files.getFileAttributeView(path, AclFileAttributeView.class,
+ LinkOption.NOFOLLOW_LINKS);
+ if (aclView != null)
+ {
+ final UserPrincipal owner = Files.getOwner(path,
LinkOption.NOFOLLOW_LINKS);
+ final List<AclEntry> acl = new ArrayList<>(aclView.getAcl());
+ final ListIterator<AclEntry> iterator = acl.listIterator();
+ boolean ownerEntryFound = false;
+ while (iterator.hasNext())
+ {
+ final AclEntry entry = iterator.next();
+ if (entry.type() == AclEntryType.ALLOW &&
owner.equals(entry.principal()))
+ {
+ ownerEntryFound = true;
+ iterator.set(AclEntry.newBuilder(entry)
+
.setPermissions(EnumSet.allOf(AclEntryPermission.class))
+ .build());
+ }
+ }
+ if (!ownerEntryFound)
+ {
+ acl.add(AclEntry.newBuilder()
+ .setType(AclEntryType.ALLOW)
+ .setPrincipal(owner)
+
.setPermissions(EnumSet.allOf(AclEntryPermission.class))
+ .build());
+ }
+ aclView.setAcl(acl);
+ }
+ }
+
+ final DosFileAttributeView dosView = Files.getFileAttributeView(path,
DosFileAttributeView.class,
+ LinkOption.NOFOLLOW_LINKS);
+
+ if (dosView != null)
+ {
+ dosView.setReadOnly(false);
+ }
+ }
+
/**
* Copies the specified InputStream to the specified destination file. If
the destination file does not exist,
* it is created.
diff --git
a/qpid-test-utils/src/test/java/org/apache/qpid/test/utils/TestFileUtilsTest.java
b/qpid-test-utils/src/test/java/org/apache/qpid/test/utils/TestFileUtilsTest.java
new file mode 100644
index 0000000000..8836146264
--- /dev/null
+++
b/qpid-test-utils/src/test/java/org/apache/qpid/test/utils/TestFileUtilsTest.java
@@ -0,0 +1,113 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.utils;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.AclEntry;
+import java.nio.file.attribute.AclEntryPermission;
+import java.nio.file.attribute.AclEntryType;
+import java.nio.file.attribute.AclFileAttributeView;
+import java.nio.file.attribute.DosFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class TestFileUtilsTest
+{
+ @TempDir
+ private Path _tempDirectory;
+
+ @Test
+ public void testDeleteRecursivelyRestoresRestrictedOwnerPermissions()
throws Exception
+ {
+ final Path root =
Files.createDirectory(_tempDirectory.resolve("restricted"));
+ final Path child = Files.createDirectory(root.resolve("child"));
+ final Path file = Files.writeString(child.resolve("key"), "secret");
+
+ restrictFile(file);
+ restrictDirectory(child);
+ restrictDirectory(root);
+
+ TestFileUtils.deleteRecursively(root);
+
+ assertFalse(Files.exists(root), "Restricted test directory was not
deleted");
+ }
+
+ private void restrictFile(final Path file) throws Exception
+ {
+ final DosFileAttributeView dosView = Files.getFileAttributeView(file,
DosFileAttributeView.class);
+ if (dosView != null)
+ {
+ dosView.setReadOnly(true);
+ }
+
+ final PosixFileAttributeView posixView =
Files.getFileAttributeView(file, PosixFileAttributeView.class);
+ if (posixView != null)
+ {
+
posixView.setPermissions(EnumSet.of(PosixFilePermission.OWNER_READ));
+ }
+ else
+ {
+ final AclFileAttributeView aclView =
Files.getFileAttributeView(file, AclFileAttributeView.class);
+ if (aclView != null)
+ {
+ final UserPrincipal owner = Files.getOwner(file);
+ aclView.setAcl(List.of(AclEntry.newBuilder()
+ .setType(AclEntryType.ALLOW)
+ .setPrincipal(owner)
+ .setPermissions(AclEntryPermission.READ_DATA,
AclEntryPermission.READ_ATTRIBUTES,
+ AclEntryPermission.READ_ACL,
AclEntryPermission.SYNCHRONIZE)
+ .build()));
+ }
+ }
+ }
+
+ private void restrictDirectory(final Path directory) throws Exception
+ {
+ final PosixFileAttributeView posixView =
Files.getFileAttributeView(directory, PosixFileAttributeView.class);
+ if (posixView != null)
+ {
+
posixView.setPermissions(EnumSet.of(PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_EXECUTE));
+ }
+ else
+ {
+ final AclFileAttributeView aclView =
Files.getFileAttributeView(directory, AclFileAttributeView.class);
+ if (aclView != null)
+ {
+ final UserPrincipal owner = Files.getOwner(directory);
+ aclView.setAcl(List.of(AclEntry.newBuilder()
+ .setType(AclEntryType.ALLOW)
+ .setPrincipal(owner)
+ .setPermissions(AclEntryPermission.ADD_FILE,
AclEntryPermission.ADD_SUBDIRECTORY,
+ AclEntryPermission.LIST_DIRECTORY)
+ .build()));
+ }
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]