private bool VerifyClientEncryptionIncludedPath(ClientEncryptionIncludedPath expected, ClientEncryptionIncludedPath actual) { return(expected.Path == actual.Path && expected.ClientEncryptionKeyId == actual.ClientEncryptionKeyId && expected.EncryptionType == actual.EncryptionType && expected.EncryptionAlgorithm == actual.EncryptionAlgorithm); }
private static EncryptionType GetEncryptionTypeForProperty(ClientEncryptionIncludedPath clientEncryptionIncludedPath) { return(clientEncryptionIncludedPath.EncryptionType switch { CosmosEncryptionType.Deterministic => EncryptionType.Deterministic, CosmosEncryptionType.Randomized => EncryptionType.Randomized, _ => throw new ArgumentException($"Invalid encryption type {clientEncryptionIncludedPath.EncryptionType}. Please refer to https://aka.ms/CosmosClientEncryption for more details. "), });
public PSClientEncryptionIncludedPath(ClientEncryptionIncludedPath clientEncryptionIncludedPath) { if (clientEncryptionIncludedPath == null) { return; } Path = clientEncryptionIncludedPath.Path; ClientEncryptionKeyId = clientEncryptionIncludedPath.ClientEncryptionKeyId; EncryptionType = clientEncryptionIncludedPath.EncryptionType; EncryptionAlgorithm = clientEncryptionIncludedPath.EncryptionAlgorithm; }
internal EncryptionType GetEncryptionTypeForProperty(ClientEncryptionIncludedPath clientEncryptionIncludedPath) { switch (clientEncryptionIncludedPath.EncryptionType) { case CosmosEncryptionType.Deterministic: return(EncryptionType.Deterministic); case CosmosEncryptionType.Randomized: return(EncryptionType.Randomized); case CosmosEncryptionType.Plaintext: return(EncryptionType.Plaintext); default: throw new ArgumentException($"Invalid encryption type {clientEncryptionIncludedPath.EncryptionType}. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } }
private static void ValidateClientEncryptionIncludedPath(ClientEncryptionIncludedPath clientEncryptionIncludedPath) { if (clientEncryptionIncludedPath == null) { throw new ArgumentNullException(nameof(clientEncryptionIncludedPath)); } if (string.IsNullOrWhiteSpace(clientEncryptionIncludedPath.Path)) { throw new ArgumentNullException(nameof(clientEncryptionIncludedPath.Path)); } if (clientEncryptionIncludedPath.Path[0] != '/' || clientEncryptionIncludedPath.Path.LastIndexOf('/') != 0 || string.Equals(clientEncryptionIncludedPath.Path.Substring(1), "id")) { throw new ArgumentException($"Invalid path '{clientEncryptionIncludedPath.Path ?? string.Empty}'."); } if (string.IsNullOrWhiteSpace(clientEncryptionIncludedPath.ClientEncryptionKeyId)) { throw new ArgumentNullException(nameof(clientEncryptionIncludedPath.ClientEncryptionKeyId)); } if (string.IsNullOrWhiteSpace(clientEncryptionIncludedPath.EncryptionType)) { throw new ArgumentNullException(nameof(clientEncryptionIncludedPath.EncryptionType)); } if (!string.Equals(clientEncryptionIncludedPath.EncryptionType, "Deterministic") && !string.Equals(clientEncryptionIncludedPath.EncryptionType, "Randomized")) { throw new ArgumentException("EncryptionType should be either 'Deterministic' or 'Randomized'. ", nameof(clientEncryptionIncludedPath)); } if (string.IsNullOrWhiteSpace(clientEncryptionIncludedPath.EncryptionAlgorithm)) { throw new ArgumentNullException(nameof(clientEncryptionIncludedPath.EncryptionAlgorithm)); } if (!string.Equals(clientEncryptionIncludedPath.EncryptionAlgorithm, "AEAD_AES_256_CBC_HMAC_SHA256")) { throw new ArgumentException("EncryptionAlgorithm should be 'AEAD_AES_256_CBC_HMAC_SHA256'. ", nameof(clientEncryptionIncludedPath)); } }
public async Task WithClientEncryptionPolicyTest() { string containerName = Guid.NewGuid().ToString(); string partitionKeyPath = "/users"; ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath() { Path = "/path1", ClientEncryptionKeyId = "key1", EncryptionType = "Randomized", EncryptionAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA256" }; ClientEncryptionIncludedPath path2 = new ClientEncryptionIncludedPath() { Path = "/path2", ClientEncryptionKeyId = "key2", EncryptionType = "Randomized", EncryptionAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA256", }; ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .WithIncludedPath(path2) .Attach() .CreateAsync(); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); Container container = containerResponse; ContainerProperties responseSettings = containerResponse; Assert.IsNotNull(responseSettings.ClientEncryptionPolicy); Assert.AreEqual(2, responseSettings.ClientEncryptionPolicy.IncludedPaths.Count()); ClientEncryptionIncludedPath clientEncryptionIncludedPath = responseSettings.ClientEncryptionPolicy.IncludedPaths.First(); Assert.IsTrue(this.VerifyClientEncryptionIncludedPath(path1, clientEncryptionIncludedPath)); clientEncryptionIncludedPath = responseSettings.ClientEncryptionPolicy.IncludedPaths.Last(); Assert.IsTrue(this.VerifyClientEncryptionIncludedPath(path2, clientEncryptionIncludedPath)); ContainerResponse readResponse = await container.ReadContainerAsync(); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); Assert.IsNotNull(readResponse.Resource.ClientEncryptionPolicy); }
public static ClientEncryptionPolicy ToSDKModel(PSClientEncryptionPolicy pSClientEncryptionPolicy, List <string> partitionKeyPathTokens) { if (pSClientEncryptionPolicy == null) { return(null); } ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy { IncludedPaths = new List <ClientEncryptionIncludedPath>(), PolicyFormatVersion = pSClientEncryptionPolicy.PolicyFormatVersion }; if (ModelHelper.IsNotNullOrEmpty(pSClientEncryptionPolicy.IncludedPaths)) { foreach (PSClientEncryptionIncludedPath includedPath in pSClientEncryptionPolicy.IncludedPaths) { ClientEncryptionIncludedPath clientEncryptionIncludedPath = new ClientEncryptionIncludedPath { Path = includedPath.Path, ClientEncryptionKeyId = includedPath.ClientEncryptionKeyId, EncryptionAlgorithm = includedPath.EncryptionAlgorithm, EncryptionType = includedPath.EncryptionType }; clientEncryptionPolicy.IncludedPaths.Add(clientEncryptionIncludedPath); } } PSClientEncryptionPolicy.ValidatePartitionKeyPathsAreNotEncrypted(clientEncryptionPolicy.IncludedPaths, partitionKeyPathTokens); if (clientEncryptionPolicy.PolicyFormatVersion != 1) { throw new InvalidOperationException($"Invalid PolicyFormatVersion:{clientEncryptionPolicy.PolicyFormatVersion} used in Client Encryption Policy. "); } return(clientEncryptionPolicy); }
public async Task WithClientEncryptionPolicyFailureTest() { string containerName = Guid.NewGuid().ToString(); string partitionKeyPath = "/users"; ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath() { ClientEncryptionKeyId = "key1", EncryptionType = "random", EncryptionAlgorithm = "LegacyAeadAes256CbcHmac256" }; // Null value for Path try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateColleciton with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentNullException ex) { Assert.IsTrue(ex.Message.Contains("Parameter name: Path")); } path1.Path = "/path"; // Invalid EncryptionType try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateColleciton with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("EncryptionType should be either 'Deterministic' or 'Randomized' or 'Plaintext'.")); } path1.EncryptionType = "Deterministic"; // Invalid EncryptionAlgorithm try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateColleciton with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("EncryptionAlgorithm should be 'AEAD_AES_256_CBC_HMAC_SHA256'.")); } }
public async Task ContainerContractTest() { ClientEncryptionIncludedPath clientEncryptionIncludedPath1 = new ClientEncryptionIncludedPath() { Path = "/path", ClientEncryptionKeyId = "dekId", EncryptionAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA256", EncryptionType = "Randomized" }; Collection <ClientEncryptionIncludedPath> paths = new Collection <ClientEncryptionIncludedPath>() { clientEncryptionIncludedPath1 }; ContainerProperties containerProperties = new ContainerProperties(Guid.NewGuid().ToString(), "/users") { IndexingPolicy = new IndexingPolicy() { Automatic = true, IndexingMode = IndexingMode.Consistent, IncludedPaths = new Collection <IncludedPath>() { new IncludedPath() { Path = "/*" } }, ExcludedPaths = new Collection <ExcludedPath>() { new ExcludedPath() { Path = "/test/*" } }, CompositeIndexes = new Collection <Collection <CompositePath> >() { new Collection <CompositePath>() { new CompositePath() { Path = "/address/city", Order = CompositePathSortOrder.Ascending }, new CompositePath() { Path = "/address/zipcode", Order = CompositePathSortOrder.Descending } } }, SpatialIndexes = new Collection <SpatialPath>() { new SpatialPath() { Path = "/address/spatial/*", SpatialTypes = new Collection <SpatialType>() { SpatialType.LineString } } } }, ClientEncryptionPolicy = new ClientEncryptionPolicy(paths) }; CosmosJsonDotNetSerializer serializer = new CosmosJsonDotNetSerializer(); Stream stream = serializer.ToStream(containerProperties); ContainerProperties deserialziedTest = serializer.FromStream <ContainerProperties>(stream); ContainerResponse response = await this.database.CreateContainerAsync(containerProperties); Assert.IsNotNull(response); Assert.IsTrue(response.RequestCharge > 0); Assert.IsNotNull(response.Headers); Assert.IsNotNull(response.Headers.ActivityId); ContainerProperties responseProperties = response.Resource; Assert.IsNotNull(responseProperties.Id); Assert.IsNotNull(responseProperties.ResourceId); Assert.IsNotNull(responseProperties.ETag); Assert.IsTrue(responseProperties.LastModified.HasValue); Assert.IsTrue(responseProperties.LastModified.Value > new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), responseProperties.LastModified.Value.ToString()); Assert.AreEqual(1, responseProperties.IndexingPolicy.IncludedPaths.Count); IncludedPath includedPath = responseProperties.IndexingPolicy.IncludedPaths.First(); Assert.AreEqual("/*", includedPath.Path); Assert.AreEqual("/test/*", responseProperties.IndexingPolicy.ExcludedPaths.First().Path); Assert.AreEqual(1, responseProperties.IndexingPolicy.CompositeIndexes.Count); Assert.AreEqual(2, responseProperties.IndexingPolicy.CompositeIndexes.First().Count); CompositePath compositePath = responseProperties.IndexingPolicy.CompositeIndexes.First().First(); Assert.AreEqual("/address/city", compositePath.Path); Assert.AreEqual(CompositePathSortOrder.Ascending, compositePath.Order); Assert.AreEqual(1, responseProperties.IndexingPolicy.SpatialIndexes.Count); SpatialPath spatialPath = responseProperties.IndexingPolicy.SpatialIndexes.First(); Assert.AreEqual("/address/spatial/*", spatialPath.Path); Assert.AreEqual(4, spatialPath.SpatialTypes.Count); // All SpatialTypes are returned Assert.AreEqual(1, responseProperties.ClientEncryptionPolicy.IncludedPaths.Count()); Assert.AreEqual(1, responseProperties.ClientEncryptionPolicy.PolicyFormatVersion); ClientEncryptionIncludedPath clientEncryptionIncludedPath = responseProperties.ClientEncryptionPolicy.IncludedPaths.First(); Assert.IsTrue(this.VerifyClientEncryptionIncludedPath(clientEncryptionIncludedPath1, clientEncryptionIncludedPath)); }
public async Task WithClientEncryptionPolicyTest() { // create ClientEncryptionKeys DatabaseInlineCore databaseInlineCore = (DatabaseInlineCore)this.database; await TestCommon.CreateClientEncryptionKey("dekId1", databaseInlineCore); await TestCommon.CreateClientEncryptionKey("dekId2", databaseInlineCore); string containerName = Guid.NewGuid().ToString(); string partitionKeyPath = "/users"; ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath() { Path = "/path1", ClientEncryptionKeyId = "dekId1", EncryptionType = "Randomized", EncryptionAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA256" }; ClientEncryptionIncludedPath path2 = new ClientEncryptionIncludedPath() { Path = "/path2", ClientEncryptionKeyId = "dekId2", EncryptionType = "Randomized", EncryptionAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA256", }; ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .WithIncludedPath(path2) .Attach() .CreateAsync(); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); Container container = containerResponse; ContainerProperties responseSettings = containerResponse; Assert.IsNotNull(responseSettings.ClientEncryptionPolicy); Assert.AreEqual(2, responseSettings.ClientEncryptionPolicy.IncludedPaths.Count()); ClientEncryptionIncludedPath clientEncryptionIncludedPath = responseSettings.ClientEncryptionPolicy.IncludedPaths.First(); Assert.IsTrue(this.VerifyClientEncryptionIncludedPath(path1, clientEncryptionIncludedPath)); clientEncryptionIncludedPath = responseSettings.ClientEncryptionPolicy.IncludedPaths.Last(); Assert.IsTrue(this.VerifyClientEncryptionIncludedPath(path2, clientEncryptionIncludedPath)); ContainerResponse readResponse = await container.ReadContainerAsync(); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); Assert.IsNotNull(readResponse.Resource.ClientEncryptionPolicy); // update CEP and replace container readResponse.Resource.ClientEncryptionPolicy = null; try { await container.ReplaceContainerAsync(readResponse.Resource); Assert.Fail("ReplaceCollection with update to ClientEncryptionPolicy should have failed."); } catch (CosmosException ex) { Assert.AreEqual(HttpStatusCode.BadRequest, ex.StatusCode); Assert.IsTrue(ex.Message.Contains("'clientEncryptionPolicy' cannot be changed as part of collection replace operation.")); } }
public async Task WithClientEncryptionPolicyFailureTest() { string containerName = Guid.NewGuid().ToString(); string partitionKeyPath = "/users"; ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath() { ClientEncryptionKeyId = "key1", EncryptionType = "random", EncryptionAlgorithm = "LegacyAeadAes256CbcHmac256" }; // Null value for Path try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentNullException ex) { Assert.IsTrue(ex.Message.Contains("Parameter 'Path'")); } path1.Path = "/path"; // Invalid EncryptionType try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("EncryptionType should be either 'Deterministic' or 'Randomized'. ")); } path1.EncryptionType = "Plaintext"; // Invalid EncryptionType try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("EncryptionType should be either 'Deterministic' or 'Randomized'. ")); } path1.EncryptionType = "Deterministic"; // Invalid EncryptionAlgorithm try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("EncryptionAlgorithm should be 'AEAD_AES_256_CBC_HMAC_SHA256'. ")); } // invalid policy version for partition key encryption path1.EncryptionAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA256"; path1.Path = partitionKeyPath; try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("Path: /users which is part of the partition key cannot be encrypted with PolicyFormatVersion: 1. Please use PolicyFormatVersion: 2."), ex.Message); } // invalid policy version for id encryption path1.Path = "/id"; try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy() .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("Path: /id cannot be encrypted with PolicyFormatVersion: 1. Please use PolicyFormatVersion: 2."), ex.Message); } // invalid encryption type for id encryption path1.EncryptionType = "Randomized"; path1.Path = partitionKeyPath; try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy(policyFormatVersion: 2) .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("Path: /users which is part of the partition key has to be encrypted with Deterministic type Encryption."), ex.Message); } // invalid encryption type for id encryption path1.Path = "/id"; try { ContainerResponse containerResponse = await this.database.DefineContainer(containerName, partitionKeyPath) .WithClientEncryptionPolicy(policyFormatVersion: 2) .WithIncludedPath(path1) .Attach() .CreateAsync(); Assert.Fail("CreateCollection with invalid ClientEncryptionPolicy should have failed."); } catch (ArgumentException ex) { Assert.IsTrue(ex.Message.Contains("Only Deterministic encryption type is supported for path: /id."), ex.Message); } }
/// <summary> /// Adds a <see cref="ClientEncryptionIncludedPath"/> to the current <see cref="ClientEncryptionPolicyDefinition"/>. /// </summary> /// <param name="path">ClientEncryptionIncludedPath to add.</param> /// <returns>An instance of the current <see cref="ClientEncryptionPolicyDefinition"/>.</returns> public ClientEncryptionPolicyDefinition WithIncludedPath(ClientEncryptionIncludedPath path) { this.clientEncryptionIncludedPaths.Add(path); return(this); }
public PSSqlClientEncryptionIncludedPath(ClientEncryptionIncludedPath clientEncryptionIncludedPath) : base(clientEncryptionIncludedPath) { }
/// <summary> /// Administrative operations - create the database, container, and generate the necessary client encryption keys. /// These are initializations and are expected to be invoked only once - do not invoke these before every item request. /// </summary> private static async Task AdminSetupAsync(CosmosClient client) { Database database = await client.CreateDatabaseIfNotExistsAsync(Program.encryptedDatabaseId); // Delete the existing container to prevent create item conflicts. using (await database.GetContainer(Program.encryptedContainerId).DeleteContainerStreamAsync()) { } Console.WriteLine("The demo will create a 1000 RU/s container, press any key to continue."); Console.ReadKey(); // Create the Client Encryption Keys for Encrypting the configured Paths. await database.CreateClientEncryptionKeyAsync( "key1", DataEncryptionAlgorithm.AeadAes256CbcHmacSha256, new EncryptionKeyWrapMetadata( KeyEncryptionKeyResolverName.AzureKeyVault, "akvMasterKey", MasterKeyUrl, EncryptionAlgorithm.RsaOaep.ToString())); await database.CreateClientEncryptionKeyAsync( "key2", DataEncryptionAlgorithm.AeadAes256CbcHmacSha256, new EncryptionKeyWrapMetadata( KeyEncryptionKeyResolverName.AzureKeyVault, "akvMasterKey", MasterKeyUrl, EncryptionAlgorithm.RsaOaep.ToString())); // Configure the required Paths to be Encrypted with appropriate settings. ClientEncryptionIncludedPath path1 = new ClientEncryptionIncludedPath() { Path = "/SubTotal", ClientEncryptionKeyId = "key1", EncryptionType = EncryptionType.Deterministic, EncryptionAlgorithm = DataEncryptionAlgorithm.AeadAes256CbcHmacSha256 }; // non primitive data type.Leaves get encrypted. ClientEncryptionIncludedPath path2 = new ClientEncryptionIncludedPath() { Path = "/Items", ClientEncryptionKeyId = "key2", EncryptionType = EncryptionType.Deterministic, EncryptionAlgorithm = DataEncryptionAlgorithm.AeadAes256CbcHmacSha256 }; ClientEncryptionIncludedPath path3 = new ClientEncryptionIncludedPath() { Path = "/OrderDate", ClientEncryptionKeyId = "key1", EncryptionType = EncryptionType.Deterministic, EncryptionAlgorithm = DataEncryptionAlgorithm.AeadAes256CbcHmacSha256 }; // Create a container with the appropriate partition key definition (we choose the "AccountNumber" property here) and throughput (we choose 1000 here). // Configure the Client Encryption Key Policy with required paths to be encrypted. await database.DefineContainer(Program.encryptedContainerId, "/AccountNumber") .WithClientEncryptionPolicy() .WithIncludedPath(path1) .WithIncludedPath(path2) .WithIncludedPath(path3) .Attach() .CreateAsync(throughput: 1000); // gets a Container with Encryption Support. containerWithEncryption = await database.GetContainer(Program.encryptedContainerId).InitializeEncryptionAsync(); }