From 79dbae563ed19adb585552c6884b033213f7c088 Mon Sep 17 00:00:00 2001 From: chris-j-h Date: Mon, 17 Dec 2018 16:58:46 +0000 Subject: [PATCH 1/5] Enable AzureKeyVaultService to retrieve the specific version of a secret --- .../azure/AzureKeyVaultClientDelegate.java | 4 + .../key/vault/azure/AzureKeyVaultService.java | 15 ++- .../vault/azure/AzureKeyVaultServiceTest.java | 92 +++++++++---------- 3 files changed, 61 insertions(+), 50 deletions(-) diff --git a/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultClientDelegate.java b/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultClientDelegate.java index c12b92d9ed..ca759787a6 100644 --- a/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultClientDelegate.java +++ b/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultClientDelegate.java @@ -17,6 +17,10 @@ SecretBundle getSecret(String vaultBaseUrl, String secretName) { return keyVaultClient.getSecret(vaultBaseUrl, secretName); } + SecretBundle getSecret(String vaultBaseUrl, String secretName, String secretVersion) { + return keyVaultClient.getSecret(vaultBaseUrl, secretName, secretVersion); + } + SecretBundle setSecret(SetSecretRequest setSecretRequest) { return keyVaultClient.setSecret(setSecretRequest); } diff --git a/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultService.java b/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultService.java index 0698cda7ad..749796d1cf 100644 --- a/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultService.java +++ b/key-vault/azure-key-vault/src/main/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultService.java @@ -18,10 +18,10 @@ public class AzureKeyVaultService implements KeyVaultService { private AzureKeyVaultClientDelegate azureKeyVaultClientDelegate; AzureKeyVaultService(AzureKeyVaultConfig keyVaultConfig, AzureKeyVaultClientDelegate azureKeyVaultClientDelegate) { - if(Objects.nonNull(keyVaultConfig)) { - this.vaultUrl = keyVaultConfig.getUrl(); - } + Objects.requireNonNull(keyVaultConfig); + Objects.requireNonNull(azureKeyVaultClientDelegate); + this.vaultUrl = keyVaultConfig.getUrl(); this.azureKeyVaultClientDelegate = azureKeyVaultClientDelegate; } @@ -33,7 +33,14 @@ public String getSecret(GetSecretData getSecretData) { AzureGetSecretData azureGetSecretData = (AzureGetSecretData) getSecretData; - SecretBundle secretBundle = azureKeyVaultClientDelegate.getSecret(vaultUrl, azureGetSecretData.getSecretName()); + SecretBundle secretBundle; + + if(azureGetSecretData.getSecretVersion() != null) { + secretBundle = azureKeyVaultClientDelegate.getSecret(vaultUrl, azureGetSecretData.getSecretName(), azureGetSecretData.getSecretVersion()); + } + else { + secretBundle = azureKeyVaultClientDelegate.getSecret(vaultUrl, azureGetSecretData.getSecretName()); + } if(secretBundle == null) { throw new VaultSecretNotFoundException("Azure Key Vault secret " + azureGetSecretData.getSecretName() + " was not found in vault " + vaultUrl); diff --git a/key-vault/azure-key-vault/src/test/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultServiceTest.java b/key-vault/azure-key-vault/src/test/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultServiceTest.java index d38b9959b9..58d3d9a036 100644 --- a/key-vault/azure-key-vault/src/test/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultServiceTest.java +++ b/key-vault/azure-key-vault/src/test/java/com/quorum/tessera/key/vault/azure/AzureKeyVaultServiceTest.java @@ -18,95 +18,97 @@ import static org.mockito.Mockito.*; public class AzureKeyVaultServiceTest { + + private AzureKeyVaultService keyVaultService; + private AzureKeyVaultClientDelegate azureKeyVaultClientDelegate; + private String vaultUrl = "url"; + + private AzureKeyVaultConfig keyVaultConfig; + @Before public void setUp() { this.azureKeyVaultClientDelegate = mock(AzureKeyVaultClientDelegate.class); + this.keyVaultConfig = mock(AzureKeyVaultConfig.class); + when(keyVaultConfig.getUrl()).thenReturn(vaultUrl); + + this.keyVaultService = new AzureKeyVaultService(keyVaultConfig, azureKeyVaultClientDelegate); } @Test - public void getSecretExceptionThrownIfKeyNotFoundInVault() { - String secretName = "secret"; - String vaultUrl = "vaultUrl"; - - AzureKeyVaultConfig keyVaultConfig = new AzureKeyVaultConfig(vaultUrl); - - when(azureKeyVaultClientDelegate.getSecret(anyString(), anyString())).thenReturn(null); - - AzureKeyVaultService azureKeyVaultService = new AzureKeyVaultService(keyVaultConfig, azureKeyVaultClientDelegate); + public void getSecretGetsLatestVersionOfSecretIfNoVersionProvided() { + String secretName = "name"; AzureGetSecretData getSecretData = mock(AzureGetSecretData.class); when(getSecretData.getSecretName()).thenReturn(secretName); + when(getSecretData.getSecretVersion()).thenReturn(null); - Throwable throwable = catchThrowable(() -> azureKeyVaultService.getSecret(getSecretData)); + SecretBundle secretBundle = mock(SecretBundle.class); + when(azureKeyVaultClientDelegate.getSecret(anyString(), anyString())).thenReturn(secretBundle); + when(secretBundle.value()).thenReturn("value"); - assertThat(throwable).isInstanceOf(VaultSecretNotFoundException.class); - assertThat(throwable).hasMessageContaining("Azure Key Vault secret " + secretName + " was not found in vault " + vaultUrl); + keyVaultService.getSecret(getSecretData); + + verify(azureKeyVaultClientDelegate).getSecret(vaultUrl, secretName); } @Test - public void getSecretUsingUrlInConfig() { - String url = "url"; - String secretId = "id"; - - AzureKeyVaultConfig keyVaultConfig = new AzureKeyVaultConfig(url); - - when(azureKeyVaultClientDelegate.getSecret(url, secretId)).thenReturn(new SecretBundle()); - - AzureKeyVaultService azureKeyVaultService = new AzureKeyVaultService(keyVaultConfig, azureKeyVaultClientDelegate); + public void getSecretGetsSpecificVersionOfSecretIfVersionProvided() { + String secretName = "name"; + String secretVersion = "version"; AzureGetSecretData getSecretData = mock(AzureGetSecretData.class); - when(getSecretData.getSecretName()).thenReturn(secretId); + when(getSecretData.getSecretName()).thenReturn(secretName); + when(getSecretData.getSecretVersion()).thenReturn(secretVersion); + + SecretBundle secretBundle = mock(SecretBundle.class); + when(azureKeyVaultClientDelegate.getSecret(anyString(), anyString(), anyString())).thenReturn(secretBundle); + when(secretBundle.value()).thenReturn("value"); - azureKeyVaultService.getSecret(getSecretData); + keyVaultService.getSecret(getSecretData); - verify(azureKeyVaultClientDelegate).getSecret(url, secretId); + verify(azureKeyVaultClientDelegate).getSecret(vaultUrl, secretName, secretVersion); } @Test - public void vaultUrlIsNotSetIfKeyVaultConfigNotDefined() { - when(azureKeyVaultClientDelegate.getSecret(any(), any())).thenReturn(new SecretBundle()); + public void getSecretThrowsExceptionIfKeyNotFoundInVault() { + when(azureKeyVaultClientDelegate.getSecret(anyString(), anyString())).thenReturn(null); - AzureKeyVaultService azureKeyVaultService = new AzureKeyVaultService(null, azureKeyVaultClientDelegate); + AzureKeyVaultService azureKeyVaultService = new AzureKeyVaultService(keyVaultConfig, azureKeyVaultClientDelegate); - AzureGetSecretData getSecretData = mock(AzureGetSecretData.class); - when(getSecretData.getSecretName()).thenReturn("secret"); + String secretName = "secret"; + AzureGetSecretData getSecretData = mock(AzureGetSecretData.class); + when(getSecretData.getSecretName()).thenReturn(secretName); - azureKeyVaultService.getSecret(getSecretData); + Throwable throwable = catchThrowable(() -> azureKeyVaultService.getSecret(getSecretData)); - verify(azureKeyVaultClientDelegate).getSecret(null, "secret"); + assertThat(throwable).isInstanceOf(VaultSecretNotFoundException.class); + assertThat(throwable).hasMessageContaining("Azure Key Vault secret " + secretName + " was not found in vault " + vaultUrl); } @Test public void getSecretThrowsExceptionIfWrongDataImplProvided() { - AzureKeyVaultService azureKeyVaultService = new AzureKeyVaultService(null, azureKeyVaultClientDelegate); - GetSecretData wrongImpl = mock(GetSecretData.class); - Throwable ex = catchThrowable(() -> azureKeyVaultService.getSecret(wrongImpl)); + Throwable ex = catchThrowable(() -> keyVaultService.getSecret(wrongImpl)); assertThat(ex).isInstanceOf(KeyVaultException.class); assertThat(ex.getMessage()).isEqualTo("Incorrect data type passed to AzureKeyVaultService. Type was null"); } @Test - public void setSecretRequestIsUsedToRetrieveSecretFromVault() { - AzureKeyVaultConfig keyVaultConfig = new AzureKeyVaultConfig("url"); - - AzureKeyVaultService azureKeyVaultService = new AzureKeyVaultService(keyVaultConfig, azureKeyVaultClientDelegate); - + public void setSecret() { + AzureSetSecretData setSecretData = mock(AzureSetSecretData.class); String secretName = "id"; String secret = "secret"; - - AzureSetSecretData setSecretData = mock(AzureSetSecretData.class); when(setSecretData.getSecretName()).thenReturn(secretName); when(setSecretData.getSecret()).thenReturn(secret); - azureKeyVaultService.setSecret(setSecretData); + keyVaultService.setSecret(setSecretData); - SetSecretRequest expected = new SetSecretRequest.Builder(keyVaultConfig.getUrl(), secretName, secret).build(); + SetSecretRequest expected = new SetSecretRequest.Builder(vaultUrl, secretName, secret).build(); ArgumentCaptor argument = ArgumentCaptor.forClass(SetSecretRequest.class); verify(azureKeyVaultClientDelegate).setSecret(argument.capture()); @@ -116,11 +118,9 @@ public void setSecretRequestIsUsedToRetrieveSecretFromVault() { @Test public void setSecretThrowsExceptionIfWrongDataImplProvided() { - AzureKeyVaultService azureKeyVaultService = new AzureKeyVaultService(null, azureKeyVaultClientDelegate); - SetSecretData wrongImpl = mock(SetSecretData.class); - Throwable ex = catchThrowable(() -> azureKeyVaultService.setSecret(wrongImpl)); + Throwable ex = catchThrowable(() -> keyVaultService.setSecret(wrongImpl)); assertThat(ex).isInstanceOf(KeyVaultException.class); assertThat(ex.getMessage()).isEqualTo("Incorrect data type passed to AzureKeyVaultService. Type was null"); From adf041d513bc54eab848395f2426572542e7891a Mon Sep 17 00:00:00 2001 From: chris-j-h Date: Mon, 17 Dec 2018 17:22:53 +0000 Subject: [PATCH 2/5] Update config to allow version of Azure secret to be specified --- .../com/quorum/tessera/config/KeyData.java | 26 ++++++++++- .../config/adapters/KeyDataAdapter.java | 8 +++- .../config/keypairs/AzureVaultKeyPair.java | 21 ++++++++- .../config/keypairs/UnsupportedKeyPair.java | 26 ++++++++++- .../config/vault/data/AzureGetSecretData.java | 9 +++- .../quorum/tessera/config/ValidationTest.java | 43 ++++++++++++++++--- .../config/adapters/KeyDataAdapterTest.java | 8 ++-- .../keypairs/AzureVaultKeyPairTest.java | 6 ++- .../keypairs/UnsupportedKeyPairTest.java | 2 +- .../vault/data/AzureGetSecretDataTest.java | 5 ++- 10 files changed, 136 insertions(+), 18 deletions(-) diff --git a/config/src/main/java/com/quorum/tessera/config/KeyData.java b/config/src/main/java/com/quorum/tessera/config/KeyData.java index b48b1823c5..cccbed665e 100644 --- a/config/src/main/java/com/quorum/tessera/config/KeyData.java +++ b/config/src/main/java/com/quorum/tessera/config/KeyData.java @@ -43,6 +43,12 @@ public class KeyData extends ConfigItem { @Pattern(regexp = "^[0-9a-zA-Z\\-]*$") private String azureVaultPrivateKeyId; + @XmlElement + private String azureVaultPublicKeyVersion; + + @XmlElement + private String azureVaultPrivateKeyVersion; + @XmlElement private String hashicorpVaultPublicKeyId; @@ -58,7 +64,7 @@ public class KeyData extends ConfigItem { @XmlElement private String hashicorpVaultSecretVersion; - public KeyData(KeyDataConfig config, String privateKey, String publicKey, Path privateKeyPath, Path publicKeyPath, String azureVaultPublicKeyId, String azureVaultPrivateKeyId, String hashicorpVaultPublicKeyId, String hashicorpVaultPrivateKeyId, String hashicorpVaultSecretEngineName, String hashicorpVaultSecretName, String hashicorpVaultSecretVersion) { + public KeyData(KeyDataConfig config, String privateKey, String publicKey, Path privateKeyPath, Path publicKeyPath, String azureVaultPublicKeyId, String azureVaultPrivateKeyId, String azureVaultPublicKeyVersion, String azureVaultPrivateKeyVersion, String hashicorpVaultPublicKeyId, String hashicorpVaultPrivateKeyId, String hashicorpVaultSecretEngineName, String hashicorpVaultSecretName, String hashicorpVaultSecretVersion) { this.config = config; this.privateKey = privateKey; this.publicKey = publicKey; @@ -66,6 +72,8 @@ public KeyData(KeyDataConfig config, String privateKey, String publicKey, Path p this.publicKeyPath = publicKeyPath; this.azureVaultPublicKeyId = azureVaultPublicKeyId; this.azureVaultPrivateKeyId = azureVaultPrivateKeyId; + this.azureVaultPublicKeyVersion = azureVaultPublicKeyVersion; + this.azureVaultPrivateKeyVersion = azureVaultPrivateKeyVersion; this.hashicorpVaultPublicKeyId = hashicorpVaultPublicKeyId; this.hashicorpVaultPrivateKeyId = hashicorpVaultPrivateKeyId; this.hashicorpVaultSecretEngineName = hashicorpVaultSecretEngineName; @@ -105,6 +113,14 @@ public String getAzureVaultPrivateKeyId() { return azureVaultPrivateKeyId; } + public String getAzureVaultPublicKeyVersion() { + return azureVaultPublicKeyVersion; + } + + public String getAzureVaultPrivateKeyVersion() { + return azureVaultPrivateKeyVersion; + } + public String getHashicorpVaultPublicKeyId() { return hashicorpVaultPublicKeyId; } @@ -153,6 +169,14 @@ public void setAzureVaultPrivateKeyId(String azureVaultPrivateKeyId) { this.azureVaultPrivateKeyId = azureVaultPrivateKeyId; } + public void setAzureVaultPublicKeyVersion(String azureVaultPublicKeyVersion) { + this.azureVaultPublicKeyVersion = azureVaultPublicKeyVersion; + } + + public void setAzureVaultPrivateKeyVersion(String azureVaultPrivateKeyVersion) { + this.azureVaultPrivateKeyVersion = azureVaultPrivateKeyVersion; + } + public void setHashicorpVaultPublicKeyId(String hashicorpVaultPublicKeyId) { this.hashicorpVaultPublicKeyId = hashicorpVaultPublicKeyId; } diff --git a/config/src/main/java/com/quorum/tessera/config/adapters/KeyDataAdapter.java b/config/src/main/java/com/quorum/tessera/config/adapters/KeyDataAdapter.java index 02ee470e33..e64f411bce 100644 --- a/config/src/main/java/com/quorum/tessera/config/adapters/KeyDataAdapter.java +++ b/config/src/main/java/com/quorum/tessera/config/adapters/KeyDataAdapter.java @@ -25,7 +25,7 @@ public ConfigKeyPair unmarshal(final KeyData keyData) { //case 3, the Azure Key Vault data is provided if(keyData.getAzureVaultPublicKeyId() != null && keyData.getAzureVaultPrivateKeyId() != null) { - return new AzureVaultKeyPair(keyData.getAzureVaultPublicKeyId(), keyData.getAzureVaultPrivateKeyId()); + return new AzureVaultKeyPair(keyData.getAzureVaultPublicKeyId(), keyData.getAzureVaultPrivateKeyId(), keyData.getAzureVaultPublicKeyVersion(), keyData.getAzureVaultPrivateKeyVersion()); } //case 4, the Hashicorp Vault data is provided @@ -48,6 +48,8 @@ public ConfigKeyPair unmarshal(final KeyData keyData) { keyData.getPublicKeyPath(), keyData.getAzureVaultPublicKeyId(), keyData.getAzureVaultPrivateKeyId(), + keyData.getAzureVaultPublicKeyVersion(), + keyData.getAzureVaultPrivateKeyVersion(), keyData.getHashicorpVaultPublicKeyId(), keyData.getHashicorpVaultPrivateKeyId(), keyData.getHashicorpVaultSecretEngineName(), @@ -82,6 +84,8 @@ public KeyData marshal(final ConfigKeyPair keyPair) { keyData.setAzureVaultPublicKeyId(kp.getPublicKeyId()); keyData.setAzureVaultPrivateKeyId(kp.getPrivateKeyId()); + keyData.setAzureVaultPublicKeyVersion(kp.getPublicKeyVersion()); + keyData.setAzureVaultPrivateKeyVersion(kp.getPrivateKeyVersion()); return keyData; } @@ -113,6 +117,8 @@ public KeyData marshal(final ConfigKeyPair keyPair) { kp.getPublicKeyPath(), kp.getAzureVaultPrivateKeyId(), kp.getAzureVaultPublicKeyId(), + kp.getAzureVaultPublicKeyVersion(), + kp.getAzureVaultPrivateKeyVersion(), kp.getHashicorpVaultPrivateKeyId(), kp.getHashicorpVaultPublicKeyId(), kp.getHashicorpVaultSecretEngineName(), diff --git a/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java b/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java index 58adf21dfc..23ffea8bde 100644 --- a/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java +++ b/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java @@ -2,6 +2,7 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; import javax.xml.bind.annotation.XmlElement; public class AzureVaultKeyPair implements ConfigKeyPair { @@ -18,9 +19,19 @@ public class AzureVaultKeyPair implements ConfigKeyPair { message = "Azure Key Vault key IDs can only contain alphanumeric characters and dashes (-)") private String privateKeyId; - public AzureVaultKeyPair(String publicKeyId, String privateKeyId) { + @XmlElement + @Size(min = 32, max = 32, message = "length must be 32 characters") + private String publicKeyVersion; + + @XmlElement + @Size(min = 32, max = 32, message = "length must be 32 characters") + private String privateKeyVersion; + + public AzureVaultKeyPair(String publicKeyId, String privateKeyId, String publicKeyVersion, String privateKeyVersion) { this.publicKeyId = publicKeyId; this.privateKeyId = privateKeyId; + this.publicKeyVersion = publicKeyVersion; + this.privateKeyVersion = privateKeyVersion; } public String getPublicKeyId() { @@ -31,6 +42,14 @@ public String getPrivateKeyId() { return this.privateKeyId; } + public String getPublicKeyVersion() { + return publicKeyVersion; + } + + public String getPrivateKeyVersion() { + return privateKeyVersion; + } + @Override public String getPublicKey() { //keys are not fetched from vault yet so return null diff --git a/config/src/main/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPair.java b/config/src/main/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPair.java index 3a1a015680..b258280d2d 100644 --- a/config/src/main/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPair.java +++ b/config/src/main/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPair.java @@ -34,6 +34,12 @@ public class UnsupportedKeyPair implements ConfigKeyPair { @XmlElement private String azureVaultPrivateKeyId; + @XmlElement + private String azureVaultPublicKeyVersion; + + @XmlElement + private String azureVaultPrivateKeyVersion; + @XmlElement private String hashicorpVaultPublicKeyId; @@ -49,7 +55,7 @@ public class UnsupportedKeyPair implements ConfigKeyPair { @XmlElement private String hashicorpVaultSecretVersion; - public UnsupportedKeyPair(KeyDataConfig config, String privateKey, String publicKey, Path privateKeyPath, Path publicKeyPath, String azureVaultPublicKeyId, String azureVaultPrivateKeyId, String hashicorpVaultPublicKeyId, String hashicorpVaultPrivateKeyId, String hashicorpVaultSecretEngineName, String hashicorpVaultSecretName, String hashicorpVaultSecretVersion) { + public UnsupportedKeyPair(KeyDataConfig config, String privateKey, String publicKey, Path privateKeyPath, Path publicKeyPath, String azureVaultPublicKeyId, String azureVaultPrivateKeyId, String azureVaultPublicKeyVersion, String azureVaultPrivateKeyVersion, String hashicorpVaultPublicKeyId, String hashicorpVaultPrivateKeyId, String hashicorpVaultSecretEngineName, String hashicorpVaultSecretName, String hashicorpVaultSecretVersion) { this.config = config; this.privateKey = privateKey; this.publicKey = publicKey; @@ -57,6 +63,8 @@ public UnsupportedKeyPair(KeyDataConfig config, String privateKey, String public this.publicKeyPath = publicKeyPath; this.azureVaultPublicKeyId = azureVaultPublicKeyId; this.azureVaultPrivateKeyId = azureVaultPrivateKeyId; + this.azureVaultPublicKeyVersion = azureVaultPublicKeyVersion; + this.azureVaultPrivateKeyVersion = azureVaultPrivateKeyVersion; this.hashicorpVaultPublicKeyId = hashicorpVaultPublicKeyId; this.hashicorpVaultPrivateKeyId = hashicorpVaultPrivateKeyId; this.hashicorpVaultSecretEngineName = hashicorpVaultSecretEngineName; @@ -98,6 +106,14 @@ public String getAzureVaultPrivateKeyId() { return azureVaultPrivateKeyId; } + public String getAzureVaultPublicKeyVersion() { + return azureVaultPublicKeyVersion; + } + + public String getAzureVaultPrivateKeyVersion() { + return azureVaultPrivateKeyVersion; + } + public String getHashicorpVaultPublicKeyId() { return hashicorpVaultPublicKeyId; } @@ -156,6 +172,14 @@ public void setAzureVaultPrivateKeyId(String azureVaultPrivateKeyId) { this.azureVaultPrivateKeyId = azureVaultPrivateKeyId; } + public void setAzureVaultPublicKeyVersion(String azureVaultPublicKeyVersion) { + this.azureVaultPublicKeyVersion = azureVaultPublicKeyVersion; + } + + public void setAzureVaultPrivateKeyVersion(String azureVaultPrivateKeyVersion) { + this.azureVaultPrivateKeyVersion = azureVaultPrivateKeyVersion; + } + public void setHashicorpVaultPublicKeyId(String hashicorpVaultPublicKeyId) { this.hashicorpVaultPublicKeyId = hashicorpVaultPublicKeyId; } diff --git a/config/src/main/java/com/quorum/tessera/config/vault/data/AzureGetSecretData.java b/config/src/main/java/com/quorum/tessera/config/vault/data/AzureGetSecretData.java index 4aec1d2d16..ba9e28324d 100644 --- a/config/src/main/java/com/quorum/tessera/config/vault/data/AzureGetSecretData.java +++ b/config/src/main/java/com/quorum/tessera/config/vault/data/AzureGetSecretData.java @@ -6,8 +6,11 @@ public class AzureGetSecretData implements GetSecretData { private String secretName; - public AzureGetSecretData(String secretName) { + private String secretVersion; + + public AzureGetSecretData(String secretName, String secretVersion) { this.secretName = secretName; + this.secretVersion = secretVersion; } @Override @@ -18,4 +21,8 @@ public KeyVaultType getType() { public String getSecretName() { return secretName; } + + public String getSecretVersion() { + return secretVersion; + } } diff --git a/config/src/test/java/com/quorum/tessera/config/ValidationTest.java b/config/src/test/java/com/quorum/tessera/config/ValidationTest.java index 961a7b0d66..2ec5e76bdc 100644 --- a/config/src/test/java/com/quorum/tessera/config/ValidationTest.java +++ b/config/src/test/java/com/quorum/tessera/config/ValidationTest.java @@ -255,7 +255,7 @@ public void keypairInlineValidation() { @Test public void azureKeyPairIdsAllowedCharacterSetIsAlphanumericAndDash() { String keyVaultId = "0123456789-abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - AzureVaultKeyPair keyPair = new AzureVaultKeyPair(keyVaultId, keyVaultId); + AzureVaultKeyPair keyPair = new AzureVaultKeyPair(keyVaultId, keyVaultId, null, null); Set> violations = validator.validate(keyPair); assertThat(violations).hasSize(0); @@ -264,7 +264,7 @@ public void azureKeyPairIdsAllowedCharacterSetIsAlphanumericAndDash() { @Test public void azureKeyPairIdsDisallowedCharactersCreateViolation() { String keyVaultId = "invalid_@!£$%^~^&_id"; - AzureVaultKeyPair keyPair = new AzureVaultKeyPair(keyVaultId, keyVaultId); + AzureVaultKeyPair keyPair = new AzureVaultKeyPair(keyVaultId, keyVaultId, null, null); Set> violations = validator.validate(keyPair); assertThat(violations).hasSize(2); @@ -274,9 +274,42 @@ public void azureKeyPairIdsDisallowedCharactersCreateViolation() { "Azure Key Vault key IDs can only contain alphanumeric characters and dashes (-)"); } + @Test + public void azureKeyPairKeyVersionMustBe32CharsLong() { + String is32Chars = "12345678901234567890123456789012"; + AzureVaultKeyPair keyPair = new AzureVaultKeyPair("id", "id", is32Chars, is32Chars); + + Set> violations = validator.validate(keyPair); + assertThat(violations).hasSize(0); + } + + @Test + public void azureKeyPairKeyVersionLongerThan32CharsCreatesViolation() { + String is33Chars = "123456789012345678901234567890123"; + AzureVaultKeyPair keyPair = new AzureVaultKeyPair("id", "id", is33Chars, is33Chars); + + Set> violations = validator.validate(keyPair); + assertThat(violations).hasSize(2); + + assertThat(violations).extracting("messageTemplate") + .containsExactly("length must be 32 characters", "length must be 32 characters"); + } + + @Test + public void azureKeyPairKeyVersionShorterThan32CharsCreatesViolation() { + String is31Chars = "1234567890123456789012345678901"; + AzureVaultKeyPair keyPair = new AzureVaultKeyPair("id", "id", is31Chars, is31Chars); + + Set> violations = validator.validate(keyPair); + assertThat(violations).hasSize(2); + + assertThat(violations).extracting("messageTemplate") + .containsExactly("length must be 32 characters", "length must be 32 characters"); + } + @Test public void azureKeyPairProvidedWithoutKeyVaultConfigCreatesViolation() { - AzureVaultKeyPair keyPair = new AzureVaultKeyPair("publicVauldId", "privateVaultId"); + AzureVaultKeyPair keyPair = new AzureVaultKeyPair("publicVauldId", "privateVaultId", null, null); KeyConfiguration keyConfiguration = new KeyConfiguration(null, null, singletonList(keyPair), null, null); Config config = new Config(null, null, null, keyConfiguration, null, null, false, false); @@ -289,7 +322,7 @@ public void azureKeyPairProvidedWithoutKeyVaultConfigCreatesViolation() { @Test public void azureKeyPairProvidedWithHashicorpKeyVaultConfigCreatesViolation() { - AzureVaultKeyPair keyPair = new AzureVaultKeyPair("publicVauldId", "privateVaultId"); + AzureVaultKeyPair keyPair = new AzureVaultKeyPair("publicVauldId", "privateVaultId", null, null); KeyConfiguration keyConfiguration = new KeyConfiguration(); keyConfiguration.setKeyData(singletonList(keyPair)); @@ -382,7 +415,7 @@ public void azureVaultConfigWithNoUrlCreatesNullViolation() { @Test public void azureVaultKeyPairProvidedButKeyVaultConfigHasNullUrlCreatesNotNullViolation() { - AzureVaultKeyPair keyPair = new AzureVaultKeyPair("pubId", "privId"); + AzureVaultKeyPair keyPair = new AzureVaultKeyPair("pubId", "privId", null, null); AzureKeyVaultConfig keyVaultConfig = new AzureKeyVaultConfig(null); KeyConfiguration keyConfiguration = new KeyConfiguration(null, null, singletonList(keyPair), keyVaultConfig, null); diff --git a/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java b/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java index b51c3bd739..0db4183c3c 100644 --- a/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java +++ b/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java @@ -60,11 +60,13 @@ public void marshallFilesystemKeys() { @Test public void marshallAzureKeys() { - final AzureVaultKeyPair keyPair = new AzureVaultKeyPair("pubId", "privId"); + final AzureVaultKeyPair keyPair = new AzureVaultKeyPair("pubId", "privId", "pubVer", "privVer"); final KeyData expected = new KeyData(); expected.setAzureVaultPublicKeyId("pubId"); expected.setAzureVaultPrivateKeyId("privId"); + expected.setAzureVaultPublicKeyVersion("pubVer"); + expected.setAzureVaultPrivateKeyVersion("privVer"); final KeyData result = adapter.marshal(keyPair); @@ -90,10 +92,10 @@ public void marshallHashicorpKeys() { public void marshallUnsupportedKeys() { final KeyDataConfig keyDataConfig = mock(KeyDataConfig.class); final Path path = mock(Path.class); - final UnsupportedKeyPair keyPair = new UnsupportedKeyPair(keyDataConfig, "priv", null, path, null, null, null, null, null, null, null, null); + //set a random selection of values that are not sufficient to make a complete key pair of any type + final UnsupportedKeyPair keyPair = new UnsupportedKeyPair(keyDataConfig, "priv", null, path, null, null, null, null, null, null, null, null, null, null); final KeyData expected = new KeyData(); - //set a random selection of values that are not sufficient to make a complete key pair of any type expected.setConfig(keyDataConfig); expected.setPrivateKey("priv"); expected.setPrivateKeyPath(path); diff --git a/config/src/test/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPairTest.java b/config/src/test/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPairTest.java index 7071709534..a59b803aad 100644 --- a/config/src/test/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPairTest.java +++ b/config/src/test/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPairTest.java @@ -11,7 +11,7 @@ public class AzureVaultKeyPairTest { @Before public void setUp() { - keyPair = new AzureVaultKeyPair("pubId", "privId"); + keyPair = new AzureVaultKeyPair("pubId", "privId", "pubVer", "privVer"); } @Test @@ -21,9 +21,11 @@ public void getPrivateAndPublicKeysReturnsNull() { } @Test - public void getIdsReturnsConstructorSetValues() { + public void getters() { assertThat(keyPair.getPublicKeyId()).isEqualTo("pubId"); assertThat(keyPair.getPrivateKeyId()).isEqualTo("privId"); + assertThat(keyPair.getPublicKeyVersion()).isEqualTo("pubVer"); + assertThat(keyPair.getPrivateKeyVersion()).isEqualTo("privVer"); } @Test diff --git a/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java b/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java index 3171ea9c42..c8c7966ee9 100644 --- a/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java +++ b/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java @@ -11,7 +11,7 @@ public class UnsupportedKeyPairTest { @Before public void setUp() { - this.keyPair = new UnsupportedKeyPair(null, null, null, null, null, null, null, null, null, null, null, null); + this.keyPair = new UnsupportedKeyPair(null, null, null, null, null, null, null, null, null, null, null, null, null, null); } @Test diff --git a/config/src/test/java/com/quorum/tessera/config/vault/data/AzureGetSecretDataTest.java b/config/src/test/java/com/quorum/tessera/config/vault/data/AzureGetSecretDataTest.java index 9efeaabbdf..5e12a85896 100644 --- a/config/src/test/java/com/quorum/tessera/config/vault/data/AzureGetSecretDataTest.java +++ b/config/src/test/java/com/quorum/tessera/config/vault/data/AzureGetSecretDataTest.java @@ -8,9 +8,10 @@ public class AzureGetSecretDataTest { @Test public void getters() { - AzureGetSecretData data = new AzureGetSecretData("secretName"); + AzureGetSecretData data = new AzureGetSecretData("name", "version"); - assertThat(data.getSecretName()).isEqualTo("secretName"); + assertThat(data.getSecretName()).isEqualTo("name"); + assertThat(data.getSecretVersion()).isEqualTo("version"); assertThat(data.getType()).isEqualTo(KeyVaultType.AZURE); } } From 6798a0b2c0faf11dca3e104a956bd3f0dbd42fd1 Mon Sep 17 00:00:00 2001 From: chris-j-h Date: Mon, 17 Dec 2018 17:28:28 +0000 Subject: [PATCH 3/5] Update keygen and converter to support version-specific Azure secrets --- .../quorum/tessera/key/generation/AzureVaultKeyGenerator.java | 2 +- .../tessera/key/generation/AzureVaultKeyGeneratorTest.java | 2 +- .../com/quorum/tessera/keypairconverter/KeyPairConverter.java | 4 ++-- .../quorum/tessera/keypairconverter/KeyPairConverterTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/key-generation/src/main/java/com/quorum/tessera/key/generation/AzureVaultKeyGenerator.java b/key-generation/src/main/java/com/quorum/tessera/key/generation/AzureVaultKeyGenerator.java index 733747fe75..3cee1ed7a7 100644 --- a/key-generation/src/main/java/com/quorum/tessera/key/generation/AzureVaultKeyGenerator.java +++ b/key-generation/src/main/java/com/quorum/tessera/key/generation/AzureVaultKeyGenerator.java @@ -53,7 +53,7 @@ public AzureVaultKeyPair generate(String filename, ArgonOptions encryptionOption saveKeyInVault(publicId.toString(), keys.getPublicKey()); saveKeyInVault(privateId.toString(), keys.getPrivateKey()); - return new AzureVaultKeyPair(publicId.toString(), privateId.toString()); + return new AzureVaultKeyPair(publicId.toString(), privateId.toString(), null, null); } private void saveKeyInVault(String id, Key key) { diff --git a/key-generation/src/test/java/com/quorum/tessera/key/generation/AzureVaultKeyGeneratorTest.java b/key-generation/src/test/java/com/quorum/tessera/key/generation/AzureVaultKeyGeneratorTest.java index a6fa763f0f..9b13492f3f 100644 --- a/key-generation/src/test/java/com/quorum/tessera/key/generation/AzureVaultKeyGeneratorTest.java +++ b/key-generation/src/test/java/com/quorum/tessera/key/generation/AzureVaultKeyGeneratorTest.java @@ -64,7 +64,7 @@ public void keysSavedInVaultWithProvidedVaultIdAndCorrectSuffix() { verifyNoMoreInteractions(keyVaultService); - final AzureVaultKeyPair expected = new AzureVaultKeyPair(pubVaultId, privVaultId); + final AzureVaultKeyPair expected = new AzureVaultKeyPair(pubVaultId, privVaultId, null, null); assertThat(result).isEqualToComparingFieldByFieldRecursively(expected); } diff --git a/key-pair-converter/src/main/java/com/quorum/tessera/keypairconverter/KeyPairConverter.java b/key-pair-converter/src/main/java/com/quorum/tessera/keypairconverter/KeyPairConverter.java index 90b94d970b..e0954e5803 100644 --- a/key-pair-converter/src/main/java/com/quorum/tessera/keypairconverter/KeyPairConverter.java +++ b/key-pair-converter/src/main/java/com/quorum/tessera/keypairconverter/KeyPairConverter.java @@ -51,8 +51,8 @@ private KeyPair convert(ConfigKeyPair configKeyPair) { AzureVaultKeyPair akp = (AzureVaultKeyPair) configKeyPair; - GetSecretData getPublicKeyData = new AzureGetSecretData(akp.getPublicKeyId()); - GetSecretData getPrivateKeyData = new AzureGetSecretData(akp.getPrivateKeyId()); + GetSecretData getPublicKeyData = new AzureGetSecretData(akp.getPublicKeyId(), akp.getPublicKeyVersion()); + GetSecretData getPrivateKeyData = new AzureGetSecretData(akp.getPrivateKeyId(), akp.getPrivateKeyVersion()); base64PublicKey = keyVaultService.getSecret(getPublicKeyData); base64PrivateKey = keyVaultService.getSecret(getPrivateKeyData); diff --git a/key-pair-converter/src/test/java/com/quorum/tessera/keypairconverter/KeyPairConverterTest.java b/key-pair-converter/src/test/java/com/quorum/tessera/keypairconverter/KeyPairConverterTest.java index 0214e0ed4f..9f1db68e4c 100644 --- a/key-pair-converter/src/test/java/com/quorum/tessera/keypairconverter/KeyPairConverterTest.java +++ b/key-pair-converter/src/test/java/com/quorum/tessera/keypairconverter/KeyPairConverterTest.java @@ -80,7 +80,7 @@ public void convertSingleInlineKeyPair() { @Test //Uses com.quorum.tessera.keypairconverter.MockAzureKeyVaultServiceFactory public void convertSingleAzureVaultKeyPair() { - final AzureVaultKeyPair keyPair = new AzureVaultKeyPair("pub", "priv"); + final AzureVaultKeyPair keyPair = new AzureVaultKeyPair("pub", "priv", null, null); Collection result = converter.convert(Collections.singletonList(keyPair)); From 02a759a734881945982e75c5024e120c98939c93 Mon Sep 17 00:00:00 2001 From: chris-j-h Date: Tue, 18 Dec 2018 09:53:58 +0000 Subject: [PATCH 4/5] Update message for incomplete Hashicorp key data --- config/src/main/resources/ValidationMessages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/src/main/resources/ValidationMessages.properties b/config/src/main/resources/ValidationMessages.properties index 301defbee8..a4eba4c2bf 100644 --- a/config/src/main/resources/ValidationMessages.properties +++ b/config/src/main/resources/ValidationMessages.properties @@ -16,7 +16,7 @@ UnsupportedKeyPair.message=Invalid key-pair. Ensure that the public and private UnsupportedKeyPair.bothDirectKeysRequired.message=Invalid direct key-pair. Ensure that both the public and private keys for the key-pair have been provided. UnsupportedKeyPair.bothInlineKeysRequired.message=Invalid inline key-pair. Ensure that both the public key and private key config for the key-pair have been provided. UnsupportedKeyPair.bothAzureKeysRequired.message=Invalid Azure Key Vault key-pair. Ensure that both the public key ID and private key ID for the key-pair have been provided. -UnsupportedKeyPair.allHashicorpKeyDataRequired.message=Invalid Hashicorp Key Vault key-pair. Ensure that the public key ID, private key ID and secret path for the key-pair have been provided. +UnsupportedKeyPair.allHashicorpKeyDataRequired.message=Invalid Hashicorp Key Vault key-pair. Ensure that the secret name, secret engine name, public key ID and private key ID for the key-pair have been provided. UnsupportedKeyPair.bothFilesystemKeysRequired.message=Invalid filesystem key-pair. Ensure that both the public key path and private key path for the key-pair have been provided. ValidKeyDataConfig.message=A locked key was provided without a password.\n Please ensure the same number of passwords are provided as there are keys and remember to include empty passwords for unlocked keys InlineKeyData.message=A locked key was provided without a password.\n Please ensure the same number of passwords are provided as there are keys and remember to include empty passwords for unlocked keys From 5fac38741c2d35cf23b82e57e63fc10e92ef373b Mon Sep 17 00:00:00 2001 From: chris-j-h Date: Tue, 18 Dec 2018 13:45:32 +0000 Subject: [PATCH 5/5] Add AzureKeyPair validation to prevent only one key version being set --- .../AzureVaultKeyPairValidator.java | 29 +++++++++ .../constraints/ValidAzureVaultKeyPair.java | 25 +++++++ .../config/keypairs/AzureVaultKeyPair.java | 3 + .../resources/ValidationMessages.properties | 1 + .../quorum/tessera/config/ValidationTest.java | 24 +++++++ .../config/adapters/KeyDataAdapterTest.java | 16 ++++- .../AzureVaultKeyPairValidatorTest.java | 65 +++++++++++++++++++ .../keypairs/UnsupportedKeyPairTest.java | 8 ++- 8 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 config/src/main/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidator.java create mode 100644 config/src/main/java/com/quorum/tessera/config/constraints/ValidAzureVaultKeyPair.java create mode 100644 config/src/test/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidatorTest.java diff --git a/config/src/main/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidator.java b/config/src/main/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidator.java new file mode 100644 index 0000000000..4c2bbbddf4 --- /dev/null +++ b/config/src/main/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidator.java @@ -0,0 +1,29 @@ +package com.quorum.tessera.config.constraints; + +import com.quorum.tessera.config.keypairs.AzureVaultKeyPair; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Objects; + +public class AzureVaultKeyPairValidator implements ConstraintValidator { + + private ValidAzureVaultKeyPair annotation; + + @Override + public void initialize(ValidAzureVaultKeyPair annotation) { + this.annotation = annotation; + } + + @Override + public boolean isValid(AzureVaultKeyPair azureVaultKeyPair, ConstraintValidatorContext cvc) { + + if (azureVaultKeyPair == null) { + return true; + } + + return Objects.isNull(azureVaultKeyPair.getPublicKeyVersion()) == Objects.isNull(azureVaultKeyPair.getPrivateKeyVersion()); + + } + +} diff --git a/config/src/main/java/com/quorum/tessera/config/constraints/ValidAzureVaultKeyPair.java b/config/src/main/java/com/quorum/tessera/config/constraints/ValidAzureVaultKeyPair.java new file mode 100644 index 0000000000..4abafc6fa8 --- /dev/null +++ b/config/src/main/java/com/quorum/tessera/config/constraints/ValidAzureVaultKeyPair.java @@ -0,0 +1,25 @@ +package com.quorum.tessera.config.constraints; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({FIELD, PARAMETER, ANNOTATION_TYPE, ElementType.TYPE}) +@Retention(RUNTIME) +@Constraint(validatedBy = AzureVaultKeyPairValidator.class) +@Documented +public @interface ValidAzureVaultKeyPair { + + String message() default "{AzureVaultKeyData.message}"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java b/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java index 23ffea8bde..44e5990e12 100644 --- a/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java +++ b/config/src/main/java/com/quorum/tessera/config/keypairs/AzureVaultKeyPair.java @@ -1,10 +1,13 @@ package com.quorum.tessera.config.keypairs; +import com.quorum.tessera.config.constraints.ValidAzureVaultKeyPair; + import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import javax.xml.bind.annotation.XmlElement; +@ValidAzureVaultKeyPair public class AzureVaultKeyPair implements ConfigKeyPair { @NotNull diff --git a/config/src/main/resources/ValidationMessages.properties b/config/src/main/resources/ValidationMessages.properties index a4eba4c2bf..1abe27bf2c 100644 --- a/config/src/main/resources/ValidationMessages.properties +++ b/config/src/main/resources/ValidationMessages.properties @@ -20,6 +20,7 @@ UnsupportedKeyPair.allHashicorpKeyDataRequired.message=Invalid Hashicorp Key Vau UnsupportedKeyPair.bothFilesystemKeysRequired.message=Invalid filesystem key-pair. Ensure that both the public key path and private key path for the key-pair have been provided. ValidKeyDataConfig.message=A locked key was provided without a password.\n Please ensure the same number of passwords are provided as there are keys and remember to include empty passwords for unlocked keys InlineKeyData.message=A locked key was provided without a password.\n Please ensure the same number of passwords are provided as there are keys and remember to include empty passwords for unlocked keys +AzureVaultKeyData.message=Only one key version was provided for the Azure vault key pair. Either set the version for both the public and private key, or leave both unset ValidKeyConfiguration.message=A password file and inline passwords were provided. Please choose one or the other ValidKeyVaultConfiguration.message=No key vault configuration was specified but vault key data was provided ValidKeyVaultConfiguration.azure.message=No azureKeyVaultConfig was specified but azureVaultPublicKeyId and azureVaultPrivateKeyId were provided diff --git a/config/src/test/java/com/quorum/tessera/config/ValidationTest.java b/config/src/test/java/com/quorum/tessera/config/ValidationTest.java index 2ec5e76bdc..6b404a9041 100644 --- a/config/src/test/java/com/quorum/tessera/config/ValidationTest.java +++ b/config/src/test/java/com/quorum/tessera/config/ValidationTest.java @@ -307,6 +307,30 @@ public void azureKeyPairKeyVersionShorterThan32CharsCreatesViolation() { .containsExactly("length must be 32 characters", "length must be 32 characters"); } + @Test + public void azureKeyPairOnlyPublicKeyVersionSetCreatesViolation() { + String is32Chars = "12345678901234567890123456789012"; + + AzureVaultKeyPair azureVaultKeyPair = new AzureVaultKeyPair("pubId", "privId", is32Chars, null); + + Set> violations = validator.validate(azureVaultKeyPair); + assertThat(violations).hasSize(1); + + assertThat(violations.iterator().next().getMessage()).isEqualTo("Only one key version was provided for the Azure vault key pair. Either set the version for both the public and private key, or leave both unset"); + } + + @Test + public void azureKeyPairOnlyPrivateKeyVersionSetCreatesViolation() { + String is32Chars = "12345678901234567890123456789012"; + + AzureVaultKeyPair azureVaultKeyPair = new AzureVaultKeyPair("pubId", "privId", null, is32Chars); + + Set> violations = validator.validate(azureVaultKeyPair); + assertThat(violations).hasSize(1); + + assertThat(violations.iterator().next().getMessage()).isEqualTo("Only one key version was provided for the Azure vault key pair. Either set the version for both the public and private key, or leave both unset"); + } + @Test public void azureKeyPairProvidedWithoutKeyVaultConfigCreatesViolation() { AzureVaultKeyPair keyPair = new AzureVaultKeyPair("publicVauldId", "privateVaultId", null, null); diff --git a/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java b/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java index 0db4183c3c..5fd8339989 100644 --- a/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java +++ b/config/src/test/java/com/quorum/tessera/config/adapters/KeyDataAdapterTest.java @@ -182,10 +182,24 @@ public void unmarshallingFilesystemKeysGivesCorrectKeypair() { } @Test - public void unmarshallingAzureKeysGivesCorrectKeyPair() { + public void unmarshallingAzureKeysWithNoVersionsGivesCorrectKeyPair() { final KeyData input = new KeyData(); input.setAzureVaultPublicKeyId("pubId"); input.setAzureVaultPrivateKeyId("privId"); + input.setAzureVaultPublicKeyVersion(null); + input.setAzureVaultPrivateKeyVersion(null); + + final ConfigKeyPair result = this.adapter.unmarshal(input); + assertThat(result).isInstanceOf(AzureVaultKeyPair.class); + } + + @Test + public void unmarshallingAzureKeysWithVersionsGivesCorrectKeyPair() { + final KeyData input = new KeyData(); + input.setAzureVaultPublicKeyId("pubId"); + input.setAzureVaultPrivateKeyId("privId"); + input.setAzureVaultPublicKeyVersion("pubVer"); + input.setAzureVaultPrivateKeyVersion("privVer"); final ConfigKeyPair result = this.adapter.unmarshal(input); assertThat(result).isInstanceOf(AzureVaultKeyPair.class); diff --git a/config/src/test/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidatorTest.java b/config/src/test/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidatorTest.java new file mode 100644 index 0000000000..7341bbb491 --- /dev/null +++ b/config/src/test/java/com/quorum/tessera/config/constraints/AzureVaultKeyPairValidatorTest.java @@ -0,0 +1,65 @@ +package com.quorum.tessera.config.constraints; + +import com.quorum.tessera.config.keypairs.AzureVaultKeyPair; +import org.junit.Before; +import org.junit.Test; + +import javax.validation.ConstraintValidatorContext; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AzureVaultKeyPairValidatorTest { + + private AzureVaultKeyPairValidator validator; + + private AzureVaultKeyPair keyPair; + + private ConstraintValidatorContext cvc; + + @Before + public void setUp() { + this.validator = new AzureVaultKeyPairValidator(); + this.keyPair = mock(AzureVaultKeyPair.class); + this.cvc = mock(ConstraintValidatorContext.class); + } + + @Test + public void nullKeyPairIsValid() { + assertThat(validator.isValid(null, cvc)).isTrue(); + } + + @Test + public void publicAndPrivateKeyVersionsNotSetIsValid() { + when(keyPair.getPublicKeyVersion()).thenReturn(null); + when(keyPair.getPrivateKeyVersion()).thenReturn(null); + + assertThat(validator.isValid(keyPair, cvc)).isTrue(); + } + + @Test + public void publicAndPrivateKeyVersionsAreSetIsValid() { + when(keyPair.getPublicKeyVersion()).thenReturn("pubVer"); + when(keyPair.getPrivateKeyVersion()).thenReturn("privVer"); + + assertThat(validator.isValid(keyPair, cvc)).isTrue(); + } + + @Test + public void onlyPublicKeyVersionSetIsNotValid() { + when(keyPair.getPublicKeyVersion()).thenReturn("pubVer"); + when(keyPair.getPrivateKeyVersion()).thenReturn(null); + + assertThat(validator.isValid(keyPair, cvc)).isFalse(); + } + + @Test + public void onlyPrivateKeyVersionSetIsNotValid() { + when(keyPair.getPublicKeyVersion()).thenReturn(null); + when(keyPair.getPrivateKeyVersion()).thenReturn("privVer"); + + assertThat(validator.isValid(keyPair, cvc)).isFalse(); + } + +} diff --git a/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java b/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java index c8c7966ee9..916e5056db 100644 --- a/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java +++ b/config/src/test/java/com/quorum/tessera/config/keypairs/UnsupportedKeyPairTest.java @@ -24,12 +24,18 @@ public void getPasswordAlwaysReturnsNull() { } @Test - public void setHashicorpVaultSecretVersion() { + public void versionSetters() { assertThat(keyPair.getHashicorpVaultSecretVersion()).isNull(); + assertThat(keyPair.getAzureVaultPublicKeyVersion()).isNull(); + assertThat(keyPair.getAzureVaultPrivateKeyVersion()).isNull(); keyPair.setHashicorpVaultSecretVersion("1"); + keyPair.setAzureVaultPublicKeyVersion("pubVer"); + keyPair.setAzureVaultPrivateKeyVersion("privVer"); assertThat(keyPair.getHashicorpVaultSecretVersion()).isEqualTo("1"); + assertThat(keyPair.getAzureVaultPublicKeyVersion()).isEqualTo("pubVer"); + assertThat(keyPair.getAzureVaultPrivateKeyVersion()).isEqualTo("privVer"); } }