From 13ce32adcd589959ca71dd7796f7fc7f78bb821a Mon Sep 17 00:00:00 2001 From: Jesse Peirce Date: Tue, 25 Oct 2016 14:43:58 -0700 Subject: [PATCH] Use the new HMAC column in secret representations --- .../automation/v2/SecretDetailResponseV2.java | 7 +++ .../keywhiz/api/model/SanitizedSecret.java | 10 ++-- .../main/java/keywhiz/api/model/Secret.java | 11 +++- .../java/keywhiz/api/model/SecretContent.java | 6 ++- .../api/AutomationSecretResponseTest.java | 2 +- .../api/SecretDeliveryResponseTest.java | 2 +- .../java/keywhiz/api/SecretsResponseTest.java | 2 + .../v2/SecretDetailResponseV2Test.java | 5 +- .../api/model/SanitizedSecretTest.java | 53 +++++++++++++++++++ .../java/keywhiz/api/model/SecretTest.java | 2 +- .../resources/fixtures/sanitizedSecret.json | 1 + .../resources/fixtures/secretsResponse.json | 2 + .../fixtures/v2/secretDetailResponse.json | 1 + .../keywhiz/cli/commands/AddActionTest.java | 2 +- .../cli/commands/AssignActionTest.java | 2 +- .../cli/commands/DeleteActionTest.java | 2 +- .../cli/commands/DescribeActionTest.java | 2 +- .../cli/commands/UnassignActionTest.java | 2 +- .../service/crypto/ContentCryptographer.java | 14 +++++ .../crypto/ContentEncodingException.java | 10 ++++ .../service/crypto/SecretTransformer.java | 1 + .../java/keywhiz/service/daos/AclDAO.java | 4 ++ .../service/daos/SecretContentDAO.java | 3 +- .../service/daos/SecretContentMapper.java | 1 + .../service/daos/SecretController.java | 16 ++++-- .../java/keywhiz/service/daos/SecretDAO.java | 12 ++--- .../automation/v2/SecretResource.java | 1 + .../service/daos/SecretContentDAOTest.java | 9 ++-- .../keywhiz/service/daos/SecretDAOTest.java | 35 +++++++----- .../keywhiz/service/daos/SecretFixtures.java | 9 +++- .../service/daos/SecretSeriesDAOTest.java | 8 +-- ...SecretDeliveryResourceIntegrationTest.java | 2 +- .../resources/SecretDeliveryResourceTest.java | 8 +-- ...ecretsDeliveryResourceIntegrationTest.java | 7 +-- .../SecretsDeliveryResourceTest.java | 4 +- .../resources/admin/ClientsResourceTest.java | 2 +- .../resources/admin/GroupsResourceTest.java | 2 +- .../admin/MembershipResourceTest.java | 2 +- .../admin/SecretsResourceIntegrationTest.java | 7 +-- .../resources/admin/SecretsResourceTest.java | 6 +-- .../AutomationGroupResourceTest.java | 4 +- .../AutomationSecretResourceTest.java | 3 +- 42 files changed, 212 insertions(+), 72 deletions(-) create mode 100644 server/src/main/java/keywhiz/service/crypto/ContentEncodingException.java diff --git a/api/src/main/java/keywhiz/api/automation/v2/SecretDetailResponseV2.java b/api/src/main/java/keywhiz/api/automation/v2/SecretDetailResponseV2.java index e1c4abca1..fac6d8269 100644 --- a/api/src/main/java/keywhiz/api/automation/v2/SecretDetailResponseV2.java +++ b/api/src/main/java/keywhiz/api/automation/v2/SecretDetailResponseV2.java @@ -22,6 +22,7 @@ public static Builder builder() { return new AutoValue_SecretDetailResponseV2.Builder() .content("") + .checksum("") .description("") .type(null) .metadata(ImmutableMap.of()); @@ -37,6 +38,7 @@ public static Builder builder() { public abstract Builder name(String name); public abstract Builder version(@Nullable long version); // Unique ID in secrets_content table public abstract Builder content(String secret); + public abstract Builder checksum(String checksum); public abstract Builder description(String description); public abstract Builder createdAtSeconds(long createdAt); public abstract Builder createdBy(String person); @@ -62,6 +64,7 @@ public Builder secret(Secret secret) { .name(secret.getName()) .description(secret.getDescription()) .content(secret.getSecret()) + .checksum(secret.getChecksum()) .createdAtSeconds(secret.getCreatedAt().toEpochSecond()) .createdBy(secret.getCreatedBy()) .type(secret.getType().orElse(null)) @@ -100,6 +103,7 @@ public SecretDetailResponseV2 build() { @JsonProperty("version") @Nullable long version, @JsonProperty("description") @Nullable String description, @JsonProperty("content") String content, + @JsonProperty("checksum") String checksum, @JsonProperty("size") UnsignedLong size, @JsonProperty("createdAtSeconds") long createdAtSeconds, @JsonProperty("createdBy") String createdBy, @@ -111,6 +115,7 @@ public SecretDetailResponseV2 build() { .version(version) .description(nullToEmpty(description)) .content(content) + .checksum(checksum) .size(size) .createdAtSeconds(createdAtSeconds) .createdBy(createdBy) @@ -125,6 +130,7 @@ public SecretDetailResponseV2 build() { @JsonProperty("version") @Nullable public abstract long version(); @JsonProperty("description") public abstract String description(); @JsonProperty("content") public abstract String content(); + @JsonProperty("checksum") public abstract String checksum(); @JsonProperty("size") public abstract UnsignedLong size(); @JsonProperty("createdAtSeconds") public abstract long createdAtSeconds(); @JsonProperty("createdBy") public abstract String createdBy(); @@ -137,6 +143,7 @@ public SecretDetailResponseV2 build() { .add("name", name()) .add("description", description()) .add("content", "[REDACTED]") + .add("checksum", checksum()) .add("size", size()) .add("createdAtSeconds", createdAtSeconds()) .add("createdBy", createdBy()) diff --git a/api/src/main/java/keywhiz/api/model/SanitizedSecret.java b/api/src/main/java/keywhiz/api/model/SanitizedSecret.java index 28633604a..488887cb9 100644 --- a/api/src/main/java/keywhiz/api/model/SanitizedSecret.java +++ b/api/src/main/java/keywhiz/api/model/SanitizedSecret.java @@ -19,9 +19,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import java.util.List; import java.util.Map; import java.util.Optional; import javax.annotation.Nullable; @@ -38,6 +36,7 @@ public abstract class SanitizedSecret { @JsonCreator public static SanitizedSecret of( @JsonProperty("id") long id, @JsonProperty("name") String name, + @JsonProperty("checksum") String checksum, @JsonProperty("description") @Nullable String description, @JsonProperty("createdAt") ApiDate createdAt, @JsonProperty("createdBy") @Nullable String createdBy, @@ -51,13 +50,13 @@ public abstract class SanitizedSecret { (metadata == null) ? ImmutableMap.of() : ImmutableMap.copyOf(metadata); ImmutableMap genOptions = (generationOptions == null) ? ImmutableMap.of() : ImmutableMap.copyOf(generationOptions); - return new AutoValue_SanitizedSecret(id, name, nullToEmpty(description), createdAt, + return new AutoValue_SanitizedSecret(id, name, checksum, nullToEmpty(description), createdAt, nullToEmpty(createdBy), updatedAt, nullToEmpty(updatedBy), meta, Optional.ofNullable(type), genOptions, expiry); } public static SanitizedSecret of(long id, String name) { - return of(id, name, null, new ApiDate(0), null, new ApiDate(0), null, null, null, null, 0); + return of(id, name, "", null, new ApiDate(0), null, new ApiDate(0), null, null, null, null, 0); } public static SanitizedSecret fromSecretSeriesAndContent(SecretSeriesAndContent seriesAndContent) { @@ -66,6 +65,7 @@ public static SanitizedSecret fromSecretSeriesAndContent(SecretSeriesAndContent return SanitizedSecret.of( series.id(), series.name(), + content.hmac(), series.description(), content.createdAt(), content.createdBy(), @@ -88,6 +88,7 @@ public static SanitizedSecret fromSecret(Secret secret) { return SanitizedSecret.of( secret.getId(), secret.getName(), + secret.getChecksum(), secret.getDescription(), secret.getCreatedAt(), secret.getCreatedBy(), @@ -101,6 +102,7 @@ public static SanitizedSecret fromSecret(Secret secret) { @JsonProperty public abstract long id(); @JsonProperty public abstract String name(); + @JsonProperty public abstract String checksum(); @JsonProperty public abstract String description(); @JsonProperty public abstract ApiDate createdAt(); @JsonProperty public abstract String createdBy(); diff --git a/api/src/main/java/keywhiz/api/model/Secret.java b/api/src/main/java/keywhiz/api/model/Secret.java index 1ad51b34c..08ca6a9aa 100644 --- a/api/src/main/java/keywhiz/api/model/Secret.java +++ b/api/src/main/java/keywhiz/api/model/Secret.java @@ -47,6 +47,7 @@ public class Secret { /** Base64-encoded content of this version of the secret. */ private String secret; private final LazyString encryptedSecret; + private final String checksum; private final ApiDate createdAt; private final String createdBy; @@ -65,6 +66,7 @@ public Secret(long id, String name, @Nullable String description, LazyString encryptedSecret, + String checksum, ApiDate createdAt, @Nullable String createdBy, ApiDate updatedAt, @@ -79,6 +81,7 @@ public Secret(long id, this.name = name; this.description = nullToEmpty(description); this.encryptedSecret = checkNotNull(encryptedSecret); + this.checksum = checksum; this.createdAt = checkNotNull(createdAt); this.createdBy = nullToEmpty(createdBy); this.updatedAt = checkNotNull(updatedAt); @@ -115,6 +118,10 @@ public String getSecret() { return secret; } + public String getChecksum() { + return checksum; + } + public ApiDate getCreatedAt() { return createdAt; } @@ -163,6 +170,7 @@ public boolean equals(Object o) { Objects.equal(this.name, that.name) && Objects.equal(this.description, that.description) && Objects.equal(this.getSecret(), that.getSecret()) && + Objects.equal(this.getChecksum(), that.getChecksum()) && Objects.equal(this.createdAt, that.createdAt) && Objects.equal(this.createdBy, that.createdBy) && Objects.equal(this.updatedAt, that.updatedAt) && @@ -178,7 +186,7 @@ public boolean equals(Object o) { } @Override public int hashCode() { - return Objects.hashCode(id, name, description, getSecret(), createdAt, createdBy, updatedAt, + return Objects.hashCode(id, name, description, getSecret(), checksum, createdAt, createdBy, updatedAt, updatedBy, metadata, type, generationOptions, expiry); } @@ -189,6 +197,7 @@ public String toString() { .add("name", name) .add("description", description) .add("secret", "[REDACTED]") + .add("checksum", checksum) .add("creationDate", createdAt) .add("createdBy", createdBy) .add("updatedDate", updatedAt) diff --git a/api/src/main/java/keywhiz/api/model/SecretContent.java b/api/src/main/java/keywhiz/api/model/SecretContent.java index 0d324eb6c..4f3c7b8cb 100644 --- a/api/src/main/java/keywhiz/api/model/SecretContent.java +++ b/api/src/main/java/keywhiz/api/model/SecretContent.java @@ -32,10 +32,10 @@ */ @AutoValue public abstract class SecretContent { - public static SecretContent of(long id, long secretSeriesId, String encryptedContent, ApiDate createdAt, + public static SecretContent of(long id, long secretSeriesId, String encryptedContent, String hmac, ApiDate createdAt, @Nullable String createdBy, ApiDate updatedAt, @Nullable String updatedBy, ImmutableMap metadata, long expiry) { - return new AutoValue_SecretContent(id, secretSeriesId, encryptedContent, + return new AutoValue_SecretContent(id, secretSeriesId, encryptedContent, hmac, createdAt, nullToEmpty(createdBy), updatedAt, nullToEmpty(updatedBy), metadata, expiry); } @@ -43,6 +43,7 @@ createdAt, nullToEmpty(createdBy), updatedAt, public abstract long id(); public abstract long secretSeriesId(); public abstract String encryptedContent(); + public abstract String hmac(); public abstract ApiDate createdAt(); public abstract String createdBy(); public abstract ApiDate updatedAt(); @@ -55,6 +56,7 @@ createdAt, nullToEmpty(createdBy), updatedAt, .add("id", id()) .add("secretSeriesId", secretSeriesId()) .add("encryptedContent", "[REDACTED]") + .add("checksum", hmac()) .add("createdAt", createdAt()) .add("createdBy", createdBy()) .add("updatedAt", updatedAt()) diff --git a/api/src/test/java/keywhiz/api/AutomationSecretResponseTest.java b/api/src/test/java/keywhiz/api/AutomationSecretResponseTest.java index eed6c0b0f..955a1a834 100644 --- a/api/src/test/java/keywhiz/api/AutomationSecretResponseTest.java +++ b/api/src/test/java/keywhiz/api/AutomationSecretResponseTest.java @@ -33,7 +33,7 @@ public class AutomationSecretResponseTest { private static final ImmutableMap metadata = ImmutableMap.of("key1", "value1", "key2", "value2"); private static final ApiDate NOW = ApiDate.now(); - private static final Secret secret = new Secret(0, "name", null, () -> "YWJj", NOW, null, NOW, null, metadata, + private static final Secret secret = new Secret(0, "name", null, () -> "YWJj", "checksum", NOW, null, NOW, null, metadata, "upload", null, 1136214245); @Test diff --git a/api/src/test/java/keywhiz/api/SecretDeliveryResponseTest.java b/api/src/test/java/keywhiz/api/SecretDeliveryResponseTest.java index ab4e7d22d..57230f610 100644 --- a/api/src/test/java/keywhiz/api/SecretDeliveryResponseTest.java +++ b/api/src/test/java/keywhiz/api/SecretDeliveryResponseTest.java @@ -30,7 +30,7 @@ public class SecretDeliveryResponseTest { private static final ImmutableMap metadata = ImmutableMap.of("key1", "value1", "key2", "value2"); private static final ApiDate NOW = ApiDate.now(); - private static final Secret secret = new Secret(0, "name", null, () -> "YWJj", NOW, null, NOW, null, metadata, + private static final Secret secret = new Secret(0, "name", null, () -> "YWJj", "checksum", NOW, null, NOW, null, metadata, "upload", null, 0); @Test diff --git a/api/src/test/java/keywhiz/api/SecretsResponseTest.java b/api/src/test/java/keywhiz/api/SecretsResponseTest.java index 8e7301b93..9ad9aa40c 100644 --- a/api/src/test/java/keywhiz/api/SecretsResponseTest.java +++ b/api/src/test/java/keywhiz/api/SecretsResponseTest.java @@ -31,6 +31,7 @@ public class SecretsResponseTest { SanitizedSecret.of( 767, "trapdoor", + "checksum", "v1", ApiDate.parse("2013-03-28T21:42:42.573Z"), "keywhizAdmin", @@ -43,6 +44,7 @@ public class SecretsResponseTest { SanitizedSecret.of( 768, "anotherSecret", + "checksum", "", ApiDate.parse("2013-04-28T21:42:42.573Z"), "keywhizAdmin", diff --git a/api/src/test/java/keywhiz/api/automation/v2/SecretDetailResponseV2Test.java b/api/src/test/java/keywhiz/api/automation/v2/SecretDetailResponseV2Test.java index 28f2d0777..c5d0c0e6d 100644 --- a/api/src/test/java/keywhiz/api/automation/v2/SecretDetailResponseV2Test.java +++ b/api/src/test/java/keywhiz/api/automation/v2/SecretDetailResponseV2Test.java @@ -37,6 +37,7 @@ public class SecretDetailResponseV2Test { .version(1) .description("secret-description") .content("YXNkZGFz") + .checksum("checksum") .createdAtSeconds(OffsetDateTime.parse("2013-03-28T21:23:04.159Z").toEpochSecond()) .createdBy("creator-user") .type("text/plain") @@ -56,6 +57,7 @@ public class SecretDetailResponseV2Test { SecretDetailResponseV2 secretDetailResponse = SecretDetailResponseV2.builder() .series(series) .content("YXNkZGFz") + .checksum("checksum") .metadata(ImmutableMap.of("owner", "root")) .expiry(1136214245) .build(); @@ -65,7 +67,7 @@ public class SecretDetailResponseV2Test { } @Test public void formsCorrectlyFromSecret() throws Exception { - Secret secret = new Secret(1, "secret-name", "secret-description", () -> "", + Secret secret = new Secret(1, "secret-name", "secret-description", () -> "", "checksum", ApiDate.parse("2013-03-28T21:23:04.159Z"), "creator-user", ApiDate.parse("2013-03-28T21:23:04.159Z"), "creator-user", ImmutableMap.of("owner", "root"), "text/plain", null, @@ -88,6 +90,7 @@ public class SecretDetailResponseV2Test { SecretDetailResponseV2 secretDetailResponse = SecretDetailResponseV2.builder() .secretVersion(version) .content("YXNkZGFz") + .checksum("checksum") .build(); assertThat(asJson(secretDetailResponse)) diff --git a/api/src/test/java/keywhiz/api/model/SanitizedSecretTest.java b/api/src/test/java/keywhiz/api/model/SanitizedSecretTest.java index adcec18e1..253435c09 100644 --- a/api/src/test/java/keywhiz/api/model/SanitizedSecretTest.java +++ b/api/src/test/java/keywhiz/api/model/SanitizedSecretTest.java @@ -29,6 +29,7 @@ public class SanitizedSecretTest { SanitizedSecret sanitizedSecret = SanitizedSecret.of( 767, "trapdoor", + "checksum", "v1", ApiDate.parse("2013-03-28T21:42:42.573Z"), "keywhizAdmin", @@ -42,4 +43,56 @@ public class SanitizedSecretTest { assertThat(asJson(sanitizedSecret)) .isEqualTo(jsonFixture("fixtures/sanitizedSecret.json")); } + + @Test public void buildsCorrectlyFromSecret() throws Exception { + SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecret( + new Secret( + 767, + "trapdoor", + "v1", + () -> "foo", + "checksum", + ApiDate.parse("2013-03-28T21:42:42.573Z"), + "keywhizAdmin", + ApiDate.parse("2013-03-28T21:42:42.573Z"), + "keywhizAdmin", + ImmutableMap.of("owner", "the king"), + "password", + ImmutableMap.of("favoriteFood", "PB&J sandwich"), + 1136214245)); + + assertThat(asJson(sanitizedSecret)) + .isEqualTo(jsonFixture("fixtures/sanitizedSecret.json")); + } + + @Test public void buildsCorrectlyFromSecretSeriesAndContent() throws Exception { + SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecretSeriesAndContent( + SecretSeriesAndContent.of( + SecretSeries.of( + 767, + "trapdoor", + "v1", + ApiDate.parse("2013-03-28T21:42:42.573Z"), + "keywhizAdmin", + ApiDate.parse("2013-03-28T21:42:42.573Z"), + "keywhizAdmin", + "password", + ImmutableMap.of("favoriteFood", "PB&J sandwich"), + 1136214245L + ), SecretContent.of( + 1L, + 767, + "foo", + "checksum", + ApiDate.parse("2013-03-28T21:42:42.573Z"), + "keywhizAdmin", + ApiDate.parse("2013-03-28T21:42:42.573Z"), + "keywhizAdmin", + ImmutableMap.of("owner", "the king"), + 1136214245L + ))); + + assertThat(asJson(sanitizedSecret)) + .isEqualTo(jsonFixture("fixtures/sanitizedSecret.json")); + } } diff --git a/api/src/test/java/keywhiz/api/model/SecretTest.java b/api/src/test/java/keywhiz/api/model/SecretTest.java index 3e08157c7..9ce9fa2b3 100644 --- a/api/src/test/java/keywhiz/api/model/SecretTest.java +++ b/api/src/test/java/keywhiz/api/model/SecretTest.java @@ -45,7 +45,7 @@ public class SecretTest { } @Test public void callsDecryptOnlyOnce() { - Secret s = new Secret(42, "toto", null, () -> String.valueOf(++called), ApiDate.now(), "", ApiDate.now(), "", null, + Secret s = new Secret(42, "toto", null, () -> String.valueOf(++called), "checksum", ApiDate.now(), "", ApiDate.now(), "", null, null, null, 0); assertThat(s.getSecret()).isEqualTo("1"); assertThat(s.getSecret()).isEqualTo("1"); diff --git a/api/src/test/resources/fixtures/sanitizedSecret.json b/api/src/test/resources/fixtures/sanitizedSecret.json index d17fb9e55..5b659c7d5 100644 --- a/api/src/test/resources/fixtures/sanitizedSecret.json +++ b/api/src/test/resources/fixtures/sanitizedSecret.json @@ -1,6 +1,7 @@ { "id" : 767, "name" : "trapdoor", + "checksum" : "checksum", "description" : "v1", "createdAt" : "2013-03-28T21:42:42.000Z", "createdBy" : "keywhizAdmin", diff --git a/api/src/test/resources/fixtures/secretsResponse.json b/api/src/test/resources/fixtures/secretsResponse.json index 27647928f..2b2dc2694 100644 --- a/api/src/test/resources/fixtures/secretsResponse.json +++ b/api/src/test/resources/fixtures/secretsResponse.json @@ -3,6 +3,7 @@ { "id" : 767, "name" : "trapdoor", + "checksum": "checksum", "description" : "v1", "createdAt" : "2013-03-28T21:42:42.000Z", "createdBy" : "keywhizAdmin", @@ -20,6 +21,7 @@ { "id" : 768, "name" : "anotherSecret", + "checksum" : "checksum", "description" : "", "createdAt" : "2013-04-28T21:42:42.000Z", "createdBy" : "keywhizAdmin", diff --git a/api/src/test/resources/fixtures/v2/secretDetailResponse.json b/api/src/test/resources/fixtures/v2/secretDetailResponse.json index a8f2cf2be..bec63624e 100644 --- a/api/src/test/resources/fixtures/v2/secretDetailResponse.json +++ b/api/src/test/resources/fixtures/v2/secretDetailResponse.json @@ -3,6 +3,7 @@ "version" : 1, "description" : "secret-description", "content": "YXNkZGFz", + "checksum": "checksum", "size":6, "createdAtSeconds": 1364505784, "createdBy": "creator-user", diff --git a/cli/src/test/java/keywhiz/cli/commands/AddActionTest.java b/cli/src/test/java/keywhiz/cli/commands/AddActionTest.java index 8e8da88f8..94a35b894 100644 --- a/cli/src/test/java/keywhiz/cli/commands/AddActionTest.java +++ b/cli/src/test/java/keywhiz/cli/commands/AddActionTest.java @@ -55,7 +55,7 @@ public class AddActionTest { Client client = new Client(4, "newClient", null, null, null, null, null, null, true, false); Group group = new Group(4, "newGroup", null, null, null, null, null, null); - Secret secret = new Secret(15, "newSecret", null, () -> "c2VjcmV0MQ==", NOW, null, NOW, null, null, null, + Secret secret = new Secret(15, "newSecret", null, () -> "c2VjcmV0MQ==", "checksum", NOW, null, NOW, null, null, null, ImmutableMap.of(), 0); SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecret(secret); SecretDetailResponse secretDetailResponse = SecretDetailResponse.fromSecret(secret, null, null); diff --git a/cli/src/test/java/keywhiz/cli/commands/AssignActionTest.java b/cli/src/test/java/keywhiz/cli/commands/AssignActionTest.java index 1dba4cd48..02eabbba4 100644 --- a/cli/src/test/java/keywhiz/cli/commands/AssignActionTest.java +++ b/cli/src/test/java/keywhiz/cli/commands/AssignActionTest.java @@ -53,7 +53,7 @@ public class AssignActionTest { Group group = new Group(5, "group", null, null, null, null, null, null); GroupDetailResponse groupDetailResponse = GroupDetailResponse.fromGroup(group, ImmutableList.of(), ImmutableList.of()); - Secret secret = new Secret(16, "secret", null, () -> "c2VjcmV0MQ==", NOW, null, NOW, null, null, null, + Secret secret = new Secret(16, "secret", null, () -> "c2VjcmV0MQ==", "checksum", NOW, null, NOW, null, null, null, ImmutableMap.of(), 0); SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecret(secret); diff --git a/cli/src/test/java/keywhiz/cli/commands/DeleteActionTest.java b/cli/src/test/java/keywhiz/cli/commands/DeleteActionTest.java index 0cb0a50d2..8a6bf0c50 100644 --- a/cli/src/test/java/keywhiz/cli/commands/DeleteActionTest.java +++ b/cli/src/test/java/keywhiz/cli/commands/DeleteActionTest.java @@ -50,7 +50,7 @@ public class DeleteActionTest { DeleteActionConfig deleteActionConfig; DeleteAction deleteAction; - Secret secret = new Secret(0, "secret", null, () -> "c2VjcmV0MQ==", NOW, null, NOW, null, null, null, + Secret secret = new Secret(0, "secret", null, () -> "c2VjcmV0MQ==", "checksum", NOW, null, NOW, null, null, null, ImmutableMap.of(), 0); SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecret(secret); diff --git a/cli/src/test/java/keywhiz/cli/commands/DescribeActionTest.java b/cli/src/test/java/keywhiz/cli/commands/DescribeActionTest.java index f3f441a3b..a22349964 100644 --- a/cli/src/test/java/keywhiz/cli/commands/DescribeActionTest.java +++ b/cli/src/test/java/keywhiz/cli/commands/DescribeActionTest.java @@ -48,7 +48,7 @@ public class DescribeActionTest { DescribeActionConfig describeActionConfig; DescribeAction describeAction; - Secret secret = new Secret(0, "secret", null, () -> "c2VjcmV0MQ==", NOW, null, NOW, null, null, null, + Secret secret = new Secret(0, "secret", null, () -> "c2VjcmV0MQ==", "checksum", NOW, null, NOW, null, null, null, ImmutableMap.of(), 0); SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecret(secret); diff --git a/cli/src/test/java/keywhiz/cli/commands/UnassignActionTest.java b/cli/src/test/java/keywhiz/cli/commands/UnassignActionTest.java index 640e6314e..dfdbea2b9 100644 --- a/cli/src/test/java/keywhiz/cli/commands/UnassignActionTest.java +++ b/cli/src/test/java/keywhiz/cli/commands/UnassignActionTest.java @@ -49,7 +49,7 @@ public class UnassignActionTest { Client client = new Client(11, "client-name", null, null, null, null, null, null, false, false); Group group = new Group(22, "group-name", null, null, null, null, null, null); - Secret secret = new Secret(33, "secret-name", null, () -> "c2VjcmV0MQ==", NOW, null, NOW, null, null, null, + Secret secret = new Secret(33, "secret-name", null, () -> "c2VjcmV0MQ==", "checksum", NOW, null, NOW, null, null, null, ImmutableMap.of(), 0); SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecret(secret); GroupDetailResponse groupDetailResponse = GroupDetailResponse.fromGroup(group, diff --git a/server/src/main/java/keywhiz/service/crypto/ContentCryptographer.java b/server/src/main/java/keywhiz/service/crypto/ContentCryptographer.java index 2794040ae..75869e0b4 100644 --- a/server/src/main/java/keywhiz/service/crypto/ContentCryptographer.java +++ b/server/src/main/java/keywhiz/service/crypto/ContentCryptographer.java @@ -23,6 +23,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.MoreObjects; import com.google.common.base.Throwables; +import com.google.common.io.BaseEncoding; import io.dropwizard.jackson.Jackson; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; @@ -35,6 +36,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; @@ -149,6 +151,18 @@ public String decrypt(String ciphertextJson) { return getEncoder().encodeToString(plaintext); } + public String computeHmac(byte[] data) { + SecretKey hmacKey = deriveKey(32, "hmackey"); + try { + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(hmacKey); + return BaseEncoding.base16().encode(mac.doFinal(data)); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + logger.warn("Error computing HMAC: ", e); + return null; + } + } + private SecretKey deriveKey(int blockSize, String info) { Hkdf hkdf = Hkdf.usingProvider(derivationProvider); byte[] infoBytes = info.getBytes(UTF_8); diff --git a/server/src/main/java/keywhiz/service/crypto/ContentEncodingException.java b/server/src/main/java/keywhiz/service/crypto/ContentEncodingException.java new file mode 100644 index 000000000..6715ee40f --- /dev/null +++ b/server/src/main/java/keywhiz/service/crypto/ContentEncodingException.java @@ -0,0 +1,10 @@ +package keywhiz.service.crypto; + +/** + * An exception to be thrown when the ContentCryptographer fails + */ +public class ContentEncodingException extends RuntimeException { + public ContentEncodingException(String msg) { + super(msg); + } +} diff --git a/server/src/main/java/keywhiz/service/crypto/SecretTransformer.java b/server/src/main/java/keywhiz/service/crypto/SecretTransformer.java index f45b5073a..b08a74010 100644 --- a/server/src/main/java/keywhiz/service/crypto/SecretTransformer.java +++ b/server/src/main/java/keywhiz/service/crypto/SecretTransformer.java @@ -47,6 +47,7 @@ public Secret transform(SecretSeriesAndContent seriesAndContent) { series.name(), series.description(), () -> cryptographer.decrypt(content.encryptedContent()), + content.hmac(), content.createdAt(), content.createdBy(), content.updatedAt(), diff --git a/server/src/main/java/keywhiz/service/daos/AclDAO.java b/server/src/main/java/keywhiz/service/daos/AclDAO.java index 02dc67db4..fcce45d1d 100644 --- a/server/src/main/java/keywhiz/service/daos/AclDAO.java +++ b/server/src/main/java/keywhiz/service/daos/AclDAO.java @@ -267,6 +267,7 @@ public ImmutableSet getSanitizedSecretsFor(Client client) { .join(SECRETS_CONTENT).on(SECRETS_CONTENT.ID.eq(SECRETS.CURRENT)) .where(CLIENTS.NAME.eq(client.getName()).and(SECRETS.CURRENT.isNotNull())) .getQuery(); + query.addSelect(SECRETS_CONTENT.CONTENT_HMAC); query.addSelect(SECRETS_CONTENT.CREATEDAT); query.addSelect(SECRETS_CONTENT.CREATEDBY); query.addSelect(SECRETS_CONTENT.UPDATEDAT); @@ -279,6 +280,7 @@ public ImmutableSet getSanitizedSecretsFor(Client client) { return SanitizedSecret.of( series.id(), series.name(), + row.getValue(SECRETS_CONTENT.CONTENT_HMAC), series.description(), new ApiDate(row.getValue(SECRETS_CONTENT.CREATEDAT)), row.getValue(SECRETS_CONTENT.CREATEDBY), @@ -322,6 +324,7 @@ public Optional getSanitizedSecretFor(Client client, String sec .and(SECRETS.NAME.eq(secretName))) .limit(1) .getQuery(); + query.addSelect(SECRETS_CONTENT.CONTENT_HMAC); query.addSelect(SECRETS_CONTENT.CREATEDAT); query.addSelect(SECRETS_CONTENT.CREATEDBY); query.addSelect(SECRETS_CONTENT.UPDATEDAT); @@ -334,6 +337,7 @@ public Optional getSanitizedSecretFor(Client client, String sec return SanitizedSecret.of( series.id(), series.name(), + row.getValue(SECRETS_CONTENT.CONTENT_HMAC), series.description(), new ApiDate(row.getValue(SECRETS_CONTENT.CREATEDAT)), row.getValue(SECRETS_CONTENT.CREATEDBY), diff --git a/server/src/main/java/keywhiz/service/daos/SecretContentDAO.java b/server/src/main/java/keywhiz/service/daos/SecretContentDAO.java index 3fb2f0ac9..20b46aa89 100644 --- a/server/src/main/java/keywhiz/service/daos/SecretContentDAO.java +++ b/server/src/main/java/keywhiz/service/daos/SecretContentDAO.java @@ -60,7 +60,7 @@ private SecretContentDAO(DSLContext dslContext, ObjectMapper mapper, this.secretContentMapper = secretContentMapper; } - public long createSecretContent(long secretId, String encryptedContent, + public long createSecretContent(long secretId, String encryptedContent, String hmac, String creator, Map metadata, long expiry) { SecretsContentRecord r = dslContext.newRecord(SECRETS_CONTENT); @@ -76,6 +76,7 @@ public long createSecretContent(long secretId, String encryptedContent, r.setSecretid(secretId); r.setEncryptedContent(encryptedContent); + r.setContentHmac(hmac); r.setCreatedby(creator); r.setCreatedat(now); r.setUpdatedby(creator); diff --git a/server/src/main/java/keywhiz/service/daos/SecretContentMapper.java b/server/src/main/java/keywhiz/service/daos/SecretContentMapper.java index 02ddfa302..994911175 100644 --- a/server/src/main/java/keywhiz/service/daos/SecretContentMapper.java +++ b/server/src/main/java/keywhiz/service/daos/SecretContentMapper.java @@ -41,6 +41,7 @@ public SecretContent map(SecretsContentRecord r) { r.getId(), r.getSecretid(), r.getEncryptedContent(), + r.getContentHmac(), new ApiDate(r.getCreatedat()), r.getCreatedby(), new ApiDate(r.getUpdatedat()), diff --git a/server/src/main/java/keywhiz/service/daos/SecretController.java b/server/src/main/java/keywhiz/service/daos/SecretController.java index ae2edc35b..1d0c69cc0 100644 --- a/server/src/main/java/keywhiz/service/daos/SecretController.java +++ b/server/src/main/java/keywhiz/service/daos/SecretController.java @@ -26,12 +26,14 @@ import keywhiz.api.model.SanitizedSecret; import keywhiz.api.model.Secret; import keywhiz.service.crypto.ContentCryptographer; +import keywhiz.service.crypto.ContentEncodingException; import keywhiz.service.crypto.SecretTransformer; import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.stream.Collectors.toList; public class SecretController { @@ -85,8 +87,12 @@ public SecretBuilder builder(String name, String secret, String creator, long ex checkArgument(!name.isEmpty()); checkArgument(!secret.isEmpty()); checkArgument(!creator.isEmpty()); + String hmac = cryptographer.computeHmac(secret.getBytes(UTF_8)); // Compute HMAC on base64 encoded data + if (hmac == null) { + throw new ContentEncodingException("Error encoding content for SecretBuilder!"); + } String encryptedSecret = cryptographer.encryptionKeyDerivedFrom(name).encrypt(secret); - return new SecretBuilder(transformer, secretDAO, name, encryptedSecret, creator, expiry); + return new SecretBuilder(transformer, secretDAO, name, encryptedSecret, hmac, creator, expiry); } /** Builder to generate new secret series or versions with. */ @@ -95,6 +101,7 @@ public static class SecretBuilder { private final SecretDAO secretDAO; private final String name; private final String encryptedSecret; + private final String hmac; private final String creator; private String description = ""; private Map metadata = ImmutableMap.of(); @@ -110,11 +117,12 @@ public static class SecretBuilder { * @param creator username responsible for creating this secret version. */ private SecretBuilder(SecretTransformer transformer, SecretDAO secretDAO, String name, String encryptedSecret, - String creator, long expiry) { + String hmac, String creator, long expiry) { this.transformer = transformer; this.secretDAO = secretDAO; this.name = name; this.encryptedSecret = encryptedSecret; + this.hmac = hmac; this.creator = creator; this.expiry = expiry; } @@ -155,13 +163,13 @@ public SecretBuilder withType(String type) { * @return an instance of the newly created secret. */ public Secret create() { - secretDAO.createSecret(name, encryptedSecret, creator, metadata, expiry, description, type, + secretDAO.createSecret(name, encryptedSecret, hmac, creator, metadata, expiry, description, type, generationOptions); return transformer.transform(secretDAO.getSecretByName(name).get()); } public Secret createOrUpdate() { - secretDAO.createOrUpdateSecret(name, encryptedSecret, creator, metadata, expiry, description, type, + secretDAO.createOrUpdateSecret(name, encryptedSecret, hmac, creator, metadata, expiry, description, type, generationOptions); return transformer.transform(secretDAO.getSecretByName(name).get()); } diff --git a/server/src/main/java/keywhiz/service/daos/SecretDAO.java b/server/src/main/java/keywhiz/service/daos/SecretDAO.java index 1078379e9..4c626ff20 100644 --- a/server/src/main/java/keywhiz/service/daos/SecretDAO.java +++ b/server/src/main/java/keywhiz/service/daos/SecretDAO.java @@ -66,7 +66,7 @@ private SecretDAO(DSLContext dslContext, SecretContentDAOFactory secretContentDA } @VisibleForTesting - public long createSecret(String name, String encryptedSecret, + public long createSecret(String name, String encryptedSecret, String hmac, String creator, Map metadata, long expiry, String description, @Nullable String type, @Nullable Map generationOptions) { return dslContext.transactionResult(configuration -> { @@ -87,7 +87,7 @@ public long createSecret(String name, String encryptedSecret, generationOptions); } - long secretContentId = secretContentDAO.createSecretContent(secretId, encryptedSecret, creator, metadata, expiry); + long secretContentId = secretContentDAO.createSecretContent(secretId, encryptedSecret, hmac, creator, metadata, expiry); secretSeriesDAO.setCurrentVersion(secretId, secretContentId); return secretId; @@ -95,9 +95,9 @@ public long createSecret(String name, String encryptedSecret, } @VisibleForTesting - public long createOrUpdateSecret(String name, String encryptedSecret, String creator, Map metadata, - long expiry, String description, @Nullable String type, - @Nullable Map generationOptions) { + public long createOrUpdateSecret(String name, String encryptedSecret, String hmac, String creator, + Map metadata, long expiry, String description, @Nullable String type, + @Nullable Map generationOptions) { return dslContext.transactionResult(configuration -> { SecretContentDAO secretContentDAO = secretContentDAOFactory.using(configuration); SecretSeriesDAO secretSeriesDAO = secretSeriesDAOFactory.using(configuration); @@ -112,7 +112,7 @@ public long createOrUpdateSecret(String name, String encryptedSecret, String cre secretId = secretSeriesDAO.createSecretSeries(name, creator, description, type, generationOptions); } - long secretContentId = secretContentDAO.createSecretContent(secretId, encryptedSecret, creator, metadata, expiry); + long secretContentId = secretContentDAO.createSecretContent(secretId, encryptedSecret, hmac, creator, metadata, expiry); secretSeriesDAO.setCurrentVersion(secretId, secretContentId); return secretId; diff --git a/server/src/main/java/keywhiz/service/resources/automation/v2/SecretResource.java b/server/src/main/java/keywhiz/service/resources/automation/v2/SecretResource.java index c10f9f3b8..b8acd0952 100644 --- a/server/src/main/java/keywhiz/service/resources/automation/v2/SecretResource.java +++ b/server/src/main/java/keywhiz/service/resources/automation/v2/SecretResource.java @@ -323,6 +323,7 @@ public SecretDetailResponseV2 secretInfo(@Auth AutomationClient automationClient .orElseThrow(NotFoundException::new); return SecretDetailResponseV2.builder() .series(secret.series()) + .checksum(secret.content().hmac()) .expiry(secret.content().expiry()) .build(); } diff --git a/server/src/test/java/keywhiz/service/daos/SecretContentDAOTest.java b/server/src/test/java/keywhiz/service/daos/SecretContentDAOTest.java index 7408e12d8..47b795d78 100644 --- a/server/src/test/java/keywhiz/service/daos/SecretContentDAOTest.java +++ b/server/src/test/java/keywhiz/service/daos/SecretContentDAOTest.java @@ -42,7 +42,7 @@ public class SecretContentDAOTest { final static ApiDate date = ApiDate.now(); ImmutableMap metadata = ImmutableMap.of("foo", "bar"); - SecretContent secretContent1 = SecretContent.of(11, 22, "[crypted]", date, "creator", date, + SecretContent secretContent1 = SecretContent.of(11, 22, "[crypted]", "checksum", date, "creator", date, "creator", metadata, 1136214245); SecretContentDAO secretContentDAO; @@ -60,6 +60,7 @@ public void setUp() throws Exception { .set(SECRETS_CONTENT.ID, secretContent1.id()) .set(SECRETS_CONTENT.SECRETID, secretContent1.secretSeriesId()) .set(SECRETS_CONTENT.ENCRYPTED_CONTENT, secretContent1.encryptedContent()) + .set(SECRETS_CONTENT.CONTENT_HMAC, "checksum") .set(SECRETS_CONTENT.CREATEDAT, secretContent1.createdAt().toEpochSecond()) .set(SECRETS_CONTENT.CREATEDBY, secretContent1.createdBy()) .set(SECRETS_CONTENT.UPDATEDAT, secretContent1.updatedAt().toEpochSecond()) @@ -71,7 +72,7 @@ public void setUp() throws Exception { @Test public void createSecretContent() { int before = tableSize(); - secretContentDAO.createSecretContent(secretContent1.secretSeriesId()+1, "encrypted", "creator", + secretContentDAO.createSecretContent(secretContent1.secretSeriesId()+1, "encrypted", "checksum", "creator", metadata, 1136214245); assertThat(tableSize()).isEqualTo(before + 1); } @@ -90,7 +91,7 @@ public void setUp() throws Exception { long[] ids = new long[15]; for (int i = 0; i < ids.length; i++) { long id = secretContentDAO.createSecretContent( - secretSeriesId, "encrypted", "creator", metadata, 1136214245); + secretSeriesId, "encrypted", "checksum", "creator", metadata, 1136214245); ids[i] = id; } @@ -137,7 +138,7 @@ public void setUp() throws Exception { long[] ids = new long[15]; for (int i = 0; i < ids.length; i++) { long id = secretContentDAO.createSecretContent( - secretSeriesId, "encrypted", "creator", metadata, 1136214245); + secretSeriesId, "encrypted", "checksum", "creator", metadata, 1136214245); ids[i] = id; } diff --git a/server/src/test/java/keywhiz/service/daos/SecretDAOTest.java b/server/src/test/java/keywhiz/service/daos/SecretDAOTest.java index c29ca526e..38fa446b5 100644 --- a/server/src/test/java/keywhiz/service/daos/SecretDAOTest.java +++ b/server/src/test/java/keywhiz/service/daos/SecretDAOTest.java @@ -37,6 +37,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import static java.nio.charset.StandardCharsets.UTF_8; import static keywhiz.jooq.tables.Secrets.SECRETS; import static keywhiz.jooq.tables.SecretsContent.SECRETS_CONTENT; import static org.assertj.core.api.Assertions.assertThat; @@ -54,21 +55,21 @@ public class SecretDAOTest { SecretSeries series1 = SecretSeries.of(1, "secret1", "desc1", date, "creator", date, "updater", null, null, 101L); String content = "c2VjcmV0MQ=="; String encryptedContent = cryptographer.encryptionKeyDerivedFrom(series1.name()).encrypt(content); - SecretContent content1 = SecretContent.of(101, 1, encryptedContent, date, "creator", date, "updater", emptyMetadata, + SecretContent content1 = SecretContent.of(101, 1, encryptedContent, "checksum", date, "creator", date, "updater", emptyMetadata, 0); SecretSeriesAndContent secret1 = SecretSeriesAndContent.of(series1, content1); SecretSeries series2 = SecretSeries.of(2, "secret2", "desc2", date, "creator", date, "updater", null, null, 103L); - SecretContent content2a = SecretContent.of(102, 2, encryptedContent, date, "creator", date, "updater", emptyMetadata, + SecretContent content2a = SecretContent.of(102, 2, encryptedContent, "checksum", date, "creator", date, "updater", emptyMetadata, 0); SecretSeriesAndContent secret2a = SecretSeriesAndContent.of(series2, content2a); - SecretContent content2b = SecretContent.of(103, 2, "some other content", date, "creator", date, "updater", + SecretContent content2b = SecretContent.of(103, 2, "some other content", "checksum", date, "creator", date, "updater", emptyMetadata, 0); SecretSeriesAndContent secret2b = SecretSeriesAndContent.of(series2, content2b); SecretSeries series3 = SecretSeries.of(3, "secret3", "desc3", date, "creator", date, "updater", null, null, null); - SecretContent content3 = SecretContent.of(104, 3, encryptedContent, date, "creator", date, "updater", emptyMetadata, + SecretContent content3 = SecretContent.of(104, 3, encryptedContent, "checksum", date, "creator", date, "updater", emptyMetadata, 0); SecretSeriesAndContent secret3 = SecretSeriesAndContent.of(series3, content3); @@ -91,6 +92,7 @@ public void setUp() throws Exception { .set(SECRETS_CONTENT.ID, secret1.content().id()) .set(SECRETS_CONTENT.SECRETID, secret1.series().id()) .set(SECRETS_CONTENT.ENCRYPTED_CONTENT, secret1.content().encryptedContent()) + .set(SECRETS_CONTENT.CONTENT_HMAC, "checksum") .set(SECRETS_CONTENT.CREATEDBY, secret1.content().createdBy()) .set(SECRETS_CONTENT.CREATEDAT, secret1.content().createdAt().toEpochSecond()) .set(SECRETS_CONTENT.UPDATEDBY, secret1.content().updatedBy()) @@ -114,6 +116,7 @@ public void setUp() throws Exception { .set(SECRETS_CONTENT.ID, secret2a.content().id()) .set(SECRETS_CONTENT.SECRETID, secret2a.series().id()) .set(SECRETS_CONTENT.ENCRYPTED_CONTENT, secret2a.content().encryptedContent()) + .set(SECRETS_CONTENT.CONTENT_HMAC, "checksum") .set(SECRETS_CONTENT.CREATEDBY, secret2a.content().createdBy()) .set(SECRETS_CONTENT.CREATEDAT, secret2a.content().createdAt().toEpochSecond()) .set(SECRETS_CONTENT.UPDATEDBY, secret2a.content().updatedBy()) @@ -125,6 +128,7 @@ public void setUp() throws Exception { .set(SECRETS_CONTENT.ID, secret2b.content().id()) .set(SECRETS_CONTENT.SECRETID, secret2b.series().id()) .set(SECRETS_CONTENT.ENCRYPTED_CONTENT, secret2b.content().encryptedContent()) + .set(SECRETS_CONTENT.CONTENT_HMAC, "checksum") .set(SECRETS_CONTENT.CREATEDBY, secret2b.content().createdBy()) .set(SECRETS_CONTENT.CREATEDAT, secret2b.content().createdAt().toEpochSecond()) .set(SECRETS_CONTENT.UPDATEDBY, secret2b.content().updatedBy()) @@ -147,6 +151,7 @@ public void setUp() throws Exception { .set(SECRETS_CONTENT.ID, secret3.content().id()) .set(SECRETS_CONTENT.SECRETID, secret3.series().id()) .set(SECRETS_CONTENT.ENCRYPTED_CONTENT, secret3.content().encryptedContent()) + .set(SECRETS_CONTENT.CONTENT_HMAC, "checksum") .set(SECRETS_CONTENT.CREATEDBY, secret3.content().createdBy()) .set(SECRETS_CONTENT.CREATEDAT, secret3.content().createdAt().toEpochSecond()) .set(SECRETS_CONTENT.UPDATEDBY, secret3.content().updatedBy()) @@ -168,8 +173,9 @@ public void setUp() throws Exception { String name = "newSecret"; String content = "c2VjcmV0MQ=="; + String hmac = cryptographer.computeHmac(content.getBytes(UTF_8)); String encryptedContent = cryptographer.encryptionKeyDerivedFrom(name).encrypt(content); - long newId = secretDAO.createSecret(name, encryptedContent, "creator", + long newId = secretDAO.createSecret(name, encryptedContent, hmac, "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); SecretSeriesAndContent newSecret = secretDAO.getSecretById(newId).get(); @@ -183,13 +189,13 @@ public void setUp() throws Exception { @Test(expected = DataAccessException.class) public void createSecretFailsIfSecretExists() { String name = "newSecret"; - secretDAO.createSecret(name, "some secret", "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); - secretDAO.createSecret(name, "some secret", "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); + secretDAO.createSecret(name, "some secret", "checksum", "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); + secretDAO.createSecret(name, "some secret", "checksum", "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); } @Test public void createSecretSucceedsIfCurrentVersionIsNull() { String name = "newSecret"; - long firstId = secretDAO.createSecret(name, "content1", "creator1", + long firstId = secretDAO.createSecret(name, "content1", cryptographer.computeHmac("content1".getBytes(UTF_8)), "creator1", ImmutableMap.of("foo", "bar"), 1000, "description1", "type1", ImmutableMap.of()); jooqContext.update(SECRETS) @@ -197,7 +203,7 @@ public void createSecretFailsIfSecretExists() { .where(SECRETS.ID.eq(firstId)) .execute(); - long secondId = secretDAO.createSecret(name, "content2", "creator2", + long secondId = secretDAO.createSecret(name, "content2", cryptographer.computeHmac("content2".getBytes(UTF_8)), "creator2", ImmutableMap.of("foo2", "bar2"), 2000, "description2", "type2", ImmutableMap.of()); assertThat(secondId).isEqualTo(firstId); @@ -221,8 +227,9 @@ public void createSecretFailsIfSecretExists() { String name = "newSecret"; String content = "c2VjcmV0MQ=="; + String hmac = cryptographer.computeHmac(content.getBytes(UTF_8)); String encryptedContent = cryptographer.encryptionKeyDerivedFrom(name).encrypt(content); - long newId = secretDAO.createOrUpdateSecret(name, encryptedContent, "creator", + long newId = secretDAO.createOrUpdateSecret(name, encryptedContent, hmac, "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); SecretSeriesAndContent newSecret = secretDAO.getSecretById(newId).get(); @@ -235,10 +242,10 @@ public void createSecretFailsIfSecretExists() { @Test public void createOrUpdateSecretWhenSecretExists() { String name = "newSecret"; - long firstId = secretDAO.createSecret(name, "content1", "creator1", + long firstId = secretDAO.createSecret(name, "content1", cryptographer.computeHmac("content1".getBytes(UTF_8)), "creator1", ImmutableMap.of("foo", "bar"), 1000, "description1", "type1", ImmutableMap.of()); - long secondId = secretDAO.createOrUpdateSecret(name, "content2", "creator2", + long secondId = secretDAO.createOrUpdateSecret(name, "content2", cryptographer.computeHmac("content2".getBytes(UTF_8)), "creator2", ImmutableMap.of("foo2", "bar2"), 2000, "description2", "type2", ImmutableMap.of()); assertThat(secondId).isEqualTo(firstId); @@ -273,7 +280,7 @@ public void createSecretFailsIfSecretExists() { String name = "nonExistantSecret"; assertThat(secretDAO.getSecretByName(name).isPresent()).isFalse(); - long newId = secretDAO.createSecret(name, "content", "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); + long newId = secretDAO.createSecret(name, "content", cryptographer.computeHmac("content".getBytes(UTF_8)), "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); SecretSeriesAndContent newSecret = secretDAO.getSecretById(newId).get(); assertThat(secretDAO.getSecretByName(name).isPresent()).isTrue(); @@ -322,7 +329,7 @@ public void getSecretByIdOneThrowsExceptionIfCurrentVersionIsInvalid() { } @Test public void deleteSecretsByName() { - secretDAO.createSecret("toBeDeleted_deleteSecretsByName", "encryptedShhh", "creator", + secretDAO.createSecret("toBeDeleted_deleteSecretsByName", "encryptedShhh", cryptographer.computeHmac("encryptedShhh".getBytes(UTF_8)), "creator", ImmutableMap.of(), 0, "", null, null); secretDAO.deleteSecretsByName("toBeDeleted_deleteSecretsByName"); diff --git a/server/src/test/java/keywhiz/service/daos/SecretFixtures.java b/server/src/test/java/keywhiz/service/daos/SecretFixtures.java index dbb907eee..f8d995b5e 100644 --- a/server/src/test/java/keywhiz/service/daos/SecretFixtures.java +++ b/server/src/test/java/keywhiz/service/daos/SecretFixtures.java @@ -19,9 +19,12 @@ import com.google.common.collect.ImmutableMap; import keywhiz.api.model.Secret; import keywhiz.service.crypto.ContentCryptographer; +import keywhiz.service.crypto.ContentEncodingException; import keywhiz.service.crypto.CryptoFixtures; import keywhiz.service.crypto.SecretTransformer; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Helper methods to make secrets, reducing the amount of work for testing. */ @@ -51,8 +54,12 @@ public static SecretFixtures using(SecretDAO secretDAO) { * @return created secret model */ public Secret createSecret(String name, String content) { + String hmac = cryptographer.computeHmac(content.getBytes(UTF_8)); + if (hmac == null) { + throw new ContentEncodingException("Error encoding content in SecretFixture!"); + } String encryptedContent = cryptographer.encryptionKeyDerivedFrom(name).encrypt(content); - long id = secretDAO.createSecret(name, encryptedContent, "creator", ImmutableMap.of(), 0, "", null, + long id = secretDAO.createSecret(name, encryptedContent, hmac, "creator", ImmutableMap.of(), 0, "", null, ImmutableMap.of()); return transformer.transform(secretDAO.getSecretById(id).get()); } diff --git a/server/src/test/java/keywhiz/service/daos/SecretSeriesDAOTest.java b/server/src/test/java/keywhiz/service/daos/SecretSeriesDAOTest.java index 4d18e517c..f24eafc69 100644 --- a/server/src/test/java/keywhiz/service/daos/SecretSeriesDAOTest.java +++ b/server/src/test/java/keywhiz/service/daos/SecretSeriesDAOTest.java @@ -71,7 +71,7 @@ public class SecretSeriesDAOTest { Optional secretSeriesById = secretSeriesDAO.getSecretSeriesById(id); assertThat(secretSeriesById.get().currentVersion().isPresent()).isFalse(); - long contentId = secretContentDAOFactory.readwrite().createSecretContent(id, "blah", "creator", null, 0); + long contentId = secretContentDAOFactory.readwrite().createSecretContent(id, "blah", "checksum", "creator", null, 0); secretSeriesDAO.setCurrentVersion(id, contentId); secretSeriesById = secretSeriesDAO.getSecretSeriesById(id); assertThat(secretSeriesById.get().currentVersion().get()).isEqualTo(contentId); @@ -81,14 +81,14 @@ public class SecretSeriesDAOTest { public void setCurrentVersion_failsWithIncorrectSecretContent() { long id = secretSeriesDAO.createSecretSeries("someSecret", "creator", "", null, null); long other = secretSeriesDAO.createSecretSeries("someOtherSecret", "creator", "", null, null); - long contentId = secretContentDAOFactory.readwrite().createSecretContent(other, "blah", "creator", null, 0); + long contentId = secretContentDAOFactory.readwrite().createSecretContent(other, "blah", "checksum", "creator", null, 0); secretSeriesDAO.setCurrentVersion(id, contentId); } @Test public void deleteSecretSeriesByName() { long id = secretSeriesDAO.createSecretSeries("toBeDeleted_deleteSecretSeriesByName", "creator", "", null, null); - long contentId = secretContentDAOFactory.readwrite().createSecretContent(id, "blah", "creator", null, 0); + long contentId = secretContentDAOFactory.readwrite().createSecretContent(id, "blah", "checksum", "creator", null, 0); secretSeriesDAO.setCurrentVersion(id, contentId); assertThat(secretSeriesDAO.getSecretSeriesByName("toBeDeleted_deleteSecretSeriesByName").get().currentVersion().isPresent()).isTrue(); @@ -98,7 +98,7 @@ public void setCurrentVersion_failsWithIncorrectSecretContent() { @Test public void deleteSecretSeriesById() { long id = secretSeriesDAO.createSecretSeries("toBeDeleted_deleteSecretSeriesById", "creator", "", null, null); - long contentId = secretContentDAOFactory.readwrite().createSecretContent(id, "blah", "creator", null, 0); + long contentId = secretContentDAOFactory.readwrite().createSecretContent(id, "blah", "checksum", "creator", null, 0); secretSeriesDAO.setCurrentVersion(id, contentId); assertThat(secretSeriesDAO.getSecretSeriesById(id).get().currentVersion().isPresent()).isTrue(); diff --git a/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceIntegrationTest.java b/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceIntegrationTest.java index 854d7ccca..5309384dc 100644 --- a/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceIntegrationTest.java +++ b/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceIntegrationTest.java @@ -43,7 +43,7 @@ public class SecretDeliveryResourceIntegrationTest { @Before public void setUp() throws Exception { client = TestClients.mutualSslClient(); - generalPassword = new Secret(0, "General_Password", null, () -> "YXNkZGFz", + generalPassword = new Secret(0, "General_Password", null, () -> "YXNkZGFz", "checksum", ApiDate.parse("2011-09-29T15:46:00Z"), null, ApiDate.parse("2011-09-29T15:46:00Z"), null, null, "upload", null, 0); } diff --git a/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceTest.java b/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceTest.java index ec38b5745..a67236217 100644 --- a/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/SecretDeliveryResourceTest.java @@ -47,9 +47,9 @@ public class SecretDeliveryResourceTest { SecretDeliveryResource secretDeliveryResource; final Client client = new Client(0, "principal", null, null, null, null, null, null, false, false); - final Secret secret = new Secret(0, "secret_name", null, () -> "secret_value", NOW, null, NOW, null, + final Secret secret = new Secret(0, "secret_name", null, () -> "secret_value", "checksum", NOW, null, NOW, null, null, null, null, 0); - final Secret secretBase64 = new Secret(1, "Base64With=", null, () -> "SGVsbG8=", NOW, null, NOW, + final Secret secretBase64 = new Secret(1, "Base64With=", null, () -> "SGVsbG8=", "checksum", NOW, null, NOW, null, null, null, null, 0); @Before public void setUp() { @@ -57,7 +57,7 @@ public class SecretDeliveryResourceTest { } @Test public void returnsSecretWhenAllowed() throws Exception { - Secret secret = new Secret(0, "secret_name", null, () -> "unused_secret", NOW, null, NOW, null, null, null, + Secret secret = new Secret(0, "secret_name", null, () -> "unused_secret", "checksum", NOW, null, NOW, null, null, null, null, 0); SanitizedSecret sanitizedSecret = SanitizedSecret.fromSecret(secret); String name = sanitizedSecret.name(); @@ -73,7 +73,7 @@ public class SecretDeliveryResourceTest { @Test public void returnsVersionedSecretWhenAllowed() throws Exception { String name = "secret_name"; - Secret versionedSecret = new Secret(2, name, null, () -> "U3BpZGVybWFu", NOW, null, NOW, + Secret versionedSecret = new Secret(2, name, null, () -> "U3BpZGVybWFu", "checksum", NOW, null, NOW, null, null, null, null, 0); when(aclDAO.getSanitizedSecretFor(client, name)) diff --git a/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceIntegrationTest.java b/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceIntegrationTest.java index a7f324689..90153cf77 100644 --- a/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceIntegrationTest.java +++ b/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceIntegrationTest.java @@ -53,24 +53,25 @@ public void setUp() throws Exception { generalPassword = SecretDeliveryResponse.fromSanitizedSecret( SanitizedSecret.fromSecret( - new Secret(0, "General_Password", null, () -> "YXNkZGFz", + new Secret(0, "General_Password", null, () -> "YXNkZGFz", "checksum", ApiDate.parse("2011-09-29T15:46:00.312Z"), null, ApiDate.parse("2011-09-29T15:46:00.312Z"), null, null, null, null, 0))); databasePassword = SecretDeliveryResponse.fromSanitizedSecret( SanitizedSecret.fromSecret( - new Secret(1, "Database_Password", null, () -> "MTIzNDU=", + new Secret(1, "Database_Password", null, () -> "MTIzNDU=","checksum", ApiDate.parse("2011-09-29T15:46:00.232Z"), null, ApiDate.parse("2011-09-29T15:46:00.232Z"), null, null, null, null, 0))); nobodyPgPassPassword = SecretDeliveryResponse.fromSanitizedSecret( SanitizedSecret.fromSecret( new Secret(2, "Nobody_PgPass", null, () -> "c29tZWhvc3Quc29tZXBsYWNlLmNvbTo1NDMyOnNvbWVkYXRhYmFzZTptaXN0ZXJhd2Vzb21lOmhlbGwwTWNGbHkK", + "checksum", ApiDate.parse("2011-09-29T15:46:00.232Z"), null, ApiDate.parse("2011-09-29T15:46:00.232Z"), null, ImmutableMap.of("owner", "nobody", "mode", "0400"), null, null, 0))); nonExistentOwnerPass = SecretDeliveryResponse.fromSanitizedSecret( SanitizedSecret.fromSecret( - new Secret(3, "NonexistentOwner_Pass", null, () -> "MTIzNDU=", + new Secret(3, "NonexistentOwner_Pass", null, () -> "MTIzNDU=", "checksum", ApiDate.parse("2011-09-29T15:46:00.232Z"), null, ApiDate.parse("2011-09-29T15:46:00.232Z"), null, ImmutableMap.of("owner", "NonExistent", "mode", "0400"), null, null, 0))); diff --git a/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceTest.java b/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceTest.java index f20861b5c..1aaad95b5 100644 --- a/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/SecretsDeliveryResourceTest.java @@ -46,11 +46,11 @@ public class SecretsDeliveryResourceTest { SecretsDeliveryResource secretsDeliveryResource; Secret firstSecret = new Secret(0, "first_secret_name", null, - () -> Base64.getEncoder().encodeToString("first_secret_contents".getBytes(UTF_8)), NOW, null, NOW, null, null, + () -> Base64.getEncoder().encodeToString("first_secret_contents".getBytes(UTF_8)), "checksum", NOW, null, NOW, null, null, null, null, 0); SanitizedSecret sanitizedFirstSecret = SanitizedSecret.fromSecret(firstSecret); Secret secondSecret = new Secret(1, "second_secret_name", null, - () -> Base64.getEncoder().encodeToString("second_secret_contents".getBytes(UTF_8)), NOW, null, NOW, null, null, + () -> Base64.getEncoder().encodeToString("second_secret_contents".getBytes(UTF_8)), "checksum", NOW, null, NOW, null, null, null, null, 0); SanitizedSecret sanitizedSecondSecret = SanitizedSecret.fromSecret(secondSecret); Client client; diff --git a/server/src/test/java/keywhiz/service/resources/admin/ClientsResourceTest.java b/server/src/test/java/keywhiz/service/resources/admin/ClientsResourceTest.java index bbc4e28d3..f1c8d4f97 100644 --- a/server/src/test/java/keywhiz/service/resources/admin/ClientsResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/admin/ClientsResourceTest.java @@ -113,7 +113,7 @@ public class ClientsResourceTest { @Test public void includesAssociations() { Group group1 = new Group(0, "group1", null, null, null, null, null, null); Group group2 = new Group(0, "group2", null, null, null, null, null, null); - Secret secret = new Secret(15, "secret", null, () -> "supersecretdata", now, "creator", now, + Secret secret = new Secret(15, "secret", null, () -> "supersecretdata", "checksum", now, "creator", now, "updater", null, null, null, 0); when(clientDAO.getClientById(1)).thenReturn(Optional.of(client)); diff --git a/server/src/test/java/keywhiz/service/resources/admin/GroupsResourceTest.java b/server/src/test/java/keywhiz/service/resources/admin/GroupsResourceTest.java index 33c4a06ff..4cb51a624 100644 --- a/server/src/test/java/keywhiz/service/resources/admin/GroupsResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/admin/GroupsResourceTest.java @@ -101,7 +101,7 @@ public void rejectsWhenGroupExists() { @Test public void getSpecificIncludesAllTheThings() { when(groupDAO.getGroupById(4444)).thenReturn(Optional.of(group)); - SanitizedSecret secret = SanitizedSecret.of(1, "name", null, now, "creator", now, "creator", null, null, null, + SanitizedSecret secret = SanitizedSecret.of(1, "name", "checksum", null, now, "creator", now, "creator", null, null, null, 1136214245); when(aclDAO.getSanitizedSecretsFor(group)).thenReturn(ImmutableSet.of(secret)); diff --git a/server/src/test/java/keywhiz/service/resources/admin/MembershipResourceTest.java b/server/src/test/java/keywhiz/service/resources/admin/MembershipResourceTest.java index 32333aaed..b25951c65 100644 --- a/server/src/test/java/keywhiz/service/resources/admin/MembershipResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/admin/MembershipResourceTest.java @@ -48,7 +48,7 @@ public class MembershipResourceTest { User user = User.named("user"); Client client = new Client(44, "client", "desc", NOW, "creator", NOW, "updater", null, true, false); Group group = new Group(55, "group", null, null, null, null, null, null); - Secret secret = new Secret(66, "secret", null, () -> "shush", NOW, null, NOW, null, null, null, null, 0); + Secret secret = new Secret(66, "secret", null, () -> "shush", "checksum", NOW, null, NOW, null, null, null, null, 0); AuditLog auditLog = new SimpleLogger(); MembershipResource resource; diff --git a/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceIntegrationTest.java b/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceIntegrationTest.java index f08740d42..eec5de946 100644 --- a/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceIntegrationTest.java +++ b/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceIntegrationTest.java @@ -31,6 +31,7 @@ import org.junit.Test; import org.junit.rules.RuleChain; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; @@ -75,7 +76,7 @@ public void adminRejectsWithoutCookie() throws IOException { @Test public void createsSecret() throws IOException { keywhizClient.login(DbSeedCommand.defaultUser, DbSeedCommand.defaultPassword.toCharArray()); SecretDetailResponse secretDetails = keywhizClient.createSecret("newSecret", "", - "content".getBytes(), ImmutableMap.of(), 0); + "content".getBytes(UTF_8), ImmutableMap.of(), 0); assertThat(secretDetails.name).isEqualTo("newSecret"); assertThat(keywhizClient.allSecrets().stream().map(SanitizedSecret::name).toArray()) @@ -86,8 +87,8 @@ public void adminRejectsWithoutCookie() throws IOException { public void rejectsCreatingDuplicateSecretWithoutVersion() throws IOException { keywhizClient.login(DbSeedCommand.defaultUser, DbSeedCommand.defaultPassword.toCharArray()); - keywhizClient.createSecret("passage", "v1", "content".getBytes(), ImmutableMap.of(), 0); - keywhizClient.createSecret("passage", "v2", "content".getBytes(), ImmutableMap.of(), 0); + keywhizClient.createSecret("passage", "v1", "content".getBytes(UTF_8), ImmutableMap.of(), 0); + keywhizClient.createSecret("passage", "v2", "content".getBytes(UTF_8), ImmutableMap.of(), 0); } @Test public void deletesSecret() throws IOException { diff --git a/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceTest.java b/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceTest.java index f1de8cb21..7dc473ba2 100644 --- a/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/admin/SecretsResourceTest.java @@ -69,7 +69,7 @@ public class SecretsResourceTest { User user = User.named("user"); ImmutableMap emptyMap = ImmutableMap.of(); - Secret secret = new Secret(22, "name", "desc", () -> "secret", NOW, "creator", NOW, + Secret secret = new Secret(22, "name", "desc", () -> "secret", "checksum", NOW, "creator", NOW, "updater", emptyMap, null, null, 1136214245); AuditLog auditLog = new SimpleLogger(); @@ -83,9 +83,9 @@ public void setUp() { @Test public void listSecrets() { - SanitizedSecret secret1 = SanitizedSecret.of(1, "name1", "desc", NOW, "user", NOW, "user", + SanitizedSecret secret1 = SanitizedSecret.of(1, "name1", "checksum", "desc", NOW, "user", NOW, "user", emptyMap, null, null, 1136214245); - SanitizedSecret secret2 = SanitizedSecret.of(2, "name2", "desc", NOW, "user", NOW, "user", + SanitizedSecret secret2 = SanitizedSecret.of(2, "name2", "checksum", "desc", NOW, "user", NOW, "user", emptyMap, null, null, 1136214245); when(secretController.getSanitizedSecrets(null, null)).thenReturn(ImmutableList.of(secret1, secret2)); diff --git a/server/src/test/java/keywhiz/service/resources/automation/AutomationGroupResourceTest.java b/server/src/test/java/keywhiz/service/resources/automation/AutomationGroupResourceTest.java index afe752c09..0777363a0 100644 --- a/server/src/test/java/keywhiz/service/resources/automation/AutomationGroupResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/automation/AutomationGroupResourceTest.java @@ -91,9 +91,9 @@ public class AutomationGroupResourceTest { Client groupClient = new Client(1, "firstClient", "Group client", now, "test", now, "test", null, true, true); SanitizedSecret firstGroupSecret = - SanitizedSecret.of(1, "name1", "desc", now, "test", now, "test", null, "", null, 1136214245); + SanitizedSecret.of(1, "name1", "checksum", "desc", now, "test", now, "test", null, "", null, 1136214245); SanitizedSecret secondGroupSecret = - SanitizedSecret.of(2, "name2", "desc", now, "test", now, "test", null, "", null, 1136214245); + SanitizedSecret.of(2, "name2", "checksum", "desc", now, "test", now, "test", null, "", null, 1136214245); when(groupDAO.getGroup("testGroup")).thenReturn(Optional.of(group)); when(aclDAO.getClientsFor(group)).thenReturn(ImmutableSet.of(groupClient)); diff --git a/server/src/test/java/keywhiz/service/resources/automation/AutomationSecretResourceTest.java b/server/src/test/java/keywhiz/service/resources/automation/AutomationSecretResourceTest.java index 787b8f6e2..515be2c77 100644 --- a/server/src/test/java/keywhiz/service/resources/automation/AutomationSecretResourceTest.java +++ b/server/src/test/java/keywhiz/service/resources/automation/AutomationSecretResourceTest.java @@ -81,6 +81,7 @@ public void addSecret() { request.name, request.description, () -> Base64.getUrlEncoder().encodeToString(request.content.getBytes(UTF_8)), + "checksum", NOW, automation.getName(), NOW, /* updatedAt set by DB */ @@ -117,7 +118,7 @@ public void deleteSecret() throws Exception { when(secretDAO.getSecretByName(secretSeries.name())) .thenReturn(Optional.of(SecretSeriesAndContent.of(secretSeries, SecretContent.of(123, secretSeries.id(), "meh", - NOW, null, NOW, null, ImmutableMap.of(), 0)))); + "checksum", NOW, null, NOW, null, ImmutableMap.of(), 0)))); resource.deleteSecretSeries(automation, "mySecret"); verify(secretDAO).deleteSecretsByName(secretSeries.name());