From ed268e3c500fdfc9c03dd10e9285b7af7f09add1 Mon Sep 17 00:00:00 2001 From: Justin Field Date: Thu, 14 Sep 2017 14:00:08 -0700 Subject: [PATCH] Bugfix/process vault data generically (#63) * Process Vault data genericaly and overwrite parse response body so it doesn't leak data if there is an error * update version --- gradle.properties | 2 +- .../cerberus/client/CerberusAdminClient.java | 56 +++++++++++++++++++ .../cerberus/domain/cms/SafeDepositBox.java | 6 +- .../core/CreateCerberusBackupOperation.java | 10 ++-- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0326a2d6..e429638f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,4 +16,4 @@ group=com.nike artifactId=cerberus-lifecycle-cli -version=3.2.0 +version=3.2.1 diff --git a/src/main/java/com/nike/cerberus/client/CerberusAdminClient.java b/src/main/java/com/nike/cerberus/client/CerberusAdminClient.java index 6eb44503..f7e5e3d7 100644 --- a/src/main/java/com/nike/cerberus/client/CerberusAdminClient.java +++ b/src/main/java/com/nike/cerberus/client/CerberusAdminClient.java @@ -17,11 +17,16 @@ package com.nike.cerberus.client; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; import com.nike.cerberus.domain.cms.SafeDepositBox; import com.nike.cerberus.domain.cms.SdbMetadataResult; import com.nike.vault.client.UrlResolver; import com.nike.vault.client.VaultAdminClient; import com.nike.vault.client.VaultClientException; +import com.nike.vault.client.VaultServerException; import com.nike.vault.client.auth.VaultCredentialsProvider; import com.nike.vault.client.http.HttpHeader; import com.nike.vault.client.http.HttpMethod; @@ -55,6 +60,11 @@ public class CerberusAdminClient extends VaultAdminClient { protected UrlResolver vaultUrlResolver; protected ObjectMapper objectMapper; + protected final Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .disableHtmlEscaping() + .create(); + /** * Explicit constructor that allows for full control over construction of the Vault client. * @@ -176,4 +186,50 @@ protected M parseCmsResponseBody(final Response response, final Class res throw new VaultClientException("Error parsing the response body from CMS", e); } } + + /** + * Read operation for a specified path. Will return a {@link Map} of the data stored at the specified path. + * If Vault returns an unexpected response code, a {@link VaultServerException} will be thrown with the code + * and error details. If an unexpected I/O error is encountered, a {@link VaultClientException} will be thrown + * wrapping the underlying exception. + * + * @param path Path to the data + * @return Map of the data + */ + public GenericVaultResponse readDataGenerically(final String path) { + final HttpUrl url = buildUrl(SECRET_PATH_PREFIX, path); + log.debug("read: requestUrl={}", url); + + final Response response = execute(url, HttpMethod.GET, null); + + if (response.code() != HttpStatus.OK) { + parseAndThrowErrorResponse(response); + } + + return parseResponseBody(response, GenericVaultResponse.class); + } + + public class GenericVaultResponse { + private Map data; + + public Map getData() { + return data; + } + + public GenericVaultResponse setData(Map data) { + this.data = data; + return this; + } + } + + protected M parseResponseBody(final Response response, final Class responseClass) { + final String responseBodyStr = responseBodyAsString(response); + try { + return gson.fromJson(responseBodyStr, responseClass); + } catch (JsonSyntaxException e) { + log.error("parseResponseBody: responseCode={}, requestUrl={}", + response.code(), response.request().url()); + throw new VaultClientException("Error parsing the response body from vault, response code: " + response.code(), e); + } + } } diff --git a/src/main/java/com/nike/cerberus/domain/cms/SafeDepositBox.java b/src/main/java/com/nike/cerberus/domain/cms/SafeDepositBox.java index e79ab5fd..ec0065dd 100644 --- a/src/main/java/com/nike/cerberus/domain/cms/SafeDepositBox.java +++ b/src/main/java/com/nike/cerberus/domain/cms/SafeDepositBox.java @@ -36,7 +36,7 @@ public class SafeDepositBox { private String lastUpdatedBy; private Map userGroupPermissions; private Map iamRolePermissions; - private Map> data = new HashMap<>(); + private Map> data = new HashMap<>(); public String getName() { return name; @@ -134,11 +134,11 @@ public void setIamRolePermissions(Map iamRolePermissions) { this.iamRolePermissions = iamRolePermissions; } - public Map> getData() { + public Map> getData() { return data; } - public void setData(Map> data) { + public void setData(Map> data) { this.data = data; } } diff --git a/src/main/java/com/nike/cerberus/operation/core/CreateCerberusBackupOperation.java b/src/main/java/com/nike/cerberus/operation/core/CreateCerberusBackupOperation.java index c8dc039a..e6ebb235 100644 --- a/src/main/java/com/nike/cerberus/operation/core/CreateCerberusBackupOperation.java +++ b/src/main/java/com/nike/cerberus/operation/core/CreateCerberusBackupOperation.java @@ -133,7 +133,7 @@ public void run(CreateCerberusBackupCommand command) { CerberusSdbMetadata cerberusSdbMetadata = new CerberusSdbMetadata(); for (SafeDepositBox sdb : sdbMetadataList) { log.info(String.format("Backing up %s", sdb.getName())); - Map> vaultData = recurseVault(sdb.getPath(), new HashMap<>()); + Map> vaultData = recurseVault(sdb.getPath(), new HashMap<>()); sdb.setData(vaultData); String key = sdb.getName().toLowerCase().replaceAll("\\W+", "-"); saveDataToS3(sdb, prefix, key, regionsToStoreBackups); @@ -217,7 +217,7 @@ private CerberusSdbMetadata processMetadata(SafeDepositBox sdb, final CerberusSd newMetadata.getUniqueNonOwnerGroups().add(userGroup); }); - Map> vaultNodes = sdb.getData(); + Map> vaultNodes = sdb.getData(); newMetadata.setNumberOfDataNodes(newMetadata.getNumberOfDataNodes() + vaultNodes.size()); vaultNodes.forEach((path, kvPairs) -> { newMetadata.setNumberOfKeyValuePairs(newMetadata.getNumberOfKeyValuePairs() + kvPairs.size()); @@ -231,7 +231,7 @@ private CerberusSdbMetadata processMetadata(SafeDepositBox sdb, final CerberusSd * @param path The path to recurse * @return Map of Vault path Strings to Maps of String, String containing the secret kv pairs */ - private Map> recurseVault(String path, Map> data) { + private Map> recurseVault(String path, Map> data) { List keys = getKeys(path); keys.forEach(key -> { @@ -263,8 +263,8 @@ private List getKeys(String path) { * @param path The path of data to download * @return The data map */ - private Map getData(String path) { - VaultResponse response = cerberusAdminClient.read(path); + private Map getData(String path) { + CerberusAdminClient.GenericVaultResponse response = cerberusAdminClient.readDataGenerically(path); return response.getData(); }