Fix bugs in KmsConnectionImpl

A few errors emerged when doing an integration test against the actual API. I've updated the unit tests to reflect the correct behavior.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=148793856
This commit is contained in:
shikhman 2017-02-28 11:27:59 -08:00 committed by Ben McIlwain
parent 726e925b4a
commit 51a613bca6
2 changed files with 89 additions and 46 deletions

View file

@ -24,6 +24,7 @@ import com.google.api.services.cloudkms.v1beta1.model.CryptoKeyVersion;
import com.google.api.services.cloudkms.v1beta1.model.DecryptRequest; import com.google.api.services.cloudkms.v1beta1.model.DecryptRequest;
import com.google.api.services.cloudkms.v1beta1.model.EncryptRequest; import com.google.api.services.cloudkms.v1beta1.model.EncryptRequest;
import com.google.api.services.cloudkms.v1beta1.model.KeyRing; import com.google.api.services.cloudkms.v1beta1.model.KeyRing;
import com.google.api.services.cloudkms.v1beta1.model.UpdateCryptoKeyPrimaryVersionRequest;
import google.registry.config.RegistryConfig.Config; import google.registry.config.RegistryConfig.Config;
import google.registry.keyring.api.KeyringException; import google.registry.keyring.api.KeyringException;
import java.io.IOException; import java.io.IOException;
@ -32,11 +33,10 @@ import javax.inject.Inject;
/** The {@link KmsConnection} which talks to Cloud KMS. */ /** The {@link KmsConnection} which talks to Cloud KMS. */
class KmsConnectionImpl implements KmsConnection { class KmsConnectionImpl implements KmsConnection {
private static final String KMS_LOCATION_FORMAT = "projects/%s/locations/global";
private static final String KMS_KEYRING_NAME_FORMAT = "projects/%s/locations/global/keyRings/%s"; private static final String KMS_KEYRING_NAME_FORMAT = "projects/%s/locations/global/keyRings/%s";
private static final String KMS_CRYPTO_KEY_NAME_FORMAT = private static final String KMS_CRYPTO_KEY_NAME_FORMAT =
"projects/%s/locations/global/keyRings/%s/cryptoKeys/%s"; "projects/%s/locations/global/keyRings/%s/cryptoKeys/%s";
private static final String KMS_CRYPTO_KEY_VERSION_NAME_FORMAT =
"projects/%s/locations/global/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions";
private final CloudKMS kms; private final CloudKMS kms;
private final String kmsKeyRingName; private final String kmsKeyRingName;
@ -68,7 +68,8 @@ class KmsConnectionImpl implements KmsConnection {
kms.projects() kms.projects()
.locations() .locations()
.keyRings() .keyRings()
.create("global", new KeyRing().setName(fullKeyRingName)) .create(getLocationName(projectId), new KeyRing())
.setKeyRingId(kmsKeyRingName)
.execute(); .execute();
} else { } else {
throw jsonException; throw jsonException;
@ -77,39 +78,53 @@ class KmsConnectionImpl implements KmsConnection {
String fullKeyName = getCryptoKeyName(projectId, kmsKeyRingName, cryptoKeyName); String fullKeyName = getCryptoKeyName(projectId, kmsKeyRingName, cryptoKeyName);
boolean newCryptoKey = false;
try { try {
kms.projects().locations().keyRings().cryptoKeys().get(fullKeyName).execute(); kms.projects().locations().keyRings().cryptoKeys().get(fullKeyName).execute();
} catch (GoogleJsonResponseException jsonException) { } catch (GoogleJsonResponseException jsonException) {
if (jsonException.getStatusCode() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) { if (jsonException.getStatusCode() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) {
newCryptoKey = true;
kms.projects() kms.projects()
.locations() .locations()
.keyRings() .keyRings()
.cryptoKeys() .cryptoKeys()
.create( .create(fullKeyRingName, new CryptoKey().setPurpose("ENCRYPT_DECRYPT"))
fullKeyName, new CryptoKey().setName(cryptoKeyName).setPurpose("ENCRYPT_DECRYPT")) .setCryptoKeyId(cryptoKeyName)
.execute(); .execute();
} else { } else {
throw jsonException; throw jsonException;
} }
} }
CryptoKeyVersion cryptoKeyVersion = // New CryptoKeys start with a CryptoKeyVersion, so we only create a new CryptoKeyVersion and
kms.projects() // rotate to it if we're dealing with an existing CryptoKey.
.locations() if (!newCryptoKey) {
.keyRings() CryptoKeyVersion cryptoKeyVersion =
.cryptoKeys() kms.projects()
.cryptoKeyVersions() .locations()
.create( .keyRings()
getCryptoKeyVersionName(projectId, kmsKeyRingName, cryptoKeyName), .cryptoKeys()
new CryptoKeyVersion()) .cryptoKeyVersions()
.execute(); .create(fullKeyName, new CryptoKeyVersion())
.execute();
kms.projects()
.locations()
.keyRings()
.cryptoKeys()
.updatePrimaryVersion(
fullKeyName,
new UpdateCryptoKeyPrimaryVersionRequest()
.setCryptoKeyVersionId(getCryptoKeyVersionId(cryptoKeyVersion)))
.execute();
}
return EncryptResponse.create( return EncryptResponse.create(
kms.projects() kms.projects()
.locations() .locations()
.keyRings() .keyRings()
.cryptoKeys() .cryptoKeys()
.encrypt(cryptoKeyVersion.getName(), new EncryptRequest().encodePlaintext(value)) .encrypt(fullKeyName, new EncryptRequest().encodePlaintext(value))
.execute()); .execute());
} }
@ -131,17 +146,21 @@ class KmsConnectionImpl implements KmsConnection {
} }
} }
static String getKeyRingName(String projectId, String kmsKeyRingName) { private static String getLocationName(String projectId) {
return String.format(KMS_LOCATION_FORMAT, projectId);
}
private static String getKeyRingName(String projectId, String kmsKeyRingName) {
return String.format(KMS_KEYRING_NAME_FORMAT, projectId, kmsKeyRingName); return String.format(KMS_KEYRING_NAME_FORMAT, projectId, kmsKeyRingName);
} }
static String getCryptoKeyName(String projectId, String kmsKeyRingName, String cryptoKeyName) { private static String getCryptoKeyName(
String projectId, String kmsKeyRingName, String cryptoKeyName) {
return String.format(KMS_CRYPTO_KEY_NAME_FORMAT, projectId, kmsKeyRingName, cryptoKeyName); return String.format(KMS_CRYPTO_KEY_NAME_FORMAT, projectId, kmsKeyRingName, cryptoKeyName);
} }
static String getCryptoKeyVersionName( private static String getCryptoKeyVersionId(CryptoKeyVersion cryptoKeyVersion) {
String projectId, String kmsKeyRingName, String cryptoKeyName) { String cryptoKeyVersionName = cryptoKeyVersion.getName();
return String.format( return cryptoKeyVersionName.substring(cryptoKeyVersionName.lastIndexOf('/') + 1);
KMS_CRYPTO_KEY_VERSION_NAME_FORMAT, projectId, kmsKeyRingName, cryptoKeyName);
} }
} }

View file

@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -32,6 +33,7 @@ import com.google.api.services.cloudkms.v1beta1.model.DecryptResponse;
import com.google.api.services.cloudkms.v1beta1.model.EncryptRequest; import com.google.api.services.cloudkms.v1beta1.model.EncryptRequest;
import com.google.api.services.cloudkms.v1beta1.model.EncryptResponse; import com.google.api.services.cloudkms.v1beta1.model.EncryptResponse;
import com.google.api.services.cloudkms.v1beta1.model.KeyRing; import com.google.api.services.cloudkms.v1beta1.model.KeyRing;
import com.google.api.services.cloudkms.v1beta1.model.UpdateCryptoKeyPrimaryVersionRequest;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -54,6 +56,9 @@ public class KmsConnectionImplTest {
@Mock private CloudKMS.Projects.Locations.KeyRings.CryptoKeys.Get kmsCryptoKeysGet; @Mock private CloudKMS.Projects.Locations.KeyRings.CryptoKeys.Get kmsCryptoKeysGet;
@Mock private CloudKMS.Projects.Locations.KeyRings.CryptoKeys.Create kmsCryptoKeysCreate; @Mock private CloudKMS.Projects.Locations.KeyRings.CryptoKeys.Create kmsCryptoKeysCreate;
@Mock
private CloudKMS.Projects.Locations.KeyRings.CryptoKeys.UpdatePrimaryVersion updatePrimaryVersion;
@Mock @Mock
private CloudKMS.Projects.Locations.KeyRings.CryptoKeys.CryptoKeyVersions kmsCryptoKeyVersions; private CloudKMS.Projects.Locations.KeyRings.CryptoKeys.CryptoKeyVersions kmsCryptoKeyVersions;
@ -67,12 +72,15 @@ public class KmsConnectionImplTest {
@Captor private ArgumentCaptor<KeyRing> keyRing; @Captor private ArgumentCaptor<KeyRing> keyRing;
@Captor private ArgumentCaptor<CryptoKey> cryptoKey; @Captor private ArgumentCaptor<CryptoKey> cryptoKey;
@Captor private ArgumentCaptor<CryptoKeyVersion> cryptoKeyVersion; @Captor private ArgumentCaptor<CryptoKeyVersion> cryptoKeyVersion;
@Captor private ArgumentCaptor<String> locationName;
@Captor private ArgumentCaptor<String> keyRingName; @Captor private ArgumentCaptor<String> keyRingName;
@Captor private ArgumentCaptor<String> cryptoKeyName; @Captor private ArgumentCaptor<String> cryptoKeyName;
@Captor private ArgumentCaptor<String> cryptoKeyVersionName;
@Captor private ArgumentCaptor<EncryptRequest> encryptRequest; @Captor private ArgumentCaptor<EncryptRequest> encryptRequest;
@Captor private ArgumentCaptor<DecryptRequest> decryptRequest; @Captor private ArgumentCaptor<DecryptRequest> decryptRequest;
@Captor
private ArgumentCaptor<UpdateCryptoKeyPrimaryVersionRequest> updateCryptoKeyPrimaryVersionRequest;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
when(kms.projects()).thenReturn(kmsProjects); when(kms.projects()).thenReturn(kmsProjects);
@ -80,9 +88,11 @@ public class KmsConnectionImplTest {
when(kmsLocations.keyRings()).thenReturn(kmsKeyRings); when(kmsLocations.keyRings()).thenReturn(kmsKeyRings);
when(kmsKeyRings.get(anyString())).thenReturn(kmsKeyRingsGet); when(kmsKeyRings.get(anyString())).thenReturn(kmsKeyRingsGet);
when(kmsKeyRings.create(anyString(), any(KeyRing.class))).thenReturn(kmsKeyRingsCreate); when(kmsKeyRings.create(anyString(), any(KeyRing.class))).thenReturn(kmsKeyRingsCreate);
when(kmsKeyRingsCreate.setKeyRingId(anyString())).thenReturn(kmsKeyRingsCreate);
when(kmsKeyRings.cryptoKeys()).thenReturn(kmsCryptoKeys); when(kmsKeyRings.cryptoKeys()).thenReturn(kmsCryptoKeys);
when(kmsCryptoKeys.get(anyString())).thenReturn(kmsCryptoKeysGet); when(kmsCryptoKeys.get(anyString())).thenReturn(kmsCryptoKeysGet);
when(kmsCryptoKeys.create(anyString(), any(CryptoKey.class))).thenReturn(kmsCryptoKeysCreate); when(kmsCryptoKeys.create(anyString(), any(CryptoKey.class))).thenReturn(kmsCryptoKeysCreate);
when(kmsCryptoKeysCreate.setCryptoKeyId(anyString())).thenReturn(kmsCryptoKeysCreate);
when(kmsCryptoKeys.cryptoKeyVersions()).thenReturn(kmsCryptoKeyVersions); when(kmsCryptoKeys.cryptoKeyVersions()).thenReturn(kmsCryptoKeyVersions);
when(kmsCryptoKeyVersions.create(anyString(), any(CryptoKeyVersion.class))) when(kmsCryptoKeyVersions.create(anyString(), any(CryptoKeyVersion.class)))
.thenReturn(kmsCryptoKeyVersionsCreate); .thenReturn(kmsCryptoKeyVersionsCreate);
@ -97,6 +107,9 @@ public class KmsConnectionImplTest {
.setCiphertext(KmsTestHelper.DUMMY_ENCRYPTED_VALUE)); .setCiphertext(KmsTestHelper.DUMMY_ENCRYPTED_VALUE));
when(kmsCryptoKeys.decrypt(anyString(), any(DecryptRequest.class))) when(kmsCryptoKeys.decrypt(anyString(), any(DecryptRequest.class)))
.thenReturn(kmsCryptoKeysDecrypt); .thenReturn(kmsCryptoKeysDecrypt);
when(kmsCryptoKeys.updatePrimaryVersion(
anyString(), any(UpdateCryptoKeyPrimaryVersionRequest.class)))
.thenReturn(updatePrimaryVersion);
} }
@Test @Test
@ -105,16 +118,17 @@ public class KmsConnectionImplTest {
new KmsConnectionImpl("foo", "bar", kms).encrypt("key", "moo".getBytes(UTF_8)); new KmsConnectionImpl("foo", "bar", kms).encrypt("key", "moo".getBytes(UTF_8));
verify(kmsKeyRings).create(keyRingName.capture(), keyRing.capture()); verify(kmsKeyRings).create(locationName.capture(), keyRing.capture());
assertThat(keyRingName.getValue()).isEqualTo("global"); assertThat(locationName.getValue()).isEqualTo("projects/foo/locations/global");
assertThat(keyRing.getValue()) assertThat(keyRing.getValue()).isEqualTo(new KeyRing());
.isEqualTo(new KeyRing().setName("projects/foo/locations/global/keyRings/bar")); verify(kmsKeyRingsCreate).setKeyRingId(keyRingName.capture());
assertThat(keyRingName.getValue()).isEqualTo("bar");
verify(kmsKeyRingsCreate).execute(); verify(kmsKeyRingsCreate).execute();
verifyEncryptKmsApiCalls( verifyEncryptKmsApiCalls(
"moo", "moo",
"projects/foo/locations/global/keyRings/bar", "projects/foo/locations/global/keyRings/bar",
"projects/foo/locations/global/keyRings/bar/cryptoKeys/key", "projects/foo/locations/global/keyRings/bar/cryptoKeys/key");
"projects/foo/locations/global/keyRings/bar/cryptoKeys/key/cryptoKeyVersions");
} }
@Test @Test
@ -123,28 +137,44 @@ public class KmsConnectionImplTest {
new KmsConnectionImpl("foo", "bar", kms).encrypt("key", "moo".getBytes(UTF_8)); new KmsConnectionImpl("foo", "bar", kms).encrypt("key", "moo".getBytes(UTF_8));
verify(kmsCryptoKeys).create(cryptoKeyName.capture(), cryptoKey.capture()); verify(kmsCryptoKeys).create(keyRingName.capture(), cryptoKey.capture());
assertThat(cryptoKeyName.getValue()) assertThat(keyRingName.getValue()).isEqualTo("projects/foo/locations/global/keyRings/bar");
.isEqualTo("projects/foo/locations/global/keyRings/bar/cryptoKeys/key"); assertThat(cryptoKey.getValue()).isEqualTo(new CryptoKey().setPurpose("ENCRYPT_DECRYPT"));
assertThat(cryptoKey.getValue()) verify(kmsCryptoKeysCreate).setCryptoKeyId(cryptoKeyName.capture());
.isEqualTo(new CryptoKey().setName("key").setPurpose("ENCRYPT_DECRYPT")); assertThat(cryptoKeyName.getValue()).isEqualTo("key");
verify(kmsCryptoKeysCreate).execute(); verify(kmsCryptoKeysCreate).execute();
verify(kmsCryptoKeyVersionsCreate, never()).execute();
verify(updatePrimaryVersion, never()).execute();
verifyEncryptKmsApiCalls( verifyEncryptKmsApiCalls(
"moo", "moo",
"projects/foo/locations/global/keyRings/bar", "projects/foo/locations/global/keyRings/bar",
"projects/foo/locations/global/keyRings/bar/cryptoKeys/key", "projects/foo/locations/global/keyRings/bar/cryptoKeys/key");
"projects/foo/locations/global/keyRings/bar/cryptoKeys/key/cryptoKeyVersions");
} }
@Test @Test
public void test_encrypt() throws Exception { public void test_encrypt() throws Exception {
new KmsConnectionImpl("foo", "bar", kms).encrypt("key", "moo".getBytes(UTF_8)); new KmsConnectionImpl("foo", "bar", kms).encrypt("key", "moo".getBytes(UTF_8));
verify(kmsCryptoKeyVersions).create(cryptoKeyName.capture(), cryptoKeyVersion.capture());
assertThat(cryptoKeyName.getValue())
.isEqualTo("projects/foo/locations/global/keyRings/bar/cryptoKeys/key");
verify(kmsCryptoKeys)
.updatePrimaryVersion(
cryptoKeyName.capture(), updateCryptoKeyPrimaryVersionRequest.capture());
assertThat(cryptoKeyName.getValue())
.isEqualTo("projects/foo/locations/global/keyRings/bar/cryptoKeys/key");
assertThat(updateCryptoKeyPrimaryVersionRequest.getValue())
.isEqualTo(
new UpdateCryptoKeyPrimaryVersionRequest()
.setCryptoKeyVersionId(KmsTestHelper.DUMMY_CRYPTO_KEY_VERSION));
verifyEncryptKmsApiCalls( verifyEncryptKmsApiCalls(
"moo", "moo",
"projects/foo/locations/global/keyRings/bar", "projects/foo/locations/global/keyRings/bar",
"projects/foo/locations/global/keyRings/bar/cryptoKeys/key", "projects/foo/locations/global/keyRings/bar/cryptoKeys/key");
"projects/foo/locations/global/keyRings/bar/cryptoKeys/key/cryptoKeyVersions");
} }
@Test @Test
@ -162,10 +192,7 @@ public class KmsConnectionImplTest {
} }
private void verifyEncryptKmsApiCalls( private void verifyEncryptKmsApiCalls(
String goldenValue, String goldenValue, String goldenCryptoKeyRingName, String goldenCryptoKeyName)
String goldenCryptoKeyRingName,
String goldenCryptoKeyName,
String goldenCryptoKeyVersionName)
throws Exception { throws Exception {
verify(kmsKeyRings).get(keyRingName.capture()); verify(kmsKeyRings).get(keyRingName.capture());
assertThat(keyRingName.getValue()).isEqualTo(goldenCryptoKeyRingName); assertThat(keyRingName.getValue()).isEqualTo(goldenCryptoKeyRingName);
@ -173,11 +200,8 @@ public class KmsConnectionImplTest {
verify(kmsCryptoKeys).get(cryptoKeyName.capture()); verify(kmsCryptoKeys).get(cryptoKeyName.capture());
assertThat(cryptoKeyName.getValue()).isEqualTo(goldenCryptoKeyName); assertThat(cryptoKeyName.getValue()).isEqualTo(goldenCryptoKeyName);
verify(kmsCryptoKeyVersions).create(cryptoKeyVersionName.capture(), cryptoKeyVersion.capture());
assertThat(cryptoKeyVersionName.getValue()).isEqualTo(goldenCryptoKeyVersionName);
verify(kmsCryptoKeys).encrypt(cryptoKeyName.capture(), encryptRequest.capture()); verify(kmsCryptoKeys).encrypt(cryptoKeyName.capture(), encryptRequest.capture());
assertThat(cryptoKeyName.getValue()).isEqualTo(KmsTestHelper.DUMMY_CRYPTO_KEY_VERSION); assertThat(cryptoKeyName.getValue()).isEqualTo(goldenCryptoKeyName);
assertThat(encryptRequest.getValue()) assertThat(encryptRequest.getValue())
.isEqualTo(new EncryptRequest().encodePlaintext(goldenValue.getBytes(UTF_8))); .isEqualTo(new EncryptRequest().encodePlaintext(goldenValue.getBytes(UTF_8)));
} }