This is an automated email from the ASF dual-hosted git repository.
dhavalshah9131 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 5dd493412 RANGER-5221 : Adding test cases for class
RangerKeyStoreProvider (#599)
5dd493412 is described below
commit 5dd4934122b2a053aeae08db663427754d3d2a5f
Author: dhavalshah9131 <[email protected]>
AuthorDate: Fri Jun 27 18:44:34 2025 +0530
RANGER-5221 : Adding test cases for class RangerKeyStoreProvider (#599)
---
.../key/kms/server/RangerKeyStoreProviderTest.java | 849 ++++++++++++++++++++-
1 file changed, 842 insertions(+), 7 deletions(-)
diff --git
a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
index 96168fb0c..8f68e2498 100644
---
a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
+++
b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
@@ -18,12 +18,16 @@
package org.apache.hadoop.crypto.key.kms.server;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.crypto.key.KeyProvider;
import org.apache.hadoop.crypto.key.KeyProvider.KeyVersion;
import org.apache.hadoop.crypto.key.KeyProvider.Options;
+import org.apache.hadoop.crypto.key.RangerKMSMKI;
+import org.apache.hadoop.crypto.key.RangerKeyStore;
import org.apache.hadoop.crypto.key.RangerKeyStoreProvider;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import javax.crypto.Cipher;
@@ -31,9 +35,37 @@
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
/**
* A test for the RangerKeyStoreProvider, which is an implementation of the
Hadoop KeyProvider interface, which stores keys in a database.
@@ -57,6 +89,25 @@ public static void stopServers() throws Exception {
}
}
+ @BeforeEach
+ public void cleanUpKeyBeforeEachTest() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ try {
+ keyProvider.deleteKey("newkey1");
+ keyProvider.flush();
+ } catch (IOException e) {
+ // Ignore if the key doesn't exist yet
+ }
+ }
+
@Test
public void testCreateDeleteKey() throws Throwable {
if (!UNRESTRICTED_POLICIES_INSTALLED) {
@@ -66,7 +117,7 @@ public void testCreateDeleteKey() throws Throwable {
Path configDir = Paths.get("src/test/resources/kms");
System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
- Configuration conf = new Configuration();
+ Configuration conf = new Configuration();
RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
// Create a key
@@ -84,14 +135,68 @@ public void testCreateDeleteKey() throws Throwable {
keyProvider.flush();
Assertions.assertEquals(0, keyProvider.getKeys().size());
+ }
- // Try to delete a key that isn't there
- try {
- keyProvider.deleteKey("newkey2");
- Assertions.fail("Failure expected on trying to delete an unknown
key");
- } catch (IOException ex) {
- // expected
+ @Test
+ public void testDeleteKey_EngineDeleteEntryThrowsForBaseKey() throws
Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+
+ // Inject mocked dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ // Mock Metadata
+ KeyProvider.Metadata metadata = mock(KeyProvider.Metadata.class);
+ when(metadata.getAlgorithm()).thenReturn("AES");
+ when(metadata.getBitLength()).thenReturn(128);
+ when(metadata.getDescription()).thenReturn("test description");
+ when(metadata.getVersions()).thenReturn(0); // No versions (only base
key)
+ when(metadata.getAttributes()).thenReturn(new HashMap<>());
+
+ // Return mocked metadata
+ doReturn(metadata).when(provider).getMetadata("testKey");
+
+ // Simulate that base key alias exists
+ doReturn(true).when(dbStore).engineContainsAlias("testKey");
+
+ // Throw exception when trying to delete base key alias
+ doThrow(new KeyStoreException("Delete
failed")).when(dbStore).engineDeleteEntry("testKey");
+
+ // Act & Assert
+ IOException ex = assertThrows(IOException.class, () ->
provider.deleteKey("testKey"));
+ assertTrue(ex.getMessage().contains("Problem removing testKey from"));
+ }
+
+ @Test
+ public void testCreateKey() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
}
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key
+ Options options = new Options(conf);
+ options.setBitLength(256);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+ Assertions.assertEquals("newkey1", keyVersion.getName());
+ Assertions.assertEquals(256 / 8, keyVersion.getMaterial().length);
+ Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+
+ // Validate the key exists
+ List<String> keys = keyProvider.getKeys();
+ Assertions.assertEquals(1, keys.size());
+ Assertions.assertEquals("newkey1", keys.get(0));
}
@Test
@@ -129,6 +234,736 @@ public void testRolloverKey() throws Throwable {
keyProvider.flush();
Assertions.assertEquals(0, keyProvider.getKeys().size());
+ try {
+ keyProvider.deleteKey("newkey1");
+ keyProvider.flush();
+ } catch (IOException e) {
+ // Ignore if key doesn't exist
+ }
+ }
+
+ @Test
+ public void testGetKeyVersion() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key version
+ Options options = new Options(conf);
+ options.setBitLength(192);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+ Assertions.assertEquals("newkey1", keyVersion.getName());
+ Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+
+ // Validate the key exists
+ Assertions.assertEquals(1, keyProvider.getKeys().size());
+
+ // Get key versions
+ List<KeyVersion> keyVersions = keyProvider.getKeyVersions("newkey1");
+ Assertions.assertEquals(1, keyVersions.size());
+
+ KeyVersion kv = keyVersions.get(0);
+ Assertions.assertEquals("newkey1", kv.getName());
+ Assertions.assertEquals(192 / 8, kv.getMaterial().length);
+ assertTrue(kv.getVersionName().startsWith("newkey1@"));
+
+ keyProvider.flush();
+ Assertions.assertNotEquals(0, keyProvider.getKeys().size());
+
+ // Try to get key versions of a non-existent key
+ try {
+ List<KeyVersion> invalidVersions =
keyProvider.getKeyVersions("newkey2");
+ if (!invalidVersions.isEmpty()) {
+ Assertions.fail("Unexpected key version found: " +
invalidVersions.get(0).getName());
+ }
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testGetKeys() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key version
+ Options options = new Options(conf);
+ options.setBitLength(192);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+ Assertions.assertEquals("newkey1", keyVersion.getName());
+ Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+
+ List<String> getkeys = keyProvider.getKeys();
+ Assertions.assertEquals(1, getkeys.size());
+ Assertions.assertEquals("newkey1", getkeys.get(0));
+
+ keyProvider.flush();
+ Assertions.assertNotEquals(0, keyProvider.getKeys().size());
+ }
+
+ @Test
+ public void testGetKeyVersionWithInvalidKey() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Try to get key versions of a non-existent key
+ try {
+ List<KeyVersion> invalidVersions =
keyProvider.getKeyVersions("nonExistentKey");
+ assertTrue(invalidVersions.isEmpty(), "Expected no key versions
for non-existent key");
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testGetKeyVersionWithInvalidVersion() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key version
+ Options options = new Options(conf);
+ options.setBitLength(192);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+ Assertions.assertEquals("newkey1", keyVersion.getName());
+ Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+
+ // Try to get an invalid version
+ try {
+ KeyVersion invalidVersion =
keyProvider.getKeyVersion("newkey1@invalid");
+ Assertions.assertNull(invalidVersion, "Expected null for invalid
version");
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testGetKeyVersions() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key version
+ Options options = new Options(conf);
+ options.setBitLength(192);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+ Assertions.assertEquals("newkey1", keyVersion.getName());
+ Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+
+ // Get key versions
+ List<KeyVersion> keyVersions = keyProvider.getKeyVersions("newkey1");
+ Assertions.assertEquals(1, keyVersions.size());
+
+ KeyVersion kv = keyVersions.get(0);
+ Assertions.assertEquals("newkey1", kv.getName());
+ Assertions.assertEquals(192 / 8, kv.getMaterial().length);
+ assertTrue(kv.getVersionName().startsWith("newkey1@"));
+ }
+
+ @Test
+ public void testGetMetadata() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key version
+ Options options = new Options(conf);
+ options.setBitLength(192);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+ Assertions.assertEquals("newkey1", keyVersion.getName());
+ Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+
+ // Get metadata
+ String metadata = String.valueOf(keyProvider.getMetadata("newkey1"));
+ assertNotNull(metadata, "Metadata should not be null");
+ assertTrue(metadata.contains("192"), "Metadata should contain key bit
length");
+ assertTrue(metadata.contains("AES"), "Metadata should contain key
cipher");
+ }
+
+ @Test
+ public void testGetKeyVersionWithInvalidKeyName() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Try to get key versions of a non-existent key
+ try {
+ KeyVersion invalidVersion =
keyProvider.getKeyVersion("nonExistentKey@0");
+ Assertions.assertNull(invalidVersion, "Expected null for
non-existent key version");
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testFlush() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key version
+ Options options = new Options(conf);
+ options.setBitLength(192);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+ Assertions.assertEquals("newkey1", keyVersion.getName());
+ Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ // Flush the provider
+ keyProvider.flush();
+
+ // Validate that the key is still present after flush
+ List<KeyVersion> keyVersions = keyProvider.getKeyVersions("newkey1");
+ Assertions.assertEquals(1, keyVersions.size());
+ }
+
+ @Test
+ public void testGetConfiguration() {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ String originalConfDir =
System.getProperty(KMSConfiguration.KMS_CONFIG_DIR);
+
+ try {
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
"relative/path");
+
+ Configuration conf = new Configuration();
+
+ RuntimeException ex = assertThrows(RuntimeException.class, () -> {
+ new RangerKeyStoreProvider(conf); // Should internally call
getConfiguration()
+ });
+
+ assertTrue(ex.getMessage().contains("must be an absolute path"));
+ } finally {
+ if (originalConfDir != null) {
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
originalConfDir);
+ } else {
+ System.clearProperty(KMSConfiguration.KMS_CONFIG_DIR);
+ }
+ }
+ }
+
+ @Test
+ public void testGetKeyVersionWithInvalidVersionName() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Try to get key version with an invalid version name
+ try {
+ KeyVersion invalidVersion =
keyProvider.getKeyVersion("newkey1@invalid");
+ Assertions.assertNull(invalidVersion, "Expected null for invalid
version name");
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testGetDBKSConf() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Get the DB configuration
+ Configuration dbConf = RangerKeyStoreProvider.getDBKSConf();
+ assertNotNull(dbConf, "DB configuration should not be null");
+ }
+
+ @Test
+ public void testRollNewVersion_ThrowsWhenKeyNotFound() throws Throwable {
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider provider = new RangerKeyStoreProvider(conf);
+
+ byte[] dummyMaterial = new byte[16]; // 128-bit material
+
+ IOException exception = assertThrows(IOException.class, () ->
+ provider.rollNewVersion("nonExistingKey", dummyMaterial));
+
+ assertTrue(exception.getMessage().contains("Key nonExistingKey not
found"));
+ }
+
+ @Test
+ public void testRollNewVersion_ThrowsWhenKeyLengthMismatch() throws
Throwable {
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider provider = new RangerKeyStoreProvider(conf);
+
+ Options options = new Options(conf);
+ options.setBitLength(128);
+ options.setCipher("AES");
+ provider.createKey("testKeyMismatch", options);
+ provider.flush();
+
+ // Use 192-bit material
+ byte[] wrongMaterial = new byte[24];
+
+ IOException exception = assertThrows(IOException.class, () ->
+ provider.rollNewVersion("testKeyMismatch", wrongMaterial));
+
+ assertTrue(exception.getMessage().contains("Wrong key length"));
+ }
+
+ @Test
+ public void testDeleteKey_MetadataIsNull() throws Throwable {
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider realProvider = new RangerKeyStoreProvider(conf);
+
+ // Spy on the real provider to override getMetadata
+ RangerKeyStoreProvider provider = spy(realProvider);
+
+ // Simulate missing metadata
+ doReturn(null).when(provider).getMetadata("testKey");
+
+ // Act & Assert
+ IOException ex = assertThrows(IOException.class, () ->
provider.deleteKey("testKey"));
+
+ // This now matches the real message thrown by deleteKey()
+ assertTrue(ex.getMessage().contains("Key testKey does not exist"));
+ }
+
+ @Test
+ public void testGetKeyVersion_DecryptKeyThrowsRuntimeException() throws
Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ // Inject dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ // Enable keyVault mode
+ Field keyVaultField =
RangerKeyStoreProvider.class.getDeclaredField("keyVaultEnabled");
+ keyVaultField.setAccessible(true);
+ keyVaultField.set(provider, true);
+
+ // Setup mocks: alias exists, but decryption fails
+ doReturn(true).when(dbStore).engineContainsAlias("testKey");
+ doThrow(new RuntimeException("decryption
failure")).when(dbStore).engineGetDecryptedZoneKeyByte("testKey");
+
+ RuntimeException ex = assertThrows(RuntimeException.class, () ->
provider.getKeyVersion("testKey"));
+ assertTrue(ex.getMessage().contains("Error while getting decrypted
key."));
+ assertTrue(ex.getMessage().contains("decryption failure"));
+ }
+
+ @Test
+ public void testGetKeyVersion_NoSuchAlgorithmException() throws Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ // Inject dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ // Setup: alias exists, key fetch throws NoSuchAlgorithmException
+ doReturn(true).when(dbStore).engineContainsAlias("testKey");
+ doThrow(new
NoSuchAlgorithmException()).when(dbStore).engineGetKey(eq("testKey"), any());
+
+ IOException ex = assertThrows(IOException.class, () ->
provider.getKeyVersion("testKey"));
+
+ assertTrue(ex.getMessage().contains("Can't get algorithm for key"));
+
+ // Setup: alias exists, key fetch throws UnrecoverableKeyException
+ doReturn(true).when(dbStore).engineContainsAlias("testKey");
+ doThrow(new
UnrecoverableKeyException()).when(dbStore).engineGetKey(eq("testKey"), any());
+
+ IOException ex1 = assertThrows(IOException.class, () ->
provider.getKeyVersion("testKey"));
+
+ assertTrue(ex1.getMessage().contains("Can't recover key "));
+ }
+
+ @Test
+ public void testGetMetadata_GenericException() throws Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+
+ // Inject mocked dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ // Simulate exception during dbStore.engineContainsAlias for
RuntimeException
+ when(dbStore.engineContainsAlias("testKey")).thenThrow(new
RuntimeException("DB failure"));
+
+ IOException ex = assertThrows(IOException.class, () ->
provider.getMetadata("testKey"));
+
+ assertTrue(ex.getMessage().contains("Please try again"));
+ assertTrue(ex.getCause().getMessage().contains("DB failure"));
+ }
+
+ @Test
+ public void testGetConfiguration1() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR,
configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Get the configuration
+ Configuration keyProviderConf = keyProvider.getConf();
+ assertNotNull(keyProviderConf, "Configuration should not be null");
+ }
+
+ @Test
+ public void testSaveKey_ThrowsIOException() throws Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+
+ // Inject mocked dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ // Set keyVaultEnabled = false
+ Field keyVaultField =
RangerKeyStoreProvider.class.getDeclaredField("keyVaultEnabled");
+ keyVaultField.setAccessible(true);
+ keyVaultField.set(provider, false);
+
+ // Mock Metadata with required getters
+ KeyProvider.Metadata metadata = mock(KeyProvider.Metadata.class);
+ when(metadata.getAlgorithm()).thenReturn("AES");
+ when(metadata.getBitLength()).thenReturn(128);
+ when(metadata.getDescription()).thenReturn("test description");
+ when(metadata.getVersions()).thenReturn(1);
+ when(metadata.getAttributes()).thenReturn(new HashMap<>());
+
+ // Mock exception on addKeyEntry
+ doThrow(new RuntimeException("decryption
failure")).when(dbStore).addKeyEntry(
+ eq("testKey"),
+ any(),
+ any(),
+ eq("AES"),
+ eq(128),
+ eq("test description"),
+ eq(1),
+ any());
+
+ Method saveKeyMethod =
RangerKeyStoreProvider.class.getDeclaredMethod("saveKey", String.class,
KeyProvider.Metadata.class);
+ saveKeyMethod.setAccessible(true);
+
+ try {
+ saveKeyMethod.invoke(provider, "testKey", metadata);
+ fail("Expected IOException to be thrown");
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ assertInstanceOf(IOException.class, cause, "Cause should be
IOException");
+ assertInstanceOf(RuntimeException.class, cause.getCause(),
"IOException cause should be RuntimeException");
+ assertTrue(cause.getCause().getMessage().contains("decryption
failure"));
+ }
+ }
+
+ @Test
+ public void testGetKeyVersion_KeyVaultTrue_SuccessPath() throws Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+
+ // Inject dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ // Set keyVaultEnabled = true
+ Field keyVaultField =
RangerKeyStoreProvider.class.getDeclaredField("keyVaultEnabled");
+ keyVaultField.setAccessible(true);
+ keyVaultField.set(provider, true);
+
+ String versionedKey = "testKey@0";
+
+ // Simulate engineContainsAlias returns false first, then true
+
when(dbStore.engineContainsAlias(versionedKey)).thenReturn(false).thenReturn(true);
+
+ // Simulate engineLoad
+ doNothing().when(dbStore).engineLoad(isNull(), any());
+
+ // Simulate decrypted key return
+ byte[] decryptedKey = new byte[] {0x01, 0x02, 0x03};
+
when(dbStore.engineGetDecryptedZoneKeyByte(versionedKey)).thenReturn(decryptedKey);
+
+ // Act
+ KeyVersion result = provider.getKeyVersion(versionedKey);
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(versionedKey, result.getVersionName());
+ assertEquals("testKey", result.getName());
+ assertArrayEquals(decryptedKey, result.getMaterial());
+ }
+
+ @Test
+ public void testGenerateAndGetMasterKey_generateMasterKeyThrows() throws
Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+ RangerKMSMKI masterKeyProvider = mock(RangerKMSMKI.class);
+
+ // simulate generateMasterKey throwing an exception
+ doThrow(new RuntimeException("Simulated failure in
generateMasterKey")).when(masterKeyProvider).generateMasterKey("abc123");
+
+ Method method =
RangerKeyStoreProvider.class.getDeclaredMethod("generateAndGetMasterKey",
RangerKMSMKI.class, String.class);
+ method.setAccessible(true);
+
+ RuntimeException ex = assertThrows(RuntimeException.class, () -> {
+ try {
+ method.invoke(provider, masterKeyProvider, "abc123");
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ });
+
+ assertTrue(ex.getMessage().contains("Error while generating Ranger
Master key"));
+ }
+
+ @Test
+ void testFlush_EngineStoreThrowsIOException() throws Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ doThrow(new IOException("Flush
failed")).when(dbStore).engineStore(any(), any());
+
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ // Inject mocks and changed = true
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ Field changedField =
RangerKeyStoreProvider.class.getDeclaredField("changed");
+ changedField.setAccessible(true);
+ changedField.set(provider, true);
+
+ IOException ex = assertThrows(IOException.class, provider::flush);
+ assertTrue(ex.getMessage().contains("Flush failed"));
+
+ verify(dbStore, times(1)).engineStore(any(), any());
+ }
+
+ @Test
+ void testFlush_EngineStoreThrowsNoSuchAlgorithmException() throws
Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ doThrow(new
NoSuchAlgorithmException()).when(dbStore).engineStore(any(), any());
+
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ Field changedField =
RangerKeyStoreProvider.class.getDeclaredField("changed");
+ changedField.setAccessible(true);
+ changedField.set(provider, true);
+
+ IOException ex = assertThrows(IOException.class, provider::flush);
+ assertTrue(ex.getMessage().contains("No such algorithm storing key"));
+
+ verify(dbStore, times(1)).engineStore(any(), any());
+ }
+
+ @Test
+ void testFlush_EngineStoreThrowsCertificateException() throws Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ doThrow(new CertificateException()).when(dbStore).engineStore(any(),
any());
+
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ Field changedField =
RangerKeyStoreProvider.class.getDeclaredField("changed");
+ changedField.setAccessible(true);
+ changedField.set(provider, true);
+
+ IOException ex = assertThrows(IOException.class, provider::flush);
+ assertTrue(ex.getMessage().contains("Certificate exception storing
key"));
+
+ verify(dbStore, times(1)).engineStore(any(), any());
+ }
+
+ @Test
+ void testDeleteKey_ShouldThrowIOException() throws Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ // Inject mocked dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ // Mock Metadata object with versions = 1
+ KeyProvider.Metadata metadata = mock(KeyProvider.Metadata.class);
+ when(metadata.getVersions()).thenReturn(1);
+
+ // Stub getMetadata to return mocked metadata
+ doReturn(metadata).when(provider).getMetadata("testKey");
+
+ // Stub dbStore responses for key existence
+ doReturn(true).when(dbStore).engineContainsAlias("testKey@0");
+ doReturn(true).when(dbStore).engineContainsAlias("testKey");
+
+ // Simulate KeyStoreException on deleting the version key
+ doThrow(new KeyStoreException("forced
exception")).when(dbStore).engineDeleteEntry("testKey@0");
+
+ // Expect IOException because KeyStoreException is caught and wrapped
+ IOException ex = assertThrows(IOException.class, () ->
provider.deleteKey("testKey"));
+ assertTrue(ex.getMessage().contains("Problem removing"));
+
+ // Verify interactions with dbStore mocks
+ verify(dbStore).engineContainsAlias("testKey@0");
+ verify(dbStore).engineDeleteEntry("testKey@0");
+ }
+
+ @Test
+ void testCreateKey_ShouldThrowIOException_WhenKeyAlreadyExists() throws
Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ // Inject mocked dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ String keyName = "existingKey";
+ byte[] material = new byte[16]; // 128 bits
+ KeyProvider.Options options = new KeyProvider.Options(conf)
+ .setCipher("AES")
+ .setBitLength(128);
+
+ // Simulate that key already exists
+ when(dbStore.engineContainsAlias(keyName)).thenReturn(true);
+
+ IOException ex = assertThrows(IOException.class, () ->
provider.createKey(keyName, material, options));
+ assertTrue(ex.getMessage().contains("Key " + keyName + " already
exists"));
+ }
+
+ @Test
+ void testCreateKey_ShouldThrowIOException_WhenKeyLengthIncorrect() throws
Throwable {
+ Configuration conf = new Configuration();
+ RangerKeyStore dbStore = mock(RangerKeyStore.class);
+ RangerKeyStoreProvider provider = spy(new
RangerKeyStoreProvider(conf));
+
+ // Inject mocked dbStore
+ Field dbStoreField =
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+ dbStoreField.setAccessible(true);
+ dbStoreField.set(provider, dbStore);
+
+ String keyName = "newKey";
+ byte[] material = new byte[10]; // 80 bits
+ KeyProvider.Options options = new KeyProvider.Options(conf)
+ .setCipher("AES")
+ .setBitLength(128); // But expects 128 bits
+
+ // Simulate key does not exist
+ when(dbStore.engineContainsAlias(keyName)).thenReturn(false);
+
+ IOException ex = assertThrows(IOException.class, () ->
provider.createKey(keyName, material, options));
+ assertTrue(ex.getMessage().contains("Wrong key length. Required 128,
but got 80"));
}
static {