keith-turner closed pull request #345: ACCUMULO-4769 Sanity check for valid 
CryptoModule and KeyEncryptionStrategy in config
URL: https://github.com/apache/accumulo/pull/345
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git 
a/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java 
b/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java
index 33453be436..e6c1894939 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java
@@ -16,9 +16,12 @@
  */
 package org.apache.accumulo.core.conf;
 
+import java.io.IOException;
 import java.util.Map.Entry;
 import java.util.Objects;
 
+import org.apache.accumulo.core.security.crypto.CryptoModule;
+import org.apache.accumulo.core.security.crypto.SecretKeyEncryptionStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -96,9 +99,16 @@ else if (!prop.getType().isValidFormat(value))
 
       if (key.equals(Property.CRYPTO_MODULE_CLASS.getKey())) {
         cryptoModule = Objects.requireNonNull(value);
+        if (!cryptoModule.equals(NULL_CRYPTO_MODULE)) {
+          verifyValidClassName(key, cryptoModule, CryptoModule.class);
+        }
+
       }
       if 
(key.equals(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey())) {
         secretKeyEncryptionStrategy = Objects.requireNonNull(value);
+        if 
(!secretKeyEncryptionStrategy.equals(NULL_SECRET_KEY_ENCRYPTION_STRATEGY)) {
+          verifyValidClassName(key, secretKeyEncryptionStrategy, 
SecretKeyEncryptionStrategy.class);
+        }
       }
     }
 
@@ -175,4 +185,24 @@ private static void fatal(String msg) {
     log.error("FATAL: {}", msg);
     throw new SanityCheckException(msg);
   }
+
+  /**
+   * Verifies a configured option is a legal class and has a required base 
class.
+   *
+   * @param confOption
+   *          The Property key name
+   * @param className
+   *          The Property value, the string representation of a class to be 
loaded
+   * @param requiredBaseClass
+   *          The base class required for the className
+   */
+  private static void verifyValidClassName(String confOption, String 
className, Class<?> requiredBaseClass) {
+    try {
+      ConfigurationTypeHelper.getClassInstance(null, className, 
requiredBaseClass);
+    } catch (ClassNotFoundException | InstantiationException | 
IllegalAccessException | IOException e) {
+      fatal(confOption + " has an invalid class name: " + className);
+    } catch (ClassCastException e) {
+      fatal(confOption + " must implement " + requiredBaseClass + ", but the 
configured class does not: " + className);
+    }
+  }
 }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
 
b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
index dd9cc4c7c4..f69e5d1588 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
@@ -71,24 +71,22 @@ public static CryptoModule getCryptoModule(String 
cryptoModuleClassname) {
     return cryptoModule;
   }
 
-  @SuppressWarnings({"rawtypes"})
   private static CryptoModule instantiateCryptoModule(String 
cryptoModuleClassname) {
     log.debug("About to instantiate crypto module {}", cryptoModuleClassname);
 
     CryptoModule cryptoModule = null;
-    Class cryptoModuleClazz = null;
+    Class<?> cryptoModuleClazz = null;
     try {
       cryptoModuleClazz = 
AccumuloVFSClassLoader.loadClass(cryptoModuleClassname);
     } catch (ClassNotFoundException e1) {
-      log.warn("Could not find configured crypto module \"{}\".  No encryption 
will be used.", cryptoModuleClassname);
-      return new NullCryptoModule();
+      throw new IllegalArgumentException("Could not find configured crypto 
module " + cryptoModuleClassname);
     }
 
     // Check if the given class implements the CryptoModule interface
-    Class[] interfaces = cryptoModuleClazz.getInterfaces();
+    Class<?>[] interfaces = cryptoModuleClazz.getInterfaces();
     boolean implementsCryptoModule = false;
 
-    for (Class clazz : interfaces) {
+    for (Class<?> clazz : interfaces) {
       if (clazz.equals(CryptoModule.class)) {
         implementsCryptoModule = true;
         break;
@@ -96,23 +94,15 @@ private static CryptoModule instantiateCryptoModule(String 
cryptoModuleClassname
     }
 
     if (!implementsCryptoModule) {
-      log.warn("Configured Accumulo crypto module \"{}\" does not implement 
the CryptoModule interface. No encryption will be used.", 
cryptoModuleClassname);
-      return new NullCryptoModule();
+      throw new IllegalArgumentException("Configured Accumulo crypto module " 
+ cryptoModuleClassname + " does not implement the CryptoModule interface.");
     } else {
       try {
         cryptoModule = (CryptoModule) cryptoModuleClazz.newInstance();
 
         log.debug("Successfully instantiated crypto module {}", 
cryptoModuleClassname);
 
-      } catch (InstantiationException e) {
-        log.warn("Got instantiation exception {} when instantiating crypto 
module \"{}\".  No encryption will be used.", e.getCause().getClass().getName(),
-            cryptoModuleClassname);
-        log.warn("InstantiationException {}", e.getCause());
-        return new NullCryptoModule();
-      } catch (IllegalAccessException e) {
-        log.warn("Got illegal access exception when trying to instantiate 
crypto module \"{}\".  No encryption will be used.", cryptoModuleClassname);
-        log.warn("IllegalAccessException", e);
-        return new NullCryptoModule();
+      } catch (InstantiationException | IllegalAccessException e) {
+        throw new IllegalArgumentException("Unable to instantiate the crypto 
module: " + cryptoModuleClassname, e);
       }
     }
     return cryptoModule;
@@ -146,25 +136,23 @@ public static SecretKeyEncryptionStrategy 
getSecretKeyEncryptionStrategy(String
     return strategy;
   }
 
-  @SuppressWarnings("rawtypes")
   private static SecretKeyEncryptionStrategy 
instantiateSecreteKeyEncryptionStrategy(String className) {
 
     log.debug("About to instantiate secret key encryption strategy {}", 
className);
 
     SecretKeyEncryptionStrategy strategy = null;
-    Class keyEncryptionStrategyClazz = null;
+    Class<?> keyEncryptionStrategyClazz = null;
     try {
       keyEncryptionStrategyClazz = AccumuloVFSClassLoader.loadClass(className);
     } catch (ClassNotFoundException e1) {
-      log.warn("Could not find configured secret key encryption strategy 
\"{}\".  No encryption will be used.", className);
-      return new NullSecretKeyEncryptionStrategy();
+      throw new IllegalArgumentException("Could not find configured secret key 
encryption strategy: " + className);
     }
 
     // Check if the given class implements the CryptoModule interface
-    Class[] interfaces = keyEncryptionStrategyClazz.getInterfaces();
+    Class<?>[] interfaces = keyEncryptionStrategyClazz.getInterfaces();
     boolean implementsSecretKeyStrategy = false;
 
-    for (Class clazz : interfaces) {
+    for (Class<?> clazz : interfaces) {
       if (clazz.equals(SecretKeyEncryptionStrategy.class)) {
         implementsSecretKeyStrategy = true;
         break;
@@ -172,23 +160,16 @@ private static SecretKeyEncryptionStrategy 
instantiateSecreteKeyEncryptionStrate
     }
 
     if (!implementsSecretKeyStrategy) {
-      log.warn("Configured Accumulo secret key encryption strategy \"%s\" does 
not implement the SecretKeyEncryptionStrategy interface. No encryption will be 
used.");
-      return new NullSecretKeyEncryptionStrategy();
+      throw new IllegalArgumentException(
+          "Configured Accumulo secret key encryption strategy \"%s\" does not 
implement the SecretKeyEncryptionStrategy interface.");
     } else {
       try {
         strategy = (SecretKeyEncryptionStrategy) 
keyEncryptionStrategyClazz.newInstance();
 
         log.debug("Successfully instantiated secret key encryption strategy 
{}", className);
 
-      } catch (InstantiationException e) {
-        log.warn("Got instantiation exception {} when instantiating secret key 
encryption strategy \"{}\".  No encryption will be used.", e.getCause()
-            .getClass().getName(), className);
-        log.warn("InstantiationException {}", e.getCause());
-        return new NullSecretKeyEncryptionStrategy();
-      } catch (IllegalAccessException e) {
-        log.warn("Got illegal access exception when trying to instantiate 
secret key encryption strategy \"{}\".  No encryption will be used.", 
className);
-        log.warn("IllegalAccessException", e);
-        return new NullSecretKeyEncryptionStrategy();
+      } catch (InstantiationException | IllegalAccessException e) {
+        throw new IllegalArgumentException("Unable to instantiate the secret 
key encryption strategy: " + className, e);
       }
     }
     return strategy;
diff --git 
a/core/src/test/java/org/apache/accumulo/core/conf/ConfigSanityCheckTest.java 
b/core/src/test/java/org/apache/accumulo/core/conf/ConfigSanityCheckTest.java
index f359b4ef74..df1e62a5a3 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/conf/ConfigSanityCheckTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/conf/ConfigSanityCheckTest.java
@@ -25,6 +25,10 @@
 public class ConfigSanityCheckTest {
   private Map<String,String> m;
 
+  // These are used when a valid class is needed for testing
+  private static final String DEFAULT_CRYPTO_MODULE = 
"org.apache.accumulo.core.security.crypto.DefaultCryptoModule";
+  private static final String DEFAULT_SECRET_KEY_ENCRYPTION_STRATEGY = 
"org.apache.accumulo.core.security.crypto.NonCachingSecretKeyEncryptionStrategy";
+
   @Before
   public void setUp() {
     m = new java.util.HashMap<>();
@@ -92,9 +96,58 @@ public void testFail_cipherSuiteNotSetKeyAlgorithmSet() {
     ConfigSanityCheck.validate(m.entrySet());
   }
 
+  @Test(expected = SanityCheckException.class)
+  public void testFail_cryptoModuleInvalidClass() {
+    // a random hex dump is unlikely to be a real class name
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), 
"e0218734bcd1e4d239203f970806786b");
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
DEFAULT_SECRET_KEY_ENCRYPTION_STRATEGY);
+    ConfigSanityCheck.validate(m.entrySet());
+  }
+
+  @Test(expected = SanityCheckException.class)
+  public void testFail_cryptoModuleValidClassNotValidInterface() {
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), "java.lang.String");
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
DEFAULT_SECRET_KEY_ENCRYPTION_STRATEGY);
+    ConfigSanityCheck.validate(m.entrySet());
+  }
+
+  @Test
+  public void 
testPass_cryptoModuleAndSecretKeyEncryptionStrategyValidClasses() {
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), DEFAULT_CRYPTO_MODULE);
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
DEFAULT_SECRET_KEY_ENCRYPTION_STRATEGY);
+    ConfigSanityCheck.validate(m.entrySet());
+  }
+
+  @Test
+  public void testPass_cryptoModuleValidNullModule() {
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), "NullCryptoModule");
+    ConfigSanityCheck.validate(m.entrySet());
+  }
+
+  @Test(expected = SanityCheckException.class)
+  public void testFail_secretKeyEncryptionStrategyInvalidClass() {
+    // a random hex dump is unlikely to be a real class name
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
"e0218734bcd1e4d239203f970806786b");
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), DEFAULT_CRYPTO_MODULE);
+    ConfigSanityCheck.validate(m.entrySet());
+  }
+
+  @Test(expected = SanityCheckException.class)
+  public void 
testFail_secretKeyEncryptionStrategyValidClassNotValidInterface() {
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
"java.lang.String");
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), DEFAULT_CRYPTO_MODULE);
+    ConfigSanityCheck.validate(m.entrySet());
+  }
+
+  @Test
+  public void testPass_secretKeyEncryptionStrategyValidNullStrategy() {
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
"NullSecretKeyEncryptionStrategy");
+    ConfigSanityCheck.validate(m.entrySet());
+  }
+
   @Test(expected = SanityCheckException.class)
   public void testFail_cryptoModuleSetSecretKeyEncryptionStrategyNotSet() {
-    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), "DefaultCryptoModule");
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), DEFAULT_CRYPTO_MODULE);
     m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
"NullSecretKeyEncryptionStrategy");
     ConfigSanityCheck.validate(m.entrySet());
   }
@@ -102,7 +155,7 @@ public void 
testFail_cryptoModuleSetSecretKeyEncryptionStrategyNotSet() {
   @Test(expected = SanityCheckException.class)
   public void testFail_cryptoModuleNotSetSecretKeyEncryptionStrategySet() {
     m.put(Property.CRYPTO_MODULE_CLASS.getKey(), "NullCryptoModule");
-    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
"SecretKeyEncryptionStrategy");
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
DEFAULT_SECRET_KEY_ENCRYPTION_STRATEGY);
     ConfigSanityCheck.validate(m.entrySet());
   }
 
@@ -115,8 +168,8 @@ public void 
testPass_cryptoModuleAndSecretKeyEncryptionStrategyBothNull() {
 
   @Test
   public void testPass_cryptoModuleAndSecretKeyEncryptionStrategyBothSet() {
-    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), "DefaultCryptoModule");
-    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
"SecretKeyEncryptionStrategy");
+    m.put(Property.CRYPTO_MODULE_CLASS.getKey(), DEFAULT_CRYPTO_MODULE);
+    m.put(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey(), 
DEFAULT_SECRET_KEY_ENCRYPTION_STRATEGY);
     ConfigSanityCheck.validate(m.entrySet());
   }
 }


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to