Skip to content

Commit 959d021

Browse files
CSHARP-4153: Add FLE 2 API to AutoEncryptionOpts.
1 parent 67cb551 commit 959d021

Some content is hidden

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

46 files changed

+5151
-145
lines changed

evergreen/evergreen.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,21 +1661,21 @@ buildvariants:
16611661

16621662
- matrix_name: "csfle-with-mocked-kms-tests-windows"
16631663
matrix_spec: { os: "windows-64", ssl: "nossl", version: [ "5.0", "6.0", "rapid", "latest" ], topology: ["standalone"] }
1664-
display_name: "CSFLE Mocked KMS ${os}"
1664+
display_name: "CSFLE Mocked KMS ${version} ${os}"
16651665
tasks:
16661666
- name: test-kms-tls-mocked-net472
16671667
- name: test-kms-tls-mocked-netstandard20
16681668
- name: test-kms-tls-mocked-netstandard21
16691669

16701670
- matrix_name: "csfle-with-mocked-kms-tests-linux"
16711671
matrix_spec: { os: "ubuntu-1804", ssl: "nossl", version: [ "5.0", "6.0", "rapid", "latest" ], topology: ["standalone"] }
1672-
display_name: "CSFLE Mocked KMS ${os}"
1672+
display_name: "CSFLE Mocked KMS ${version} ${os}"
16731673
tasks:
16741674
- name: test-kms-tls-mocked-netstandard20
16751675
- name: test-kms-tls-mocked-netstandard21
16761676

16771677
- matrix_name: "csfle-with-mocked-kms-tests-macOS"
16781678
matrix_spec: { os: "macos-1014", ssl: "nossl", version: [ "5.0", "6.0", "rapid", "latest" ], topology: ["standalone"] }
1679-
display_name: "CSFLE Mocked KMS ${os}"
1679+
display_name: "CSFLE Mocked KMS ${version} ${os}"
16801680
tasks:
16811681
- name: test-kms-tls-mocked-netstandard21

src/MongoDB.Driver.Core/Core/Clusters/Cluster.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ protected virtual void Dispose(bool disposing)
187187
UpdateClusterDescription(newClusterDescription);
188188

189189
_rapidHeartbeatTimer.Dispose();
190+
_cryptClient?.Dispose();
190191
}
191192
}
192193

@@ -222,9 +223,13 @@ public virtual void Initialize()
222223
ThrowIfDisposed();
223224
if (_state.TryChange(State.Initial, State.Open))
224225
{
225-
if (_settings.KmsProviders != null || _settings.SchemaMap != null)
226+
if (_settings.KmsProviders != null || _settings.SchemaMap != null || _settings.EncryptedFieldsMap != null || _settings.BypassQueryAnalysis.HasValue)
226227
{
227-
_cryptClient = CryptClientCreator.CreateCryptClient(_settings.KmsProviders, _settings.SchemaMap);
228+
_cryptClient = CryptClientCreator.CreateCryptClient(
229+
_settings.BypassQueryAnalysis,
230+
encryptedFieldsMap: _settings.EncryptedFieldsMap,
231+
_settings.KmsProviders,
232+
_settings.SchemaMap);
228233
}
229234
}
230235
}

src/MongoDB.Driver.Core/Core/Clusters/CryptClientCreator.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,37 @@ public sealed class CryptClientCreator
3333
/// <summary>
3434
/// Create a CryptClient instance.
3535
/// </summary>
36+
/// <param name="bypassQueryAnalysis">The bypass query analysis flag.</param>
37+
/// <param name="encryptedFieldsMap">The encrypted fields map.</param>
3638
/// <param name="kmsProviders">The kms providers.</param>
3739
/// <param name="schemaMap">The schema map.</param>
3840
/// <returns>The CryptClient instance.</returns>
3941
public static CryptClient CreateCryptClient(
42+
bool? bypassQueryAnalysis,
43+
IReadOnlyDictionary<string, BsonDocument> encryptedFieldsMap,
4044
IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> kmsProviders,
4145
IReadOnlyDictionary<string, BsonDocument> schemaMap)
4246
{
43-
var helper = new CryptClientCreator(kmsProviders, schemaMap);
47+
var helper = new CryptClientCreator(bypassQueryAnalysis, encryptedFieldsMap, kmsProviders, schemaMap);
4448
var cryptOptions = helper.CreateCryptOptions();
4549
return helper.CreateCryptClient(cryptOptions);
4650
}
4751
#pragma warning restore
4852
#endregion
4953

54+
private readonly bool? _bypassQueryAnalysis;
55+
private readonly IReadOnlyDictionary<string, BsonDocument> _encryptedFieldsMap;
5056
private readonly IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> _kmsProviders;
5157
private readonly IReadOnlyDictionary<string, BsonDocument> _schemaMap;
5258

5359
private CryptClientCreator(
60+
bool? bypassQueryAnalysis,
61+
IReadOnlyDictionary<string, BsonDocument> encryptedFieldsMap,
5462
IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> kmsProviders,
5563
IReadOnlyDictionary<string, BsonDocument> schemaMap)
5664
{
65+
_bypassQueryAnalysis = bypassQueryAnalysis;
66+
_encryptedFieldsMap = encryptedFieldsMap;
5767
_kmsProviders = Ensure.IsNotNull(kmsProviders, nameof(kmsProviders));
5868
_schemaMap = schemaMap;
5969
}
@@ -85,19 +95,16 @@ private CryptOptions CreateCryptOptions()
8595
byte[] schemaBytes = null;
8696
if (_schemaMap != null)
8797
{
88-
var schemaMapElements = _schemaMap.Select(c => new BsonElement(c.Key, c.Value));
89-
var schemaDocument = new BsonDocument(schemaMapElements);
90-
#pragma warning disable 618
91-
var writerSettings = new BsonBinaryWriterSettings();
92-
if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
93-
{
94-
writerSettings.GuidRepresentation = GuidRepresentation.Unspecified;
95-
}
96-
#pragma warning restore 618
97-
schemaBytes = schemaDocument.ToBson(writerSettings: writerSettings);
98+
schemaBytes = GetBytesFromMap(_schemaMap);
99+
}
100+
101+
byte[] encryptedFieldsBytes = null;
102+
if (_encryptedFieldsMap != null)
103+
{
104+
encryptedFieldsBytes = GetBytesFromMap(_encryptedFieldsMap);
98105
}
99106

100-
return new CryptOptions(kmsProviders, schemaBytes);
107+
return new CryptOptions(kmsProviders, encryptedFieldsMap: encryptedFieldsBytes, schema: schemaBytes, bypassQueryAnalysis: _bypassQueryAnalysis.GetValueOrDefault(false));
101108
}
102109

103110
private BsonDocument CreateProviderDocument(string kmsType, IReadOnlyDictionary<string, object> data)
@@ -110,5 +117,19 @@ private BsonDocument CreateProviderDocument(string kmsType, IReadOnlyDictionary<
110117
var providerDocument = new BsonDocument(kmsType, providerContent);
111118
return providerDocument;
112119
}
120+
121+
private byte[] GetBytesFromMap(IReadOnlyDictionary<string, BsonDocument> map)
122+
{
123+
var mapElements = map.Select(c => new BsonElement(c.Key, c.Value));
124+
var mapDocument = new BsonDocument(mapElements);
125+
#pragma warning disable 618
126+
var writerSettings = new BsonBinaryWriterSettings();
127+
if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
128+
{
129+
writerSettings.GuidRepresentation = GuidRepresentation.Unspecified;
130+
}
131+
#pragma warning restore 618
132+
return mapDocument.ToBson(writerSettings: writerSettings);
133+
}
113134
}
114135
}

src/MongoDB.Driver.Core/Core/Clusters/LoadBalancedCluster.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ public void Initialize()
170170
var stopwatch = Stopwatch.StartNew();
171171
_openingEventHandler?.Invoke(new ClusterOpeningEvent(ClusterId, Settings));
172172

173-
if (_settings.KmsProviders != null || _settings.SchemaMap != null)
173+
if (_settings.KmsProviders != null || _settings.SchemaMap != null || _settings.EncryptedFieldsMap != null || _settings.BypassQueryAnalysis.HasValue)
174174
{
175-
_cryptClient = CryptClientCreator.CreateCryptClient(_settings.KmsProviders, _settings.SchemaMap);
175+
_cryptClient = CryptClientCreator.CreateCryptClient(_settings.BypassQueryAnalysis, _settings.EncryptedFieldsMap, _settings.KmsProviders, _settings.SchemaMap);
176176
}
177177

178178
var endPoint = _settings.EndPoints.Single();

src/MongoDB.Driver.Core/Core/Configuration/ClusterSettings.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ public class ClusterSettings
3535
#endregion
3636

3737
// fields
38+
private readonly bool? _bypassQueryAnalysis;
3839
#pragma warning disable CS0618 // Type or member is obsolete
3940
private readonly ClusterConnectionMode _connectionMode;
4041
private readonly ConnectionModeSwitch _connectionModeSwitch;
4142
#pragma warning restore CS0618 // Type or member is obsolete
4243
private readonly bool? _directConnection;
44+
private readonly IReadOnlyDictionary<string, BsonDocument> _encryptedFieldsMap;
4345
private readonly IReadOnlyList<EndPoint> _endPoints;
4446
private readonly IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> _kmsProviders;
4547
private readonly bool _loadBalanced;
@@ -74,6 +76,8 @@ public class ClusterSettings
7476
/// <param name="schemaMap">The schema map.</param>
7577
/// <param name="scheme">The connection string scheme.</param>
7678
/// <param name="srvMaxHosts">Limits the number of SRV records used to populate the seedlist during initial discovery, as well as the number of additional hosts that may be added during SRV polling.</param>
79+
/// <param name="encryptedFieldsMap">The encrypted fields map.</param>
80+
/// <param name="bypassQueryAnalysis">The bypass query analysis flag.</param>
7781
public ClusterSettings(
7882
#pragma warning disable CS0618 // Type or member is obsolete
7983
Optional<ClusterConnectionMode> connectionMode = default(Optional<ClusterConnectionMode>),
@@ -92,13 +96,17 @@ public ClusterSettings(
9296
Optional<IServerSelector> postServerSelector = default(Optional<IServerSelector>),
9397
Optional<IReadOnlyDictionary<string, BsonDocument>> schemaMap = default(Optional<IReadOnlyDictionary<string, BsonDocument>>),
9498
Optional<ConnectionStringScheme> scheme = default(Optional<ConnectionStringScheme>),
95-
Optional<int> srvMaxHosts = default)
99+
Optional<int> srvMaxHosts = default,
100+
Optional<IReadOnlyDictionary<string, BsonDocument>> encryptedFieldsMap = default,
101+
Optional<bool?> bypassQueryAnalysis = default)
96102
{
103+
_bypassQueryAnalysis = bypassQueryAnalysis.WithDefault(null);
97104
#pragma warning disable CS0618 // Type or member is obsolete
98105
_connectionMode = connectionMode.WithDefault(ClusterConnectionMode.Automatic);
99106
_connectionModeSwitch = connectionModeSwitch.WithDefault(ConnectionModeSwitch.NotSet);
100107
#pragma warning restore CS0618 // Type or member is obsolete
101108
_directConnection = directConnection.WithDefault(null);
109+
_encryptedFieldsMap = encryptedFieldsMap.WithDefault(null);
102110
_endPoints = Ensure.IsNotNull(endPoints.WithDefault(__defaultEndPoints), nameof(endPoints)).ToList();
103111
_kmsProviders = kmsProviders.WithDefault(null);
104112
_loadBalanced = loadBalanced.WithDefault(false);
@@ -117,6 +125,11 @@ public ClusterSettings(
117125
}
118126

119127
// properties
128+
/// <summary>
129+
/// Gets a value indicating whether to bypass query analysis.
130+
/// </summary>
131+
public bool? BypassQueryAnalysis => _bypassQueryAnalysis;
132+
120133
/// <summary>
121134
/// Gets the connection mode.
122135
/// </summary>
@@ -162,6 +175,11 @@ public bool? DirectConnection
162175
}
163176
}
164177

178+
/// <summary>
179+
/// Gets the encrypted fields map.
180+
/// </summary>
181+
public IReadOnlyDictionary<string, BsonDocument> EncryptedFieldsMap => _encryptedFieldsMap;
182+
165183
/// <summary>
166184
/// Gets the end points.
167185
/// </summary>
@@ -319,6 +337,8 @@ public IServerSelector PostServerSelector
319337
/// <param name="scheme">The connection string scheme.</param>
320338
/// <param name="srvMaxHosts">Limits the number of SRV records used to populate the seedlist during initial discovery, as well as the number of additional hosts that may be added during SRV polling.</param>
321339
/// <returns>A new ClusterSettings instance.</returns>
340+
/// <param name="encryptedFieldsMap">The encrypted fields map.</param>
341+
/// <param name="bypassQueryAnalysis">The bypass query analysis flag.</param>
322342
public ClusterSettings With(
323343
#pragma warning disable CS0618 // Type or member is obsolete
324344
Optional<ClusterConnectionMode> connectionMode = default(Optional<ClusterConnectionMode>),
@@ -337,7 +357,9 @@ public ClusterSettings With(
337357
Optional<IServerSelector> postServerSelector = default(Optional<IServerSelector>),
338358
Optional<IReadOnlyDictionary<string, BsonDocument>> schemaMap = default(Optional<IReadOnlyDictionary<string, BsonDocument>>),
339359
Optional<ConnectionStringScheme> scheme = default(Optional<ConnectionStringScheme>),
340-
Optional<int> srvMaxHosts = default)
360+
Optional<int> srvMaxHosts = default,
361+
Optional<IReadOnlyDictionary<string, BsonDocument>> encryptedFieldsMap = default,
362+
Optional<bool?> bypassQueryAnalysis = default)
341363
{
342364
return new ClusterSettings(
343365
connectionMode: connectionMode.WithDefault(_connectionMode),
@@ -355,7 +377,9 @@ public ClusterSettings With(
355377
postServerSelector: Optional.Create(postServerSelector.WithDefault(_postServerSelector)),
356378
schemaMap: Optional.Create(schemaMap.WithDefault(_schemaMap)),
357379
scheme: scheme.WithDefault(_scheme),
358-
srvMaxHosts: srvMaxHosts.WithDefault(_srvMaxHosts));
380+
srvMaxHosts: srvMaxHosts.WithDefault(_srvMaxHosts),
381+
encryptedFieldsMap: Optional.Create(encryptedFieldsMap.WithDefault(_encryptedFieldsMap)),
382+
bypassQueryAnalysis: bypassQueryAnalysis.WithDefault(_bypassQueryAnalysis));
359383
}
360384

361385
// internal methods

src/MongoDB.Driver.Legacy/MongoServerSettings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,13 +1191,15 @@ internal ClusterKey ToClusterKey()
11911191
return new ClusterKey(
11921192
_allowInsecureTls,
11931193
_applicationName,
1194+
bypassQueryAnalysis: null, // not supported for legacy
11941195
_clusterConfigurator,
11951196
_compressors,
11961197
_connectionMode,
11971198
_connectionModeSwitch,
11981199
_connectTimeout,
11991200
_credentials.ToList(),
12001201
_directConnection,
1202+
encryptedFieldsMap: null, // not supported for legacy
12011203
_heartbeatInterval,
12021204
_heartbeatTimeout,
12031205
_ipv6,

src/MongoDB.Driver/ClusterKey.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ internal class ClusterKey
2929
// fields
3030
private readonly bool _allowInsecureTls;
3131
private readonly string _applicationName;
32+
private readonly bool? _bypassQueryAnalysis;
3233
private readonly Action<ClusterBuilder> _clusterConfigurator;
3334
private readonly IReadOnlyList<CompressorConfiguration> _compressors;
3435
#pragma warning disable CS0618 // Type or member is obsolete
@@ -38,6 +39,7 @@ internal class ClusterKey
3839
private readonly TimeSpan _connectTimeout;
3940
private readonly IReadOnlyList<MongoCredential> _credentials;
4041
private readonly bool? _directConnection;
42+
private readonly IReadOnlyDictionary<string, BsonDocument> _encryptedFieldsMap;
4143
private readonly int _hashCode;
4244
private readonly TimeSpan _heartbeatInterval;
4345
private readonly TimeSpan _heartbeatTimeout;
@@ -70,6 +72,7 @@ internal class ClusterKey
7072
public ClusterKey(
7173
bool allowInsecureTls,
7274
string applicationName,
75+
bool? bypassQueryAnalysis,
7376
Action<ClusterBuilder> clusterConfigurator,
7477
IReadOnlyList<CompressorConfiguration> compressors,
7578
#pragma warning disable CS0618 // Type or member is obsolete
@@ -79,6 +82,7 @@ public ClusterKey(
7982
TimeSpan connectTimeout,
8083
IReadOnlyList<MongoCredential> credentials,
8184
bool? directConnection,
85+
IReadOnlyDictionary<string, BsonDocument> encryptedFieldsMap,
8286
TimeSpan heartbeatInterval,
8387
TimeSpan heartbeatTimeout,
8488
bool ipv6,
@@ -110,13 +114,15 @@ public ClusterKey(
110114

111115
_allowInsecureTls = allowInsecureTls;
112116
_applicationName = applicationName;
117+
_bypassQueryAnalysis = bypassQueryAnalysis;
113118
_clusterConfigurator = clusterConfigurator;
114119
_compressors = compressors;
115120
_connectionMode = connectionMode;
116121
_connectionModeSwitch = connectionModeSwitch;
117122
_connectTimeout = connectTimeout;
118123
_credentials = credentials;
119124
_directConnection = directConnection;
125+
_encryptedFieldsMap = encryptedFieldsMap;
120126
_heartbeatInterval = heartbeatInterval;
121127
_heartbeatTimeout = heartbeatTimeout;
122128
_ipv6 = ipv6;
@@ -150,6 +156,7 @@ public ClusterKey(
150156
// properties
151157
public bool AllowInsecureTls => _allowInsecureTls;
152158
public string ApplicationName { get { return _applicationName; } }
159+
public bool? BypassQueryAnalysis { get { return _bypassQueryAnalysis; } }
153160
public Action<ClusterBuilder> ClusterConfigurator { get { return _clusterConfigurator; } }
154161
public IReadOnlyList<CompressorConfiguration> Compressors { get { return _compressors; } }
155162
[Obsolete("Use DirectConnection instead.")]
@@ -181,6 +188,7 @@ public bool? DirectConnection
181188
return _directConnection;
182189
}
183190
}
191+
public IReadOnlyDictionary<string, BsonDocument> EncryptedFieldsMap { get { return _encryptedFieldsMap; } }
184192
public TimeSpan HeartbeatInterval { get { return _heartbeatInterval; } }
185193
public TimeSpan HeartbeatTimeout { get { return _heartbeatTimeout; } }
186194
public bool IPv6 { get { return _ipv6; } }
@@ -229,13 +237,15 @@ public override bool Equals(object obj)
229237
_hashCode == rhs._hashCode && // fail fast
230238
_allowInsecureTls == rhs._allowInsecureTls &&
231239
_applicationName == rhs._applicationName &&
240+
_bypassQueryAnalysis == rhs._bypassQueryAnalysis &&
232241
object.ReferenceEquals(_clusterConfigurator, rhs._clusterConfigurator) &&
233242
_compressors.SequenceEqual(rhs._compressors) &&
234243
_connectionMode == rhs._connectionMode &&
235244
_connectionModeSwitch == rhs._connectionModeSwitch &&
236245
_connectTimeout == rhs._connectTimeout &&
237246
_credentials.SequenceEqual(rhs._credentials) &&
238247
_directConnection.Equals(rhs._directConnection) &&
248+
_encryptedFieldsMap.IsEquivalentTo(rhs._encryptedFieldsMap, object.Equals) &&
239249
_heartbeatInterval == rhs._heartbeatInterval &&
240250
_heartbeatTimeout == rhs._heartbeatTimeout &&
241251
_ipv6 == rhs._ipv6 &&

src/MongoDB.Driver/ClusterRegistry.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ private ClusterSettings ConfigureCluster(ClusterSettings settings, ClusterKey cl
8686
Optional<ClusterConnectionMode> connectionMode = connectionModeSwitch == ConnectionModeSwitch.UseConnectionMode ? clusterKey.ConnectionMode.ToCore() : default;
8787
Optional<bool?> directConnection = connectionModeSwitch == ConnectionModeSwitch.UseDirectConnection ? clusterKey.DirectConnection : default;
8888
return settings.With(
89+
bypassQueryAnalysis: clusterKey.BypassQueryAnalysis,
8990
connectionMode: connectionMode,
9091
connectionModeSwitch: connectionModeSwitch,
9192
directConnection: directConnection,
93+
encryptedFieldsMap: Optional.Create(clusterKey.EncryptedFieldsMap),
9294
endPoints: Optional.Enumerable(endPoints),
9395
kmsProviders: Optional.Create(clusterKey.KmsProviders),
9496
loadBalanced: clusterKey.LoadBalanced,

0 commit comments

Comments
 (0)