From 1a2cdfb5cf5f89348e8fee7ceeaa699d4aa54cea Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Thu, 21 Apr 2016 15:17:15 +0000
Subject: [PATCH] OPENDJ-2616 Support protection of pluggable backend data at rest

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java |   85 ++++++++++++++++++++++++++++--------------
 1 files changed, 57 insertions(+), 28 deletions(-)

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 05f2f3a..8e71e8a 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
@@ -88,10 +88,12 @@
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.SearchOperation;
+import org.opends.server.core.ServerContext;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.CanceledOperationException;
 import org.opends.server.types.Control;
+import org.opends.server.crypto.CryptoSuite;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
 import org.opends.server.types.Modification;
@@ -161,6 +163,10 @@
    */
   private final String treePrefix;
 
+  private final ServerContext serverContext;
+
+  private CryptoSuite cryptoSuite;
+
   /**
    * This class is responsible for managing the configuration for attribute
    * indexes used within this entry container.
@@ -174,7 +180,7 @@
     {
       try
       {
-        new AttributeIndex(cfg, state, EntryContainer.this);
+        newAttributeIndex(cfg);
         return true;
       }
       catch(Exception e)
@@ -190,7 +196,7 @@
       final ConfigChangeResult ccr = new ConfigChangeResult();
       try
       {
-        final AttributeIndex index = new AttributeIndex(cfg, state, EntryContainer.this);
+        final AttributeIndex index = newAttributeIndex(cfg);
         storage.write(new WriteOperation()
         {
           @Override
@@ -338,26 +344,15 @@
   final Lock sharedLock = lock.readLock();
   final Lock exclusiveLock = lock.writeLock();
 
-  /**
-   * Create a new entry container object.
-   *
-   * @param baseDN  The baseDN this entry container will be responsible for
-   *                storing on disk.
-   * @param backendID  ID of the backend that is creating this entry container.
-   *                   It is needed by the Directory Server entry cache methods.
-   * @param config The configuration of the backend.
-   * @param storage The storage for this entryContainer.
-   * @param rootContainer The root container this entry container is in.
-   * @throws ConfigException if a configuration related error occurs.
-   */
-  EntryContainer(DN baseDN, String backendID, PluggableBackendCfg config, Storage storage,
-      RootContainer rootContainer) throws ConfigException
+  EntryContainer(DN baseDN, String backendID, PluggableBackendCfg config, Storage storage, RootContainer rootContainer,
+      ServerContext serverContext) throws ConfigException
   {
     this.backendID = backendID;
     this.baseDN = baseDN;
     this.config = config;
     this.storage = storage;
     this.rootContainer = rootContainer;
+    this.serverContext = serverContext;
     this.treePrefix = baseDN.toNormalizedUrlSafeString();
     this.id2childrenCount = new ID2ChildrenCount(getIndexName(ID2CHILDREN_COUNT_TREE_NAME));
     this.dn2id = new DN2ID(getIndexName(DN2ID_TREE_NAME), baseDN);
@@ -375,6 +370,22 @@
     config.addBackendVLVIndexDeleteListener(vlvIndexCfgManager);
   }
 
+  private AttributeIndex newAttributeIndex(BackendIndexCfg cfg) throws ConfigException
+  {
+    return new AttributeIndex(cfg, state, this, cryptoSuite);
+  }
+
+  private DataConfig newDataConfig(PluggableBackendCfg config)
+  {
+    return new DataConfig.Builder()
+        .compress(config.isEntriesCompressed())
+        .encode(config.isCompactEncoding())
+        .encrypt(config.isConfidentialityEnabled())
+        .cryptoSuite(cryptoSuite)
+        .schema(rootContainer.getCompressedSchema())
+        .build();
+  }
+
   private TreeName getIndexName(String indexId)
   {
     return new TreeName(treePrefix, indexId);
@@ -393,10 +404,9 @@
     boolean shouldCreate = accessMode.isWriteable();
     try
     {
-      DataConfig entryDataConfig = new DataConfig(
-          config.isEntriesCompressed(), config.isCompactEncoding(), rootContainer.getCompressedSchema());
-
-      id2entry = new ID2Entry(getIndexName(ID2ENTRY_TREE_NAME), entryDataConfig);
+      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);
       dn2id.open(txn, shouldCreate);
@@ -407,7 +417,7 @@
       {
         BackendIndexCfg indexCfg = config.getBackendIndex(idx);
 
-        final AttributeIndex index = new AttributeIndex(indexCfg, state, this);
+        final AttributeIndex index = newAttributeIndex(indexCfg);
         index.open(txn, shouldCreate);
         if(!index.isTrusted())
         {
@@ -2341,11 +2351,25 @@
   }
 
   @Override
-  public boolean isConfigurationChangeAcceptable(
-      PluggableBackendCfg cfg, List<LocalizableMessage> unacceptableReasons)
+  public boolean isConfigurationChangeAcceptable(PluggableBackendCfg cfg, List<LocalizableMessage> unacceptableReasons)
   {
-    // This is always true because only all config attributes used
-    // by the entry container should be validated by the admin framework.
+    StringBuilder builder = new StringBuilder();
+    for (AttributeIndex attributeIndex : attrIndexMap.values())
+    {
+      if (attributeIndex.isConfidentialityEnabled() && !cfg.isConfidentialityEnabled())
+      {
+        if (builder.length() > 0)
+        {
+          builder.append(", ");
+        }
+        builder.append(attributeIndex.getAttributeType().getNameOrOID());
+      }
+    }
+    if (builder.length() > 0)
+    {
+      unacceptableReasons.add(ERR_BACKEND_CANNOT_CHANGE_CONFIDENTIALITY.get(getBaseDN(), builder.toString()));
+      return false;
+    }
     return true;
   }
 
@@ -2362,9 +2386,9 @@
         @Override
         public void run(WriteableTransaction txn) throws Exception
         {
-          DataConfig entryDataConfig = new DataConfig(cfg.isEntriesCompressed(),
-              cfg.isCompactEncoding(), rootContainer.getCompressedSchema());
-          id2entry.setDataConfig(entryDataConfig);
+          cryptoSuite.setCipherTransformation(cfg.getCipherTransformation());
+          cryptoSuite.setCipherKeyLength(cfg.getCipherKeyLength());
+          id2entry.setDataConfig(newDataConfig(cfg));
 
           EntryContainer.this.config = cfg;
         }
@@ -2476,6 +2500,11 @@
     return false;
   }
 
+  boolean isConfidentialityEnabled()
+  {
+    return config.isConfidentialityEnabled();
+  }
+
   /**
    * Fetch the base Entry of the EntryContainer.
    * @param searchBaseDN the DN for the base entry

--
Gitblit v1.10.0