Skip to content

Commit

Permalink
Fixes JSON property name of ClientEncryptionKeyProperties to match ba…
Browse files Browse the repository at this point in the history
…ckend (#24160)

* Fixes JSON property name of ClientEncryptionKeyProperties to match backend

* Adding overloaded methods for CRUD operations

* Fixes JSON property name of ClientEncryptionKeyProperties to match backend

* Adding overloaded methods for CRUD operations

* Resolving comments

Co-authored-by: Aayush Kataria <[email protected]>
  • Loading branch information
aayush3011 and Aayush Kataria authored Sep 18, 2021
1 parent 334793a commit 71b1c8b
Show file tree
Hide file tree
Showing 8 changed files with 541 additions and 108 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,41 @@ public class CosmosEncryptionContainer {
}

/**
* create item and encrypts the requested fields
* Creates a new item synchronously and returns its respective Cosmos item response.
*
* @param item the Cosmos item represented as a POJO or Cosmos item object.
* @param partitionKey the partition key.
* @param requestOptions request option
* @param <T> serialization class type
* @return the Cosmos item resource response.
* @param <T> the type parameter
* @param item the item
* @return the Cosmos item response
*/
public <T> CosmosItemResponse<T> createItem(T item) {
return this.blockItemResponse(this.cosmosEncryptionAsyncContainer.createItem(item));
}

/**
* Creates a new item synchronously and returns its respective Cosmos item response
* while specifying additional options.
* <p>
* The partition key value will be automatically extracted from the item's content.
*
* @param <T> the type parameter.
* @param item the item.
* @param options the options.
* @return the cosmos item response.
*/

public <T> CosmosItemResponse<T> createItem(T item, CosmosItemRequestOptions options) {
return this.blockItemResponse(this.cosmosEncryptionAsyncContainer.createItem(item, options));
}

/**
* Creates a new item synchronously and returns its respective Cosmos item response
* while specifying additional options.
*
* @param <T> the type parameter.
* @param item the item.
* @param partitionKey the partition key.
* @param requestOptions the options.
* @return the Cosmos item response.
*/
@SuppressWarnings("unchecked")
public <T> CosmosItemResponse<T> createItem(T item,
Expand All @@ -55,12 +83,12 @@ public <T> CosmosItemResponse<T> createItem(T item,
}

/**
* Deletes the item.
* Deletes an item in the current container.
*
* @param itemId id of the item.
* @param partitionKey partitionKey of the item.
* @param requestOptions the request options.
* @return the Cosmos item resource response.
* @param itemId the item id.
* @param partitionKey the partition key.
* @param requestOptions the options.
* @return the Cosmos item response.
*/
public CosmosItemResponse<Object> deleteItem(String itemId,
PartitionKey partitionKey,
Expand All @@ -70,13 +98,62 @@ public CosmosItemResponse<Object> deleteItem(String itemId,
}

/**
* upserts item and encrypts the requested fields
* Deletes an item in the current container.
*
* @param <T> the type parameter.
* @param item the item to be deleted.
* @param options the options.
* @return the Cosmos item response.
*/
public <T> CosmosItemResponse<Object> deleteItem(T item, CosmosItemRequestOptions options) {
return this.blockDeleteItemResponse(this.cosmosEncryptionAsyncContainer.deleteItem(item, options));
}

/**
* Deletes all items in the Container with the specified partitionKey value.
* Starts an asynchronous Cosmos DB background operation which deletes all items in the Container with the specified value.
* The asynchronous Cosmos DB background operation runs using a percentage of user RUs.
*
* @param partitionKey the partition key.
* @param options the options.
* @return the Cosmos item response
*/
@Beta(value = Beta.SinceVersion.V1, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public CosmosItemResponse<Object> deleteAllItemsByPartitionKey(PartitionKey partitionKey, CosmosItemRequestOptions options) {
return this.blockDeleteItemResponse(this.cosmosEncryptionAsyncContainer.deleteAllItemsByPartitionKey(partitionKey, options));
}

/**
* Upserts an Cosmos item in the current container.
*
* @param item the Cosmos item represented as a POJO or Cosmos item object.
* @param partitionKey the partition key.
* @param requestOptions request option
* @param <T> serialization class type
* @return the Cosmos item resource response.
* @param <T> the type parameter.
* @param item the item.
* @return the Cosmos item response.
*/
public <T> CosmosItemResponse<T> upsertItem(T item) {
return this.blockItemResponse(this.cosmosEncryptionAsyncContainer.upsertItem(item));
}

/**
* Upserts a item Cosmos sync item while specifying additional options.
*
* @param <T> the type parameter.
* @param item the item.
* @param options the options.
* @return the Cosmos item response.
*/
public <T> CosmosItemResponse<T> upsertItem(T item, CosmosItemRequestOptions options) {
return this.blockItemResponse(this.cosmosEncryptionAsyncContainer.upsertItem(item, options));
}

/**
* Upserts a item Cosmos sync item while specifying additional options.
*
* @param <T> the type parameter.
* @param item the item.
* @param partitionKey the partitionKey.
* @param requestOptions the options.
* @return the Cosmos item response.
*/
@SuppressWarnings("unchecked")
public <T> CosmosItemResponse<T> upsertItem(T item,
Expand All @@ -86,14 +163,14 @@ public <T> CosmosItemResponse<T> upsertItem(T item,
}

/**
* replaces item and encrypts the requested fields
* Replaces an item in the current container.
*
* @param item the Cosmos item represented as a POJO or Cosmos item object.
* @param itemId the item id.
* @param partitionKey the partition key.
* @param requestOptions request option
* @param <T> serialization class type
* @return the Cosmos item resource response.
* @param <T> the type parameter.
* @param item the item.
* @param itemId the item id.
* @param partitionKey the partition key.
* @param requestOptions the options.
* @return the Cosmos item response.
*/
@SuppressWarnings("unchecked")
public <T> CosmosItemResponse<T> replaceItem(T item,
Expand All @@ -105,14 +182,30 @@ public <T> CosmosItemResponse<T> replaceItem(T item,
}

/**
* Reads item and decrypt the encrypted fields
* Reads an item in the current container.
*
* @param id item id
* @param partitionKey the partition key.
* @param requestOptions request options
* @param classType deserialization class type
* @param <T> type
* @return the Cosmos item resource response.
* @param <T> the type parameter.
* @param id the item id.
* @param partitionKey the partition key.
* @param classType the class type of item.
* @return the Cosmos item response.
*/
public <T> CosmosItemResponse<T> readItem(String id, PartitionKey partitionKey, Class<T> classType) {
return this.blockItemResponse(this.cosmosEncryptionAsyncContainer.readItem(id,
partitionKey,
new CosmosItemRequestOptions(),
classType));
}

/**
* Reads an item in the current container while specifying additional options.
*
* @param <T> the type parameter.
* @param id the item id.
* @param partitionKey the partition key.
* @param requestOptions the options.
* @param classType the class type of item.
* @return the Cosmos item response.
*/
public <T> CosmosItemResponse<T> readItem(String id,
PartitionKey partitionKey,
Expand All @@ -123,33 +216,33 @@ public <T> CosmosItemResponse<T> readItem(String id,
}

/**
* Query for items in the current container using a string.
* Query items in the current container returning the results as {@link CosmosPagedIterable}.
*
* @param <T> the type parameter.
* @param query the query text.
* @param options the query request options.
* @param <T> the type parameter.
* @param query the query.
* @param requestOptions the options.
* @param classType the class type.
* @return a {@link CosmosPagedIterable}.
* @return the {@link CosmosPagedIterable}.
*/
public <T> CosmosPagedIterable<T> queryItems(String query, CosmosQueryRequestOptions options,
public <T> CosmosPagedIterable<T> queryItems(String query, CosmosQueryRequestOptions requestOptions,
Class<T> classType) {

return getCosmosPagedIterable(this.cosmosEncryptionAsyncContainer.queryItems(query, options, classType));
return getCosmosPagedIterable(this.cosmosEncryptionAsyncContainer.queryItems(query, requestOptions, classType));
}

/**
* Query for items in the current container using a {@link SqlQuerySpec}.
* Query items in the current container returning the results as {@link CosmosPagedIterable}.
*
* @param <T> the type parameter.
* @param query the query.
* @param options the query request options.
* @param <T> the type parameter.
* @param query the query spec.
* @param requestOptions the options.
* @param classType the class type.
* @return a {@link CosmosPagedIterable}.
* @return the {@link CosmosPagedIterable}.
*/
public <T> CosmosPagedIterable<T> queryItems(SqlQuerySpec query,
CosmosQueryRequestOptions options,
CosmosQueryRequestOptions requestOptions,
Class<T> classType) {
return getCosmosPagedIterable(this.cosmosEncryptionAsyncContainer.queryItems(query, options, classType));
return getCosmosPagedIterable(this.cosmosEncryptionAsyncContainer.queryItems(query, requestOptions, classType));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public void createItemEncrypt_readItemDecrypt() throws IOException {
private CosmosClientEncryptionKeyProperties getEncryptionPropertiesFromJsonFile(String filePath) throws IOException {
JsonNode node = MAPPER.readTree(new File(filePath));
String clientEncryptionKey = node.get("id").asText();
String algorithm = node.get("encryptionAlgorithmId").asText();
String algorithm = node.get("encryptionAlgorithm").asText();
byte[] wrappedDataEncryptionKey = MAPPER.treeToValue(node.get("wrappedDataEncryptionKey"), byte[].class);
ObjectNode objectNode = (ObjectNode) node.get("keyWrapMetadata");
EncryptionKeyWrapMetadata keyWrapMetadata = MAPPER.convertValue(objectNode, EncryptionKeyWrapMetadata.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.azure.cosmos.models.SqlParameter;
import com.azure.cosmos.models.SqlQuerySpec;
import com.azure.cosmos.util.CosmosPagedFlux;
import com.azure.cosmos.util.CosmosPagedIterable;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.microsoft.data.encryption.cryptography.EncryptionKeyStoreProvider;
Expand All @@ -35,12 +36,9 @@
import org.testng.annotations.Test;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.*;

public class EncryptionAsyncApiCrudTest extends TestSuiteBase {
private CosmosAsyncClient client;
Expand Down Expand Up @@ -579,6 +577,108 @@ public void batchExecutionWithOptionsApi() {
validateResponse(batchResponse.getResults().get(3).getItem(EncryptionPojo.class), createPojo);
}

@Test(groups = {"encryption"}, timeOut = TIMEOUT)
public void crudOnDifferentOverload() {
List<EncryptionPojo> actualProperties = new ArrayList<>();
// Read item
EncryptionPojo properties = getItem(UUID.randomUUID().toString());
CosmosItemResponse<EncryptionPojo> itemResponse = cosmosEncryptionAsyncContainer.createItem(properties).block();
assertThat(itemResponse.getRequestCharge()).isGreaterThan(0);
EncryptionPojo responseItem = itemResponse.getItem();
validateResponse(properties, responseItem);
actualProperties.add(properties);

properties = getItem(UUID.randomUUID().toString());
CosmosItemResponse<EncryptionPojo> itemResponse1 = cosmosEncryptionAsyncContainer.createItem(properties, new CosmosItemRequestOptions()).block();
assertThat(itemResponse1.getRequestCharge()).isGreaterThan(0);
EncryptionPojo responseItem1 = itemResponse1.getItem();
validateResponse(properties, responseItem1);
actualProperties.add(properties);

//Upsert Item
properties = getItem(UUID.randomUUID().toString());
CosmosItemResponse<EncryptionPojo> upsertResponse1 = cosmosEncryptionAsyncContainer.upsertItem(properties).block();
assertThat(upsertResponse1.getRequestCharge()).isGreaterThan(0);
EncryptionPojo responseItem2 = upsertResponse1.getItem();
validateResponse(properties, responseItem2);
actualProperties.add(properties);

properties = getItem(UUID.randomUUID().toString());
CosmosItemResponse<EncryptionPojo> upsertResponse2 = cosmosEncryptionAsyncContainer.upsertItem(properties, new CosmosItemRequestOptions()).block();
assertThat(upsertResponse2.getRequestCharge()).isGreaterThan(0);
EncryptionPojo responseItem3 = upsertResponse2.getItem();
validateResponse(properties, responseItem3);
actualProperties.add(properties);

//Read Item
EncryptionPojo readItem = cosmosEncryptionAsyncContainer.readItem(actualProperties.get(0).getId(),
new PartitionKey(actualProperties.get(0).getMypk()), EncryptionPojo.class).block().getItem();
validateResponse(actualProperties.get(0), readItem);

//Query Item
String query = String.format("SELECT * from c where c.id = '%s'", actualProperties.get(1).getId());

CosmosPagedFlux<EncryptionPojo> feedResponseIterator =
cosmosEncryptionAsyncContainer.queryItems(query, EncryptionPojo.class);
List<EncryptionPojo> feedResponse = feedResponseIterator.byPage().blockFirst().getResults();
assertThat(feedResponse.size()).isGreaterThanOrEqualTo(1);
for (EncryptionPojo pojo : feedResponse) {
if (pojo.getId().equals(actualProperties.get(1).getId())) {
validateResponse(pojo, responseItem1);
}
}

CosmosQueryRequestOptions cosmosQueryRequestOptions1 = new CosmosQueryRequestOptions();

CosmosPagedFlux<EncryptionPojo> feedResponseIterator1 =
cosmosEncryptionAsyncContainer.queryItems(query, cosmosQueryRequestOptions1, EncryptionPojo.class);
List<EncryptionPojo> feedResponse1 = feedResponseIterator1.byPage().blockFirst().getResults();
assertThat(feedResponse1.size()).isGreaterThanOrEqualTo(1);
for (EncryptionPojo pojo : feedResponse1) {
if (pojo.getId().equals(actualProperties.get(1).getId())) {
validateResponse(pojo, responseItem1);
}
}

CosmosQueryRequestOptions cosmosQueryRequestOptions2 = new CosmosQueryRequestOptions();
SqlQuerySpec querySpec = new SqlQuerySpec(query);

CosmosPagedFlux<EncryptionPojo> feedResponseIterator2 =
cosmosEncryptionAsyncContainer.queryItems(querySpec, cosmosQueryRequestOptions2, EncryptionPojo.class);
List<EncryptionPojo> feedResponse2 = feedResponseIterator2.byPage().blockFirst().getResults();
assertThat(feedResponse2.size()).isGreaterThanOrEqualTo(1);
for (EncryptionPojo pojo : feedResponse2) {
if (pojo.getId().equals(actualProperties.get(1).getId())) {
validateResponse(pojo, responseItem1);
}
}

//Replace Item
CosmosItemResponse<EncryptionPojo> replaceResponse =
cosmosEncryptionAsyncContainer.replaceItem(actualProperties.get(2), actualProperties.get(2).getId(),
new PartitionKey(actualProperties.get(2).getMypk())).block();
assertThat(upsertResponse1.getRequestCharge()).isGreaterThan(0);
responseItem = replaceResponse.getItem();
validateResponse(actualProperties.get(2), responseItem);

//Delete Item
CosmosItemResponse<?> deleteResponse = cosmosEncryptionAsyncContainer.deleteItem(actualProperties.get(0).getId(),
new PartitionKey(actualProperties.get(0).getMypk())).block();
assertThat(deleteResponse.getStatusCode()).isEqualTo(204);

CosmosItemResponse<?> deleteResponse1 = cosmosEncryptionAsyncContainer.deleteItem(actualProperties.get(1).getId(),
new PartitionKey(actualProperties.get(1).getMypk()), new CosmosItemRequestOptions()).block();
assertThat(deleteResponse1.getStatusCode()).isEqualTo(204);

CosmosItemResponse<?> deleteResponse2 = cosmosEncryptionAsyncContainer.deleteItem(actualProperties.get(2),
new CosmosItemRequestOptions()).block();
assertThat(deleteResponse2.getStatusCode()).isEqualTo(204);

CosmosItemResponse<?> deleteResponse3 = cosmosEncryptionAsyncContainer.deleteAllItemsByPartitionKey(new PartitionKey(actualProperties.get(3).getMypk()),
new CosmosItemRequestOptions()).block();
assertThat(deleteResponse3.getStatusCode()).isEqualTo(200);
}

static void validateResponseWithOneFieldEncryption(EncryptionPojo originalItem, EncryptionPojo result) {
assertThat(result.getId()).isEqualTo(originalItem.getId());
assertThat(result.getNonSensitive()).isEqualTo(originalItem.getNonSensitive());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "key1",
"encryptionAlgorithmId": "AEAD_AES_256_CBC_HMAC_SHA256",
"encryptionAlgorithm": "AEAD_AES_256_CBC_HMAC_SHA256",
"wrappedDataEncryptionKey": "S84PieiyZNyHxeuUuX5IXSV2KOktpt02tQM4QLhm8dI=",
"keyWrapMetadata": {
"type": "TESTKEYSTORE_VAULT",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "key2",
"encryptionAlgorithmId": "AEAD_AES_256_CBC_HMAC_SHA256",
"encryptionAlgorithm": "AEAD_AES_256_CBC_HMAC_SHA256",
"wrappedDataEncryptionKey": "ydjdH/ANRnjhldUgFGW9X/cohiFKuNom5tGm24aBgZU=",
"keyWrapMetadata": {
"type": "TESTKEYSTORE_VAULT",
Expand Down
Loading

0 comments on commit 71b1c8b

Please sign in to comment.