Skip to content

Commit 2f68bdf

Browse files
CSHARP-2796: FLE GA Spec changes.
1 parent 3644271 commit 2f68bdf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+624
-290
lines changed

Docs/reference/content/reference/driver/crud/client_side_encryption.md

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,18 @@ client-side. The following example has been adapted from
5050
[`ClientSideEncryptionExamples.cs`](https://github.com/mongodb/mongo-csharp-driver/blob/master/tests/MongoDB.Driver.Examples/ClientEncryptionExamples.cs), which can be found on GitHub along with the driver source.
5151

5252
```csharp
53-
using MongoDB.Driver.Core.Misc;
54-
using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
5553
using System;
5654
using System.Collections.Generic;
57-
using System.Threading;
5855
using MongoDB.Bson;
5956
using MongoDB.Driver.Encryption;
60-
using Xunit;
61-
using Xunit.Abstractions;
6257

6358
namespace MongoDB.Driver.Examples
6459
{
6560
public class ClientEncryptionExamples
6661
{
6762
private const string LocalMasterKey = "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk";
6863

69-
public void ClientSideEncryptionSimpleTour()
64+
public static void Main(string[] args)
7065
{
7166
var localMasterKey = Convert.FromBase64String(LocalMasterKey);
7267

@@ -109,23 +104,19 @@ example has been adapted from
109104
which can be found on Github along with the driver source.
110105

111106
```csharp
112-
using MongoDB.Driver.Core.Misc;
113-
using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
114107
using System;
115108
using System.Collections.Generic;
116109
using System.Threading;
117110
using MongoDB.Bson;
118111
using MongoDB.Driver.Encryption;
119-
using Xunit;
120-
using Xunit.Abstractions;
121112

122113
namespace MongoDB.Driver.Examples
123114
{
124115
public class ClientEncryptionExamples
125116
{
126117
private const string LocalMasterKey = "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk";
127118

128-
public void ClientSideEncryptionAutoEncryptionSettingsTour()
119+
public static void Main(string[] args)
129120
{
130121
var localMasterKey = Convert.FromBase64String(LocalMasterKey);
131122

src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldEncryptor.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,10 @@ private byte[] GetUnencryptedCommandBytes(CommandRequestMessage unencryptedReque
169169
}
170170

171171
private void WriteUnencryptedRequestMessageToStream(
172-
Stream stream,
172+
Stream stream,
173173
CommandRequestMessage unencryptedRequestMessage)
174174
{
175175
var clonedMessageEncoderSettings = _messageEncoderSettings.Clone();
176-
clonedMessageEncoderSettings.Set(MessageEncoderSettingsName.MaxDocumentSize, 2097152);
177-
clonedMessageEncoderSettings.Set(MessageEncoderSettingsName.MaxMessageSize, 2097152 + 16384);
178176
var encoderFactory = new BinaryMessageEncoderFactory(stream, clonedMessageEncoderSettings, compressorSource: null);
179177
var encoder = encoderFactory.GetCommandRequestMessageEncoder();
180178
encoder.WriteMessage(unencryptedRequestMessage);

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,17 +289,25 @@ private void WriteType1Section(BsonBinaryWriter writer, Type1CommandMessageSecti
289289
var stream = writer.BsonStream;
290290
var serializer = section.DocumentSerializer;
291291
var context = BsonSerializationContext.CreateRoot(writer);
292-
var maxMessageSize = MaxMessageSize;
292+
293+
int? maxMessageSize;
294+
if (IsEncryptionConfigured)
295+
{
296+
var maxBatchSize = 2 * 1024 * 1024; // 2 MiB
297+
var maxMessageEndPosition = stream.Position + maxBatchSize;
298+
maxMessageSize = (int)(maxMessageEndPosition - messageStartPosition);
299+
}
300+
else
301+
{
302+
maxMessageSize = MaxMessageSize;
303+
}
293304

294305
var payloadStartPosition = stream.Position;
295306
stream.WriteInt32(0); // size
296307
stream.WriteCString(section.Identifier);
297308

298309
var batch = section.Documents;
299-
var maxDocumentSize =
300-
IsEncryptionConfigured && MaxDocumentSize.HasValue
301-
? MaxDocumentSize.Value
302-
: section.MaxDocumentSize ?? writer.Settings.MaxDocumentSize;
310+
var maxDocumentSize = section.MaxDocumentSize ?? writer.Settings.MaxDocumentSize;
303311
writer.PushSettings(s => ((BsonBinaryWriterSettings)s).MaxDocumentSize = maxDocumentSize);
304312
writer.PushElementNameValidator(section.ElementNameValidator);
305313
try
@@ -313,7 +321,7 @@ private void WriteType1Section(BsonBinaryWriter writer, Type1CommandMessageSecti
313321
serializer.Serialize(context, document);
314322

315323
var messageSize = stream.Position - messageStartPosition;
316-
if (messageSize > maxMessageSize && batch.CanBeSplit)
324+
if (messageSize > maxMessageSize && batch.CanBeSplit && i > 0)
317325
{
318326
stream.Position = documentStartPosition;
319327
stream.SetLength(documentStartPosition);

src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<ItemGroup>
4646
<PackageReference Include="DnsClient" Version="1.2.0" />
4747
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.2" PrivateAssets="All" />
48-
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.0.0-beta01" />
48+
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.0.0-beta03" />
4949
<PackageReference Include="SharpCompress" Version="0.23.0" />
5050
</ItemGroup>
5151

src/MongoDB.Driver/Encryption/ExplicitEncryptionLibMongoCryptController.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,9 @@ private IKmsKeyId GetKmsKeyId(string kmsProvider, IReadOnlyList<string> alternat
231231
{
232232
case "aws":
233233
var customerMasterKey = masterKey["key"].ToString();
234+
var endpoint = masterKey.GetValue("endpoint", null)?.ToString();
234235
var region = masterKey["region"].ToString();
235-
return wrappedAlternateKeyNamesBytes != null
236-
? new AwsKeyId(customerMasterKey, region, wrappedAlternateKeyNamesBytes)
237-
: new AwsKeyId(customerMasterKey, region);
236+
return new AwsKeyId(customerMasterKey, region, wrappedAlternateKeyNamesBytes, endpoint);
238237
case "local":
239238
return wrappedAlternateKeyNamesBytes != null ? new LocalKeyId(wrappedAlternateKeyNamesBytes) : new LocalKeyId();
240239
default:

src/MongoDB.Driver/Encryption/LibMongoCryptControllerBase.cs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@
1515

1616
using System;
1717
using System.Collections.Generic;
18+
using System.Net;
1819
using System.Net.Security;
1920
using System.Net.Sockets;
21+
using System.Text.RegularExpressions;
2022
using System.Threading;
2123
using System.Threading.Tasks;
2224
using MongoDB.Bson;
2325
using MongoDB.Bson.IO;
26+
using MongoDB.Driver.Core.Misc;
2427
using MongoDB.Libmongocrypt;
2528

2629
namespace MongoDB.Driver.Encryption
@@ -133,7 +136,28 @@ protected async Task<byte[]> ProcessStatesAsync(CryptContext context, string dat
133136
private IMongoCollection<BsonDocument> GetKeyVaultCollection()
134137
{
135138
var keyVaultDatabase = _keyVaultClient.GetDatabase(_keyVaultNamespace.DatabaseNamespace.DatabaseName);
136-
return keyVaultDatabase.GetCollection<BsonDocument>(_keyVaultNamespace.CollectionName);
139+
140+
var collectionSettings = new MongoCollectionSettings
141+
{
142+
ReadConcern = ReadConcern.Majority,
143+
WriteConcern = WriteConcern.WMajority
144+
};
145+
return keyVaultDatabase.GetCollection<BsonDocument>(_keyVaultNamespace.CollectionName, collectionSettings);
146+
}
147+
148+
private void ParseKmsEndPoint(string value, out string host, out int port)
149+
{
150+
var match = Regex.Match(value, @"^(?<host>.*):(?<port>\d+)$");
151+
if (match.Success)
152+
{
153+
host = match.Groups["host"].Value;
154+
port = int.Parse(match.Groups["port"].Value);
155+
}
156+
else
157+
{
158+
host = value;
159+
port = 443;
160+
}
137161
}
138162

139163
private void ProcessNeedKmsState(CryptContext context, CancellationToken cancellationToken)
@@ -184,15 +208,16 @@ private byte[] ProcessReadyState(CryptContext context)
184208
private void SendKmsRequest(KmsRequest request, CancellationToken cancellation)
185209
{
186210
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
187-
socket.Connect(request.Endpoint, 443);
211+
ParseKmsEndPoint(request.Endpoint, out var host, out var port);
212+
socket.Connect(host, port);
188213

189214
using (var networkStream = new NetworkStream(socket, ownsSocket: true))
190215
using (var sslStream = new SslStream(networkStream, leaveInnerStreamOpen: false))
191216
{
192217
#if NETSTANDARD1_5
193-
sslStream.AuthenticateAsClientAsync(request.Endpoint).ConfigureAwait(false).GetAwaiter().GetResult();
218+
sslStream.AuthenticateAsClientAsync(host).ConfigureAwait(false).GetAwaiter().GetResult();
194219
#else
195-
sslStream.AuthenticateAsClient(request.Endpoint);
220+
sslStream.AuthenticateAsClient(host);
196221
#endif
197222

198223
var requestBytes = request.Message.ToArray();
@@ -212,16 +237,17 @@ private void SendKmsRequest(KmsRequest request, CancellationToken cancellation)
212237
private async Task SendKmsRequestAsync(KmsRequest request, CancellationToken cancellation)
213238
{
214239
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
240+
ParseKmsEndPoint(request.Endpoint, out var host, out var port);
215241
#if NETSTANDARD1_5
216-
await socket.ConnectAsync(request.Endpoint, 443).ConfigureAwait(false);
242+
await socket.ConnectAsync(host, port).ConfigureAwait(false);
217243
#else
218-
await Task.Factory.FromAsync(socket.BeginConnect(request.Endpoint, 443, null, null), socket.EndConnect).ConfigureAwait(false);
244+
await Task.Factory.FromAsync(socket.BeginConnect(host, port, null, null), socket.EndConnect).ConfigureAwait(false);
219245
#endif
220246

221247
using (var networkStream = new NetworkStream(socket, ownsSocket: true))
222248
using (var sslStream = new SslStream(networkStream, leaveInnerStreamOpen: false))
223249
{
224-
await sslStream.AuthenticateAsClientAsync(request.Endpoint).ConfigureAwait(false);
250+
await sslStream.AuthenticateAsClientAsync(host).ConfigureAwait(false);
225251

226252
var requestBytes = request.Message.ToArray();
227253
await sslStream.WriteAsync(requestBytes, 0, requestBytes.Length).ConfigureAwait(false);

src/MongoDB.Driver/Encryption/MongocryptdFactory.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ private bool ShouldMongocryptdBeSpawned(out string path, out string args)
127127
args = string.Empty;
128128
if (_extraOptions.TryGetValue("mongocryptdSpawnArgs", out var mongocryptdSpawnArgs))
129129
{
130-
string trimStartHyphens(string str) => str.TrimStart('-').TrimStart('-');
131130
switch (mongocryptdSpawnArgs)
132131
{
133132
case string str:
@@ -136,7 +135,7 @@ private bool ShouldMongocryptdBeSpawned(out string path, out string args)
136135
case IEnumerable enumerable:
137136
foreach (var item in enumerable)
138137
{
139-
args += $"--{trimStartHyphens(item.ToString())} ";
138+
args += $"--{item.ToString().TrimStart('-')} ";
140139
}
141140
break;
142141
default:
@@ -149,6 +148,17 @@ private bool ShouldMongocryptdBeSpawned(out string path, out string args)
149148
{
150149
args += " --idleShutdownTimeoutSecs 60";
151150
}
151+
152+
if (!args.Contains("logpath")) // disable logging by the mongocryptd process
153+
{
154+
// "nul" is the windows specific value. Unix-based platforms should use "/dev/null"
155+
args += " --logpath nul";
156+
157+
if (!args.Contains("logappend"))
158+
{
159+
args += " --logappend";
160+
}
161+
}
152162
args = args.Trim();
153163

154164
return true;

src/MongoDB.Driver/MongoDB.Driver.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
</PropertyGroup>
4343
<ItemGroup>
4444
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.2" PrivateAssets="All" />
45-
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.0.0-beta01" />
45+
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.0.0-beta03" />
4646
</ItemGroup>
4747

4848
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.5'">

tests/MongoDB.Driver.Tests/MongocryptdFactoryTests.cs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,29 @@ public void CreateMongocryptdConnectionString_should_create_expected_connection_
4242

4343
[SkippableTheory]
4444
[InlineData("{ mongocryptdBypassSpawn : true }", null, null, false)]
45-
[InlineData(null, "mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)]
46-
[InlineData("{ mongocryptdBypassSpawn : false }", "mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)]
47-
[InlineData("{ mongocryptdBypassSpawn : false }", "mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)]
48-
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/' }", "c:/mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)]
49-
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/mgcr.exe' }", "c:/mgcr.exe", "--idleShutdownTimeoutSecs 60", true)]
50-
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/mgcr.exe' }", "c:/mgcr.exe", "--idleShutdownTimeoutSecs 60", true)]
45+
[InlineData(null, "mongocryptd.exe", "--idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
46+
[InlineData("{ mongocryptdBypassSpawn : false }", "mongocryptd.exe", "--idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
47+
[InlineData("{ mongocryptdBypassSpawn : false }", "mongocryptd.exe", "--idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
48+
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/' }", "c:/mongocryptd.exe", "--idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
49+
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/mgcr.exe' }", "c:/mgcr.exe", "--idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
50+
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/mgcr.exe' }", "c:/mgcr.exe", "--idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
5151
// args string
52-
[InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B' }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 60", true)]
53-
[InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B --idleShutdownTimeoutSecs 50' }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)]
54-
// args list
55-
[InlineData("{ mongocryptdSpawnArgs : [ 'arg1 A', 'arg2 B'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 60", true)]
56-
[InlineData("{ mongocryptdSpawnArgs : [ 'arg1 A', 'arg2 B', 'idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)]
57-
[InlineData("{ mongocryptdSpawnArgs : [ '--arg1 A', '--arg2 B', '--idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)]
52+
[InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B' }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
53+
[InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B --idleShutdownTimeoutSecs 50' }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50 --logpath nul --logappend", true)]
54+
[InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B --logpath path.txt' }", "mongocryptd.exe", "--arg1 A --arg2 B --logpath path.txt --idleShutdownTimeoutSecs 60", true)]
55+
[InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B --logpath path.txt --logappend' }", "mongocryptd.exe", "--arg1 A --arg2 B --logpath path.txt --logappend --idleShutdownTimeoutSecs 60", true)]
56+
[InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B --logappend' }", "mongocryptd.exe", "--arg1 A --arg2 B --logappend --idleShutdownTimeoutSecs 60 --logpath nul", true)]
57+
// args IEnumerable
58+
[InlineData("{ mongocryptdSpawnArgs : ['arg1 A', 'arg2 B'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 60 --logpath nul --logappend", true)]
59+
[InlineData("{ mongocryptdSpawnArgs : ['arg1 A', 'arg2 B', 'idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50 --logpath nul --logappend", true)]
60+
[InlineData("{ mongocryptdSpawnArgs : ['arg1 A', '--arg2 B', '--idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50 --logpath nul --logappend", true)]
61+
[InlineData("{ mongocryptdSpawnArgs : ['arg1 A', 'arg2 B', '--logpath path.txt'] }", "mongocryptd.exe", "--arg1 A --arg2 B --logpath path.txt --idleShutdownTimeoutSecs 60", true)]
62+
[InlineData("{ mongocryptdSpawnArgs : ['arg1 A', 'arg2 B', '--logpath path.txt', '--logappend'] }", "mongocryptd.exe", "--arg1 A --arg2 B --logpath path.txt --logappend --idleShutdownTimeoutSecs 60", true)]
63+
[InlineData("{ mongocryptdSpawnArgs : ['arg1 A', 'arg2 B', '--logappend'] }", "mongocryptd.exe", "--arg1 A --arg2 B --logappend --idleShutdownTimeoutSecs 60 --logpath nul", true)]
5864

59-
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnArgs : [ '--arg1 A', '--arg2 B', '--idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)]
65+
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnArgs : [ '--arg1 A', '--arg2 B', '--idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50 --logpath nul --logappend", true)]
66+
67+
[InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnArgs : [ '--arg1 A', '--arg2 B', '--idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50 --logpath nul --logappend", true)]
6068
public void Mongocryptd_should_be_spawned_with_correct_extra_arguments(
6169
string stringExtraOptions,
6270
string expectedPath,

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,13 @@ protected override void InsertData(IMongoClient client, string databaseName, str
111111
if (shared.TryGetValue("key_vault_data", out var keyVaultData))
112112
{
113113
var adminDatabase = client.GetDatabase("admin");
114-
var keyVaultCollection = adminDatabase.GetCollection<BsonDocument>(
115-
"datakeys",
116-
new MongoCollectionSettings
117-
{
118-
AssignIdOnInsert = false
119-
});
114+
var collectionSettings = new MongoCollectionSettings
115+
{
116+
AssignIdOnInsert = false,
117+
ReadConcern = ReadConcern.Majority,
118+
WriteConcern = WriteConcern.WMajority
119+
};
120+
var keyVaultCollection = adminDatabase.GetCollection<BsonDocument>("datakeys", collectionSettings);
120121
var keyVaultDocuments = keyVaultData.AsBsonArray.Select(c => c.AsBsonDocument);
121122
keyVaultCollection.InsertMany(keyVaultDocuments);
122123
}

0 commit comments

Comments
 (0)