Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client Encryption: Fixes issue with clients using incorrect/stale Encryption Policy or Encryption Keys from the cache. #2403

Merged
merged 48 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
9f14c48
Remove caching of AeadAes256CbcHmac256EncryptionAlgorithm object
kr-santosh Mar 11, 2021
f5c8441
Merge branch 'master' into users/sakulk/removealgocaching
kr-santosh Mar 11, 2021
7fa67b6
Update DotNetPreviewSDKAPI.json
kr-santosh Mar 11, 2021
9755436
Merge branch 'master' into users/sakulk/removealgocaching
kr-santosh Mar 22, 2021
bc81034
Merge branch 'master' into users/sakulk/removealgocaching
kr-santosh Mar 25, 2021
5fea326
Merge branch 'master' into users/sakulk/removealgocaching
kr-santosh Mar 29, 2021
e695aa8
Updates to latest Cryptography package.Test updates.
kr-santosh Mar 29, 2021
86ed4b5
Minor Refactoring.
kr-santosh Mar 29, 2021
5a02a6c
Fixes as per review comments.
kr-santosh Mar 29, 2021
c038300
Changes as per review comments.
kr-santosh Apr 9, 2021
f780a77
Merge branch 'master' into users/sakulk/removealgocaching
kr-santosh Apr 9, 2021
02a394c
Update MdeCustomEncryptionTests.cs
kr-santosh Apr 9, 2021
10f97eb
Updated contracts.
kr-santosh Apr 9, 2021
9310436
Update MdeEncryptionTests.cs
kr-santosh Apr 9, 2021
0ebd6f4
Merge branch 'master' into users/sakulk/removealgocaching
kr-santosh Apr 14, 2021
67a13bb
Fixes Encryption Cosmos Client Encryption Policy and Keys cache.
kr-santosh Apr 20, 2021
0985bae
Update EncryptionContainer.cs
kr-santosh Apr 20, 2021
fe75344
Update EncryptionContainer.cs
kr-santosh Apr 20, 2021
a5360b7
Merge branch 'master' of https://github.com/Azure/azure-cosmos-dotnet-v3
kr-santosh Apr 20, 2021
03c3fdb
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh Apr 20, 2021
1841a51
Update EncryptionCosmosClient.cs
kr-santosh Apr 20, 2021
8456a91
Fixes.
kr-santosh Apr 27, 2021
cf2392d
Merge branch 'master' of https://github.com/Azure/azure-cosmos-dotnet-v3
kr-santosh Apr 27, 2021
51fbdb0
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh Apr 27, 2021
2f08396
Fixes.
kr-santosh Apr 27, 2021
e3c2e2d
Fixes as per review comments and Refactoring.
kr-santosh Apr 28, 2021
69b361a
Refactoring
kr-santosh Apr 28, 2021
1862729
Update EncryptionContainer.cs
kr-santosh Apr 28, 2021
fa8897a
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh Apr 28, 2021
5a5dfec
Update EncryptionSettingForProperty.cs
kr-santosh Apr 28, 2021
b8900d8
Merge branch 'master' of https://github.com/Azure/azure-cosmos-dotnet-v3
kr-santosh Apr 29, 2021
77930c5
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh Apr 29, 2021
1a0b2d6
Fixes as per review comments.
kr-santosh Apr 30, 2021
13b356d
Merge branch 'master' of https://github.com/Azure/azure-cosmos-dotnet-v3
kr-santosh Apr 30, 2021
05591d2
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh Apr 30, 2021
d55161e
Update EncryptionContainer.cs
kr-santosh Apr 30, 2021
a0e3037
Fixes as per review comments.
kr-santosh Apr 30, 2021
01ea0be
Update EncryptionContainer.cs
kr-santosh Apr 30, 2021
32261f7
Fixes as per review comments.
kr-santosh Apr 30, 2021
dcb30f5
Fixes as per review comments.
kr-santosh May 1, 2021
fabd4fc
Merge branch 'master' of https://github.com/Azure/azure-cosmos-dotnet-v3
kr-santosh May 4, 2021
202ceb5
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh May 4, 2021
55c7e7a
Changes as per review comments.
kr-santosh May 6, 2021
77374f3
Merge branch 'master' of https://github.com/Azure/azure-cosmos-dotnet-v3
kr-santosh May 6, 2021
8911cfd
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh May 6, 2021
2fcb5e7
Fixes as per review comments.
kr-santosh May 6, 2021
2e33d55
Merge branch 'master' of https://github.com/Azure/azure-cosmos-dotnet-v3
kr-santosh May 6, 2021
b1faa22
Merge branch 'master' into users/sakulk/fixclientcache
kr-santosh May 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -926,5 +926,33 @@ public override Task<ResponseMessage> PatchItemStreamAsync(
{
throw new NotImplementedException();
}

public override ChangeFeedProcessorBuilder GetChangeFeedProcessorBuilder<T>(
string processorName,
ChangeFeedHandler<T> onChangesDelegate)
{
throw new NotImplementedException();
}

public override ChangeFeedProcessorBuilder GetChangeFeedProcessorBuilderWithManualCheckpoint<T>(
string processorName,
ChangeFeedHandlerWithManualCheckpoint<T> onChangesDelegate)
{
throw new NotImplementedException();
}

public override ChangeFeedProcessorBuilder GetChangeFeedProcessorBuilder(
string processorName,
ChangeFeedStreamHandler onChangesDelegate)
{
throw new NotImplementedException();
}

public override ChangeFeedProcessorBuilder GetChangeFeedProcessorBuilderWithManualCheckpoint(
string processorName,
ChangeFeedStreamHandlerWithManualCheckpoint onChangesDelegate)
{
throw new NotImplementedException();
}
}
}
306 changes: 268 additions & 38 deletions Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainer.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public static FeedIterator ToEncryptionStreamIterator<T>(

return new EncryptionFeedIterator(
query.ToStreamIterator(),
encryptionContainer.EncryptionProcessor);
encryptionContainer);
}

/// <summary>
Expand Down
14 changes: 12 additions & 2 deletions Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ internal async Task<ClientEncryptionPolicy> GetClientEncryptionPolicyAsync(
throw new ArgumentNullException(nameof(container));
}

EncryptionContainer encryptionContainer = (EncryptionContainer)container;

(string databaseRidvalue, string containerRidvalue) = await encryptionContainer.GetorUpdateDatabaseAndContainerRidFromCacheAsync(
cancellationToken: cancellationToken);

// container Id is unique within a Database.
string cacheKey = container.Database.Id + "/" + container.Id;
string cacheKey = databaseRidvalue + "|" + containerRidvalue + container.Database.Id + "/" + container.Id;

// cache it against Database and Container ID key.
return await this.clientEncryptionPolicyCacheByContainerId.GetAsync(
Expand All @@ -77,8 +82,13 @@ internal async Task<ClientEncryptionKeyProperties> GetClientEncryptionKeyPropert
throw new ArgumentNullException(nameof(container));
}

EncryptionContainer encryptionContainer = (EncryptionContainer)container;

(string databaseRidvalue, string containerRidvalue) = await encryptionContainer.GetorUpdateDatabaseAndContainerRidFromCacheAsync(
kr-santosh marked this conversation as resolved.
Show resolved Hide resolved
cancellationToken: cancellationToken);

// Client Encryption key Id is unique within a Database.
string cacheKey = container.Database.Id + "/" + clientEncryptionKeyId;
string cacheKey = databaseRidvalue + "|" + containerRidvalue + container.Database.Id + "/" + clientEncryptionKeyId;
kr-santosh marked this conversation as resolved.
Show resolved Hide resolved

return await this.clientEncryptionKeyPropertiesCacheByKeyId.GetAsync(
cacheKey,
Expand Down
21 changes: 19 additions & 2 deletions Microsoft.Azure.Cosmos.Encryption/src/EncryptionFeedIterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ internal sealed class EncryptionFeedIterator : FeedIterator
{
private readonly FeedIterator feedIterator;
private readonly EncryptionProcessor encryptionProcessor;
private readonly EncryptionContainer encryptionContainer;

public EncryptionFeedIterator(
FeedIterator feedIterator,
EncryptionProcessor encryptionProcessor)
EncryptionContainer encryptionContainer)
{
this.feedIterator = feedIterator ?? throw new ArgumentNullException(nameof(feedIterator));
this.encryptionProcessor = encryptionProcessor ?? throw new ArgumentNullException(nameof(encryptionProcessor));
this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer));
this.encryptionProcessor = encryptionContainer.EncryptionProcessor;
}

public override bool HasMoreResults => this.feedIterator.HasMoreResults;
Expand All @@ -32,6 +34,21 @@ public override async Task<ResponseMessage> ReadNextAsync(CancellationToken canc
{
ResponseMessage responseMessage = await this.feedIterator.ReadNextAsync(cancellationToken);

// check for Bad Request and Wrong RID intended and update the cached RID and Client Encryption Policy.
if (responseMessage.StatusCode != System.Net.HttpStatusCode.OK
&& responseMessage.StatusCode != System.Net.HttpStatusCode.NotModified
&& string.Equals(responseMessage.Headers.Get("x-ms-substatus"), "1024"))
kr-santosh marked this conversation as resolved.
Show resolved Hide resolved
{
await this.encryptionContainer.InitEncryptionContainerCacheIfNotInitAsync(cancellationToken, shouldForceRefresh: true);

throw new CosmosException(
"Operation has failed due to a possible mismatch in Client Encryption Policy configured on the container. Please refer to https://aka.ms/CosmosClientEncryption for more details. " + responseMessage.ErrorMessage,
responseMessage.StatusCode,
1024,
kr-santosh marked this conversation as resolved.
Show resolved Hide resolved
responseMessage.Headers.ActivityId,
responseMessage.Headers.RequestCharge);
}

if (responseMessage.IsSuccessStatusCode && responseMessage.Content != null)
{
Stream decryptedContent = await this.DeserializeAndDecryptResponseAsync(
Expand Down
28 changes: 15 additions & 13 deletions Microsoft.Azure.Cosmos.Encryption/src/EncryptionProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Microsoft.Azure.Cosmos.Encryption
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -61,11 +60,11 @@ public EncryptionProcessor(
/// </summary>
/// <param name="cancellationToken"> cancellation token </param>
/// <returns> Task </returns>
internal async Task InitializeEncryptionSettingsAsync(CancellationToken cancellationToken = default)
internal async Task InitializeEncryptionSettingsAsync(CancellationToken cancellationToken = default, bool shouldForceRefresh = false)
{
cancellationToken.ThrowIfCancellationRequested();

if (this.isEncryptionSettingsInitDone)
if (this.isEncryptionSettingsInitDone && !shouldForceRefresh)
{
throw new InvalidOperationException("The Encrypton Processor has already been initialized. ");
}
Expand Down Expand Up @@ -95,9 +94,10 @@ internal async Task InitializeEncryptionSettingsAsync(CancellationToken cancella

string propertyName = propertyToEncrypt.Path.Substring(1);

this.EncryptionSettings.SetEncryptionSettingForProperty(
await this.EncryptionSettings.SetEncryptionSettingForPropertyAsync(
propertyName,
encryptionSettingsForProperty);
encryptionSettingsForProperty,
cancellationToken);
}

this.isEncryptionSettingsInitDone = true;
Expand All @@ -108,20 +108,20 @@ internal async Task InitializeEncryptionSettingsAsync(CancellationToken cancella
/// </summary>
/// <param name="cancellationToken">(Optional) Token to cancel the operation.</param>
/// <returns>Task to await.</returns>
internal async Task InitEncryptionSettingsIfNotInitializedAsync(CancellationToken cancellationToken = default)
internal async Task InitEncryptionSettingsIfNotInitializedAsync(CancellationToken cancellationToken = default, bool shouldForceRefresh = false)
{
if (this.isEncryptionSettingsInitDone)
if (this.isEncryptionSettingsInitDone && !shouldForceRefresh)
{
return;
}

if (await CacheInitSema.WaitAsync(-1))
{
if (!this.isEncryptionSettingsInitDone)
if (!this.isEncryptionSettingsInitDone || shouldForceRefresh)
{
try
{
await this.InitializeEncryptionSettingsAsync(cancellationToken);
await this.InitializeEncryptionSettingsAsync(cancellationToken, shouldForceRefresh);
}
finally
{
Expand Down Expand Up @@ -260,7 +260,7 @@ private JToken SerializeAndEncryptValue(
/// Else input stream will be disposed, and a new stream is returned.
/// In case of an exception, input stream won't be disposed, but position will be end of stream.
/// </remarks>
public async Task<Stream> EncryptAsync(
public async Task<(Stream encryptedStream, bool isEncryptionSuccessful, JObject plainItemJobject)> EncryptAsync(
Stream input,
CosmosDiagnosticsContext diagnosticsContext,
CancellationToken cancellationToken)
Expand All @@ -276,11 +276,13 @@ public async Task<Stream> EncryptAsync(

if (this.ClientEncryptionPolicy == null)
{
return input;
return (input, false, null);
}

JObject itemJObj = EncryptionProcessor.BaseSerializer.FromStream<JObject>(input);

JObject plainItemObj = (JObject)itemJObj.DeepClone();

foreach (ClientEncryptionIncludedPath pathToEncrypt in this.ClientEncryptionPolicy.IncludedPaths)
{
string propertyName = pathToEncrypt.Path.Substring(1);
Expand All @@ -291,7 +293,7 @@ public async Task<Stream> EncryptAsync(
continue;
}

EncryptionSettingForProperty settingforProperty = await this.EncryptionSettings.GetEncryptionSettingForPropertyAsync(propertyName,cancellationToken);
EncryptionSettingForProperty settingforProperty = await this.EncryptionSettings.GetEncryptionSettingForPropertyAsync(propertyName, cancellationToken);

if (settingforProperty == null)
{
Expand All @@ -307,7 +309,7 @@ public async Task<Stream> EncryptAsync(
}

input.Dispose();
return EncryptionProcessor.BaseSerializer.ToStream(itemJObj);
return (EncryptionProcessor.BaseSerializer.ToStream(itemJObj), true, plainItemObj);
}

private JToken DecryptAndDeserializeValue(
Expand Down
25 changes: 21 additions & 4 deletions Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace Microsoft.Azure.Cosmos.Encryption

internal sealed class EncryptionSettings
{
// The cacheKey used here is combination of Database Rid, Container Rid and property name.
// This allows to access the exact version of setting incase the containers are created with same name.
internal AsyncCache<string, EncryptionSettingForProperty> EncryptionSettingCacheByPropertyName { get; } = new AsyncCache<string, EncryptionSettingForProperty>();

public EncryptionProcessor EncryptionProcessor { get; }
Expand All @@ -24,8 +26,15 @@ internal async Task<EncryptionSettingForProperty> GetEncryptionSettingForPropert
string propertyName,
CancellationToken cancellationToken)
{
EncryptionContainer encryptionContainer = (EncryptionContainer)this.EncryptionProcessor.Container;

(string databaseRid, string containerRid) = await encryptionContainer.GetorUpdateDatabaseAndContainerRidFromCacheAsync(
cancellationToken: cancellationToken);

string cacheKey = databaseRid + "|" + containerRid + "/" + propertyName;

EncryptionSettingForProperty encryptionSettingsForProperty = await this.EncryptionSettingCacheByPropertyName.GetAsync(
propertyName,
cacheKey,
obsoleteValue: null,
async () => await this.FetchEncryptionSettingForPropertyAsync(propertyName, cancellationToken),
cancellationToken);
Expand Down Expand Up @@ -63,6 +72,7 @@ private async Task<EncryptionSettingForProperty> FetchEncryptionSettingForProper
}
}

Console.WriteLine("Could not find for property: {0} \n", propertyName);
kr-santosh marked this conversation as resolved.
Show resolved Hide resolved
return null;
}

Expand All @@ -81,11 +91,18 @@ internal EncryptionType GetEncryptionTypeForProperty(ClientEncryptionIncludedPat
}
}

internal void SetEncryptionSettingForProperty(
internal async Task SetEncryptionSettingForPropertyAsync(
string propertyName,
EncryptionSettingForProperty encryptionSettingsForProperty)
EncryptionSettingForProperty encryptionSettingsForProperty,
CancellationToken cancellationToken)
{
this.EncryptionSettingCacheByPropertyName.Set(propertyName, encryptionSettingsForProperty);
EncryptionContainer encryptionContainer = (EncryptionContainer)this.EncryptionProcessor.Container;

(string databaseRid, string containerRid) = await encryptionContainer.GetorUpdateDatabaseAndContainerRidFromCacheAsync(
cancellationToken: cancellationToken);

string cacheKey = databaseRid + "|" + containerRid + "/" + propertyName;
this.EncryptionSettingCacheByPropertyName.Set(cacheKey, encryptionSettingsForProperty);
}
}
}
Loading