getEncryptedItem(EncryptionSettings encryptionSettings, String propertyName, String propertyValue) {
+ return encryptionSettings
+ .getEncryptionSettingForPropertyAsync(propertyName, this.encryptionProcessor)
+ .flatMap(settings -> {
+ try {
+ return Mono.just(
+ this.encryptionProcessor.encryptAndSerializeValue(settings, propertyValue, propertyName));
+ } catch (MicrosoftDataEncryptionException ex) {
+ return Mono.error(ex);
+ }
+ });
+ }
+
+
/**
* Deletes the item.
*
@@ -225,10 +326,14 @@ public Mono> deleteItem(T item, CosmosItemRequest
*/
// TODO Make this api public once it is GA in cosmos core library
Mono> deleteAllItemsByPartitionKey(PartitionKey partitionKey, CosmosItemRequestOptions requestOptions) {
- if (requestOptions == null) {
- requestOptions = new CosmosItemRequestOptions();
- }
- return container.deleteAllItemsByPartitionKey(partitionKey, requestOptions);
+ Objects.requireNonNull(partitionKey, "partitionKey cannot be null");
+ final CosmosItemRequestOptions options = Optional.ofNullable(requestOptions)
+ .orElse(new CosmosItemRequestOptions());
+
+ return this.encryptionProcessor.initEncryptionSettingsIfNotInitializedAsync()
+ .thenReturn(this.encryptionProcessor.getEncryptionSettings())
+ .flatMap(encryptedSettings -> checkAndGetEncryptedPartitionKey(partitionKey, encryptedSettings))
+ .flatMap(encryptedPartitionKey -> container.deleteAllItemsByPartitionKey(partitionKey, options));
}
/**
@@ -380,15 +485,23 @@ public Mono> readItem(String id,
PartitionKey partitionKey,
CosmosItemRequestOptions requestOptions,
Class classType) {
- if (requestOptions == null) {
- requestOptions = new CosmosItemRequestOptions();
- }
-
- Mono> responseMessageMono = this.readItemHelper(id, partitionKey, requestOptions, false);
-
- return responseMessageMono.publishOn(encryptionScheduler).flatMap(cosmosItemResponse -> setByteArrayContent(cosmosItemResponse,
- this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse)))
- .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, classType)));
+ final CosmosItemRequestOptions options = Optional.ofNullable(requestOptions)
+ .orElse(new CosmosItemRequestOptions());
+
+ return this.encryptionProcessor.initEncryptionSettingsIfNotInitializedAsync()
+ .thenReturn(this.encryptionProcessor.getEncryptionSettings())
+ .flatMap(encryptedSettings -> Mono.zip(
+ checkAndGetEncryptedId(id, encryptedSettings),
+ checkAndGetEncryptedPartitionKey(partitionKey, encryptedSettings))
+ .flatMap(encryptedIdPartitionKeyTuple ->
+ this.readItemHelper(encryptedIdPartitionKeyTuple.getT1(),
+ encryptedIdPartitionKeyTuple.getT2(), options, false))
+ .publishOn(encryptionScheduler)
+ .flatMap(cosmosItemResponse -> setByteArrayContent(
+ cosmosItemResponse,
+ this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor
+ .getByteArrayContent(cosmosItemResponse))
+ ).map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, classType))));
}
/**
@@ -554,11 +667,15 @@ public Mono> patchItem(
checkNotNull(partitionKey, "expected non-null partitionKey for patchItem");
checkNotNull(cosmosPatchOperations, "expected non-null cosmosPatchOperations");
- if (options == null) {
- options = new CosmosPatchItemRequestOptions();
- }
+ final CosmosPatchItemRequestOptions patchOptions = Optional.ofNullable(options)
+ .orElse(new CosmosPatchItemRequestOptions());
- return patchItemHelper(itemId, partitionKey, cosmosPatchOperations, options, itemType);
+ return this.encryptionProcessor.initEncryptionSettingsIfNotInitializedAsync()
+ .thenReturn(this.encryptionProcessor.getEncryptionSettings())
+ .flatMap(encryptionSettings -> Mono.zip(
+ checkAndGetEncryptedId(itemId, encryptionSettings),
+ checkAndGetEncryptedPartitionKey(partitionKey, encryptionSettings))
+ .flatMap(encryptedIdPartitionKeyTuple -> patchItemHelper(encryptedIdPartitionKeyTuple.getT1(), encryptedIdPartitionKeyTuple.getT2(), cosmosPatchOperations, patchOptions, itemType)));
}
private Mono> patchItemHelper(String itemId,
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/Constants.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/Constants.java
index c06ae1b71f2ca..888752d3959f1 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/Constants.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/Constants.java
@@ -15,4 +15,6 @@ public class Constants {
public static final String ALLOW_CACHED_READS_HEADER = "x-ms-cosmos-allow-cachedreads";
public static final String DATABASE_RID_HEADER = "x-ms-cosmos-database-rid";
+
+ public static final String PROPERTY_NAME_ID = "id";
}
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java
index 42032b0f2947f..a10f3849cd206 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java
@@ -24,6 +24,7 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
@@ -41,6 +42,7 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Base64;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -58,6 +60,7 @@ public class EncryptionProcessor {
private ClientEncryptionPolicy clientEncryptionPolicy;
private String containerRid;
private String databaseRid;
+ private List partitionKeyPaths;
private CosmosClientEncryptionKeyProperties cosmosClientEncryptionKeyProperties;
private final EncryptionKeyStoreProviderImpl encryptionKeyStoreProviderImpl;
private final static ImplementationBridgeHelpers.CosmosContainerPropertiesHelper.CosmosContainerPropertiesAccessor cosmosContainerPropertiesAccessor = ImplementationBridgeHelpers.CosmosContainerPropertiesHelper.getCosmosContainerPropertiesAccessor();
@@ -99,7 +102,15 @@ public Mono initializeEncryptionSettingsAsync(boolean isRetry) {
{
this.containerRid = cosmosContainerProperties.getResourceId();
this.databaseRid = cosmosContainerPropertiesAccessor.getSelfLink(cosmosContainerProperties).split("/")[1];
+
+ if (cosmosContainerProperties.getPartitionKeyDefinition().getPaths().isEmpty()) {
+ this.partitionKeyPaths = cosmosContainerProperties.getPartitionKeyDefinition().getPaths();
+ } else {
+ this.partitionKeyPaths = new ArrayList<>();
+ }
+
this.encryptionSettings.setDatabaseRid(this.databaseRid);
+ this.encryptionSettings.setPartitionKeyPaths(partitionKeyPaths);
if (cosmosContainerProperties.getClientEncryptionPolicy() == null) {
this.isEncryptionSettingsInitDone.set(true);
return Mono.empty();
@@ -206,7 +217,7 @@ public Mono initEncryptionSettingsIfNotInitializedAsync() {
return Mono.empty();
}
- ClientEncryptionPolicy getClientEncryptionPolicy() {
+ public ClientEncryptionPolicy getClientEncryptionPolicy() {
return clientEncryptionPolicy;
}
@@ -438,16 +449,37 @@ public void encryptAndSerializeProperty(EncryptionSettings encryptionSettings, J
}
}
+ public String encryptAndSerializeValue(EncryptionSettings encryptionSettings, String propertyValue, String propertyName) throws MicrosoftDataEncryptionException {
+ JsonNode propertyValueHolder = toJsonNode(propertyValue.getBytes(StandardCharsets.US_ASCII), TypeMarker.STRING);
+ return new String(encryptAndSerializeValue(encryptionSettings, null, propertyValueHolder, propertyName), StandardCharsets.US_ASCII);
+ }
+
public byte[] encryptAndSerializeValue(EncryptionSettings encryptionSettings, ObjectNode objectNode,
JsonNode propertyValueHolder, String propertyName) throws MicrosoftDataEncryptionException {
byte[] cipherText;
byte[] cipherTextWithTypeMarker;
+ if (propertyName.equals(Constants.PROPERTY_NAME_ID)) {
+ if (propertyValueHolder.getNodeType() != JsonNodeType.STRING) {
+ throw new IllegalArgumentException("Unsupported argument type. The value to escape has to be string " +
+ "type. Please refer to https://aka.ms/CosmosClientEncryption for more details.");
+ }
+ }
Pair typeMarkerPair = toByteArray(propertyValueHolder);
cipherText =
encryptionSettings.getAeadAes256CbcHmac256EncryptionAlgorithm().encrypt(typeMarkerPair.getRight());
cipherTextWithTypeMarker = new byte[cipherText.length + 1];
cipherTextWithTypeMarker[0] = (byte) typeMarkerPair.getLeft().getValue();
System.arraycopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.length);
+
+ if (propertyName.equals(Constants.PROPERTY_NAME_ID)) {
+ // case: id does not support '/','\','?','#'. Convert Base64 string to Uri safe string
+ String base64UriSafeString = convertToBase64UriSafeString(cipherTextWithTypeMarker);
+ if (objectNode != null && !objectNode.isNull()) {
+ objectNode.put(propertyName, base64UriSafeString);
+ }
+ return base64UriSafeString.getBytes(StandardCharsets.UTF_8);
+ }
+
if (objectNode != null && !objectNode.isNull()) {
objectNode.put(propertyName, cipherTextWithTypeMarker);
}
@@ -567,7 +599,15 @@ public JsonNode decryptAndSerializeValue(EncryptionSettings encryptionSettings,
JsonNode propertyValueHolder, String propertyName) throws MicrosoftDataEncryptionException, IOException {
byte[] cipherText;
byte[] cipherTextWithTypeMarker;
- cipherTextWithTypeMarker = propertyValueHolder.binaryValue();
+ if (propertyName.equals(Constants.PROPERTY_NAME_ID)) {
+ if (propertyValueHolder.getNodeType() == JsonNodeType.NULL) {
+ return null;
+ }
+ cipherTextWithTypeMarker = convertFromBase64UriSafeString(propertyValueHolder.asText());
+ } else {
+ cipherTextWithTypeMarker = propertyValueHolder.binaryValue();
+ }
+
cipherText = new byte[cipherTextWithTypeMarker.length - 1];
System.arraycopy(cipherTextWithTypeMarker, 1, cipherText, 0,
cipherTextWithTypeMarker.length - 1);
@@ -627,6 +667,27 @@ public static JsonNode toJsonNode(byte[] serializedBytes, TypeMarker typeMarker)
throw BridgeInternal.createCosmosException(0, "Invalid or Unsupported Data Type Passed " + typeMarker);
}
+ private String convertToBase64UriSafeString(byte[] bytesToProcess) {
+ // Base 64 Encoding with URL and Filename Safe Alphabet https://datatracker.ietf.org/doc/html/rfc4648#section-5
+ // https://docs.microsoft.com/en-us/azure/cosmos-db/concepts-limits#per-item-limits, due to base64 conversion and encryption
+ // the permissible size of the property will further reduce.
+ return Base64.getUrlEncoder().encodeToString(bytesToProcess);
+ }
+
+ private byte[] convertFromBase64UriSafeString(String base64UriSafeString) {
+ return Base64.getUrlDecoder().decode(base64UriSafeString);
+ }
+
+ private StringBuilder replaceString(StringBuilder sb,
+ String toReplace,
+ String replacement) {
+ int index = -1;
+ while ((index = sb.lastIndexOf(toReplace)) != -1) {
+ sb.replace(index, index + toReplace.length(), replacement);
+ }
+ return sb;
+ }
+
public enum TypeMarker {
NULL(1), // not used
BOOLEAN(2),
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionSettings.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionSettings.java
index 8c45d9be3e33e..e25c13be68e07 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionSettings.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionSettings.java
@@ -25,6 +25,7 @@
import java.security.InvalidKeyException;
import java.time.Duration;
import java.time.Instant;
+import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -39,6 +40,7 @@ public final class EncryptionSettings {
private EncryptionType encryptionType;
private String databaseRid;
private CosmosClientEncryptionKeyProperties cosmosClientEncryptionKeyProperties;
+ private List partitionKeyPaths;
private final static EncryptionImplementationBridgeHelpers.CosmosEncryptionAsyncClientHelper.CosmosEncryptionAsyncClientAccessor cosmosEncryptionAsyncClientAccessor =
EncryptionImplementationBridgeHelpers.CosmosEncryptionAsyncClientHelper.getCosmosEncryptionAsyncClientAccessor();
@@ -226,6 +228,14 @@ public void setEncryptionSettingForProperty(String propertyName, EncryptionSetti
this.encryptionSettingCacheByPropertyName.set(propertyName, cachedEncryptionSettings);
}
+ public List getPartitionKeyPaths() {
+ return partitionKeyPaths;
+ }
+
+ public void setPartitionKeyPaths(List partitionKeyPaths) {
+ this.partitionKeyPaths = partitionKeyPaths;
+ }
+
static EncryptionSettings create(
EncryptionSettings settingsForKey,
EncryptionType encryptionType) throws MicrosoftDataEncryptionException {
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/EncryptionCodeSnippet.java b/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/EncryptionCodeSnippet.java
index 4eb0467d764c7..e8f9e2898701a 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/EncryptionCodeSnippet.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/EncryptionCodeSnippet.java
@@ -124,7 +124,7 @@ void createContainerWithClientEncryptionPolicy(CosmosAsyncClient client) {
paths.add(includedPath6);
paths.add(includedPath7);
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths);
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths, 2);
String containerId = "myCol";
CosmosContainerProperties properties = new CosmosContainerProperties(containerId, "/mypk");
properties.setClientEncryptionPolicy(clientEncryptionPolicy);
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/Program.java b/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/Program.java
index 4c8a47ec840a7..9aad3fb512193 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/Program.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/Program.java
@@ -155,7 +155,7 @@ private static void initialize(CosmosEncryptionAsyncClient cosmosEncryptionAsync
CosmosContainerProperties containerProperties = new CosmosContainerProperties(Program.containerId,
"/purchaseOrderNumber");
- containerProperties.setClientEncryptionPolicy(new ClientEncryptionPolicy(paths));
+ containerProperties.setClientEncryptionPolicy(new ClientEncryptionPolicy(paths, 2));
cosmosEncryptionAsyncDatabase.getCosmosAsyncDatabase().createContainer(containerProperties,
ThroughputProperties.createManualThroughput(1000)).block();
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/ReadmeSamples.java b/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/ReadmeSamples.java
index 3e9dbd3104c7d..c95291168c19c 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/ReadmeSamples.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/samples/java/com/azure/cosmos/encryption/ReadmeSamples.java
@@ -86,7 +86,7 @@ public void createCosmosEncryptionContainer() {
List paths = new ArrayList<>();
paths.add(includedPath);
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths);
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths, 2);
CosmosContainerProperties properties = new CosmosContainerProperties("", "/mypk");
properties.setClientEncryptionPolicy(clientEncryptionPolicy);
return cosmosEncryptionAsyncDatabase.getCosmosAsyncDatabase().createContainer(properties);
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionClientCachesTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionClientCachesTest.java
index efc84fa304dce..a2fb743d14fe1 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionClientCachesTest.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionClientCachesTest.java
@@ -68,7 +68,7 @@ public void before_CosmosItemTest() {
CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName(), metadata2).block();
//Create collection with clientEncryptionPolicy
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths());
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths(), 2);
CosmosContainerProperties containerProperties = new CosmosContainerProperties("TestCollForEncryptionCacheTest"
, "/mypk");
containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/DotNetCompatibleTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/DotNetCompatibleTest.java
index 58fe54893f845..db181101ba0b8 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/DotNetCompatibleTest.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/DotNetCompatibleTest.java
@@ -70,7 +70,7 @@ public void before_CosmosItemTest() throws IOException {
cosmosEncryptionAsyncClient.getCosmosEncryptionAsyncDatabase(cosmosAsyncDatabase.getId());
ClientEncryptionPolicy clientEncryptionPolicy =
- new ClientEncryptionPolicy(getPaths());
+ new ClientEncryptionPolicy(getPaths(), 2);
String containerId = UUID.randomUUID().toString();
CosmosContainerProperties containerProperties = new CosmosContainerProperties(containerId, "/mypk");
containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
@@ -100,12 +100,13 @@ public void createItemEncrypt_readItemDecrypt() throws IOException {
this.cosmosEncryptionAsyncContainer.getCosmosAsyncContainer().createItem(dotNetEncryptedPocoJsonNode,
partitionKey, requestOptions).block();
+ JsonNode dotNetPOCOJsonNode = MAPPER.readTree(new File("src/test/resources/dotnetEncryption/POCO.json"));
+ partitionKey = new PartitionKey(dotNetPOCOJsonNode.get("mypk").asText());
//reading above saved .net encrypted json via java encryption library
EncryptionPojo unencryptedPojo =
- this.cosmosEncryptionAsyncContainer.readItem(dotNetEncryptedPocoJsonNode.get("id").asText(), partitionKey
+ this.cosmosEncryptionAsyncContainer.readItem(dotNetPOCOJsonNode.get("id").asText(), partitionKey
, new CosmosItemRequestOptions(), EncryptionPojo.class).block().getItem();
- JsonNode dotNetPOCOJsonNode = MAPPER.readTree(new File("src/test/resources/dotnetEncryption/POCO.json"));
EncryptionPojo unencryptedPoco = MAPPER.treeToValue(dotNetPOCOJsonNode, EncryptionPojo.class);
//validating java decrypted pojo similar to original .net unencrypted poco
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionAsyncApiCrudTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionAsyncApiCrudTest.java
index a5415f557db45..ba2702015ac0b 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionAsyncApiCrudTest.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionAsyncApiCrudTest.java
@@ -57,6 +57,7 @@ public class EncryptionAsyncApiCrudTest extends TestSuiteBase {
private CosmosAsyncClient client;
private CosmosEncryptionAsyncClient cosmosEncryptionAsyncClient;
private CosmosEncryptionAsyncContainer encryptionContainerWithIncompatiblePolicyVersion;
+ private CosmosContainerProperties propertiesWithIdAndPartitionKeyPath;
CosmosEncryptionAsyncContainer cosmosEncryptionAsyncContainer;
CosmosEncryptionAsyncDatabase cosmosEncryptionAsyncDatabase;
@@ -76,12 +77,12 @@ public void before_CosmosItemTest() {
cosmosEncryptionAsyncDatabase = getSharedEncryptionDatabase(cosmosEncryptionAsyncClient);
cosmosEncryptionAsyncContainer = getSharedEncryptionContainer(cosmosEncryptionAsyncClient);
- ClientEncryptionPolicy clientEncryptionWithPolicyFormatVersion2 = new ClientEncryptionPolicy(getPaths());
- ReflectionUtils.setPolicyFormatVersion(clientEncryptionWithPolicyFormatVersion2, 2);
+ ClientEncryptionPolicy clientEncryptionWithPolicyFormatVersion2 = new ClientEncryptionPolicy(getPaths(), 2);
String containerId = UUID.randomUUID().toString();
CosmosContainerProperties properties = new CosmosContainerProperties(containerId, "/mypk");
properties.setClientEncryptionPolicy(clientEncryptionWithPolicyFormatVersion2);
cosmosEncryptionAsyncDatabase.getCosmosAsyncDatabase().createContainer(properties).block();
+
encryptionContainerWithIncompatiblePolicyVersion =
cosmosEncryptionAsyncDatabase.getCosmosEncryptionAsyncContainer(containerId);
}
@@ -95,6 +96,7 @@ public void afterClass() {
@Test(groups = {"encryption"}, timeOut = TIMEOUT)
public void createItemEncrypt_readItemDecrypt() {
EncryptionPojo properties = getItem(UUID.randomUUID().toString());
+
CosmosItemResponse itemResponse = cosmosEncryptionAsyncContainer.createItem(properties,
new PartitionKey(properties.getMypk()), new CosmosItemRequestOptions()).block();
assertThat(itemResponse.getRequestCharge()).isGreaterThan(0);
@@ -365,7 +367,7 @@ public void crudQueryStaleCache() {
cosmosEncryptionAsyncClient.getCosmosEncryptionAsyncDatabase(asyncClient.getDatabase(databaseId));
String containerId = UUID.randomUUID().toString();
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths());
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths(), 2);
createEncryptionContainer(cosmosEncryptionAsyncDatabase, clientEncryptionPolicy, containerId);
CosmosEncryptionAsyncContainer encryptionAsyncContainerOriginal =
cosmosEncryptionAsyncDatabase.getCosmosEncryptionAsyncContainer(containerId);
@@ -398,7 +400,7 @@ public void crudQueryStaleCache() {
//Deleting and creating container
encryptionAsyncContainerOriginal.getCosmosAsyncContainer().delete().block();
- ClientEncryptionPolicy policyWithOneEncryptionPolicy = new ClientEncryptionPolicy(getPathWithOneEncryptionField());
+ ClientEncryptionPolicy policyWithOneEncryptionPolicy = new ClientEncryptionPolicy(getPathWithOneEncryptionField(), 2);
createEncryptionContainer(cosmosEncryptionAsyncDatabase, policyWithOneEncryptionPolicy, containerId);
CosmosEncryptionAsyncContainer encryptionAsyncContainerNew = getNewEncryptionContainerProxyObject(cosmosEncryptionAsyncDatabase.getCosmosAsyncDatabase().getId(), containerId);
encryptionAsyncContainerNew.createItem(encryptionPojo,
@@ -1011,6 +1013,109 @@ public void crudOnDifferentOverload() {
assertThat(deleteResponse3.getStatusCode()).isEqualTo(200);
}
+// @Test(groups = {"encryption"}, timeOut = TIMEOUT)
+// public void crudOperationsWithIdAndPartitionKeyEncrypted() {
+// cosmosEncryptionAsyncDatabase.getCosmosAsyncDatabase().createContainer(propertiesWithIdAndPartitionKeyPath).block();
+// List actualProperties = new ArrayList<>();
+// // Read item
+// EncryptionPojo properties = getItem(UUID.randomUUID().toString());
+// CosmosItemResponse 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 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 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 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 feedResponseIterator =
+// cosmosEncryptionAsyncContainer.queryItems(query, EncryptionPojo.class);
+// List 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 feedResponseIterator1 =
+// cosmosEncryptionAsyncContainer.queryItems(query, cosmosQueryRequestOptions1, EncryptionPojo.class);
+// List 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 feedResponseIterator2 =
+// cosmosEncryptionAsyncContainer.queryItems(querySpec, cosmosQueryRequestOptions2, EncryptionPojo.class);
+// List 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 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());
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionCosmosEncryptionChangeFeedTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionCosmosEncryptionChangeFeedTest.java
index 497487b8deeb8..8b670a266048c 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionCosmosEncryptionChangeFeedTest.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/EncryptionCosmosEncryptionChangeFeedTest.java
@@ -264,7 +264,7 @@ private CosmosAsyncContainer createLeaseCollection(int provisionedThroughput) {
}
private CosmosEncryptionAsyncContainer createFeedCollection() {
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths());
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths(), 2);
String containerId = UUID.randomUUID().toString();
CosmosContainerProperties properties = new CosmosContainerProperties(containerId, "/mypk");
properties.setClientEncryptionPolicy(clientEncryptionPolicy);
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java
index 3d09303f79bfc..16077a9bba142 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java
@@ -240,7 +240,7 @@ public static void beforeSuite() {
SHARED_ENCRYPTION_DATABASE.createClientEncryptionKey("key2",
CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName(), metadata2).block();
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths());
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(getPaths(),2);
String containerId = UUID.randomUUID().toString();
CosmosContainerProperties properties = new CosmosContainerProperties(containerId, "/mypk");
properties.setClientEncryptionPolicy(clientEncryptionPolicy);
@@ -1292,6 +1292,18 @@ protected static List getPaths() {
includedPath13.setEncryptionType(CosmosEncryptionType.DETERMINISTIC.getName());
includedPath13.setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName());
+ ClientEncryptionIncludedPath includedPath14 = new ClientEncryptionIncludedPath();
+ includedPath14.setClientEncryptionKeyId("key1");
+ includedPath14.setPath("/id");
+ includedPath14.setEncryptionType(CosmosEncryptionType.DETERMINISTIC.getName());
+ includedPath14.setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName());
+
+ ClientEncryptionIncludedPath includedPath15 = new ClientEncryptionIncludedPath();
+ includedPath15.setClientEncryptionKeyId("key1");
+ includedPath15.setPath("/pk");
+ includedPath15.setEncryptionType(CosmosEncryptionType.DETERMINISTIC.getName());
+ includedPath15.setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName());
+
List paths = new ArrayList<>();
paths.add(includedPath1);
paths.add(includedPath2);
@@ -1306,6 +1318,8 @@ protected static List getPaths() {
paths.add(includedPath11);
paths.add(includedPath12);
paths.add(includedPath13);
+ paths.add(includedPath14);
+ paths.add(includedPath15);
return paths;
}
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java
index 066ae900e80fb..18913e31c1790 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java
+++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java
@@ -206,7 +206,7 @@ private ClientEncryptionPolicy generateClientEncryptionPolicy() {
includedPath1.setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName());
List paths = new ArrayList<>();
paths.add(includedPath1);
- return new ClientEncryptionPolicy(paths);
+ return new ClientEncryptionPolicy(paths, 1);
}
private CosmosContainerProperties generateContainerWithCosmosEncryptionPolicy() {
@@ -219,7 +219,7 @@ private CosmosContainerProperties generateContainerWithCosmosEncryptionPolicy()
includedPath1.setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName());
List paths = new ArrayList<>();
paths.add(includedPath1);
- return containerProperties.setClientEncryptionPolicy(new ClientEncryptionPolicy(paths));
+ return containerProperties.setClientEncryptionPolicy(new ClientEncryptionPolicy(paths, 1));
}
private CosmosClientEncryptionKeyProperties generateClientEncryptionKeyProperties() throws JsonProcessingException {
diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/resources/dotnetEncryption/EncryptedPOCO.json b/sdk/cosmos/azure-cosmos-encryption/src/test/resources/dotnetEncryption/EncryptedPOCO.json
index 448e61486361c..7f1e2684fbcdc 100644
--- a/sdk/cosmos/azure-cosmos-encryption/src/test/resources/dotnetEncryption/EncryptedPOCO.json
+++ b/sdk/cosmos/azure-cosmos-encryption/src/test/resources/dotnetEncryption/EncryptedPOCO.json
@@ -1,20 +1,20 @@
{
- "id": "7d925bf9-d583-4c6d-a49f-137bee7cff91",
+ "id": "BQF1OMHlXj-zDxKasrXQFwusq5lZf-AjwlS5Z4ZFdtljRO9ljKsPhPdZ4bGsXYbgtO4WrsHdqVy7r_EB101kO7xfjmGMvTOBiRt_M80AcNwiwJ1vFX9-uLudp3ttD-wKyZs=",
"mypk": "7d925bf9-d583-4c6d-a49f-137bee7cff91",
"nonSensitive": "cf012e6a-3dd1-4f1a-bd93-dc2b7fee5e97",
"sensitiveString": "BQE8sgzM2aDfOlOiU9tYsgR5CghB/WZ/jsluf4HoYotfeUBqDBn3hVfx3A+o4m2mm5dEvnJyOR2Sl+NZezsYN71d",
"sensitiveInt": "BAF+h8xlYiIqaH9TmN8/mgzX8ulodNhbYPASSPEGIVb+3qTR8J4qo/jZoz/qQdkxkEv8TV/aj0UdPEpGF4EBe+88",
- "sensitiveFloat": "AwHBSYf0AqKfOX60Ppn/yj9ycfuFlOWEHGQ230BypHacyeBX/o3jRmlgnRNJuZpr1I9n0pNQl1yCfJkscMUVs8ao",
+ "sensitiveFloat": "BAFjPNt6v/gmO/v1uZCeTPgT6Tioja+rOzr1I8OK3hjC6tU6eZlXk0TUBVtu6ZkbIMo+cMAxH7IVC5diCnJfkjlS",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
- "sensitiveDouble": "AwHu2zdLESFrjQ7L9KbCenSeEXHOXKjV9d2UCfhNhR/ImYmODXymlKGxapHhzmUabdEp6hKP6ZNIjqJ5xvFD6EYs",
+ "sensitiveDouble": "AwHMrObWBev4hnUulDL5dvLxybF22O3VzY7//PXyano3Hrl8A967TAp3fdRATdaFHydATozMzgREtbhjJNk1WT1d",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
"sensitiveNestedPojo": {
- "id": "BQERuT+l/kKc51OtABiPG3/lu8hpIJNGwUgJVzr71dKJk9wcuuzZbMqtsxj+Ue4B0oY0OYbKCuOYF3wLctg7P0cO",
+ "id": "BQERuT-l_kKc51OtABiPG3_lu8hpIJNGwUgJVzr71dKJk9wcuuzZbMqtsxj-Ue4B0oY0OYbKCuOYF3wLctg7P0cO",
"mypk": "BQERuT+l/kKc51OtABiPG3/lu8hpIJNGwUgJVzr71dKJk9wcuuzZbMqtsxj+Ue4B0oY0OYbKCuOYF3wLctg7P0cO",
"nonSensitive": null,
"sensitiveString": "BQERuT+l/kKc51OtABiPG3/lu8hpIJNGwUgJVzr71dKJk9wcuuzZbMqtsxj+Ue4B0oY0OYbKCuOYF3wLctg7P0cO",
"sensitiveInt": "BAFZBTqQK+9Z7UC1W1NBh+LHLzAEcfFgCc53BD6EtcfGxLZXjKm/F9OFNB+gMeM3T4SFj6jG5DH6TtjVh1XRum4/",
- "sensitiveFloat": "AwHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
+ "sensitiveFloat": "BAHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
"sensitiveDouble": "AwHAQXtks16DzqIkLNWYZ7TWcjNCLPIYdiTe3NG7hXqg+DJirv5y2hx/fPiGuSKQ30ocEKkiqnxwISegmxZQt1De",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
@@ -82,12 +82,12 @@
"sensitiveChildPojo2DArray": [
[
{
- "id": "BQHRkzWrw6w88Rak29a/mWMh57hvictUtZEK0YuYV+LNRuvCBPU74+btLrxseJ4VZ3zesySbaBGkICzT7zq44M1j",
+ "id": "BQHRkzWrw6w88Rak29a_mWMh57hvictUtZEK0YuYV-LNRuvCBPU74-btLrxseJ4VZ3zesySbaBGkICzT7zq44M1j",
"mypk": null,
"nonSensitive": null,
"sensitiveString": "BQFfH6UGQgHuCZ1SKb8uDdEEdpjZ9+oFgKXDZGR5awXt5hY7B0D5i+6WQQNp2y2Vwsql32ZhCGEyg2vpew/heajPaIqKEPCCklz0WiVc/lrePg==",
"sensitiveInt": "BAFZBTqQK+9Z7UC1W1NBh+LHLzAEcfFgCc53BD6EtcfGxLZXjKm/F9OFNB+gMeM3T4SFj6jG5DH6TtjVh1XRum4/",
- "sensitiveFloat": "AwHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
+ "sensitiveFloat": "BAHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
"sensitiveDouble": "AwHAQXtks16DzqIkLNWYZ7TWcjNCLPIYdiTe3NG7hXqg+DJirv5y2hx/fPiGuSKQ30ocEKkiqnxwISegmxZQt1De",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
@@ -123,12 +123,12 @@
"sensitiveChildPojoList": null
},
{
- "id": "BQEUkOOtKpvfp4tbzdsgHToSUv8fUstDi025Q6n6oOvi5mFelP1C/wEauxKAYYswqUJ6DWd5eiIsFB/bjGViIq5A",
+ "id": "BQEUkOOtKpvfp4tbzdsgHToSUv8fUstDi025Q6n6oOvi5mFelP1C_wEauxKAYYswqUJ6DWd5eiIsFB_bjGViIq5A",
"mypk": null,
"nonSensitive": null,
"sensitiveString": "BQG3BuavLLquGcjrQw50+NLMm/86/+qVs+75b0jVTcfgjdkwXpTyFY7bRb/SSvxb7DYG7/za32PJ9Q5L4t5d3jvluLs2JWe6wb0fzjw5HSVuEA==",
"sensitiveInt": "BAFZBTqQK+9Z7UC1W1NBh+LHLzAEcfFgCc53BD6EtcfGxLZXjKm/F9OFNB+gMeM3T4SFj6jG5DH6TtjVh1XRum4/",
- "sensitiveFloat": "AwHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
+ "sensitiveFloat": "BAHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
"sensitiveDouble": "AwHAQXtks16DzqIkLNWYZ7TWcjNCLPIYdiTe3NG7hXqg+DJirv5y2hx/fPiGuSKQ30ocEKkiqnxwISegmxZQt1De",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
@@ -142,12 +142,12 @@
],
[
{
- "id": "BQHRkzWrw6w88Rak29a/mWMh57hvictUtZEK0YuYV+LNRuvCBPU74+btLrxseJ4VZ3zesySbaBGkICzT7zq44M1j",
+ "id": "BQHRkzWrw6w88Rak29a_mWMh57hvictUtZEK0YuYV-LNRuvCBPU74-btLrxseJ4VZ3zesySbaBGkICzT7zq44M1j",
"mypk": null,
"nonSensitive": null,
"sensitiveString": "BQFfH6UGQgHuCZ1SKb8uDdEEdpjZ9+oFgKXDZGR5awXt5hY7B0D5i+6WQQNp2y2Vwsql32ZhCGEyg2vpew/heajPaIqKEPCCklz0WiVc/lrePg==",
"sensitiveInt": "BAFZBTqQK+9Z7UC1W1NBh+LHLzAEcfFgCc53BD6EtcfGxLZXjKm/F9OFNB+gMeM3T4SFj6jG5DH6TtjVh1XRum4/",
- "sensitiveFloat": "AwHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
+ "sensitiveFloat": "BAHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
"sensitiveDouble": "AwHAQXtks16DzqIkLNWYZ7TWcjNCLPIYdiTe3NG7hXqg+DJirv5y2hx/fPiGuSKQ30ocEKkiqnxwISegmxZQt1De",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
@@ -183,12 +183,12 @@
"sensitiveChildPojoList": null
},
{
- "id": "BQEUkOOtKpvfp4tbzdsgHToSUv8fUstDi025Q6n6oOvi5mFelP1C/wEauxKAYYswqUJ6DWd5eiIsFB/bjGViIq5A",
+ "id": "BQEUkOOtKpvfp4tbzdsgHToSUv8fUstDi025Q6n6oOvi5mFelP1C_wEauxKAYYswqUJ6DWd5eiIsFB_bjGViIq5A",
"mypk": null,
"nonSensitive": null,
"sensitiveString": "BQG3BuavLLquGcjrQw50+NLMm/86/+qVs+75b0jVTcfgjdkwXpTyFY7bRb/SSvxb7DYG7/za32PJ9Q5L4t5d3jvluLs2JWe6wb0fzjw5HSVuEA==",
"sensitiveInt": "BAFZBTqQK+9Z7UC1W1NBh+LHLzAEcfFgCc53BD6EtcfGxLZXjKm/F9OFNB+gMeM3T4SFj6jG5DH6TtjVh1XRum4/",
- "sensitiveFloat": "AwHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
+ "sensitiveFloat": "BAHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
"sensitiveDouble": "AwHAQXtks16DzqIkLNWYZ7TWcjNCLPIYdiTe3NG7hXqg+DJirv5y2hx/fPiGuSKQ30ocEKkiqnxwISegmxZQt1De",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
@@ -203,12 +203,12 @@
],
"sensitiveChildPojoList": [
{
- "id": "BQHRkzWrw6w88Rak29a/mWMh57hvictUtZEK0YuYV+LNRuvCBPU74+btLrxseJ4VZ3zesySbaBGkICzT7zq44M1j",
+ "id": "BQHRkzWrw6w88Rak29a_mWMh57hvictUtZEK0YuYV-LNRuvCBPU74-btLrxseJ4VZ3zesySbaBGkICzT7zq44M1j",
"mypk": null,
"nonSensitive": null,
"sensitiveString": "BQFfH6UGQgHuCZ1SKb8uDdEEdpjZ9+oFgKXDZGR5awXt5hY7B0D5i+6WQQNp2y2Vwsql32ZhCGEyg2vpew/heajPaIqKEPCCklz0WiVc/lrePg==",
"sensitiveInt": "BAFZBTqQK+9Z7UC1W1NBh+LHLzAEcfFgCc53BD6EtcfGxLZXjKm/F9OFNB+gMeM3T4SFj6jG5DH6TtjVh1XRum4/",
- "sensitiveFloat": "AwHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
+ "sensitiveFloat": "BAHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
"sensitiveDouble": "AwHAQXtks16DzqIkLNWYZ7TWcjNCLPIYdiTe3NG7hXqg+DJirv5y2hx/fPiGuSKQ30ocEKkiqnxwISegmxZQt1De",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
@@ -244,12 +244,12 @@
"sensitiveChildPojoList": null
},
{
- "id": "BQEUkOOtKpvfp4tbzdsgHToSUv8fUstDi025Q6n6oOvi5mFelP1C/wEauxKAYYswqUJ6DWd5eiIsFB/bjGViIq5A",
+ "id": "BQEUkOOtKpvfp4tbzdsgHToSUv8fUstDi025Q6n6oOvi5mFelP1C_wEauxKAYYswqUJ6DWd5eiIsFB_bjGViIq5A",
"mypk": null,
"nonSensitive": null,
"sensitiveString": "BQG3BuavLLquGcjrQw50+NLMm/86/+qVs+75b0jVTcfgjdkwXpTyFY7bRb/SSvxb7DYG7/za32PJ9Q5L4t5d3jvluLs2JWe6wb0fzjw5HSVuEA==",
"sensitiveInt": "BAFZBTqQK+9Z7UC1W1NBh+LHLzAEcfFgCc53BD6EtcfGxLZXjKm/F9OFNB+gMeM3T4SFj6jG5DH6TtjVh1XRum4/",
- "sensitiveFloat": "AwHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
+ "sensitiveFloat": "BAHRoUMnYT23ocPkUoERjaSVcWxN05sjBivH0Dt4S5rC92YyZoyZokxGa5wnfpKuK49wr9wPynxF5QurRIha2d+c",
"sensitiveLong": "BAG8flsdV8r870XeoPwTErbRBPCU5wdoAPSICreKQigwYblfexcEAosleZ+FO261u/m8X97ObH5m8hkxEuQzPURL",
"sensitiveDouble": "AwHAQXtks16DzqIkLNWYZ7TWcjNCLPIYdiTe3NG7hXqg+DJirv5y2hx/fPiGuSKQ30ocEKkiqnxwISegmxZQt1De",
"sensitiveBoolean": "AgHOBKDUuHWgivJCu+I8JgIqI3CuSgNKYKpn6nNUN8nqtyPkwnOJXYIeKpXS55/UzzaMAfRd1CZbT2oHdkIzUfuN",
@@ -261,9 +261,9 @@
"sensitiveChildPojoList": null
}
],
- "_rid": "-dspAMVPSPMBAAAAAAAAAA==",
- "_self": "dbs/-dspAA==/colls/-dspAMVPSPM=/docs/-dspAMVPSPMBAAAAAAAAAA==/",
- "_etag": "00000000-0000-0000-984f-74dd1e6e01d7",
+ "_rid": "frBRAOuISWIBAAAAAAAAAA==",
+ "_self": "dbs/frBRAA==/colls/frBRAOuISWI=/docs/frBRAOuISWIBAAAAAAAAAA==/",
+ "_etag": "\"01094fbb-0000-0300-0000-63f528970000\"",
"_attachments": "attachments/",
- "_ts": 1629744506
+ "_ts": 1677011095
}
diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ClientEncryptionPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ClientEncryptionPolicy.java
index 9e58f9da1b991..5ea5efe4ac4e0 100644
--- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ClientEncryptionPolicy.java
+++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ClientEncryptionPolicy.java
@@ -7,7 +7,6 @@
import com.azure.cosmos.implementation.JsonSerializable;
import com.azure.cosmos.implementation.apachecommons.lang.StringUtils;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.ArrayList;
import java.util.List;
@@ -35,40 +34,40 @@ public final class ClientEncryptionPolicy {
* Constructor.
*
* @param paths list of path of the item that need encryption along with path-specific settings.
+ * the PolicyFormatVersion will be set to 1 which is the default value.
+ * Note: If you need to include partition key or id field paths as part of the ClientEncryptionPolicy, please set PolicyFormatVersion to 2.
*/
public ClientEncryptionPolicy(List paths) {
- this.validateIncludedPaths(paths);
- this.includedPaths = paths;
this.policyFormatVersion = 1;
- }
-
- /**
- * Constructor.
- */
- public ClientEncryptionPolicy() {
- this.jsonSerializable = new JsonSerializable();
+ validateIncludedPaths(paths, policyFormatVersion);
+ this.includedPaths = paths;
}
/**
* Constructor.
*
- * @param jsonString the json string that represents the client encryption policy.
+ * @param paths list of path of the item that need encryption along with path-specific settings.
+ * @param policyFormatVersion version of the client encryption policy definition. Current supported versions are 1 and 2. Default version is 1.
+ * Note: If you need to include partition key or id field paths as part of the ClientEncryptionPolicy, please set PolicyFormatVersion to 2.
*/
- ClientEncryptionPolicy(String jsonString) {
- this.jsonSerializable = new JsonSerializable(jsonString);
+ public ClientEncryptionPolicy(List paths, int policyFormatVersion) {
+ if (policyFormatVersion > 2 || policyFormatVersion < 1) {
+ throw new IllegalArgumentException("Supported versions of client encryption policy are 1 and 2.");
+ }
+ this.policyFormatVersion = policyFormatVersion;
+ validateIncludedPaths(paths, policyFormatVersion);
+ this.includedPaths = paths;
}
/**
* Constructor.
- *
- * @param objectNode the object node that represents the client encryption policy.
*/
- ClientEncryptionPolicy(ObjectNode objectNode) {
- this.jsonSerializable = new JsonSerializable(objectNode);
+ public ClientEncryptionPolicy() {
+ this.jsonSerializable = new JsonSerializable();
}
/**
- * Gets the list of path of the item that need encryption along with path-specific settings.
+ * Gets the list of paths of the item that need encryption along with path-specific settings.
* @return includedPaths
*/
public List getIncludedPaths() {
@@ -83,28 +82,46 @@ public int getPolicyFormatVersion() {
return policyFormatVersion;
}
- void validatePartitionKeyPathsAreNotEncrypted(List> partitionKeyPathTokens) {
+ /**
+ * Ensures that partition key paths specified in the client encryption policy for encryption are encrypted using Deterministic encryption algorithm.
+ * @param partitionKeyPathTokens Tokens corresponding to validated partition key.
+ */
+ void validatePartitionKeyPathsIfEncrypted(List> partitionKeyPathTokens) {
checkNotNull(partitionKeyPathTokens, "partitionKeyPathTokens cannot be null");
- List propertiesToEncrypt =
- this.includedPaths.stream().map(clientEncryptionIncludedPath -> clientEncryptionIncludedPath.getPath().substring(1)).collect(Collectors.toList());
+
for (List tokensInPath : partitionKeyPathTokens) {
checkNotNull(tokensInPath);
if (tokensInPath.size() > 0) {
String topLevelToken = tokensInPath.get(0);
- if (propertiesToEncrypt.contains(topLevelToken)) {
- throw new IllegalArgumentException(String.format("Path %s which is part of the partition key " +
- "cannot be included" +
- " in the ClientEncryptionPolicy.", topLevelToken));
+
+ // paths in included paths start with "/". Get the ClientEncryptionIncludedPath and validate.
+ List encrypterPartitionKeyPath =
+ this.includedPaths.stream().filter(clientEncryptionIncludedPath -> clientEncryptionIncludedPath.getPath().substring(1).equals(topLevelToken)).collect(Collectors.toList());
+
+ if (encrypterPartitionKeyPath.size() >0) {
+ if (this.policyFormatVersion < 2) {
+ throw new IllegalArgumentException(String.format("Path %s which is part of the partition key " +
+ "cannot be encrypted" +
+ " with PolicyFormatVersion %s. Please use PolicyFormatVersion 2.", topLevelToken, policyFormatVersion));
+ }
+
+ // for the ClientEncryptionIncludedPath found check the encryption type.
+ if (!encrypterPartitionKeyPath.stream().map(encrypter -> encrypter.getEncryptionType()).findFirst().orElse(null).equals(Constants.Properties.DETERMINISTIC)) {
+ throw new IllegalArgumentException(String.format("Path %s which is part of the partition key " +
+ "has to be encrypted" +
+ " with Deterministic type Encryption.", topLevelToken));
+ }
+
}
}
}
}
- private void validateIncludedPaths(List clientEncryptionIncludedPath) {
+ private static void validateIncludedPaths(List clientEncryptionIncludedPath, int policyFormatVersion) {
List includedPathsList = new ArrayList<>();
for (ClientEncryptionIncludedPath path : clientEncryptionIncludedPath) {
- this.validateClientEncryptionIncludedPath(path);
+ validateClientEncryptionIncludedPath(path, policyFormatVersion);
if (includedPathsList.contains(path.getPath())) {
throw new IllegalArgumentException("Duplicate Path found in clientEncryptionIncludedPath.");
}
@@ -113,7 +130,7 @@ private void validateIncludedPaths(List clientEncr
}
}
- private void validateClientEncryptionIncludedPath(ClientEncryptionIncludedPath clientEncryptionIncludedPath) {
+ private static void validateClientEncryptionIncludedPath(ClientEncryptionIncludedPath clientEncryptionIncludedPath, int policyFormatVersion) {
if (clientEncryptionIncludedPath == null) {
throw new IllegalArgumentException("clientEncryptionIncludedPath is null");
}
@@ -123,11 +140,20 @@ private void validateClientEncryptionIncludedPath(ClientEncryptionIncludedPath c
}
if (clientEncryptionIncludedPath.getPath().charAt(0) != '/'
- || clientEncryptionIncludedPath.getPath().lastIndexOf('/') != 0
- || clientEncryptionIncludedPath.getPath().substring(1).equals("id")) {
+ || clientEncryptionIncludedPath.getPath().lastIndexOf('/') != 0) {
throw new IllegalArgumentException("Invalid path " + clientEncryptionIncludedPath.getPath());
}
+ if (clientEncryptionIncludedPath.getPath().substring(1).equals(Constants.Properties.ID)) {
+ if (policyFormatVersion < 2) {
+ throw new IllegalArgumentException(String.format("Path %s cannot be encrypted with policyFormatVersion %s.", clientEncryptionIncludedPath.getPath(), policyFormatVersion));
+ }
+
+ if (!clientEncryptionIncludedPath.getEncryptionType().equals(Constants.Properties.DETERMINISTIC)) {
+ throw new IllegalArgumentException(String.format("Only deterministic encryption type is supported for path %s.", clientEncryptionIncludedPath.getPath()));
+ }
+ }
+
if (StringUtils.isEmpty(clientEncryptionIncludedPath.getClientEncryptionKeyId())) {
throw new IllegalArgumentException("clientEncryptionKeyId in clientEncryptionIncludedPath is empty");
}
diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java
index 78675b6e29ffd..565eb6a367908 100644
--- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java
+++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java
@@ -126,7 +126,7 @@ public PartitionKeyDefinition getPartitionKeyDefinition() {
public CosmosContainerProperties setPartitionKeyDefinition(PartitionKeyDefinition partitionKeyDefinition) {
this.documentCollection.setPartitionKey(partitionKeyDefinition);
if (this.getClientEncryptionPolicy() != null) {
- this.getClientEncryptionPolicy().validatePartitionKeyPathsAreNotEncrypted(this.getPartitionKeyPathTokensList());
+ this.getClientEncryptionPolicy().validatePartitionKeyPathsIfEncrypted(this.getPartitionKeyPathTokensList());
}
return this;
@@ -315,7 +315,7 @@ public ClientEncryptionPolicy getClientEncryptionPolicy() {
*/
public CosmosContainerProperties setClientEncryptionPolicy(ClientEncryptionPolicy value) {
if (value != null) {
- value.validatePartitionKeyPathsAreNotEncrypted(this.getPartitionKeyPathTokensList());
+ value.validatePartitionKeyPathsIfEncrypted(this.getPartitionKeyPathTokensList());
}
this.documentCollection.setClientEncryptionPolicy(value);
diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java
index 36ce99c42b75e..3a12249a7559f 100644
--- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java
+++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java
@@ -119,16 +119,23 @@ public void createContainer_withEncryption() {
path1.setClientEncryptionKeyId("containerTestKey1");
ClientEncryptionIncludedPath path2 = new ClientEncryptionIncludedPath();
- path2.setPath("/path2");
+ path2.setPath("/mypk");
path2.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
path2.setEncryptionType("Deterministic");
path2.setClientEncryptionKeyId("containerTestKey2");
+ ClientEncryptionIncludedPath path3 = new ClientEncryptionIncludedPath();
+ path3.setPath("/id");
+ path3.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
+ path3.setEncryptionType("Deterministic");
+ path3.setClientEncryptionKeyId("containerTestKey2");
+
List paths = new ArrayList<>();
paths.add(path1);
paths.add(path2);
+ paths.add(path3);
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths);
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths,2);
containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
CosmosContainerResponse containerResponse = createdDatabase.createContainer(containerProperties);
@@ -137,7 +144,111 @@ public void createContainer_withEncryption() {
}
@Test(groups = {"emulator"}, timeOut = TIMEOUT)
- public void createContainer_withPartitionKeyInEncryption() {
+ public void createContainer_withPartitionKeyWrongPolicyFormatVersion() {
+ String collectionName = UUID.randomUUID().toString();
+ CosmosContainerProperties containerProperties = getCollectionDefinition(collectionName);
+
+ ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath();
+ path1.setPath("/mypk");
+ path1.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
+ path1.setEncryptionType("Deterministic");
+ path1.setClientEncryptionKeyId("containerTestKey1");
+
+ ClientEncryptionIncludedPath path2 = new ClientEncryptionIncludedPath();
+ path2.setPath("/path2");
+ path2.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
+ path2.setEncryptionType("Deterministic");
+ path2.setClientEncryptionKeyId("containerTestKey2");
+
+ List paths = new ArrayList<>();
+ paths.add(path1);
+ paths.add(path2);
+
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths, 1);
+ CosmosContainerResponse containerResponse = null;
+
+ //Verify partition key in CosmosContainerProperties constructor with encrypted field.
+ try {
+ containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
+ containerResponse = createdDatabase.createContainer(containerProperties);
+ fail("createContainer should fail as mypk which is part of the partition key cannot be encrypted with " +
+ "PolicyFormatVersion 1.");
+ } catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key cannot be encrypted with PolicyFormatVersion 1. Please use PolicyFormatVersion 2.");
+ }
+
+
+ //Verify for composite key
+ collectionName = UUID.randomUUID().toString();
+ containerProperties = new CosmosContainerProperties(collectionName, "/mypk/mypk1");
+ try {
+ containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
+ containerResponse = createdDatabase.createContainer(containerProperties);
+ fail("createContainer should fail as mypk which is part of the partition key cannot be encrypted with " +
+ "PolicyFormatVersion 1.");
+ } catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key cannot be encrypted with PolicyFormatVersion 1. Please use PolicyFormatVersion 2.");
+ }
+
+
+ //Verify setPartitionKeyDefinition with encrypted field.
+ collectionName = UUID.randomUUID().toString();
+ containerProperties = new CosmosContainerProperties(collectionName, "/differentKey");
+ try {
+ containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
+ PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition();
+ List keyPaths = new ArrayList<>();
+ keyPaths.add("/mypk");
+ partitionKeyDefinition.setPaths(keyPaths);
+ containerProperties.setPartitionKeyDefinition(partitionKeyDefinition);
+ containerResponse = createdDatabase.createContainer(containerProperties);
+ fail("createContainer should fail as mypk which is part of the partition key cannot be encrypted with " +
+ "PolicyFormatVersion 1.");
+ } catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key cannot be encrypted with PolicyFormatVersion 1. Please use PolicyFormatVersion 2.");
+ }
+
+ //This should pass as we check only the first key of the composite key.
+ collectionName = UUID.randomUUID().toString();
+ containerProperties = new CosmosContainerProperties(collectionName, "/mypk1/mypk");
+ containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
+ containerResponse = createdDatabase.createContainer(containerProperties);
+ assertThat(containerResponse.getRequestCharge()).isGreaterThan(0);
+ validateContainerResponseWithEncryption(containerProperties, containerResponse, clientEncryptionPolicy);
+ }
+
+ @Test(groups = {"emulator"}, timeOut = TIMEOUT)
+ public void createEncryptionPolicy_withIdWrongPolicyFormatVersion() {
+ String collectionName = UUID.randomUUID().toString();
+ CosmosContainerProperties containerProperties = getCollectionDefinition(collectionName);
+
+ ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath();
+ path1.setPath("/id");
+ path1.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
+ path1.setEncryptionType("Deterministic");
+ path1.setClientEncryptionKeyId("containerTestKey1");
+
+ ClientEncryptionIncludedPath path2 = new ClientEncryptionIncludedPath();
+ path2.setPath("/path2");
+ path2.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
+ path2.setEncryptionType("Deterministic");
+ path2.setClientEncryptionKeyId("containerTestKey2");
+
+ List paths = new ArrayList<>();
+ paths.add(path1);
+ paths.add(path2);
+
+ try {
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths, 1);
+ fail("clientEncryptionPolicy should fail as id which is part of the partition key cannot be encrypted with " +
+ "PolicyFormatVersion 1.");
+ } catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage()).isEqualTo("Path /id cannot be encrypted with policyFormatVersion 1.");
+ }
+ }
+
+ @Test(groups = {"emulator"}, timeOut = TIMEOUT)
+ public void createContainer_withPartitionKeyWrongEncryptionType() {
String collectionName = UUID.randomUUID().toString();
CosmosContainerProperties containerProperties = getCollectionDefinition(collectionName);
@@ -157,18 +268,17 @@ public void createContainer_withPartitionKeyInEncryption() {
paths.add(path1);
paths.add(path2);
- ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths);
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths, 2);
CosmosContainerResponse containerResponse = null;
//Verify partition key in CosmosContainerProperties constructor with encrypted field.
try {
containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
containerResponse = createdDatabase.createContainer(containerProperties);
- fail("createContainer should fail as mypk which is part of the partition key cannot be included in the " +
- "ClientEncryptionPolicy.");
+ fail("createContainer should fail as mypk which is part of the partition key has to be encrypted with " +
+ "Deterministic type Encryption.");
} catch (IllegalArgumentException ex) {
- assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key cannot be included in" +
- " the ClientEncryptionPolicy.");
+ assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key has to be encrypted with Deterministic type Encryption.");
}
@@ -178,11 +288,10 @@ public void createContainer_withPartitionKeyInEncryption() {
try {
containerProperties.setClientEncryptionPolicy(clientEncryptionPolicy);
containerResponse = createdDatabase.createContainer(containerProperties);
- fail("createContainer should fail as mypk which is part of the partition key cannot be included in the " +
- "ClientEncryptionPolicy.");
+ fail("createContainer should fail as mypk which is part of the partition key has to be encrypted with " +
+ "Deterministic type Encryption.");
} catch (IllegalArgumentException ex) {
- assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key cannot be included in" +
- " the ClientEncryptionPolicy.");
+ assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key has to be encrypted with Deterministic type Encryption.");
}
@@ -197,11 +306,10 @@ public void createContainer_withPartitionKeyInEncryption() {
partitionKeyDefinition.setPaths(keyPaths);
containerProperties.setPartitionKeyDefinition(partitionKeyDefinition);
containerResponse = createdDatabase.createContainer(containerProperties);
- fail("createContainer should fail as mypk which is part of the partition key cannot be included in the " +
- "ClientEncryptionPolicy.");
+ fail("createContainer should fail as mypk which is part of the partition key has to be encrypted with " +
+ "Deterministic type Encryption.");
} catch (IllegalArgumentException ex) {
- assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key cannot be included in" +
- " the ClientEncryptionPolicy.");
+ assertThat(ex.getMessage()).isEqualTo("Path mypk which is part of the partition key has to be encrypted with Deterministic type Encryption.");
}
//This should pass as we check only the first key of the composite key.
@@ -213,6 +321,36 @@ public void createContainer_withPartitionKeyInEncryption() {
validateContainerResponseWithEncryption(containerProperties, containerResponse, clientEncryptionPolicy);
}
+ @Test(groups = {"emulator"}, timeOut = TIMEOUT)
+ public void createEncryptionPolicy_withIdWrongEncryptionType() {
+ String collectionName = UUID.randomUUID().toString();
+ CosmosContainerProperties containerProperties = getCollectionDefinition(collectionName);
+
+ ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath();
+ path1.setPath("/id");
+ path1.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
+ path1.setEncryptionType("Randomized");
+ path1.setClientEncryptionKeyId("containerTestKey1");
+
+ ClientEncryptionIncludedPath path2 = new ClientEncryptionIncludedPath();
+ path2.setPath("/path2");
+ path2.setEncryptionAlgorithm("AEAD_AES_256_CBC_HMAC_SHA256");
+ path2.setEncryptionType("Deterministic");
+ path2.setClientEncryptionKeyId("containerTestKey2");
+
+ List paths = new ArrayList<>();
+ paths.add(path1);
+ paths.add(path2);
+
+ try {
+ ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(paths, 2);
+ fail("clientEncryptionPolicy should fail as id which is part of the partition key has to be encrypted with " +
+ "Deterministic type Encryption.");
+ } catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage()).isEqualTo("Only deterministic encryption type is supported for path /id.");
+ }
+ }
+
@DataProvider
public static Object[][] analyticalTTLProvider() {
return new Object[][]{