Skip to content

Commit 59eb17e

Browse files
authored
CSHARP-4675: Ignore __safecontent__ field in deserialization (#1150)
1 parent 628577e commit 59eb17e

File tree

3 files changed

+102
-6
lines changed

3 files changed

+102
-6
lines changed

src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@ public TClass DeserializeClass(BsonDeserializationContext context)
199199
continue;
200200
}
201201

202+
// In QE server returns __safeContent__ fields, which should be skipped over.
203+
if (elementName == "__safeContent__")
204+
{
205+
bsonReader.SkipValue(); // skip over unwanted element
206+
continue;
207+
}
208+
202209
if (extraElementsMemberMapIndex >= 0)
203210
{
204211
var extraElementsMemberMap = _classMap.ExtraElementsMemberMap;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using FluentAssertions;
17+
using MongoDB.Bson.Serialization;
18+
using Xunit;
19+
20+
namespace MongoDB.Bson.Tests.Jira
21+
{
22+
public class CSharp4675Tests
23+
{
24+
public class A
25+
{
26+
public int X { get; set; }
27+
}
28+
29+
[Fact]
30+
public void SafeContent_element_should_be_ignored()
31+
{
32+
var subject = BsonSerializer.Deserialize<A>("{ X : 1, \"__safeContent__\": [] }");
33+
34+
subject.X.Should().Be(1);
35+
}
36+
}
37+
}

tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ void RunTestCase(int testCase)
148148
case 4: // Case 4: Insert encrypted value
149149
{
150150
var createCollectionOptions = new CreateCollectionOptions { EncryptedFields = encryptedFields };
151-
var collection = CreateEncryptedCollection(client, clientEncryption, __collCollectionNamespace, createCollectionOptions, kmsProvider, async, out var effectiveEncryptedFields);
151+
var collection = CreateEncryptedCollection<BsonDocument>(client, clientEncryption, __collCollectionNamespace, createCollectionOptions, kmsProvider, async, out var effectiveEncryptedFields);
152152
var dataKey = effectiveEncryptedFields["fields"].AsBsonArray[0].AsBsonDocument["keyId"].AsGuid; // get generated datakey
153153
var encryptedValue = ExplicitEncrypt(clientEncryption, new EncryptOptions(algorithm: EncryptionAlgorithm.Unindexed, keyId: dataKey), "123-45-6789", async); // use explicit encryption to encrypt data before inserting
154154
Insert(collection, async, new BsonDocument("ssn", encryptedValue));
@@ -486,6 +486,43 @@ DisposableMongoClient EnsureEnvironmentAndConfigureTestClientEncrypted()
486486
}
487487
}
488488

489+
[Fact]
490+
public void ConcreteTypeDeserializationTest()
491+
{
492+
RequireServer.Check().Supports(Feature.Csfle2QEv2).ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded, ClusterType.LoadBalanced);
493+
494+
using var client = ConfigureClient(keyVaultNamespace: __keyVaultCollectionNamespace, kmsProviders: EncryptionTestHelper.GetKmsProviders("local"));
495+
using var clientEncryption = ConfigureClientEncryption(client, kmsProviderFilter: "local");
496+
497+
var datakeysCollection = GetCollection(client, __keyVaultCollectionNamespace);
498+
var externalKey = JsonFileReader.Instance.Documents["external.external-key.json"];
499+
datakeysCollection.InsertOne(externalKey);
500+
501+
var encryptedFields = new BsonDocument
502+
{
503+
{
504+
"fields", new BsonArray
505+
{
506+
new BsonDocument
507+
{
508+
{ "keyId", externalKey["_id"].AsBsonBinaryData },
509+
{ "path", "Ssn" },
510+
{ "bsonType", "string" },
511+
{ "queries", new BsonDocument("queryType", "equality") }
512+
},
513+
}
514+
}
515+
};
516+
517+
var collection = CreateEncryptedCollection<Patient>(client, clientEncryption, __collCollectionNamespace, encryptedFields, "local", false, out _);
518+
519+
var patient = new Patient() { Name = "Name", Ssn = "14159265359" };
520+
collection.InsertOne(patient);
521+
522+
var deserializedPatient = collection.Find(FilterDefinition<Patient>.Empty).ToList().Single();
523+
deserializedPatient.Ssn.Should().Be(patient.Ssn);
524+
}
525+
489526
[Theory]
490527
[ParameterAttributeData]
491528
public void CorpusTest(
@@ -2485,9 +2522,11 @@ private DisposableMongoClient ConfigureClient(
24852522
WriteConcern writeConcern = null,
24862523
ReadConcern readConcern = null,
24872524
CollectionNamespace mainCollectionNamespace = null,
2488-
BsonDocument encryptedFields = null)
2525+
BsonDocument encryptedFields = null,
2526+
CollectionNamespace keyVaultNamespace = null,
2527+
IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> kmsProviders = null)
24892528
{
2490-
var client = CreateMongoClient(maxPoolSize: maxPoolSize, writeConcern: writeConcern, readConcern: readConcern);
2529+
var client = CreateMongoClient(maxPoolSize: maxPoolSize, writeConcern: writeConcern, readConcern: readConcern, keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders);
24912530
if (clearCollections)
24922531
{
24932532
var clientKeyVaultDatabase = client.GetDatabase(__keyVaultCollectionNamespace.DatabaseNamespace.DatabaseName);
@@ -2636,10 +2675,16 @@ private void CreateCollection(IMongoClient client, CollectionNamespace collectio
26362675
private IMongoCollection<BsonDocument> CreateEncryptedCollection(IMongoClient client, ClientEncryption clientEncryption, CollectionNamespace collectionNamespace, BsonDocument encryptedFields, string kmsProvider, bool async, out BsonDocument effectiveEncryptedFields)
26372676
{
26382677
var createCollectionOptions = new CreateCollectionOptions { EncryptedFields = encryptedFields };
2639-
return CreateEncryptedCollection(client, clientEncryption, collectionNamespace, createCollectionOptions, kmsProvider, async, out effectiveEncryptedFields);
2678+
return CreateEncryptedCollection<BsonDocument>(client, clientEncryption, collectionNamespace, createCollectionOptions, kmsProvider, async, out effectiveEncryptedFields);
26402679
}
26412680

2642-
private IMongoCollection<BsonDocument> CreateEncryptedCollection(IMongoClient client, ClientEncryption clientEncryption, CollectionNamespace collectionNamespace, CreateCollectionOptions createCollectionOptions, string kmsProvider, bool async, out BsonDocument effectiveEncryptedFields)
2681+
private IMongoCollection<T> CreateEncryptedCollection<T>(IMongoClient client, ClientEncryption clientEncryption, CollectionNamespace collectionNamespace, BsonDocument encryptedFields, string kmsProvider, bool async, out BsonDocument effectiveEncryptedFields)
2682+
{
2683+
var createCollectionOptions = new CreateCollectionOptions { EncryptedFields = encryptedFields };
2684+
return CreateEncryptedCollection<T>(client, clientEncryption, collectionNamespace, createCollectionOptions, kmsProvider, async, out effectiveEncryptedFields);
2685+
}
2686+
2687+
private IMongoCollection<T> CreateEncryptedCollection<T>(IMongoClient client, ClientEncryption clientEncryption, CollectionNamespace collectionNamespace, CreateCollectionOptions createCollectionOptions, string kmsProvider, bool async, out BsonDocument effectiveEncryptedFields)
26432688
{
26442689
var datakeyOptions = CreateDataKeyOptions(kmsProvider, alternateKeyNames: null);
26452690
var database = client.GetDatabase(collectionNamespace.DatabaseNamespace.DatabaseName);
@@ -2651,7 +2696,7 @@ private IMongoCollection<BsonDocument> CreateEncryptedCollection(IMongoClient cl
26512696

26522697
effectiveEncryptedFields = result.EncryptedFields;
26532698

2654-
return client.GetDatabase(collectionNamespace.DatabaseNamespace.DatabaseName).GetCollection<BsonDocument>(collectionNamespace.CollectionName);
2699+
return client.GetDatabase(collectionNamespace.DatabaseNamespace.DatabaseName).GetCollection<T>(collectionNamespace.CollectionName);
26552700
}
26562701

26572702
private Guid CreateDataKey(
@@ -3090,6 +3135,13 @@ public Task<string> GetHttpContentAsync(HttpRequestMessage request, string excep
30903135
return _httpClientWrapper.GetHttpContentAsync(request, exceptionMessage, cancellationToken);
30913136
}
30923137
}
3138+
3139+
private class Patient
3140+
{
3141+
public ObjectId Id { get; set; }
3142+
public string Name { get; set; }
3143+
public string Ssn { get; set; }
3144+
}
30933145
}
30943146

30953147
public static class ClientEncryptionOptionsReflector

0 commit comments

Comments
 (0)