Skip to content

Commit fa6b526

Browse files
author
Frank Natividad
committed
Use BlobTargetOption and BlobWriteOption
1 parent afd6eb3 commit fa6b526

7 files changed

Lines changed: 98 additions & 26 deletions

File tree

google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ public abstract static class Builder {
273273
* Sets the blob's kmsKeyName.
274274
*/
275275
@GcpLaunchStage.Beta
276-
public abstract Builder setKmsKeyName(String kmsKeyName);
276+
abstract Builder setKmsKeyName(String kmsKeyName);
277277

278278
/**
279279
* Creates a {@code BlobInfo} object.

google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ private Tuple<BlobInfo, Storage.BlobTargetOption> toTargetOption(BlobInfo blobIn
187187
case CUSTOMER_SUPPLIED_KEY:
188188
return Tuple.of(blobInfo,
189189
Storage.BlobTargetOption.encryptionKey((String) getValue()));
190+
case KMS_KEY_NAME:
191+
return Tuple.of(blobInfo,
192+
Storage.BlobTargetOption.kmsKeyName((String) getValue()));
190193
case USER_PROJECT:
191194
return Tuple.of(blobInfo,
192195
Storage.BlobTargetOption.userProject((String) getValue()));
@@ -266,6 +269,16 @@ public static BlobTargetOption encryptionKey(String key) {
266269
return new BlobTargetOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, key);
267270
}
268271

272+
/**
273+
* Returns an option to set a customer-managed KMS key for server-side encryption of the
274+
* blob.
275+
*
276+
* @param kmsKeyName the KMS key resource id
277+
*/
278+
public static BlobTargetOption kmsKeyName(String kmsKeyName) {
279+
return new BlobTargetOption(StorageRpc.Option.KMS_KEY_NAME, kmsKeyName);
280+
}
281+
269282
/**
270283
* Returns an option for blob's billing user project. This option is only used by the buckets with
271284
* 'requester_pays' flag.
@@ -343,6 +356,9 @@ private Tuple<BlobInfo, Storage.BlobWriteOption> toWriteOption(BlobInfo blobInfo
343356
case CUSTOMER_SUPPLIED_KEY:
344357
return Tuple.of(blobInfo,
345358
Storage.BlobWriteOption.encryptionKey((String) value));
359+
case KMS_KEY_NAME:
360+
return Tuple.of(blobInfo,
361+
Storage.BlobWriteOption.kmsKeyName((String) value));
346362
case USER_PROJECT:
347363
return Tuple.of(blobInfo, Storage.BlobWriteOption.userProject((String) value));
348364
default:

google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,11 @@
1919
import static com.google.common.base.Preconditions.checkArgument;
2020
import static com.google.common.base.Preconditions.checkNotNull;
2121

22-
import com.google.api.client.util.Data;
23-
import com.google.api.core.BetaApi;
2422
import com.google.api.gax.paging.Page;
2523
import com.google.auth.ServiceAccountSigner;
2624
import com.google.auth.ServiceAccountSigner.SigningException;
27-
import com.google.cloud.FieldSelector;
25+
import com.google.cloud.*;
2826
import com.google.cloud.FieldSelector.Helper;
29-
import com.google.cloud.GcpLaunchStage;
30-
import com.google.cloud.Policy;
31-
import com.google.cloud.ReadChannel;
32-
import com.google.cloud.Service;
33-
import com.google.cloud.Tuple;
34-
import com.google.cloud.WriteChannel;
3527
import com.google.cloud.storage.Acl.Entity;
3628
import com.google.cloud.storage.spi.v1.StorageRpc;
3729
import com.google.common.collect.ImmutableList;
@@ -385,6 +377,14 @@ public static BlobTargetOption encryptionKey(String key) {
385377
return new BlobTargetOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, key);
386378
}
387379

380+
/**
381+
* Returns an option to set a customer-managed key for server-side encryption of the blob.
382+
*/
383+
@GcpLaunchStage.Beta
384+
public static BlobTargetOption kmsKeyName(String kmsKeyName) {
385+
return new BlobTargetOption(StorageRpc.Option.KMS_KEY_NAME, kmsKeyName);
386+
}
387+
388388
static Tuple<BlobInfo, BlobTargetOption[]> convert(BlobInfo info, BlobWriteOption... options) {
389389
BlobInfo.Builder infoBuilder = info.toBuilder().setCrc32c(null).setMd5(null);
390390
List<BlobTargetOption> targetOptions = Lists.newArrayListWithCapacity(options.length);
@@ -418,7 +418,7 @@ class BlobWriteOption implements Serializable {
418418

419419
enum Option {
420420
PREDEFINED_ACL, IF_GENERATION_MATCH, IF_GENERATION_NOT_MATCH, IF_METAGENERATION_MATCH,
421-
IF_METAGENERATION_NOT_MATCH, IF_MD5_MATCH, IF_CRC32C_MATCH, CUSTOMER_SUPPLIED_KEY, USER_PROJECT;
421+
IF_METAGENERATION_NOT_MATCH, IF_MD5_MATCH, IF_CRC32C_MATCH, CUSTOMER_SUPPLIED_KEY, KMS_KEY_NAME, USER_PROJECT;
422422

423423
StorageRpc.Option toRpcOption() {
424424
return StorageRpc.Option.valueOf(this.name());
@@ -536,6 +536,17 @@ public static BlobWriteOption encryptionKey(String key) {
536536
return new BlobWriteOption(Option.CUSTOMER_SUPPLIED_KEY, key);
537537
}
538538

539+
/**
540+
* Returns an option to set a customer-managed KMS key for server-side encryption of the
541+
* blob.
542+
*
543+
* @param kmsKeyName the KMS key resource id
544+
*/
545+
@GcpLaunchStage.Beta
546+
public static BlobWriteOption kmsKeyName(String kmsKeyName) {
547+
return new BlobWriteOption(Option.KMS_KEY_NAME, kmsKeyName);
548+
}
549+
539550
/**
540551
* Returns an option for blob's billing user project. This option is only used by the buckets with
541552
* 'requester_pays' flag.

google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ public StorageObject create(StorageObject storageObject, final InputStream conte
286286
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(options))
287287
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options))
288288
.setUserProject(Option.USER_PROJECT.getString(options))
289+
.setKmsKeyName(Option.KMS_KEY_NAME.getString(options))
289290
.execute();
290291
} catch (IOException ex) {
291292
span.setStatus(Status.UNKNOWN.withDescription(ex.getMessage()));
@@ -790,7 +791,7 @@ private RewriteResponse rewrite(RewriteRequest req, String token) {
790791
if (userProject == null) {
791792
userProject = Option.USER_PROJECT.getString(req.targetOptions);
792793
}
793-
String kmsKeyName = req.target.getKmsKeyName();
794+
String kmsKeyName = Option.KMS_KEY_NAME.getString(req.targetOptions);
794795

795796
Long maxBytesRewrittenPerCall = req.megabytesRewrittenPerCall != null
796797
? req.megabytesRewrittenPerCall * MEGABYTE : null;

google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public class BlobTest {
9191
private static final String KEY_SHA256 = "keySha";
9292
private static final BlobInfo.CustomerEncryption CUSTOMER_ENCRYPTION =
9393
new BlobInfo.CustomerEncryption(ENCRYPTION_ALGORITHM, KEY_SHA256);
94+
private static final String KMS_KEY_NAME = "projects/p/locations/kr-loc/keyRings/kr/cryptoKeys/key";
9495
private static final BlobInfo FULL_BLOB_INFO = BlobInfo.newBuilder("b", "n", GENERATION)
9596
.setAcl(ACLS)
9697
.setComponentCount(COMPONENT_COUNT)
@@ -113,6 +114,7 @@ public class BlobTest {
113114
.setUpdateTime(UPDATE_TIME)
114115
.setCreateTime(CREATE_TIME)
115116
.setCustomerEncryption(CUSTOMER_ENCRYPTION)
117+
.setKmsKeyName(KMS_KEY_NAME)
116118
.build();
117119
private static final BlobInfo BLOB_INFO = BlobInfo.newBuilder("b", "n")
118120
.setMetageneration(42L)
@@ -457,6 +459,7 @@ public void testBuilder() {
457459
.setCrc32c(CRC32)
458460
.setCreateTime(CREATE_TIME)
459461
.setCustomerEncryption(CUSTOMER_ENCRYPTION)
462+
.setKmsKeyName(KMS_KEY_NAME)
460463
.setDeleteTime(DELETE_TIME)
461464
.setEtag(ETAG)
462465
.setGeneratedId(GENERATED_ID)
@@ -511,6 +514,7 @@ public void testBuilder() {
511514
assertNull(blob.getCrc32c());
512515
assertNull(blob.getCreateTime());
513516
assertNull(blob.getCustomerEncryption());
517+
assertNull(blob.getKmsKeyName());
514518
assertNull(blob.getDeleteTime());
515519
assertNull(blob.getEtag());
516520
assertNull(blob.getGeneratedId());

google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ public class StorageImplTest {
102102
private static final String BASE64_KEY = "JVzfVl8NLD9FjedFuStegjRfES5ll5zc59CIXw572OA=";
103103
private static final Key KEY =
104104
new SecretKeySpec(BaseEncoding.base64().decode(BASE64_KEY), "AES256");
105+
private static final String KMS_KEY_NAME =
106+
"projects/gcloud-devel/locations/us/keyRings/gcs_kms_key_ring_us/cryptoKeys/key";
105107

106108
// BucketInfo objects
107109
private static final BucketInfo BUCKET_INFO1 =
@@ -245,6 +247,9 @@ public class StorageImplTest {
245247
private static final Map<StorageRpc.Option, ?> ENCRYPTION_KEY_OPTIONS =
246248
ImmutableMap.of(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, BASE64_KEY);
247249

250+
// Customer managed encryption key options
251+
private static final Map<StorageRpc.Option, ?> KMS_KEY_NAME_OPTIONS =
252+
ImmutableMap.of(StorageRpc.Option.KMS_KEY_NAME, KMS_KEY_NAME);
248253
// IAM policies
249254
private static final String POLICY_ETAG1 = "CAE=";
250255
private static final String POLICY_ETAG2 = "CAI=";

google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,13 @@ public void testCreateBlobWithEncryptionKey() {
239239
@Test
240240
public void testCreateBlobWithKmsKeyName() {
241241
String blobName = "test-create-with-kms-key-name-blob";
242-
BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).setKmsKeyName(KMS_KEY_NAME_1).build();
243-
Blob remoteBlob = storage.create(blob, BLOB_BYTE_CONTENT);
242+
BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).build();
243+
Blob remoteBlob = storage.create(blob, BLOB_BYTE_CONTENT, Storage.BlobTargetOption.kmsKeyName(KMS_KEY_NAME_1));
244244
assertNotNull(remoteBlob);
245245
assertEquals(blob.getBucket(), remoteBlob.getBucket());
246246
assertEquals(blob.getName(), remoteBlob.getName());
247-
assertTrue(remoteBlob.getKmsKeyName().startsWith(blob.getKmsKeyName()));
247+
assertNotNull(remoteBlob.getKmsKeyName());
248+
assertTrue(remoteBlob.getKmsKeyName().startsWith(KMS_KEY_NAME_1));
248249
byte[] readBytes = storage.readAllBytes(BUCKET, blobName);
249250
assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
250251
}
@@ -253,8 +254,9 @@ public void testCreateBlobWithKmsKeyName() {
253254
public void testCreateBlobWithKmsKeyNameAndCustomerSuppliedKey() {
254255
try {
255256
String blobName = "test-create-with-kms-key-name-blob";
256-
BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).setKmsKeyName(KMS_KEY_NAME_1).build();
257-
storage.create(blob, BLOB_BYTE_CONTENT, Storage.BlobTargetOption.encryptionKey(KEY));
257+
BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).build();
258+
storage.create(blob, BLOB_BYTE_CONTENT, Storage.BlobTargetOption.encryptionKey(KEY),
259+
Storage.BlobTargetOption.kmsKeyName(KMS_KEY_NAME_1));
258260
fail("StorageException was expected"); // can't supply both.
259261
} catch (StorageException ex) {
260262
// expected
@@ -367,6 +369,20 @@ public void testGetBlobSelectedFields() {
367369
assertNull(remoteBlob.getContentType());
368370
}
369371

372+
@Test
373+
public void testGetBlobKmsKeyNameField() {
374+
String blobName = "test-get-selected-kms-key-name-field-blob";
375+
BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName)
376+
.setContentType(CONTENT_TYPE)
377+
.build();
378+
assertNotNull(storage.create(blob, Storage.BlobTargetOption.kmsKeyName(KMS_KEY_NAME_1)));
379+
Blob remoteBlob = storage.get(blob.getBlobId(), Storage.BlobGetOption.fields(
380+
BlobField.KMS_KEY_NAME));
381+
assertEquals(blob.getBlobId(), remoteBlob.getBlobId());
382+
assertTrue(remoteBlob.getKmsKeyName().startsWith(KMS_KEY_NAME_1));
383+
assertNull(remoteBlob.getContentType());
384+
}
385+
370386
@Test
371387
public void testGetBlobAllSelectedFields() {
372388
String blobName = "test-get-all-selected-fields-blob";
@@ -459,14 +475,12 @@ public void testListBlobsKmsKeySelectedFields() throws InterruptedException {
459475
"test-list-blobs-selected-field-kms-key-name-blob2"};
460476
BlobInfo blob1 = BlobInfo.newBuilder(BUCKET, blobNames[0])
461477
.setContentType(CONTENT_TYPE)
462-
.setKmsKeyName(KMS_KEY_NAME_1)
463478
.build();
464479
BlobInfo blob2 = BlobInfo.newBuilder(BUCKET, blobNames[1])
465480
.setContentType(CONTENT_TYPE)
466-
.setKmsKeyName(KMS_KEY_NAME_1)
467481
.build();
468-
Blob remoteBlob1 = storage.create(blob1);
469-
Blob remoteBlob2 = storage.create(blob2);
482+
Blob remoteBlob1 = storage.create(blob1, Storage.BlobTargetOption.kmsKeyName(KMS_KEY_NAME_1));
483+
Blob remoteBlob2 = storage.create(blob2, Storage.BlobTargetOption.kmsKeyName(KMS_KEY_NAME_1));
470484
assertNotNull(remoteBlob1);
471485
assertNotNull(remoteBlob2);
472486
Page<Blob> page = storage.list(BUCKET,
@@ -936,12 +950,11 @@ public void testRotateFromCustomerEncryptionToKmsKey() {
936950
BlobInfo target = BlobInfo.newBuilder(BUCKET, targetBlobName)
937951
.setContentType(CONTENT_TYPE)
938952
.setMetadata(metadata)
939-
.setKmsKeyName(KMS_KEY_NAME_1)
940953
.build();
941954
Storage.CopyRequest req = Storage.CopyRequest.newBuilder()
942955
.setSource(source)
943956
.setSourceOptions(Storage.BlobSourceOption.decryptionKey(BASE64_KEY))
944-
.setTarget(target)
957+
.setTarget(target, Storage.BlobTargetOption.kmsKeyName(KMS_KEY_NAME_1))
945958
.build();
946959
CopyWriter copyWriter = storage.copy(req);
947960
assertEquals(BUCKET, copyWriter.getResult().getBucket());
@@ -967,13 +980,13 @@ public void testRotateFromCustomerEncryptionToKmsKeyWithCustomerEncrytion() {
967980
BlobInfo target = BlobInfo.newBuilder(BUCKET, targetBlobName)
968981
.setContentType(CONTENT_TYPE)
969982
.setMetadata(metadata)
970-
.setKmsKeyName(KMS_KEY_NAME_1)
971983
.build();
972984
try {
973985
Storage.CopyRequest req = Storage.CopyRequest.newBuilder()
974986
.setSource(source)
975987
.setSourceOptions(Storage.BlobSourceOption.decryptionKey(BASE64_KEY))
976-
.setTarget(target, Storage.BlobTargetOption.encryptionKey(KEY))
988+
.setTarget(target, Storage.BlobTargetOption.encryptionKey(KEY),
989+
Storage.BlobTargetOption.kmsKeyName(KMS_KEY_NAME_1))
977990
.build();
978991
storage.copy(req);
979992
fail("StorageException was expected");
@@ -982,7 +995,6 @@ public void testRotateFromCustomerEncryptionToKmsKeyWithCustomerEncrytion() {
982995
}
983996
}
984997

985-
986998
@Test
987999
public void testCopyBlobUpdateMetadata() {
9881000
String sourceBlobName = "test-copy-blob-update-metadata-source";
@@ -1847,6 +1859,29 @@ public void testListBucketRequesterPaysFails() throws InterruptedException {
18471859
}
18481860
}
18491861

1862+
@Test
1863+
public void testListBucketDefaultKmsKeyName() throws InterruptedException {
1864+
Bucket remoteBucket = storage.get(BUCKET, Storage.BucketGetOption.fields(BucketField.ENCRYPTION));
1865+
assertNull(remoteBucket.getDefaultKmsKeyName());
1866+
remoteBucket = remoteBucket.toBuilder().setDefaultKmsKeyName(KMS_KEY_NAME_1).build().update();
1867+
assertTrue(remoteBucket.getDefaultKmsKeyName().startsWith(KMS_KEY_NAME_1));
1868+
Iterator<Bucket> bucketIterator = storage.list(Storage.BucketListOption.prefix(BUCKET),
1869+
Storage.BucketListOption.fields(BucketField.ENCRYPTION)).iterateAll().iterator();
1870+
while (!bucketIterator.hasNext()) {
1871+
Thread.sleep(500);
1872+
bucketIterator = storage.list(Storage.BucketListOption.prefix(BUCKET),
1873+
Storage.BucketListOption.fields(BucketField.ENCRYPTION)).iterateAll().iterator();
1874+
}
1875+
while (bucketIterator.hasNext()) {
1876+
Bucket bucket = bucketIterator.next();
1877+
assertTrue(bucket.getName().startsWith(BUCKET));
1878+
assertNotNull(bucket.getDefaultKmsKeyName());
1879+
assertTrue(bucket.getDefaultKmsKeyName().startsWith(KMS_KEY_NAME_1));
1880+
assertNull(bucket.getCreateTime());
1881+
assertNull(bucket.getSelfLink());
1882+
}
1883+
}
1884+
18501885
@Test
18511886
public void testGetServiceAccount() throws InterruptedException {
18521887
String projectId = remoteStorageHelper.getOptions().getProjectId();

0 commit comments

Comments
 (0)