You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ad...@apache.org on 2021/06/25 12:28:33 UTC
[jackrabbit-oak] branch trunk updated: OAK-9473 - Cold Standby:
configure decryption password for SSL key in OSGi
This is an automated email from the ASF dual-hosted git repository.
adulceanu pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new cb14ad4 OAK-9473 - Cold Standby: configure decryption password for SSL key in OSGi
cb14ad4 is described below
commit cb14ad47d4c0570fead4c082da9b6bec54130c15
Author: Axel Hanikel <ah...@adobe.com>
AuthorDate: Thu Jun 24 17:41:12 2021 +0200
OAK-9473 - Cold Standby: configure decryption password for SSL key in OSGi
---
.../oak/segment/standby/client/StandbyClient.java | 18 ++--
.../segment/standby/client/StandbyClientSync.java | 22 +++--
.../oak/segment/standby/server/StandbyServer.java | 20 ++--
.../segment/standby/server/StandbyServerSync.java | 36 +++++---
.../segment/standby/store/StandbyStoreService.java | 33 ++++---
.../oak/segment/standby/StandbyTestIT.java | 101 ++++++++++++++++++++-
.../jackrabbit/oak/segment/standby/TestBase.java | 95 +++++++++++++++++++
7 files changed, 277 insertions(+), 48 deletions(-)
diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java
index 2105df0..3e92a73 100644
--- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java
+++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java
@@ -73,8 +73,9 @@ class StandbyClient implements AutoCloseable {
private int readTimeoutMs;
private File spoolFolder;
private String sslKeyFile;
+ private String sslKeyPassword;
private String sslChainFile;
- public String sslServerSubjectPattern;
+ public String sslSubjectPattern;
private Builder() {}
@@ -118,13 +119,18 @@ class StandbyClient implements AutoCloseable {
return this;
}
+ public Builder withSSLKeyPassword(String sslKeyPassword) {
+ this.sslKeyPassword = sslKeyPassword;
+ return this;
+ }
+
public Builder withSSLChainFile(String sslChainFile) {
this.sslChainFile = sslChainFile;
return this;
}
- public Builder withSSLServerSubjectPattern(String sslServerSubjectPattern) {
- this.sslServerSubjectPattern = sslServerSubjectPattern;
+ public Builder withSSLSubjectPattern(String sslServerSubjectPattern) {
+ this.sslSubjectPattern = sslServerSubjectPattern;
return this;
}
@@ -169,14 +175,14 @@ class StandbyClient implements AutoCloseable {
if (builder.secure) {
SslContext sslContext;
if (builder.sslKeyFile != null && !"".equals(builder.sslKeyFile)) {
- sslContext = SslContextBuilder.forClient().keyManager(new File(builder.sslChainFile), new File(builder.sslKeyFile)).build();
+ sslContext = SslContextBuilder.forClient().keyManager(new File(builder.sslChainFile), new File(builder.sslKeyFile), builder.sslKeyPassword).build();
} else {
sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
}
p.addLast("ssl", sslContext.newHandler(ch.alloc()));
- if (builder.sslServerSubjectPattern != null) {
- p.addLast(new SSLSubjectMatcher(builder.sslServerSubjectPattern));
+ if (builder.sslSubjectPattern != null) {
+ p.addLast(new SSLSubjectMatcher(builder.sslSubjectPattern));
}
}
diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java
index 6af99db..ebca61d 100644
--- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java
+++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java
@@ -59,8 +59,9 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab
private boolean autoClean;
private File spoolFolder;
private String sslKeyFile;
+ private String sslKeyPassword;
private String sslChainFile;
- private String sslServerSubjectPattern;
+ private String sslSubjectPattern;
private Builder() {}
@@ -104,13 +105,18 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab
return this;
}
+ public Builder withSSLKeyPassword(String sslKeyPassword) {
+ this.sslKeyPassword = sslKeyPassword;
+ return this;
+ }
+
public Builder withSSLChainFile(String sslChainFile) {
this.sslChainFile = sslChainFile;
return this;
}
- public Builder withSSLServerSubjectPattern(String sslServerSubjectPattern) {
- this.sslServerSubjectPattern = sslServerSubjectPattern;
+ public Builder withSSLSubjectPattern(String sslSubjectPattern) {
+ this.sslSubjectPattern = sslSubjectPattern;
return this;
}
@@ -149,9 +155,11 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab
private final String sslKeyFile;
+ private final String sslKeyPassword;
+
private final String sslChainFile;
- private final String sslServerSubjectPattern;
+ private final String sslSubjectPattern;
private int failedRequests;
@@ -192,8 +200,9 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab
this.execution = new StandbyClientSyncExecution(fileStore, () -> running);
this.spoolFolder = builder.spoolFolder;
this.sslKeyFile = builder.sslKeyFile;
+ this.sslKeyPassword = builder.sslKeyPassword;
this.sslChainFile = builder.sslChainFile;
- this.sslServerSubjectPattern = builder.sslServerSubjectPattern;
+ this.sslSubjectPattern = builder.sslSubjectPattern;
try {
ManagementFactory.getPlatformMBeanServer().registerMBean(new StandardMBean(this, ClientStandbyStatusMBean.class), new ObjectName(this.getMBeanName()));
} catch (Exception e) {
@@ -253,8 +262,9 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab
.withReadTimeoutMs(readTimeoutMs)
.withSpoolFolder(spoolFolder)
.withSSLKeyFile(sslKeyFile)
+ .withSSLKeyPassword(sslKeyPassword)
.withSSLChainFile(sslChainFile)
- .withSSLServerSubjectPattern(sslServerSubjectPattern).build()) {
+ .withSSLSubjectPattern(sslSubjectPattern).build()) {
execution.execute(client);
}
diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java
index b1e2d66..29adcba 100644
--- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java
+++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java
@@ -109,11 +109,13 @@ class StandbyServer implements AutoCloseable {
private String sslKeyFile;
+ private String sslKeyPassword;
+
private String sslChainFile;
private boolean sslClientValidation;
- public String sslClientSubjectPattern;
+ private String sslSubjectPattern;
private Builder(final int port, final StoreProvider storeProvider, final int blobChunkSize) {
this.port = port;
@@ -166,6 +168,11 @@ class StandbyServer implements AutoCloseable {
return this;
}
+ Builder withSSLKeyPassword(String sslKeyPassword) {
+ this.sslKeyPassword = sslKeyPassword;
+ return this;
+ }
+
Builder withSSLChainFile(String sslChainFile) {
this.sslChainFile = sslChainFile;
return this;
@@ -176,8 +183,8 @@ class StandbyServer implements AutoCloseable {
return this;
}
- Builder withSSLClientSubjectPattern(String sslClientSubjectPattern) {
- this.sslClientSubjectPattern = sslClientSubjectPattern;
+ Builder withSSLSubjectPattern(String sslSubjectPattern) {
+ this.sslSubjectPattern = sslSubjectPattern;
return this;
}
@@ -204,7 +211,6 @@ class StandbyServer implements AutoCloseable {
return new StandbyServer(this);
}
-
}
private StandbyServer(final Builder builder) throws CertificateException, SSLException {
@@ -212,7 +218,7 @@ class StandbyServer implements AutoCloseable {
if (builder.secure) {
if (builder.sslKeyFile != null && !"".equals(builder.sslKeyFile)) {
- sslContext = SslContextBuilder.forServer(new File(builder.sslChainFile), new File(builder.sslKeyFile)).build();
+ sslContext = SslContextBuilder.forServer(new File(builder.sslChainFile), new File(builder.sslKeyFile), builder.sslKeyPassword).build();
} else {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
@@ -244,8 +250,8 @@ class StandbyServer implements AutoCloseable {
handler.engine().setNeedClientAuth(builder.sslClientValidation);
p.addLast("ssl", handler);
- if (builder.sslClientSubjectPattern != null) {
- p.addLast(new SSLSubjectMatcher(builder.sslClientSubjectPattern));
+ if (builder.sslSubjectPattern != null) {
+ p.addLast(new SSLSubjectMatcher(builder.sslSubjectPattern));
}
}
diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java
index d547973..5917d5e 100644
--- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java
+++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java
@@ -69,7 +69,9 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto
private boolean sslValidateClient;
- public String sslClientSubjectPattern;
+ private String sslKeyPassword;
+
+ private String sslSubjectPattern;
private Builder() {
// Prevent external instantiation
@@ -132,6 +134,11 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto
return this;
}
+ public Builder withSSLKeyPassword(String sslKeyPassword) {
+ this.sslKeyPassword = sslKeyPassword;
+ return this;
+ }
+
public Builder withSSLChainFile(String sslChainFile) {
this.sslChainFile = sslChainFile;
return this;
@@ -142,8 +149,8 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto
return this;
}
- public Builder withSSLClientSubjectPattern(String sslClientSubjectPattern) {
- this.sslClientSubjectPattern = sslClientSubjectPattern;
+ public Builder withSSLSubjectPattern(String sslSubjectPattern) {
+ this.sslSubjectPattern = sslSubjectPattern;
return this;
}
@@ -153,7 +160,6 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto
checkArgument(blobChunkSize > 0);
return new StandbyServerSync(this);
}
-
}
private static final Logger log = LoggerFactory.getLogger(StandbyServer.class);
@@ -184,13 +190,15 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto
private StandbyServer server;
- private final String sslCertificate;
+ private final String sslKeyFile;
+
+ private final String sslKeyPassword;
- private final String sslChain;
+ private final String sslChainFile;
private final boolean sslValidateClient;
- private final String sslClientSubjectPattern;
+ private final String sslSubjectPattern;
private StandbyServerSync(Builder builder) {
this.port = builder.port;
@@ -202,10 +210,11 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto
this.standbyHeadReader = builder.standbyHeadReader;
this.standbyReferencesReader = builder.standbyReferencesReader;
this.standbySegmentReader = builder.standbySegmentReader;
- this.sslCertificate = builder.sslKeyFile;
- this.sslChain = builder.sslChainFile;
+ this.sslKeyFile = builder.sslKeyFile;
+ this.sslKeyPassword = builder.sslKeyPassword;
+ this.sslChainFile = builder.sslChainFile;
this.sslValidateClient = builder.sslValidateClient;
- this.sslClientSubjectPattern = builder.sslClientSubjectPattern;
+ this.sslSubjectPattern = builder.sslSubjectPattern;
this.observer = new CommunicationObserver("primary");
final MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer();
@@ -245,10 +254,11 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto
.withStandbyHeadReader(standbyHeadReader)
.withStandbyReferencesReader(standbyReferencesReader)
.withStandbySegmentReader(standbySegmentReader)
- .withSSLKeyFile(sslCertificate)
- .withSSLChainFile(sslChain)
+ .withSSLKeyFile(sslKeyFile)
+ .withSSLKeyPassword(sslKeyPassword)
+ .withSSLChainFile(sslChainFile)
.withSSLClientValidation(sslValidateClient)
- .withSSLClientSubjectPattern(sslClientSubjectPattern);
+ .withSSLSubjectPattern(sslSubjectPattern);
server = builder.build();
server.start();
diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java
index deeb6a1..8efbb9e 100644
--- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java
+++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java
@@ -39,6 +39,7 @@ import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.service.metatype.annotations.Option;
@@ -124,6 +125,12 @@ public class StandbyStoreService {
String sslKeyFile();
@AttributeDefinition(
+ name = "SSL Key Password",
+ description = "Password for the SSL key. If this is empty, an unencrypted key is expected.",
+ type = AttributeType.PASSWORD)
+ String sslKeyPassword() default "";
+
+ @AttributeDefinition(
name = "SSL Certificate Chain File",
description = "The file name which contains the SSL certificate chain."
)
@@ -136,16 +143,10 @@ public class StandbyStoreService {
boolean sslValidateClient() default false;
@AttributeDefinition(
- name = "SSL Server Certificate Subject Pattern",
- description = "The server certificate subject must match this pattern in order to be accepted by the client."
- )
- String sslServerSubjectPattern();
-
- @AttributeDefinition(
- name = "SSL Client Certificate Subject Pattern",
- description = "The client certificate subject must match this pattern in order to be accepted by the server."
+ name = "SSL Certificate Subject Pattern",
+ description = "The peer certificate's subject must match this pattern in order to be accepted."
)
- String sslClientSubjectPattern();
+ String sslSubjectPattern();
}
@Reference(policy = STATIC, policyOption = GREEDY)
@@ -190,7 +191,7 @@ public class StandbyStoreService {
String sslKeyFile = config.sslKeyFile();
String sslChainFile = config.sslChainFile();
boolean sslValidateClient = config.sslValidateClient();
- String sslClientSubjectPattern = config.sslClientSubjectPattern();
+ String sslSubjectPattern = config.sslSubjectPattern();
StandbyServerSync.Builder builder = StandbyServerSync.builder()
.withPort(port)
@@ -201,7 +202,11 @@ public class StandbyStoreService {
.withSSLKeyFile(sslKeyFile)
.withSSLChainFile(sslChainFile)
.withSSLClientValidation(sslValidateClient)
- .withSSLClientSubjectPattern(sslClientSubjectPattern);
+ .withSSLSubjectPattern(sslSubjectPattern);
+
+ if (!"".equals(config.sslKeyPassword())) {
+ builder.withSSLKeyPassword(config.sslKeyPassword());
+ }
StandbyServerSync standbyServerSync = builder.build();
@@ -224,7 +229,11 @@ public class StandbyStoreService {
.withSecureConnection(config.secure())
.withSSLKeyFile(config.sslKeyFile())
.withSSLChainFile(config.sslChainFile())
- .withSSLServerSubjectPattern(config.sslClientSubjectPattern());
+ .withSSLSubjectPattern(config.sslSubjectPattern());
+
+ if (!"".equals(config.sslKeyPassword())) {
+ builder.withSSLKeyPassword(config.sslKeyPassword());
+ }
StandbyClientSync standbyClientSync = builder.build();
closer.register(standbyClientSync);
diff --git a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java
index 8908891..b437b98 100644
--- a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java
+++ b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java
@@ -345,6 +345,99 @@ public class StandbyTestIT extends TestBase {
* This test syncs a few segments over an encrypted connection.
* The server has a configured certificate which can be validated with the truststore.
* The server validates the client certificate.
+ * The client has a configured certificate which can be validated with the truststore.
+ * All the keys are encrypted.
+ */
+ @Test
+ @Ignore("This test takes ~2s and is therefore disabled by default")
+ public void testSyncSSLValidClientEncryptedKeys() throws Exception {
+ int blobSize = 5 * MB;
+ FileStore primary = serverFileStore.fileStore();
+ FileStore secondary = clientFileStore.fileStore();
+
+ FileOutputStream fos;
+
+ File serverKeyFile = folder.newFile();
+ fos = new FileOutputStream(serverKeyFile);
+ IOUtils.writeString(fos, encryptedServerKey);
+ fos.close();
+
+ File clientKeyFile = folder.newFile();
+ fos = new FileOutputStream(clientKeyFile);
+ IOUtils.writeString(fos, encryptedClientKey);
+ fos.close();
+
+ File serverCertFile = folder.newFile();
+ fos = new FileOutputStream(serverCertFile);
+ IOUtils.writeString(fos, serverCert);
+ fos.close();
+
+ File clientCertFile = folder.newFile();
+ fos = new FileOutputStream(clientCertFile);
+ IOUtils.writeString(fos, clientCert);
+ fos.close();
+
+ File keyStoreFile = folder.newFile();
+ KeyStore keyStore = KeyStore.getInstance("JKS");
+ keyStore.load(null, "changeit".toCharArray());
+ Certificate c = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(caCert.getBytes()));
+ keyStore.setCertificateEntry("the-ca-cert", c);
+ keyStore.store(new FileOutputStream(keyStoreFile), "changeit".toCharArray());
+ System.setProperty("javax.net.ssl.trustStore", keyStoreFile.getAbsolutePath());
+
+ NodeStore store = SegmentNodeStoreBuilders.builder(primary).build();
+ try (
+ StandbyServerSync serverSync = StandbyServerSync.builder()
+ .withPort(serverPort.getPort())
+ .withFileStore(primary)
+ .withBlobChunkSize(MB)
+ .withSecureConnection(true)
+ .withSSLKeyFile(serverKeyFile.getAbsolutePath())
+ .withSSLKeyPassword(secretPassword)
+ .withSSLChainFile(serverCertFile.getAbsolutePath())
+ .withSSLClientValidation(true)
+ .build();
+ StandbyClientSync clientSync = StandbyClientSync.builder()
+ .withHost(getServerHost())
+ .withPort(serverPort.getPort())
+ .withFileStore(secondary)
+ .withSecureConnection(true)
+ .withReadTimeoutMs(getClientTimeout())
+ .withAutoClean(false)
+ .withSpoolFolder(folder.newFolder())
+ .withSSLKeyFile(clientKeyFile.getAbsolutePath())
+ .withSSLKeyPassword(secretPassword)
+ .withSSLChainFile(clientCertFile.getAbsolutePath())
+ .build()
+ ) {
+ serverSync.start();
+ byte[] data = addTestContent(store, "server", blobSize, 1);
+ primary.flush();
+
+ clientSync.run();
+
+ assertEquals(primary.getHead(), secondary.getHead());
+
+ assertTrue(primary.getStats().getApproximateSize() > blobSize);
+ assertTrue(secondary.getStats().getApproximateSize() > blobSize);
+
+ PropertyState ps = secondary.getHead().getChildNode("root")
+ .getChildNode("server").getProperty("testBlob");
+ assertNotNull(ps);
+ assertEquals(Type.BINARY.tag(), ps.getType().tag());
+ Blob b = ps.getValue(Type.BINARY);
+ assertEquals(blobSize, b.length());
+
+ byte[] testData = new byte[blobSize];
+ ByteStreams.readFully(b.getNewStream(), testData);
+ assertArrayEquals(data, testData);
+ }
+ }
+
+ /**
+ * This test syncs a few segments over an encrypted connection.
+ * The server has a configured certificate which can be validated with the truststore.
+ * The server validates the client certificate.
* The client has a configured certificate which cannot be validated with the truststore.
* The SSL connection is expected to fail.
*/
@@ -550,7 +643,7 @@ public class StandbyTestIT extends TestBase {
.withSSLKeyFile(serverKeyFile.getAbsolutePath())
.withSSLChainFile(serverCertFile.getAbsolutePath())
.withSSLClientValidation(true)
- .withSSLClientSubjectPattern("foobar")
+ .withSSLSubjectPattern("foobar")
.build();
StandbyClientSync clientSync = StandbyClientSync.builder()
.withHost(getServerHost())
@@ -628,7 +721,7 @@ public class StandbyTestIT extends TestBase {
.withSSLKeyFile(serverKeyFile.getAbsolutePath())
.withSSLChainFile(serverCertFile.getAbsolutePath())
.withSSLClientValidation(true)
- .withSSLClientSubjectPattern(".*.esting.*")
+ .withSSLSubjectPattern(".*.esting.*")
.build();
StandbyClientSync clientSync = StandbyClientSync.builder()
.withHost(getServerHost())
@@ -718,7 +811,7 @@ public class StandbyTestIT extends TestBase {
.withSpoolFolder(folder.newFolder())
.withSSLKeyFile(clientKeyFile.getAbsolutePath())
.withSSLChainFile(clientCertFile.getAbsolutePath())
- .withSSLServerSubjectPattern("foobar")
+ .withSSLSubjectPattern("foobar")
.build()
) {
serverSync.start();
@@ -796,7 +889,7 @@ public class StandbyTestIT extends TestBase {
.withSpoolFolder(folder.newFolder())
.withSSLKeyFile(clientKeyFile.getAbsolutePath())
.withSSLChainFile(clientCertFile.getAbsolutePath())
- .withSSLServerSubjectPattern(".*.esting.*")
+ .withSSLSubjectPattern(".*.esting.*")
.build()
) {
serverSync.start();
diff --git a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java
index 7a83709..e89e374 100644
--- a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java
+++ b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java
@@ -241,4 +241,99 @@ public class TestBase {
"pKHE9hkL/dxsEBXkVdaRHzrfxCBxsP3b3EmOJ4xdl1phGhedUk/+RUWGY8VSnyaq\n" +
"uVMy1feUqV+AebfUSPzPVubV\n" +
"-----END PRIVATE KEY-----\n";
+
+ static final String encryptedClientKey =
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
+ "MIIE6TAbBgkqhkiG9w0BBQMwDgQIZuy9oMDzt8wCAggABIIEyH7Rbg5VcLV/ZDqp\n" +
+ "AJ6tzPqMlnLVtspB/qk5nZRz2/n42yaqgO2eO7DJ5qNbBGZ6KzLosC6DHd1aXA7E\n" +
+ "8l5RTWQj0u16ANeKsjJ86o5/MRJkeUMh2tPLdVcG0e5nifgbWzXYpS6LuwKQpGEL\n" +
+ "ufSAWhF9BY1hMe58qzCFBsFjrd0tB232sDOnhopaLiO5tQ6h3iMvwK/EPXJGPKHX\n" +
+ "5++DlV/QNaENb/EsCvPlrRgpSWn6dAJ1kemKcvLbnHzTwK88B1n3GUr1B3Z+0jSV\n" +
+ "9IGNeIRVz97KGxW0v33SD1Kw4QpPH+PHH/HhmJ48Vv/mf1rINwA/yRE0iS89glhW\n" +
+ "NPh5O7HD2l2qZZDq74RUfvSzaW738/108ppck/uo+nOvEHnl346XJ7Etbp+fRYj1\n" +
+ "y/irfT7yZ1ZMUkms39M+yBwCp/AqdhvJemOLCAgSJcWWWsNnNqlQlJJsuvkcRPBr\n" +
+ "foYAsPWnZRcowZLyQ80gG5ZKoTa8Kyf/V2CuULHwYv16MLf0koLpGAEjd4QDLrun\n" +
+ "ybsRisrAFupgxNBLovyh6I4b97n0Qeotf/iIfmBOH7azYqpmvgJxNB6hNVwz2LAM\n" +
+ "JgnirRgY+FEdAyTd44/qPQpwXoz4ac3wrdGEU0oLwKk/J2bX1Eqh3tfziPycCO6v\n" +
+ "2IC3WGP59/ty3T1xA/LI0TqInAkUD+0Rkp1HhmPL4xEL/bGLL5FViFkybjO6pgoK\n" +
+ "xjq/dqTbrnmjyhVIjfdCbl2MFEsqUgemH/5J5o75P6mS0HOBaK6ERI9tM6dHz5Wk\n" +
+ "2AbwUUvEebLA6zR5+57dFKSQXhOOekRCQ9w8gDhPHMxyYp3YAdiFitweY/5Xhokt\n" +
+ "l3OXtLPNiqONcYp/Xkz5/CgsjoIHDGgQGy4sWYUQYCdAFXP8/ogR4zVpsUBP0Hjv\n" +
+ "9isg5MlXEEj+YOFYQr/HbON9zxP4LhzuYUWynvVJDfPxY1x7JI+aequHZRPj9Qct\n" +
+ "X6Va5c+G8q87fj/qCJCplGslhJsxBidTQw88+wNeVAVPd+456bszwIE5ey7glvTb\n" +
+ "gwmU4mXDm75T+PW3Y7Gz1HZ9ZCMuUBelBEKxVSOOXCxkO4zzfI9PVxVzkqfurVOO\n" +
+ "9R9i3gV3J6rQj98XtbvBTSrq9nylnzRiFSP2T0aRNLVRmGBahm9YIK+kll/VM2uL\n" +
+ "VzUYPJv22Q/cXR2lkwNFbScOGNzJ3UXiuWOM1CkBgadoHpKhmD4IypvMpA/B0tTL\n" +
+ "l4kL0z7Cg50kXYY77pl6cxorRnPs9fTpPWTPymqWp8Se+pfn/Fxqz11xD0P45Rlo\n" +
+ "0CHLS3536c2zX3/1Uh4ZIGTAwoWeiCfizTnaS7GbIniqJ1/KVx9L5gIu/uWHGSnY\n" +
+ "sU/gOHQw+HxkYGXYI5AqWUp79CZUEnKsNVZDAexKWraG3TBJSydZcyl3OcEfez+f\n" +
+ "ISw//WpK5Wc+Zc+KabT8eWGwN1bIV/5HP1hSx6kggtQBs6BSkEDirzzzvQeIvdol\n" +
+ "ddjGSudEjO2EBE25utg+5omiR8uCQwwInNNOr2otMikmWRgQ3AuIuqxYAF0qH1+f\n" +
+ "n6ePw/b30oy4xIKWz8Kxrn8oPLYgs1Dl3lF6LjRwq1urC2leYb6ZPaX5QjdarMJp\n" +
+ "sxOT5nOmsaG0vinlsQ==\n" +
+ "-----END ENCRYPTED PRIVATE KEY-----";
+
+ static final String encryptedServerKey =
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
+ "MIIE6TAbBgkqhkiG9w0BBQMwDgQIto3hFjULIx0CAggABIIEyNWG0f8x6yY3XeE+\n" +
+ "WZjuFYe5WG4ftC8hvKgYCY1NhkFSH3R4FIkAdRanuskUI9rU6tzXEEVKpnsMNTf5\n" +
+ "AhQz/bI4fdu57vyz/ujwmdBMtP9m5hBjyfcJq6w/g1bECC6garbeTYvXgUljyV1n\n" +
+ "h8WQ4rClFhAZ1Qrujc6DTd63BGVoGxY+Jxe6FA2mZj2Z1bCsiWFGU0ShnU+QDF/O\n" +
+ "2SPcHHy37uckIdSrSFAuY8+iwQ5fL5mRH3Gw1CopQY07R8RKyRKpuZV56zJDXmGv\n" +
+ "j0NfJul26EmqXJSTLJyMlYdIP+xSPo50qTWqOl7w37fRcAw7duVP2jIlHJEJD9Y1\n" +
+ "UJe4ypihLp402Amw19wnsaxwk9PDDUd7kN1xFQMJ/eVF5k2hEL3m+2g6PbuFoSHt\n" +
+ "FVQEMDGqeAIPvrUr9FwO0qU7x0hJ1ce/v6IyYhJwbuVDzUFP0nHalTSVM/lXOshO\n" +
+ "dUqY97hOMh+q9drNUCQM08gq3XD/HQP/zA6LYH+X9Ts9Y0R+cocOXwbxc2jKAimo\n" +
+ "MwmP9bSD9MPabGGTv4ZeTVK9JTq4uetCk3ehqNEpS7d69bq0pJ3F6xvGaL7GjiQA\n" +
+ "8YyEUFtbyaBDgg4iwIiPsy/jo7h6Gj1Io/TjcDnp38h1YMTrER2nljB8lSm3t7DA\n" +
+ "5KOzLKHvvB8gUfMiM3OzbIcXtBJIWWidELToqEljAVHWt054yaI4oX1laHOa3zPG\n" +
+ "yriTUARkp5lA2llrm9E1AevlOxpUz3cr94ohvSI40QZgehcvraHJ7FCP7SUi54uY\n" +
+ "o7MRDe27zLsjYRoSLD6saSFL1XigjCa4dpOu3yN8q/R0NyjmBySxOlPbglyl/OmD\n" +
+ "czWFvUQcHcuSsPosbp30nsDD5SIGY6p+XR8tqJdKrCh+vgFlQPb1OkvGcXD7uzjI\n" +
+ "0jYVc23pUwrM3oynAjll2uEBlMfHsdYTB5ehv/sp7tqnc3/VbPhW9WOercbQvVnq\n" +
+ "Gb13aL4ra94glERJFH5LitvmjkylD6tjOttDONYg9ow1dA5g2q/A7WD0UV4TrW2w\n" +
+ "LRze30kKG2p94DE1if54VMA91QLhU3YwntDSk8jZ6bO7rG91d98npwHWZfMzJI6J\n" +
+ "blHM5gaAmHCTvwX6/Px/tS+8HmG5l8BBBqz70gh24uYjMgsTWsfRsjfypBmXzEFt\n" +
+ "JiFJIBwGQ0uHDM2JXqIdCf1em875eK3XR6qvrQDPiA5HVXFaGdRGbx0aK7lzDHrn\n" +
+ "7cn02kNLb4/kbZnpj04p7/j6dpfGLMnkSH7Pxx4f0cfirfDvcZQwjpl/n4bHnIxT\n" +
+ "Qv6XWq67dQObvbiCZF14CayEEqNU6Q9wq+EBji2739FhAAbZ0P1Uj792wk50tOgg\n" +
+ "+EqXzCGaqSRn7RrMEiQQTGBson9L6aBlNxyBRH6LMLAsvcKzlYB5zMQHwObd/eaU\n" +
+ "43WdwOly9CLeJbTpPNvZoeDGT7jdin3XiuauMnDa4W1wwKHKgpbD543ScZfIkNm1\n" +
+ "Wcibp27rE4/5eIsNyQnxkDRN7f3x0a9iwhlgrToXGabileLsonx3Jdf/YXgiqiQY\n" +
+ "4lLGr4EIVjKg8YbJvpnrEZQNeTHwPr8/N5N51VZvoVePBq/ZnBi9EK/aCL+f+0Dx\n" +
+ "yZio9eDGsuOXwR7iOg==\n" +
+ "-----END ENCRYPTED PRIVATE KEY-----";
+
+ static final String encryptedArbitraryKey =
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
+ "MIIE6TAbBgkqhkiG9w0BBQMwDgQIT+Z6cmw0caMCAggABIIEyCCZWzPzrAGr7nsi\n" +
+ "ifNxQbX0GO6wYb3ND7yinc/0Yw+d38l0S5LTLg+5GD7SbXfoMmC44rUxSGnBV5Bj\n" +
+ "/bUW30B/s0+I3Ya1pXXyVP98vjy71Pspw/sHH3tYU73fPdqzh538Jf9qEgqgaJej\n" +
+ "MRdiQfQmXexmkyeWAYQutbONrwfuH8NqLGxuPjrc21WjKkijnv9X8CuUk6M1MCPc\n" +
+ "jN2iPhTsYiOkgKkyjF817792jDBYJHtoOuG5OmhSAdw6I3Tm5TRqAO/6IGPuDqWb\n" +
+ "7ho3ZyLBxBaLHTOawQkGm842lhwn5fACCCYNGsQhVGdbZN4KVgSYzJwvGw8vaawE\n" +
+ "VhD+zcDzhAydlhMXwFxDMgoZD5qRZujuDoBLgBYrDFDDEUfDNoUJSmWPpHXVc2tq\n" +
+ "RBiP3xb152lWiqRcXLZVHfXfxT79qZAxvlRBUgYEA/u2ud3p2/7R9UBvRzE6P6IA\n" +
+ "9ZuO6CgJgGvHXY2u721/MvvhY/75X1c1t0VJsdU2H6+E34QDtSqmQD08zBlZw5TK\n" +
+ "qltQpxgjMO1jtdEuHWPbR5Aoa5smOL9qBleptSGsm0I5zET+hv4y3f5AHIx3X3xy\n" +
+ "UH6Nw30oQtSbbZzPX4sqZuzA66W9Z4yW3Pn1EYcpuacypty/gvRZrvnwb6gYNB+h\n" +
+ "XTTaikNiGebcAZhSukcKmL3mjlpbUZC3Bjbz5AstZJyd0tMSaw0E4C8VQQHYyX5X\n" +
+ "lteW1O2TvHyGdeb0LNwsXzIMqsqmgsuNsms12Xx7KurxhPGk3Za2SdXQUASSryWX\n" +
+ "XPlKxlQDDM9DvSQsRw6BCUoUKZ/2YiXnnL/zrY1+xegXumwolgT8Dsu6CFxvzT7E\n" +
+ "16/4FeaVDB0/A5nmR71gkwm/b/JJL/Qj0H+E0rhCyZJeW9ddg4IWolEFTvCrVmHG\n" +
+ "gZ8DQIHJHSPilG8gdjzJ8cs89pctswnjuLMI2wT2/jqtM76Ibr9d0eIB6CzT17dh\n" +
+ "ASchmnUUXgjY/djAO8M3LuMUgu6OTCpIwAjfz7DOaakI42Dvrz0sTCkBwjD3XY7v\n" +
+ "1EyxoxCPoxTlHE1BLNgT5OD0B9SPC9aQLt+DOcDXVh8vQvIGtqMbxthIoi61XTeo\n" +
+ "sm35wkdiC0wSCgqPKIiz/LcyaWcOwbK2F7Q1dKluBT29L6X35FLqbp8RNZLJSX18\n" +
+ "53gJJLH4Hd7XcAn2Sat+vyuY3Z3vNiFMmx+vbho3ZgGL5KTNdmpN1fM7EqpGOUfp\n" +
+ "easRPOw3P1KuVqTVCvm/osf4VniV3xCvgwffJ/kOlHChnIrHGZpeBFmiV4xk7ucb\n" +
+ "7PSVt8BLV2+krXSTijFepeuVckitj3Kf4o++WePE6wlPi0rPYG47IE10xHojSKgr\n" +
+ "xdEonxiGL07/MEdI9+9PHLg5+ZakymRmMnEcJdpd7+WxaFy8jhvCCZ+7ppZBpYQC\n" +
+ "azdkciNz9d/YZRQH5M6VGk1VqqkQbenasUuZpXAxDOraLPlq801JyYyPqeROAgb8\n" +
+ "hTQXseAe+7lHWpmUGKuN0Y9EcV/3fiAP+PeMt/QXeGF5jcRVGWLs6nDVOaBQ/SB3\n" +
+ "syFXwJR6WtajR5OC7dEGZPTxaNfiu4GFuE73i3cVEJH2MH7+c/yB/40RJQdJ4kd6\n" +
+ "7KJYwr8P4TrNulM60Q==\n" +
+ "-----END ENCRYPTED PRIVATE KEY-----\n";
+
+ static final String secretPassword = "secret";
}