From d8ecac31301960d58a6dc856939a97d709e82773 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Tue, 03 May 2016 09:43:02 +0000
Subject: [PATCH] OPENDJ-2617 Add confidentiality (encryption) option for replication changelog
---
opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java | 5
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java | 17 +
opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java | 4
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java | 9
opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java | 5
opendj-server-legacy/src/messages/org/opends/messages/replication.properties | 5
opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java | 25 +-
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java | 78 ++++++-
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java | 8
opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java | 85 ++++----
opendj-server-legacy/resource/schema/02-config.ldif | 5
opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java | 41 +++-
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java | 3
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java | 7
opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java | 24 ++
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java | 5
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java | 4
opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java | 20 ++
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml | 100 +++++++++++
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java | 35 ++-
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java | 7
opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java | 3
opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java | 3
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java | 6
24 files changed, 379 insertions(+), 125 deletions(-)
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml
index cec8277..00ece7b 100644
--- a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml
@@ -13,7 +13,7 @@
information: "Portions Copyright [year] [name of copyright owner]".
Copyright 2007-2010 Sun Microsystems, Inc.
- Portions copyright 2011-2015 ForgeRock AS.
+ Portions copyright 2011-2016 ForgeRock AS.
! -->
<adm:managed-object name="replication-server"
plural-name="replication-servers"
@@ -368,4 +368,102 @@
</ldap:attribute>
</adm:profile>
</adm:property>
+ <adm:property name="cipher-transformation">
+ <adm:synopsis>
+ Specifies the cipher for the directory server.
+ The syntax is "algorithm/mode/padding".
+ </adm:synopsis>
+ <adm:description>
+ The full transformation is required: specifying only an algorithm
+ and allowing the cipher provider to supply the default mode and
+ padding is not supported, because there is no guarantee these
+ default values are the same among different implementations.
+ Some cipher algorithms, including RC4 and ARCFOUR, do not have a
+ mode or padding, and hence must be specified using NONE for the
+ mode field and NoPadding for the padding field. For example,
+ RC4/NONE/NoPadding.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:none>
+ <adm:synopsis>
+ Changes to this property take effect immediately but
+ only affect cryptographic operations performed after the
+ change.
+ </adm:synopsis>
+ </adm:none>
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>AES/CBC/PKCS5Padding</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-cipher-transformation</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="cipher-key-length">
+ <adm:synopsis>
+ Specifies the key length in bits for the preferred cipher.
+ </adm:synopsis>
+ <adm:requires-admin-action>
+ <adm:none>
+ <adm:synopsis>
+ Changes to this property take effect immediately but
+ only affect cryptographic operations performed after the
+ change.
+ </adm:synopsis>
+ </adm:none>
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>128</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:integer />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-cipher-key-length</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="confidentiality-enabled">
+ <adm:synopsis>
+ Indicates whether the replication change-log should make records readable only by Directory Server.
+ Throughput and disk space are affected by the more expensive operations taking place.
+ </adm:synopsis>
+ <adm:description>
+ Confidentiality is achieved by encrypting records on all domains managed by this replication server.
+ Encrypting the records prevents unauthorized parties from accessing contents of LDAP operations.
+ For complete protection, consider enabling secure communications between servers.
+ Change number indexing is not affected by the setting.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:none>
+ <adm:synopsis>
+ Changes to this property take effect immediately but
+ only affect operations performed after the change.
+ </adm:synopsis>
+ </adm:none>
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>false</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean/>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-confidentiality-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
</adm:managed-object>
diff --git a/opendj-server-legacy/resource/schema/02-config.ldif b/opendj-server-legacy/resource/schema/02-config.ldif
index 6926c4c..f4e4fba 100644
--- a/opendj-server-legacy/resource/schema/02-config.ldif
+++ b/opendj-server-legacy/resource/schema/02-config.ldif
@@ -4560,7 +4560,10 @@
ds-cfg-weight $
ds-cfg-monitoring-period $
ds-cfg-compute-change-number $
- ds-cfg-source-address )
+ ds-cfg-source-address $
+ ds-cfg-cipher-transformation $
+ ds-cfg-cipher-key-length $
+ ds-cfg-confidentiality-enabled)
X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.65
NAME 'ds-backup-directory'
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
index 00fd5bb..e9980bd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
@@ -108,11 +108,10 @@
private MatchingRuleIndex(EntryContainer entryContainer, AttributeType attributeType, State state, Indexer indexer,
int indexEntryLimit, boolean encryptValues, CryptoSuite cryptoSuite)
{
- super(getIndexName(entryContainer, attributeType, indexer.getIndexID()), state, indexEntryLimit, entryContainer);
+ super(getIndexName(entryContainer, attributeType, indexer.getIndexID()), state, indexEntryLimit, entryContainer,
+ cryptoSuite);
this.attributeType = attributeType;
this.indexer = indexer;
- this.encryptValues = encryptValues;
- this.cryptoSuite = cryptoSuite;
}
Set<ByteString> indexEntry(Entry entry)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java
index 75538b0..7dbedef 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java
@@ -53,7 +53,6 @@
private int indexEntryLimit;
private EntryIDSetCodec codec;
- protected boolean encryptValues;
protected CryptoSuite cryptoSuite;
/**
@@ -79,16 +78,18 @@
* The configured limit on the number of entry IDs that may be indexed by one key.
* @param entryContainer
* The entryContainer holding this index.
+ * @param cryptoSuite
* @throws StorageRuntimeException
* If an error occurs in the storage.
*/
- DefaultIndex(TreeName name, State state, int indexEntryLimit, EntryContainer entryContainer)
+ DefaultIndex(TreeName name, State state, int indexEntryLimit, EntryContainer entryContainer, CryptoSuite cryptoSuite)
throws StorageRuntimeException
{
super(name);
this.indexEntryLimit = indexEntryLimit;
this.state = state;
this.entryContainer = entryContainer;
+ this.cryptoSuite = cryptoSuite;
}
@Override
@@ -96,7 +97,7 @@
{
final EnumSet<IndexFlag> flags = state.getIndexFlags(txn, getName());
codec = flags.contains(COMPACTED) ? CODEC_V2 : CODEC_V1;
- if (encryptValues)
+ if (cryptoSuite.isEncrypted())
{
codec = new EntryIDSet.EntryIDSetCodecV3(codec, cryptoSuite);
}
@@ -154,12 +155,14 @@
// Keeps temporary values during import encrypted even in on-disk buffers.
long importDecodeValue(ByteString value)
{
- return encryptValues ? decodeValue(ByteString.empty(), value).iterator().next().longValue() : value.toLong();
+ return cryptoSuite.isEncrypted()
+ ? decodeValue(ByteString.empty(), value).iterator().next().longValue()
+ : value.toLong();
}
ByteString importToValue(EntryID entryID)
{
- return encryptValues ? toValue(newDefinedSet(entryID.longValue())) : entryID.toByteString();
+ return cryptoSuite.isEncrypted() ? toValue(newDefinedSet(entryID.longValue())) : entryID.toByteString();
}
@Override
@@ -293,9 +296,7 @@
@Override
public boolean setConfidential(boolean indexConfidential)
{
- final boolean rebuildRequired = !this.encryptValues && indexConfidential;
- this.encryptValues = indexConfidential;
- return rebuildRequired;
+ return cryptoSuite.isEncrypted() != indexConfidential;
}
@Override
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
index 8e71e8a..c2bd410 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
@@ -154,6 +154,8 @@
/** The set of attribute indexes. */
private final Map<AttributeType, AttributeIndex> attrIndexMap = new HashMap<>();
+
+ private final Map<AttributeType, CryptoSuite> attrCryptoMap = new HashMap<>();
/** The set of VLV (Virtual List View) indexes. */
private final Map<String, VLVIndex> vlvIndexMap = new HashMap<>();
@@ -165,8 +167,6 @@
private final ServerContext serverContext;
- private CryptoSuite cryptoSuite;
-
/**
* This class is responsible for managing the configuration for attribute
* indexes used within this entry container.
@@ -180,7 +180,7 @@
{
try
{
- newAttributeIndex(cfg);
+ newAttributeIndex(cfg, null);
return true;
}
catch(Exception e)
@@ -196,7 +196,8 @@
final ConfigChangeResult ccr = new ConfigChangeResult();
try
{
- final AttributeIndex index = newAttributeIndex(cfg);
+ final CryptoSuite cryptoSuite = newCryptoSuite(cfg.isConfidentialityEnabled());
+ final AttributeIndex index = newAttributeIndex(cfg, cryptoSuite);
storage.write(new WriteOperation()
{
@Override
@@ -209,6 +210,7 @@
ccr.addMessage(NOTE_INDEX_ADD_REQUIRES_REBUILD.get(cfg.getAttribute().getNameOrOID()));
}
attrIndexMap.put(cfg.getAttribute(), index);
+ attrCryptoMap.put(cfg.getAttribute(), cryptoSuite);
}
});
}
@@ -242,6 +244,7 @@
public void run(WriteableTransaction txn) throws Exception
{
attrIndexMap.remove(cfg.getAttribute()).closeAndDelete(txn);
+ attrCryptoMap.remove(cfg.getAttribute());
}
});
}
@@ -370,7 +373,13 @@
config.addBackendVLVIndexDeleteListener(vlvIndexCfgManager);
}
- private AttributeIndex newAttributeIndex(BackendIndexCfg cfg) throws ConfigException
+ private CryptoSuite newCryptoSuite(boolean confidentiality)
+ {
+ return serverContext.getCryptoManager().newCryptoSuite(config.getCipherTransformation(),
+ config.getCipherKeyLength(), confidentiality);
+ }
+
+ private AttributeIndex newAttributeIndex(BackendIndexCfg cfg, CryptoSuite cryptoSuite) throws ConfigException
{
return new AttributeIndex(cfg, state, this, cryptoSuite);
}
@@ -381,7 +390,8 @@
.compress(config.isEntriesCompressed())
.encode(config.isCompactEncoding())
.encrypt(config.isConfidentialityEnabled())
- .cryptoSuite(cryptoSuite)
+ .cryptoSuite(serverContext.getCryptoManager().newCryptoSuite(config.getCipherTransformation(),
+ config.getCipherKeyLength(),config.isConfidentialityEnabled()))
.schema(rootContainer.getCompressedSchema())
.build();
}
@@ -404,8 +414,6 @@
boolean shouldCreate = accessMode.isWriteable();
try
{
- cryptoSuite = serverContext.getCryptoManager().newCryptoSuite(config.getCipherTransformation(),
- config.getCipherKeyLength());
id2entry = new ID2Entry(getIndexName(ID2ENTRY_TREE_NAME), newDataConfig(config));
id2entry.open(txn, shouldCreate);
id2childrenCount.open(txn, shouldCreate);
@@ -417,13 +425,15 @@
{
BackendIndexCfg indexCfg = config.getBackendIndex(idx);
- final AttributeIndex index = newAttributeIndex(indexCfg);
+ CryptoSuite cryptoSuite = newCryptoSuite(indexCfg.isConfidentialityEnabled());
+ final AttributeIndex index = newAttributeIndex(indexCfg, cryptoSuite);
index.open(txn, shouldCreate);
if(!index.isTrusted())
{
logger.info(NOTE_INDEX_ADD_REQUIRES_REBUILD, index.getName());
}
attrIndexMap.put(indexCfg.getAttribute(), index);
+ attrCryptoMap.put(indexCfg.getAttribute(), cryptoSuite);
}
for (String idx : config.listBackendVLVIndexes())
@@ -2386,13 +2396,14 @@
@Override
public void run(WriteableTransaction txn) throws Exception
{
- cryptoSuite.setCipherTransformation(cfg.getCipherTransformation());
- cryptoSuite.setCipherKeyLength(cfg.getCipherKeyLength());
id2entry.setDataConfig(newDataConfig(cfg));
-
EntryContainer.this.config = cfg;
}
});
+ for (CryptoSuite indexCrypto : attrCryptoMap.values())
+ {
+ indexCrypto.newParameters(cfg.getCipherTransformation(), cfg.getCipherKeyLength(), indexCrypto.isEncrypted());
+ }
}
catch (Exception e)
{
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
index 8a69589..04c921f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
@@ -2752,8 +2752,8 @@
}
@Override
- public CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength)
+ public CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength, boolean encrypt)
{
- return new CryptoSuite(this, cipherTransformation, cipherKeyLength);
+ return new CryptoSuite(this, cipherTransformation, cipherKeyLength, encrypt);
}
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java
index d6f3e67..e1bc522 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java
@@ -15,6 +15,7 @@
*/
package org.opends.server.crypto;
+import net.jcip.annotations.Immutable;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
@@ -33,8 +34,23 @@
/** Defines cipher transformation and hash algorithm for cryptographic related operations. */
public class CryptoSuite
{
- private String cipherTransformation;
- private int cipherKeyLength;
+ /** Cipher specific settings that can change at runtime. */
+ @Immutable
+ private static final class CipherInfo
+ {
+ private final String cipherTransformation;
+ private final int cipherKeyLength;
+ private final boolean encrypt;
+
+ CipherInfo(String cipherTransformation, int cipherKeyLength, boolean encrypt)
+ {
+ this.cipherTransformation = cipherTransformation;
+ this.cipherKeyLength = cipherKeyLength;
+ this.encrypt = encrypt;
+ }
+ }
+
+ private volatile CipherInfo cipherInfo;
private final CryptoManager cryptoManager;
/**
@@ -42,52 +58,24 @@
* @param cryptoManager the CryptoManager to use for cryptographic operations
* @param cipherTransformation the initial cipher transformation
* @param cipherKeyLength the initial key length for the cipher
+ * @param encrypt if the user of the crypto suite needs encryption
*/
- public CryptoSuite(CryptoManager cryptoManager, String cipherTransformation, int cipherKeyLength)
+ public CryptoSuite(CryptoManager cryptoManager, String cipherTransformation, int cipherKeyLength, boolean encrypt)
{
this.cryptoManager = cryptoManager;
- this.cipherTransformation = cipherTransformation;
- this.cipherKeyLength = cipherKeyLength;
+ this.cipherInfo = new CipherInfo(cipherTransformation, cipherKeyLength, encrypt);
}
/**
- * Returns the cipher transformation to use.
- *
- * @return the cipher transformation to use
- */
- public String getCipherTransformation()
- {
- return cipherTransformation;
- }
-
- /**
- * Returns the cipher key length to use.
- *
- * @return the cipher key length to use
- */
- public int getCipherKeyLength()
- {
- return cipherKeyLength;
- }
-
- /**
- * Sets the cipher transformation for the CryptoSuite.
+ * Set new cipher and enable parameters for the crypto suite.
*
* @param cipherTransformation the new cipher transformation
- */
- public void setCipherTransformation(String cipherTransformation)
- {
- this.cipherTransformation = cipherTransformation;
- }
-
- /**
- * Sets the key length for the CryptoSuite.
- *
* @param cipherKeyLength the new key length
+ * @param enabled true if the user of the crypto suite needs encryption
*/
- public void setCipherKeyLength(int cipherKeyLength)
+ public void newParameters(String cipherTransformation, int cipherKeyLength, boolean enabled)
{
- this.cipherKeyLength = cipherKeyLength;
+ cipherInfo = new CipherInfo(cipherTransformation, cipherKeyLength, enabled);
}
/**
@@ -113,7 +101,8 @@
*/
public byte[] encrypt(byte[] data) throws GeneralSecurityException, CryptoManagerException
{
- return cryptoManager.encrypt(cipherTransformation, cipherKeyLength, data);
+ CipherInfo currentCipher = cipherInfo;
+ return cryptoManager.encrypt(currentCipher.cipherTransformation, currentCipher.cipherKeyLength, data);
}
/**
@@ -127,7 +116,8 @@
*/
public CipherOutputStream getCipherOutputStream(OutputStream os) throws CryptoManagerException
{
- return cryptoManager.getCipherOutputStream(cipherTransformation, cipherKeyLength, os);
+ CipherInfo currentCipher = cipherInfo;
+ return cryptoManager.getCipherOutputStream(currentCipher.cipherTransformation, currentCipher.cipherKeyLength, os);
}
/**
@@ -162,14 +152,27 @@
}
}
+ /**
+ * Returns whether the user of the crypto suite needs encryption.
+ *
+ * @return true if the user of the crypto suite needs encryption
+ */
+ public boolean isEncrypted()
+ {
+ return cipherInfo.encrypt;
+ }
+
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
+ CipherInfo currentCipher = cipherInfo;
builder.append("CryptoSuite(cipherTransformation=");
- builder.append(cipherTransformation);
+ builder.append(currentCipher.cipherTransformation);
builder.append(", keyLength=");
- builder.append(cipherKeyLength);
+ builder.append(currentCipher.cipherKeyLength);
+ builder.append(", encrypt=");
+ builder.append(currentCipher.encrypt);
builder.append(")");
return builder.toString();
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java
index 75d825f..bb0f2bd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java
@@ -12,7 +12,7 @@
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2006-2010 Sun Microsystems, Inc.
- * Portions copyright 2013-2014 ForgeRock AS.
+ * Portions copyright 2013-2016 ForgeRock AS.
*/
package org.opends.server.replication.protocol;
@@ -27,6 +27,9 @@
*/
public abstract class ReplicationMsg
{
+ /** Reserved type for uses other than protocol messages. */
+ public static final byte MSG_TYPE_DISK_ENCODING = -1;
+
// PDU type values kept for compatibility with replication protocol version 1
static final byte MSG_TYPE_MODIFY_V1 = 1;
static final byte MSG_TYPE_ADD_V1 = 2;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
index f58a2c0..01377c6 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
@@ -53,6 +53,7 @@
import org.opends.server.api.VirtualAttributeProvider;
import org.opends.server.backends.ChangelogBackend;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.crypto.CryptoSuite;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.MultiDomainServerState;
import org.opends.server.replication.common.ServerState;
@@ -129,6 +130,8 @@
*/
private static final List<ReplicationServer> allInstances = new ArrayList<>();
+ private final CryptoSuite cryptoSuite;
+
/**
* Creates a new Replication server using the provided configuration entry.
*
@@ -170,7 +173,10 @@
this.domainPredicate = predicate;
enableExternalChangeLog();
- this.changelogDB = new FileChangelogDB(this, config.getReplicationDBDirectory());
+ cryptoSuite = DirectoryServer.getInstance().getServerContext().getCryptoManager().
+ newCryptoSuite(cfg.getCipherTransformation(), cfg.getCipherKeyLength(), cfg.isConfidentialityEnabled());
+
+ this.changelogDB = new FileChangelogDB(this, config.getReplicationDBDirectory(), cryptoSuite);
replSessionSecurity = new ReplSessionSecurity();
initialize();
@@ -871,6 +877,9 @@
}
}
+ cryptoSuite.newParameters(config.getCipherTransformation(), config.getCipherKeyLength(),
+ config.isConfidentialityEnabled());
+
// changing the listen port requires to stop the listen thread
// and restart it.
if (getReplicationPort() != oldConfig.getReplicationPort())
@@ -1337,6 +1346,15 @@
return MultimasterReplication.isECLEnabled();
}
+ /**
+ * Return whether change-log records should be encrypted.
+ * @return trus if change-log records should be encrypted
+ */
+ public boolean isEncrypted()
+ {
+ return config.isConfidentialityEnabled();
+ }
+
@Override
public String toString()
{
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java
index dcc93de..526f542 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java
@@ -11,7 +11,7 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2014-2015 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
*/
package org.opends.server.replication.server.changelog.file;
@@ -123,7 +123,7 @@
write(parser.encodeRecord(record));
writer.flush();
}
- catch (IOException e)
+ catch (Exception e)
{
throw new ChangelogException(ERR_CHANGELOG_UNABLE_TO_ADD_RECORD.get(record.toString(),
writer.getFile().getPath()), e);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java
index c9ec958..642c29d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java
@@ -17,6 +17,7 @@
import static org.opends.messages.ReplicationMessages.*;
+import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -388,7 +389,7 @@
private static final byte STRING_SEPARATOR = 0;
@Override
- public ByteString encodeRecord(final Record<Long, ChangeNumberIndexRecord> record)
+ public ByteString encodeRecord(final Record<Long, ChangeNumberIndexRecord> record) throws IOException
{
final ChangeNumberIndexRecord cnIndexRecord = record.getValue();
return new ByteStringBuilder()
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
index defe9e2..2ea1b35 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
@@ -42,6 +42,7 @@
import org.forgerock.util.time.TimeService;
import org.opends.server.api.DirectoryThread;
import org.opends.server.backends.ChangelogBackend;
+import org.opends.server.crypto.CryptoSuite;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.MultiDomainServerState;
import org.opends.server.replication.common.ServerState;
@@ -116,6 +117,7 @@
private static final DBCursor<UpdateMsg> EMPTY_CURSOR_REPLICA_DB =
new FileReplicaDBCursor(EMPTY_CURSOR, null, AFTER_MATCHING_KEY);
+ private final CryptoSuite cryptoSuite;
/**
* Creates a new changelog DB.
*
@@ -123,14 +125,17 @@
* the local replication server.
* @param dbDirectoryPath
* the path where the changelog files reside.
+ * @param cryptoSuite
+ * the cryptosuite to use for encryption
* @throws ConfigException
* if a problem occurs opening the supplied directory
*/
- public FileChangelogDB(final ReplicationServer replicationServer, String dbDirectoryPath)
+ public FileChangelogDB(final ReplicationServer replicationServer, String dbDirectoryPath, CryptoSuite cryptoSuite)
throws ConfigException
{
this.replicationServer = replicationServer;
this.dbDirectory = makeDir(dbDirectoryPath);
+ this.cryptoSuite = cryptoSuite;
}
private File makeDir(final String dbDirName) throws ConfigException
@@ -266,7 +271,7 @@
return null;
}
- final FileReplicaDB newDB = new FileReplicaDB(serverId, baseDN, server, replicationEnv);
+ final FileReplicaDB newDB = new FileReplicaDB(serverId, baseDN, server, cryptoSuite, replicationEnv);
domainMap.put(serverId, newDB);
return Pair.of(newDB, true);
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java
index 23228b8..709b87e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java
@@ -16,7 +16,10 @@
package org.opends.server.replication.server.changelog.file;
import static org.opends.messages.ReplicationMessages.*;
+import static org.opends.server.replication.protocol.ProtocolVersion.REPLICATION_PROTOCOL_V7;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -24,12 +27,13 @@
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ByteStringBuilder;
import org.opends.server.api.MonitorData;
import org.forgerock.opendj.server.config.server.MonitorProviderCfg;
import org.opends.server.api.MonitorProvider;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.crypto.CryptoSuite;
import org.opends.server.replication.common.CSN;
-import org.opends.server.replication.protocol.ProtocolVersion;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.server.ReplicationServerDomain;
@@ -39,6 +43,7 @@
import org.opends.server.replication.server.changelog.api.DBCursor.PositionStrategy;
import org.opends.server.replication.server.changelog.file.Log.RepositionableCursor;
import org.forgerock.opendj.ldap.DN;
+import org.opends.server.types.CryptoManagerException;
import org.opends.server.types.InitializationException;
/**
@@ -54,10 +59,6 @@
*/
class FileReplicaDB
{
-
- /** The parser of records stored in Replica DB. */
- static final RecordParser<CSN, UpdateMsg> RECORD_PARSER = new ReplicaDBParser();
-
/** Class that allows atomically setting oldest and newest CSNs without synchronization. */
@Immutable
private static final class CSNLimits
@@ -105,13 +106,13 @@
* If a database problem happened
*/
FileReplicaDB(final int serverId, final DN baseDN, final ReplicationServer replicationServer,
- final ReplicationEnvironment replicationEnv) throws ChangelogException
+ final CryptoSuite cryptoSuite, final ReplicationEnvironment replicationEnv) throws ChangelogException
{
this.serverId = serverId;
this.baseDN = baseDN;
this.replicationServer = replicationServer;
this.replicationEnv = replicationEnv;
- this.log = createLog(replicationEnv);
+ this.log = createLog(replicationEnv, cryptoSuite);
this.csnLimits = new CSNLimits(readOldestCSN(), readNewestCSN());
DirectoryServer.deregisterMonitorProvider(dbMonitor);
@@ -130,10 +131,11 @@
return record == null ? null : record.getKey();
}
- private Log<CSN, UpdateMsg> createLog(final ReplicationEnvironment replicationEnv) throws ChangelogException
+ private Log<CSN, UpdateMsg> createLog(final ReplicationEnvironment replicationEnv, final CryptoSuite cryptoSuite)
+ throws ChangelogException
{
final ReplicationServerDomain domain = replicationServer.getReplicationServerDomain(baseDN, true);
- return replicationEnv.getOrCreateReplicaDB(baseDN, serverId, domain.getGenerationId());
+ return replicationEnv.getOrCreateReplicaDB(baseDN, serverId, domain.getGenerationId(), cryptoSuite);
}
/**
@@ -336,14 +338,49 @@
log.dumpAsTextFile(log.getPath());
}
+ static ReplicaDBParser newReplicaDBParser(final CryptoSuite cryptoSuite)
+ {
+ return new ReplicaDBParser(cryptoSuite);
+ }
+
/** Parser of records persisted in the ReplicaDB log. */
private static class ReplicaDBParser implements RecordParser<CSN, UpdateMsg>
{
+ private static final byte RECORD_VERSION = 0x01;
+ private final CryptoSuite cryptoSuite;
+ /** Adjusts the ByteStringBuilder capacity to avoid capacity increases (and copies) when encoding records. */
+ private int encryptionOverhead;
+
+ ReplicaDBParser(CryptoSuite cryptoSuite)
+ {
+ this.cryptoSuite = cryptoSuite;
+ }
@Override
- public ByteString encodeRecord(final Record<CSN, UpdateMsg> record)
+ public ByteString encodeRecord(final Record<CSN, UpdateMsg> record) throws IOException
{
final UpdateMsg message = record.getValue();
+ if (cryptoSuite.isEncrypted())
+ {
+ try
+ {
+ byte[] messageBytes = message.getBytes();
+ ByteStringBuilder builder = new ByteStringBuilder(messageBytes.length + encryptionOverhead);
+ builder.appendByte(UpdateMsg.MSG_TYPE_DISK_ENCODING);
+ builder.appendByte(RECORD_VERSION);
+ builder.appendBytes(cryptoSuite.encrypt(messageBytes));
+ final int overhead = builder.length() - messageBytes.length;
+ if (encryptionOverhead < overhead)
+ {
+ encryptionOverhead = overhead;
+ }
+ return builder.toByteString();
+ }
+ catch (GeneralSecurityException | CryptoManagerException e)
+ {
+ throw new IOException(e);
+ }
+ }
return ByteString.wrap(message.getBytes());
}
@@ -352,8 +389,21 @@
{
try
{
- final UpdateMsg msg =
- (UpdateMsg) UpdateMsg.generateMsg(data.toByteArray(), ProtocolVersion.REPLICATION_PROTOCOL_V7);
+ byte[] recordBytes;
+ if (data.byteAt(0) == UpdateMsg.MSG_TYPE_DISK_ENCODING)
+ {
+ final int version = data.byteAt(1);
+ if (version != RECORD_VERSION)
+ {
+ throw new DecodingException(ERR_UNRECOGNIZED_RECORD_VERSION.get(version));
+ }
+ recordBytes = cryptoSuite.decrypt(data.subSequence(2, data.length()).toByteArray());
+ }
+ else
+ {
+ recordBytes = data.toByteArray();
+ }
+ final UpdateMsg msg = (UpdateMsg) UpdateMsg.generateMsg(recordBytes, REPLICATION_PROTOCOL_V7);
return Record.from(msg.getCSN(), msg);
}
catch (Exception e)
@@ -362,26 +412,22 @@
}
}
- /** {@inheritDoc} */
@Override
public CSN decodeKeyFromString(String key) throws ChangelogException
{
return new CSN(key);
}
- /** {@inheritDoc} */
@Override
public String encodeKeyToString(CSN key)
{
return key.toString();
}
- /** {@inheritDoc} */
@Override
public CSN getMaxKey()
{
return CSN.MAX_CSN_VALUE;
}
}
-
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java
index e7d40e3..e31489d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java
@@ -11,13 +11,15 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2014 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
*/
package org.opends.server.replication.server.changelog.file;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.replication.server.changelog.api.ChangelogException;
+import java.io.IOException;
+
/**
* Parser of a log record.
* <p>
@@ -55,7 +57,7 @@
* The record to encode.
* @return the bytes array representing the (key,value) record
*/
- ByteString encodeRecord(Record<K, V> record);
+ ByteString encodeRecord(Record<K, V> record) throws IOException;
/**
* Read the key from the provided string.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java
index c05faee..9d0cedf 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java
@@ -48,6 +48,7 @@
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.util.time.TimeService;
+import org.opends.server.crypto.CryptoSuite;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.ChangelogState;
@@ -338,8 +339,8 @@
* @throws ChangelogException
* if an error occurs.
*/
- Log<CSN, UpdateMsg> getOrCreateReplicaDB(final DN domainDN, final int serverId, final long generationId)
- throws ChangelogException
+ Log<CSN, UpdateMsg> getOrCreateReplicaDB(final DN domainDN, final int serverId, final long generationId,
+ final CryptoSuite cryptoSuite) throws ChangelogException
{
if (logger.isTraceEnabled())
{
@@ -367,7 +368,7 @@
ensureGenerationIdFileExists(generationIdPath);
changelogState.setDomainGenerationId(domainDN, generationId);
- return openLog(serverIdPath, FileReplicaDB.RECORD_PARSER,
+ return openLog(serverIdPath, FileReplicaDB.newReplicaDBParser(cryptoSuite),
new LogRotationParameters(REPLICA_DB_MAX_LOG_FILE_SIZE_IN_BYTES, 0, 0), logsReplicaDB);
}
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java b/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java
index 5bdda79..2e9ddc7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java
@@ -430,6 +430,7 @@
* @return a new {@link CryptoSuite} for the cipher and key
* @param cipherTransformation cipher transformation string specification
* @param cipherKeyLength length of key in bits
+ * @param encrypt true if the user of the crypto suite needs encryption
*/
- CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength);
+ CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength, boolean encrypt);
}
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/replication.properties b/opendj-server-legacy/src/messages/org/opends/messages/replication.properties
index f83bfb3..7056411 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/replication.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/replication.properties
@@ -589,5 +589,6 @@
ERR_CHANGELOG_RESET_CHANGE_NUMBER_CSN_TOO_OLD_294=The change number could not be reset to %d because the associated \
change with CSN '%s' has already been purged from the change log. Try resetting to a more recent change
ERR_REPLICATION_CHANGE_NUMBER_DISABLED_295=Change number indexing is disabled for replication domain '%s'
-INFO_CHANGELOG_FILTER_OUT_RECORD_BREAKING_ORDER_296=Filtering out from log file '%s' the record '%s'\
- because it would break ordering. Last key appended is '%s'.
\ No newline at end of file
+INFO_CHANGELOG_FILTER_OUT_RECORD_BREAKING_ORDER_296=Filtering out from log file '%s' the record '%s' \
+ because it would break ordering. Last key appended is '%s'.
+ERR_UNRECOGNIZED_RECORD_VERSION_297=Cannot decode change-log record with version %x
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
index 29ee4ce..e3b01b8 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
@@ -11,7 +11,7 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2015 ForgeRock AS.
+ * Copyright 2015-2016 ForgeRock AS.
*/
package org.opends.server.backends.pluggable;
@@ -41,6 +41,7 @@
import org.opends.server.backends.pluggable.spi.TreeName;
import org.opends.server.backends.pluggable.spi.UpdateFunction;
import org.opends.server.backends.pluggable.spi.WriteableTransaction;
+import org.opends.server.crypto.CryptoSuite;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -118,7 +119,10 @@
{
final State state = mock(State.class);
when(state.getIndexFlags(any(ReadableTransaction.class), any(TreeName.class))).thenReturn(indexFlags);
- return new DefaultIndex(new TreeName("dc=example,dc=com", name), state, indexLimit, mock(EntryContainer.class));
+ final CryptoSuite cryptoSuite = mock(CryptoSuite.class);
+ when(cryptoSuite.isEncrypted()).thenReturn(false);
+ return new DefaultIndex(new TreeName("dc=example,dc=com", name), state, indexLimit, mock(EntryContainer.class),
+ cryptoSuite);
}
static final class DummyWriteableTransaction implements WriteableTransaction {
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java
index e8dac4f..4cdfafd 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java
@@ -61,6 +61,7 @@
import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
import org.opends.server.backends.pluggable.spi.TreeName;
import org.opends.server.backends.pluggable.spi.WriteableTransaction;
+import org.opends.server.crypto.CryptoSuite;
import org.testng.annotations.Test;
import com.forgerock.opendj.util.PackedLong;
@@ -483,6 +484,7 @@
{
private static final State state;
private static final EntryContainer entryContainer;
+ private static final CryptoSuite cryptoSuite;
static
{
@@ -493,11 +495,14 @@
state = Mockito.mock(State.class);
Mockito.when(state.getIndexFlags(Mockito.any(ReadableTransaction.class), Mockito.any(TreeName.class))).thenReturn(
EnumSet.of(State.IndexFlag.COMPACTED));
+
+ cryptoSuite = Mockito.mock(CryptoSuite.class);
+ Mockito.when(cryptoSuite.isEncrypted()).thenReturn(false);
};
DummyIndex(int indexEntryLimit) throws StorageRuntimeException
{
- super(TreeName.valueOf("/dumy/dummy"), state, indexEntryLimit, entryContainer);
+ super(TreeName.valueOf("/dummy/dummy"), state, indexEntryLimit, entryContainer, cryptoSuite);
open(Mockito.mock(WriteableTransaction.class), false);
}
}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java
index 3bc909d..d7f2d6d 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java
@@ -40,6 +40,7 @@
private int queueSize;
private int windowSize;
private SortedSet<String> servers;
+ private boolean confidentialityEnabled;
/*
* Assured mode properties
@@ -203,12 +204,30 @@
}
@Override
+ public boolean isConfidentialityEnabled()
+ {
+ return confidentialityEnabled;
+ }
+
+ @Override
public long getAssuredTimeout()
{
return assuredTimeout;
}
@Override
+ public int getCipherKeyLength()
+ {
+ return 128;
+ }
+
+ @Override
+ public String getCipherTransformation()
+ {
+ return "AES/CBC/PKCS5Padding";
+ }
+
+ @Override
public int getDegradedStatusThreshold()
{
return degradedStatusThreshold;
@@ -246,4 +265,9 @@
{
this.computeChangenumber = computeChangenumber;
}
+
+ public void setConfidentialityEnabled(boolean confidentialityEnabled)
+ {
+ this.confidentialityEnabled = confidentialityEnabled;
+ }
}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java
index cd0ec2b..be57032 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java
@@ -11,7 +11,7 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2014-2015 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
*/
package org.opends.server.replication.server.changelog.file;
@@ -22,6 +22,7 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
@@ -494,7 +495,7 @@
}
@Override
- public ByteString encodeRecord(Record<Integer, Integer> record)
+ public ByteString encodeRecord(Record<Integer, Integer> record) throws IOException
{
return new ByteStringBuilder().appendInt(record.getKey()).appendInt(record.getValue()).toByteString();
}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java
index 28d7c57..89627f1 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java
@@ -25,6 +25,8 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.util.time.TimeService;
import org.opends.server.TestCaseUtils;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.crypto.CryptoSuite;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
@@ -54,6 +56,8 @@
public class FileReplicaDBTest extends ReplicationTestCase
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+ private final String cipherTransformation = "AES/CBC/PKCS5Padding";
+ private final int keyLength = 128;
private DN TEST_ROOT_DN;
/**
@@ -76,16 +80,17 @@
{
CSN[] csns = generateCSNs(1, 0, 2);
return new Object[][] {
- { new DeleteMsg(TEST_ROOT_DN, csns[0], "uid") },
- { new DeleteMsg(TEST_ROOT_DN, csns[1], "uid") },
+ { new DeleteMsg(TEST_ROOT_DN, csns[0], "uid"), false },
+ { new DeleteMsg(TEST_ROOT_DN, csns[1], "uid"), false },
+ { new DeleteMsg(TEST_ROOT_DN, csns[0], "uid"), true },
+ { new DeleteMsg(TEST_ROOT_DN, csns[1], "uid"), true },
};
}
@Test(dataProvider="messages")
- public void testRecordParser(UpdateMsg msg) throws Exception
+ public void testRecordParser(UpdateMsg msg, boolean confidential) throws Exception
{
- RecordParser<CSN, UpdateMsg> parser = FileReplicaDB.RECORD_PARSER;
-
+ RecordParser<CSN, UpdateMsg> parser = FileReplicaDB.newReplicaDBParser(createCryptoSuite(confidential));
ByteString data = parser.encodeRecord(Record.from(msg.getCSN(), msg));
Record<CSN, UpdateMsg> record = parser.decodeRecord(data);
@@ -94,6 +99,23 @@
assertThat(record.getValue()).isEqualTo(msg);
}
+ @Test(dataProvider="messages")
+ public void testRecordEncodingWithAndWithoutConfidentiality(UpdateMsg msg, boolean confidential) throws Exception
+ {
+ CryptoSuite cryptoSuite = createCryptoSuite(confidential);
+ RecordParser<CSN, UpdateMsg> parser = FileReplicaDB.newReplicaDBParser(cryptoSuite);
+
+ ByteString data1 = parser.encodeRecord(Record.from(msg.getCSN(), msg));
+ cryptoSuite.newParameters(cipherTransformation, keyLength, !confidential);
+ ByteString data2 = parser.encodeRecord(Record.from(msg.getCSN(), msg));
+
+ assertFalse(data1.equals(data2));
+ }
+
+ private CryptoSuite createCryptoSuite(boolean confidential)
+ {
+ return DirectoryServer.getCryptoManager().newCryptoSuite(cipherTransformation, keyLength, confidential);
+ }
@Test
public void testDomainDNWithForwardSlashes() throws Exception
{
@@ -407,7 +429,7 @@
testRoot = createCleanDir();
dbEnv = new ReplicationEnvironment(testRoot.getPath(), replicationServer, TimeService.SYSTEM);
- replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, dbEnv);
+ replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, createCryptoSuite(false), dbEnv);
// Populate the db with 'max' msg
int mySeqnum = 1;
@@ -428,7 +450,7 @@
debugInfo(tn, "SHUTDOWN replicaDB and recreate");
replicaDB.shutdown();
- replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, dbEnv);
+ replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, createCryptoSuite(false), dbEnv);
assertLimits(replicaDB, csns[1], csns[max]);
// Populate the db with 'max' msg
@@ -521,8 +543,9 @@
throws IOException, ConfigException
{
final int changelogPort = findFreePort();
- return new ReplicationServer(
- new ReplServerFakeConfiguration(changelogPort, null, 0, 2, queueSize, windowSize, null));
+ ReplServerFakeConfiguration replServerFakeCfg =
+ new ReplServerFakeConfiguration(changelogPort, null, 0, 2, queueSize, windowSize, null);
+ return new ReplicationServer(replServerFakeCfg);
}
private FileReplicaDB newReplicaDB(ReplicationServer rs) throws Exception
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java
index 2247dcf..8dfc2d0 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java
@@ -16,6 +16,7 @@
package org.opends.server.replication.server.changelog.file;
import java.io.File;
+import java.io.IOException;
import java.io.RandomAccessFile;
import org.forgerock.i18n.LocalizableMessage;
@@ -327,7 +328,7 @@
}
@Override
- public ByteString encodeRecord(Record<String, String> record)
+ public ByteString encodeRecord(Record<String, String> record) throws IOException
{
return new ByteStringBuilder()
.appendUtf8(record.getKey()).appendByte(STRING_SEPARATOR)
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java
index 899435c..26dd93f 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java
@@ -24,6 +24,7 @@
import org.forgerock.util.time.TimeService;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
+import org.opends.server.crypto.CryptoSuite;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.replication.protocol.UpdateMsg;
@@ -52,14 +53,16 @@
private static final String DN1_AS_STRING = "cn=test1,dc=company.com";
private static final String DN2_AS_STRING = "cn=te::st2,dc=company.com";
private static final String DN3_AS_STRING = "cn=test3,dc=company.com";
-
private static final String TEST_DIRECTORY_CHANGELOG = "test-output/changelog";
+ private static final CryptoSuite cryptoSuite = mock(CryptoSuite.class);
+
@BeforeClass
public void setUp() throws Exception
{
// This test suite depends on having the schema available for DN decoding.
TestCaseUtils.startFakeServer();
+ when(cryptoSuite.isEncrypted()).thenReturn(false);
}
@AfterClass
@@ -89,8 +92,8 @@
final DN domainDN = DN.valueOf(DN1_AS_STRING);
ReplicationEnvironment environment = createReplicationEnv(rootPath);
cnDB = environment.getOrCreateCNIndexDB();
- replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
- replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1);
+ replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
+ replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1, cryptoSuite);
final ChangelogState state = environment.readOnDiskChangelogState();
@@ -123,7 +126,7 @@
for (int j = 1; j <= 10; j++)
{
// 3 domains, 10 server id each, generation id is different for each domain
- replicaDBs.add(environment.getOrCreateReplicaDB(domainDNs.get(i), j, i+1));
+ replicaDBs.add(environment.getOrCreateReplicaDB(domainDNs.get(i), j, i+1, cryptoSuite));
}
}
@@ -159,7 +162,7 @@
final DN domainDN = DN.valueOf(DN1_AS_STRING);
ReplicationEnvironment environment = createReplicationEnv(rootPath);
cnDB = environment.getOrCreateCNIndexDB();
- replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+ replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
// put server id 1 offline
CSN offlineCSN = new CSN(TimeThread.getTime(), 0, SERVER_ID_1);
@@ -189,7 +192,7 @@
final DN domainDN = DN.valueOf(DN1_AS_STRING);
ReplicationEnvironment environment = createReplicationEnv(rootPath);
cnDB = environment.getOrCreateCNIndexDB();
- replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+ replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
File offlineStateFile = new File(environment.getServerIdPath("1", 1), REPLICA_OFFLINE_STATE_FILENAME);
offlineStateFile.createNewFile();
@@ -214,7 +217,7 @@
ReplicationEnvironment environment = createReplicationEnv(rootPath);
cnDB = environment.getOrCreateCNIndexDB();
- replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+ replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
// put server id 1 offline twice
CSNGenerator csnGenerator = new CSNGenerator(SERVER_ID_1, 100);
@@ -245,7 +248,7 @@
ReplicationEnvironment environment = createReplicationEnv(rootPath);
cnDB = environment.getOrCreateCNIndexDB();
- replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+ replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
// put server id 1 offline
environment.notifyReplicaOffline(domainDN, new CSN(TimeThread.getTime(), 0, SERVER_ID_1));
@@ -274,7 +277,7 @@
ReplicationEnvironment environment = createReplicationEnv(rootPath);
cnDB = environment.getOrCreateCNIndexDB();
- replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+ replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
CSN offlineCSN = new CSN(TimeThread.getTime(), 0, SERVER_ID_1);
environment.notifyReplicaOffline(domainDN, offlineCSN);
@@ -304,8 +307,8 @@
File rootPath = new File(TEST_DIRECTORY_CHANGELOG);
DN domainDN = DN.valueOf(DN1_AS_STRING);
ReplicationEnvironment environment = createReplicationEnv(rootPath);
- replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
- replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1);
+ replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
+ replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1, cryptoSuite);
// delete the domain directory created for the 2 replica DBs to break the
// consistency with domain state file
--
Gitblit v1.10.0