diff --git a/src/main/java/com/bettercloud/vault/api/Logical.java b/src/main/java/com/bettercloud/vault/api/Logical.java index 0fed2937..75a29063 100644 --- a/src/main/java/com/bettercloud/vault/api/Logical.java +++ b/src/main/java/com/bettercloud/vault/api/Logical.java @@ -28,6 +28,7 @@ public class Logical { private final VaultConfig config; + private static final int defaultSecretVersion = 0; //set as logical flag to read latest secrets of kv v1 and v2 without a given version number public Logical(final VaultConfig config) { this.config = config; @@ -51,20 +52,36 @@ public Logical(final VaultConfig config) { * @throws VaultException If any errors occurs with the REST request (e.g. non-200 status code, invalid JSON payload, etc), and the maximum number of retries is exceeded. */ public LogicalResponse read(final String path) throws VaultException { + return read(path, defaultSecretVersion); + } + + /** + *
Basic read operation to retrieve a secret of specific version
+ * + * @param path The Vault key value from which to read + * @param secretVersion version number of key-value secret, set to 0 for kv version-1, set greater than 0 for kv version-2 + * @return The response information returned from Vault + * @throws VaultException If any errors occurs with the REST request (e.g. non-200 status code, invalid JSON payload, etc), and the maximum number of retries is exceeded. + */ + public LogicalResponse read(final String path, final int secretVersion) throws VaultException { final String version = getSecretEngineVersion(getPathSegments(path).get(0)); + if (secretVersion > 0 && "1".equals(version)) { + throw new VaultException("Detected vault v1 which doesn't support kv v2 secret versioning, please enable KV Secrets Engine - Version 2 \n"); + } final String adjustedPath = adjustPathForReadOrWrite(path); + final String url = getVersionedUrl(secretVersion, adjustedPath); int retryCount = 0; while (true) { try { // Make an HTTP request to Vault final RestResponse restResponse = new Rest()//NOPMD - .url(config.getAddress() + "/v1/" + adjustedPath) - .header("X-Vault-Token", config.getToken()) - .connectTimeoutSeconds(config.getOpenTimeout()) - .readTimeoutSeconds(config.getReadTimeout()) - .sslPemUTF8(config.getSslPemUTF8()) - .sslVerification(config.isSslVerify() != null ? config.isSslVerify() : null) - .get(); + .url(url) + .header("X-Vault-Token", config.getToken()) + .connectTimeoutSeconds(config.getOpenTimeout()) + .readTimeoutSeconds(config.getReadTimeout()) + .sslPemUTF8(config.getSslPemUTF8()) + .sslVerification(config.isSslVerify() != null ? config.isSslVerify() : null) + .get(); // Validate response if (restResponse.getStatus() != 200) { @@ -93,6 +110,11 @@ public LogicalResponse read(final String path) throws VaultException { } } + private String getVersionedUrl(int secretVersion, String adjustedPath) { + return secretVersion > 0 ? String.format("%s/v1/%s?version=%d", config.getAddress(), adjustedPath, secretVersion) : + String.format("%s/v1/%s", config.getAddress(), adjustedPath); + } + /** *Basic operation to store secrets. Multiple name value pairs can be stored under the same secret key. * E.g.:
diff --git a/src/test-integration/java/com/bettercloud/vault/api/LogicalV2Tests.java b/src/test-integration/java/com/bettercloud/vault/api/LogicalV2Tests.java new file mode 100644 index 00000000..6b47685f --- /dev/null +++ b/src/test-integration/java/com/bettercloud/vault/api/LogicalV2Tests.java @@ -0,0 +1,48 @@ +package com.bettercloud.vault.api; + +import com.bettercloud.vault.Vault; +import com.bettercloud.vault.VaultConfig; +import com.bettercloud.vault.VaultException; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; + +/** + * Integration test to run on KV Secrets Engine - Version 2 + * This test expects the vault is running with url http://localhost:8200 and enabled a token as "00000000-0000-0000-0000-000000000000" with read and write privilege. + */ +public class LogicalV2Tests { + private static final String address = "http://localhost:8200"; + private static final String token = "00000000-0000-0000-0000-000000000000"; + private static final boolean isVerifySsl = false; + private static Vault vault; + + @BeforeClass + public static void setUp() throws VaultException { + VaultConfig vaultConfig = new VaultConfig().address(address) + .token(token).sslVerify(isVerifySsl).build(); + vault = new Vault(vaultConfig); + } + + @Test + public void testReadAndWrite() throws VaultException { + final String path = "secret/place"; + final String key = "city"; + final String value_1 = "Bangalore"; + final String value_2 = "Denver"; + vault.logical().write(path, new HashMap