QPID-8623: [Broker-J] AESKeyFile encryption breaks SimpleLDAPAuthenticationManager user search (#186)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java b/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java
index d227cee..260e829 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/store/GenericRecoverer.java
@@ -242,6 +242,10 @@
updatesMade = true;
unresolvedIter.remove();
ConfiguredObject<?> resolved = unresolvedObject.resolve();
+ if (!isNew)
+ {
+ resolved.decryptSecrets();
+ }
resolvedObjects.put(resolved.getId(), resolved);
}
}
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 0bc5eb9..8919c2a 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,17 +25,34 @@
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.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.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
+import java.util.Comparator;
+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;
@@ -48,6 +65,9 @@
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.State;
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.UnitTestBase;
public class BrokerRecovererTest extends UnitTestBase
@@ -80,7 +100,7 @@
when(_brokerEntry.getParents()).thenReturn(Map.of(SystemConfig.class.getSimpleName(), _systemConfig
.getId()));
- //Add a base AuthenticationProvider for all tests
+ // Add a base AuthenticationProvider for all tests
final AuthenticationProvider<?> authenticationProvider1 = mock(AuthenticationProvider.class);
when(authenticationProvider1.getName()).thenReturn("authenticationProvider1");
when(authenticationProvider1.getId()).thenReturn(_authenticationProvider1Id);
@@ -90,6 +110,18 @@
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 (Stream<Path> stream = Files.walk(path))
+ {
+ stream.sorted(Comparator.reverseOrder()).map(Path::toFile).filter(File::exists).forEach(file ->
+ {
+ makeFileDeletable(file);
+ file.delete();
+ });
+ }
+ }
}
@Test
@@ -129,6 +161,16 @@
return new ConfiguredObjectRecordImpl(id, AuthenticationProvider.class.getSimpleName(), authProviderAttrs, Map.of(Broker.class.getSimpleName(), _brokerEntry.getId()));
}
+ public ConfiguredObjectRecord createSimpleLDAPAuthProviderRecord(final UUID id, final String name, final String password)
+ {
+ final Map<String, Object> authProviderAttrs = Map.of(AuthenticationProvider.NAME, name,
+ SimpleLDAPAuthenticationManager.TYPE, SimpleLDAPAuthenticationManager.PROVIDER_TYPE,
+ SimpleLDAPAuthenticationManager.PROVIDER_URL, "ldap://localhost:%d",
+ SimpleLDAPAuthenticationManager.SEARCH_CONTEXT, "ou=users,dc=qpid,dc=org",
+ SimpleLDAPAuthenticationManager.SEARCH_FILTER, "(uid={0})",
+ SimpleLDAPAuthenticationManager.SEARCH_PASSWORD, password);
+ return new ConfiguredObjectRecordImpl(id, AuthenticationProvider.class.getSimpleName(), authProviderAttrs, Map.of(Broker.class.getSimpleName(), _brokerEntry.getId()));
+ }
public ConfiguredObjectRecord createGroupProviderRecord(final UUID id, final String name)
{
@@ -181,6 +223,34 @@
@Test
@SuppressWarnings("unchecked")
+ public void testCreateBrokerWithSimpleLDAPAuthenticationProvider() throws Exception
+ {
+ final UUID authProviderId = randomUUID();
+
+ final String password = "password";
+ final ConfigurationSecretEncrypter configurationSecretEncrypter =
+ new AESGCMKeyFileEncrypterFactory().createEncrypter(_systemConfig);
+ final String encryptedPassword = configurationSecretEncrypter.encrypt(password);
+
+ final Method setter = _systemConfig.getClass().getSuperclass().getSuperclass().getSuperclass()
+ .getDeclaredMethod("setEncrypter", ConfigurationSecretEncrypter.class);
+ setter.setAccessible(true);
+ setter.invoke(_systemConfig, configurationSecretEncrypter);
+
+ // SimpleLDAPAuthenticationManager with the encrypted password is created
+ resolveObjects(_brokerEntry, createSimpleLDAPAuthProviderRecord(authProviderId, "ldap", encryptedPassword));
+ final Broker<?> broker = _systemConfig.getContainer(Broker.class);
+
+ broker.open();
+
+ // check if SimpleLDAPAuthenticationManager returns decrypted password
+ final SimpleLDAPAuthenticationManager<?> simpleLDAPAuthenticationManager =
+ (SimpleLDAPAuthenticationManager<?>) broker.getAuthenticationProviders().iterator().next();
+ assertEquals(password, simpleLDAPAuthenticationManager.getSearchPassword());
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
public void testCreateBrokerWithMultipleAuthenticationProvidersAndPorts()
{
final UUID authProviderId = randomUUID();
@@ -291,4 +361,39 @@
final GenericRecoverer recoverer = new GenericRecoverer(_systemConfig);
recoverer.recover(Arrays.asList(records), false);
}
+
+ private void makeFileDeletable(File file)
+ {
+ try
+ {
+ if (Files.getFileAttributeView(file.toPath(), PosixFileAttributeView.class) != 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");
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalConfigurationException("Failed to change file permissions", e);
+ }
+ }
}