From 405cb7c727f476ee220e1a0c305ad56acd54efc3 Mon Sep 17 00:00:00 2001 From: rstam Date: Mon, 23 Sep 2019 17:01:12 +0300 Subject: [PATCH] CSHARP-2431: Support Client-side Field Level Encryption. --- .../IO/ElementAppendingBsonWriter.cs | 24 + src/MongoDB.Bson/IO/JsonReader.cs | 2 +- .../ObjectModel/BsonBinarySubType.cs | 4 + .../Core/Clusters/Cluster.cs | 19 +- .../Core/Clusters/CryptClientCreator.cs | 105 + .../Core/Clusters/ICluster.cs | 9 + .../Core/Configuration/ClusterSettings.cs | 37 + src/MongoDB.Driver.Core/Core/Misc/Feature.cs | 6 + .../CommandMessageFieldDecryptor.cs | 79 + .../CommandMessageFieldEncryptor.cs | 183 + .../CommandUsingCommandMessageWireProtocol.cs | 102 +- .../IBinaryCommandFieldEncryptor.cs | 44 + .../IBinaryDocumentFieldDecryptor.cs | 42 + .../CommandMessageBinaryEncoder.cs | 5 +- .../MessageBinaryEncoderBase.cs | 14 + .../Encoders/MessageEncoderSettings.cs | 24 +- .../MongoDB.Driver.Core.csproj | 1 + .../MongoServerSettings.cs | 2 + src/MongoDB.Driver/ClusterKey.cs | 14 +- src/MongoDB.Driver/ClusterRegistry.cs | 2 + .../AutoEncryptionLibMongoController.cs | 227 + .../Encryption/AutoEncryptionOptions.cs | 229 + .../Encryption/ClientEncryption.cs | 151 + .../Encryption/ClientEncryptionOptions.cs | 92 + .../Encryption/DataKeyOptions.cs | 76 + .../Encryption/EncryptOptions.cs | 99 + ...plicitEncryptionLibMongoCryptController.cs | 283 ++ .../Encryption/KmsProvidersHelper.cs | 64 + .../Encryption/LibMongoCryptControllerBase.cs | 240 + .../Encryption/MongoEncryptionException.cs | 41 + .../Encryption/MongocryptdFactory.cs | 184 + .../NoopBinaryDocumentFieldCryptor.cs | 44 + .../IReadOnlyDictionaryExtensions.cs | 53 + src/MongoDB.Driver/MongoClient.cs | 39 +- src/MongoDB.Driver/MongoClientSettings.cs | 27 +- src/MongoDB.Driver/MongoCollectionImpl.cs | 24 +- src/MongoDB.Driver/MongoDB.Driver.csproj | 1 + src/MongoDB.Driver/MongoDatabaseImpl.cs | 22 +- .../JsonDrivenTests/AspectAsserter.cs | 6 + .../EmbeddedResourceJsonFileReader.cs | 75 + .../JsonDrivenTests/JsonDrivenTest.cs | 4 +- .../JsonDrivenTests/JsonDrivenTestCase.cs | 35 +- .../JsonDrivenTestCaseFactory.cs | 43 +- tests/MongoDB.Bson.TestHelpers/Reflector.cs | 28 + .../MongoDB.Bson.Tests/IO/JsonReaderTests.cs | 15 + .../CommandStartedEventAsserter.cs | 41 +- tests/MongoDB.Driver.Tests/ClusterKeyTests.cs | 203 + .../ClusterRegistryTests.cs | 13 + tests/MongoDB.Driver.Tests/EncryptionTests.cs | 274 ++ .../JsonDrivenBulkWriteTest.cs | 8 + .../JsonDrivenDatabaseAggregateTest.cs | 98 + .../JsonDrivenTests/JsonDrivenFindTest.cs | 15 +- .../JsonDrivenInsertOneTest.cs | 6 +- .../JsonDrivenTests/JsonDrivenTestFactory.cs | 5 +- .../JsonDrivenUpdateOneTest.cs | 14 + .../MongoDB.Driver.Tests.csproj | 10 +- .../MongocryptdFactoryTests.cs | 112 + ...MongoClientJsonDrivenSessionsTestRunner.cs | 16 +- .../MongoClientJsonDrivenTestRunnerBase.cs | 210 +- .../ClientSideEncryptionTestRunner.cs | 316 ++ .../prose-tests/ClientEncryptionProseTests.cs | 835 ++++ .../prose-tests/corpus/corpus-encrypted.json | 4025 +++++++++++++++++ .../prose-tests/corpus/corpus-key-aws.json | 33 + .../prose-tests/corpus/corpus-key-local.json | 31 + .../prose-tests/corpus/corpus-schema.json | 2057 +++++++++ .../prose-tests/corpus/corpus.json | 2905 ++++++++++++ .../prose-tests/external/external-key.json | 31 + .../prose-tests/external/external-schema.json | 19 + .../prose-tests/limits/limits-doc.json | 102 + .../prose-tests/limits/limits-key.json | 31 + .../prose-tests/limits/limits-schema.json | 1405 ++++++ .../client-side-encryption/tests/README.rst | 491 ++ .../tests/aggregate.json | 416 ++ .../tests/aggregate.yml | 136 + .../tests/badQueries.json | 1446 ++++++ .../tests/badQueries.yml | 526 +++ .../tests/badSchema.json | 254 ++ .../tests/badSchema.yml | 73 + .../client-side-encryption/tests/basic.json | 372 ++ .../client-side-encryption/tests/basic.yml | 118 + .../client-side-encryption/tests/bulk.json | 338 ++ .../client-side-encryption/tests/bulk.yml | 86 + .../tests/bypassAutoEncryption.json | 396 ++ .../tests/bypassAutoEncryption.yml | 98 + .../tests/bypassedCommand.json | 106 + .../tests/bypassedCommand.yml | 42 + .../client-side-encryption/tests/count.json | 240 + .../client-side-encryption/tests/count.yml | 62 + .../tests/countDocuments.json | 257 ++ .../tests/countDocuments.yml | 60 + .../client-side-encryption/tests/delete.json | 362 ++ .../client-side-encryption/tests/delete.yml | 107 + .../tests/distinct.json | 287 ++ .../client-side-encryption/tests/distinct.yml | 74 + .../client-side-encryption/tests/explain.json | 250 + .../client-side-encryption/tests/explain.yml | 65 + .../client-side-encryption/tests/find.json | 430 ++ .../client-side-encryption/tests/find.yml | 121 + .../tests/findOneAndDelete.json | 232 + .../tests/findOneAndDelete.yml | 58 + .../tests/findOneAndReplace.json | 238 + .../tests/findOneAndReplace.yml | 58 + .../tests/findOneAndUpdate.json | 242 + .../tests/findOneAndUpdate.yml | 58 + .../client-side-encryption/tests/getMore.json | 274 ++ .../client-side-encryption/tests/getMore.yml | 69 + .../client-side-encryption/tests/insert.json | 366 ++ .../client-side-encryption/tests/insert.yml | 104 + .../tests/keyAltName.json | 239 + .../tests/keyAltName.yml | 72 + .../tests/localKMS.json | 205 + .../client-side-encryption/tests/localKMS.yml | 56 + .../tests/localSchema.json | 268 ++ .../tests/localSchema.yml | 72 + .../tests/malformedCiphertext.json | 321 ++ .../tests/malformedCiphertext.yml | 69 + .../tests/maxWireVersion.json | 71 + .../tests/maxWireVersion.yml | 20 + .../tests/missingKey.json | 190 + .../tests/missingKey.yml | 50 + .../tests/replaceOne.json | 250 + .../tests/replaceOne.yml | 62 + .../client-side-encryption/tests/types.json | 1726 +++++++ .../client-side-encryption/tests/types.yml | 527 +++ .../tests/unsupportedCommand.json | 152 + .../tests/unsupportedCommand.yml | 25 + .../tests/updateMany.json | 318 ++ .../tests/updateMany.yml | 78 + .../tests/updateOne.json | 478 ++ .../tests/updateOne.yml | 170 + tests/MongoDB.Driver.Tests/xunit.runner.json | 3 +- 131 files changed, 29776 insertions(+), 193 deletions(-) create mode 100644 src/MongoDB.Driver.Core/Core/Clusters/CryptClientCreator.cs create mode 100644 src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldDecryptor.cs create mode 100644 src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldEncryptor.cs create mode 100644 src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryCommandFieldEncryptor.cs create mode 100644 src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryDocumentFieldDecryptor.cs create mode 100644 src/MongoDB.Driver/Encryption/AutoEncryptionLibMongoController.cs create mode 100644 src/MongoDB.Driver/Encryption/AutoEncryptionOptions.cs create mode 100644 src/MongoDB.Driver/Encryption/ClientEncryption.cs create mode 100644 src/MongoDB.Driver/Encryption/ClientEncryptionOptions.cs create mode 100644 src/MongoDB.Driver/Encryption/DataKeyOptions.cs create mode 100644 src/MongoDB.Driver/Encryption/EncryptOptions.cs create mode 100644 src/MongoDB.Driver/Encryption/ExplicitEncryptionLibMongoCryptController.cs create mode 100644 src/MongoDB.Driver/Encryption/KmsProvidersHelper.cs create mode 100644 src/MongoDB.Driver/Encryption/LibMongoCryptControllerBase.cs create mode 100644 src/MongoDB.Driver/Encryption/MongoEncryptionException.cs create mode 100644 src/MongoDB.Driver/Encryption/MongocryptdFactory.cs create mode 100644 src/MongoDB.Driver/Encryption/NoopBinaryDocumentFieldCryptor.cs create mode 100644 src/MongoDB.Driver/IReadOnlyDictionaryExtensions.cs create mode 100644 tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/EmbeddedResourceJsonFileReader.cs create mode 100644 tests/MongoDB.Driver.Tests/EncryptionTests.cs create mode 100644 tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenDatabaseAggregateTest.cs create mode 100644 tests/MongoDB.Driver.Tests/MongocryptdFactoryTests.cs create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/ClientSideEncryptionTestRunner.cs create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-encrypted.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-aws.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-local.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-schema.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-key.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-schema.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-doc.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-key.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-schema.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/README.rst create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.yml create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.json create mode 100644 tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.yml diff --git a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs index a587e873efc..046a5f909ac 100644 --- a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs +++ b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs @@ -74,6 +74,30 @@ public override void WriteEndDocument() base.WriteEndDocument(); } + public override void WriteRawBsonDocument(IByteBuffer slice) + { + WriteStartDocument(); + + if (Wrapped is BsonBinaryWriter binaryWriter) + { + // just copy the bytes (without the length and terminating null) + var lengthBytes = new byte[4]; + slice.GetBytes(0, lengthBytes, 0, 4); + var length = BitConverter.ToInt32(lengthBytes, 0); + using (var elements = slice.GetSlice(4, length - 5)) + { + var stream = binaryWriter.BsonStream; + stream.WriteSlice(elements); + } + } + else + { + throw new NotSupportedException("WriteRawBsonDocument supports only BsonBinaryWriter."); + } + + WriteEndDocument(); + } + /// public override void WriteStartDocument() { diff --git a/src/MongoDB.Bson/IO/JsonReader.cs b/src/MongoDB.Bson/IO/JsonReader.cs index 3c2e9e96132..f33ec492c3c 100644 --- a/src/MongoDB.Bson/IO/JsonReader.cs +++ b/src/MongoDB.Bson/IO/JsonReader.cs @@ -1195,7 +1195,7 @@ private BsonValue ParseDateTimeExtendedJson() } else if (valueToken.Type == JsonTokenType.BeginObject) { - VerifyToken("$numberLong"); + VerifyString("$numberLong"); VerifyToken(":"); var millisecondsSinceEpochToken = PopToken(); if (millisecondsSinceEpochToken.Type == JsonTokenType.String) diff --git a/src/MongoDB.Bson/ObjectModel/BsonBinarySubType.cs b/src/MongoDB.Bson/ObjectModel/BsonBinarySubType.cs index d960b140128..eb617e0c010 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonBinarySubType.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonBinarySubType.cs @@ -51,6 +51,10 @@ public enum BsonBinarySubType /// MD5 = 0x05, /// + /// Encrypted binary data. + /// + Encrypted = 0x06, + /// /// User defined binary data. /// UserDefined = 0x80 diff --git a/src/MongoDB.Driver.Core/Core/Clusters/Cluster.cs b/src/MongoDB.Driver.Core/Core/Clusters/Cluster.cs index 2f8a1504729..249c75135ab 100644 --- a/src/MongoDB.Driver.Core/Core/Clusters/Cluster.cs +++ b/src/MongoDB.Driver.Core/Core/Clusters/Cluster.cs @@ -26,6 +26,7 @@ using MongoDB.Driver.Core.Events; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.Servers; +using MongoDB.Libmongocrypt; namespace MongoDB.Driver.Core.Clusters { @@ -62,6 +63,7 @@ internal abstract class Cluster : ICluster // fields private readonly IClusterClock _clusterClock = new ClusterClock(); private readonly ClusterId _clusterId; + private CryptClient _cryptClient = null; private ClusterDescription _description; private TaskCompletionSource _descriptionChangedTaskCompletionSource; private readonly object _descriptionLock = new object(); @@ -109,6 +111,11 @@ public ClusterId ClusterId get { return _clusterId; } } + public CryptClient CryptClient + { + get { return _cryptClient; } + } + public ClusterDescription Description { get @@ -188,7 +195,13 @@ private void ExitServerSelectionWaitQueue() public virtual void Initialize() { ThrowIfDisposed(); - _state.TryChange(State.Initial, State.Open); + if (_state.TryChange(State.Initial, State.Open)) + { + if (_settings.KmsProviders != null || _settings.SchemaMap != null) + { + _cryptClient = CryptClientCreator.CreateCryptClient(_settings.KmsProviders, _settings.SchemaMap); + } + } } private void RapidHeartbeatTimerCallback(object args) @@ -350,7 +363,7 @@ private async Task WaitForDescriptionChangedAsync(IServerSelector selector, Clus { using (var helper = new WaitForDescriptionChangedHelper(this, selector, description, descriptionChangedTask, timeout, cancellationToken)) { - var completedTask = await Task.WhenAny(helper.Tasks).ConfigureAwait(false); + var completedTask = await Task.WhenAny(helper.Tasks).ConfigureAwait(false); helper.HandleCompletedTask(completedTask); } } @@ -528,7 +541,7 @@ private sealed class WaitForDescriptionChangedHelper : IDisposable private readonly CancellationTokenSource _timeoutCancellationTokenSource; private readonly Task _timeoutTask; - public WaitForDescriptionChangedHelper(Cluster cluster, IServerSelector selector, ClusterDescription description, Task descriptionChangedTask , TimeSpan timeout, CancellationToken cancellationToken) + public WaitForDescriptionChangedHelper(Cluster cluster, IServerSelector selector, ClusterDescription description, Task descriptionChangedTask, TimeSpan timeout, CancellationToken cancellationToken) { _cluster = cluster; _description = description; diff --git a/src/MongoDB.Driver.Core/Core/Clusters/CryptClientCreator.cs b/src/MongoDB.Driver.Core/Core/Clusters/CryptClientCreator.cs new file mode 100644 index 00000000000..8ece458840a --- /dev/null +++ b/src/MongoDB.Driver.Core/Core/Clusters/CryptClientCreator.cs @@ -0,0 +1,105 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Driver.Core.Misc; +using MongoDB.Libmongocrypt; + +namespace MongoDB.Driver.Core.Clusters +{ + /// + /// Represents a creator for CryptClient. + /// + public sealed class CryptClientCreator + { + #region static +#pragma warning disable 3002 + /// + /// Create a CryptClient instance. + /// + /// The kms providers. + /// The schema map. + /// The CryptClient instance. + public static CryptClient CreateCryptClient( + IReadOnlyDictionary> kmsProviders, + IReadOnlyDictionary schemaMap) + { + var helper = new CryptClientCreator(kmsProviders, schemaMap); + var cryptOptions = helper.CreateCryptOptions(); + return helper.CreateCryptClient(cryptOptions); + } +#pragma warning restore + #endregion + + private readonly IReadOnlyDictionary> _kmsProviders; + private readonly IReadOnlyDictionary _schemaMap; + + private CryptClientCreator( + IReadOnlyDictionary> kmsProviders, + IReadOnlyDictionary schemaMap) + { + _kmsProviders = Ensure.IsNotNull(kmsProviders, nameof(kmsProviders)); + _schemaMap = schemaMap; + } + + private CryptClient CreateCryptClient(CryptOptions options) + { + return CryptClientFactory.Create(options); + } + + private CryptOptions CreateCryptOptions() + { + Dictionary kmsProvidersMap = null; + if (_kmsProviders != null && _kmsProviders.Count > 0) + { + kmsProvidersMap = new Dictionary(); + if (_kmsProviders.TryGetValue("aws", out var awsProvider)) + { + if (awsProvider.TryGetValue("accessKeyId", out var accessKeyId) && + awsProvider.TryGetValue("secretAccessKey", out var secretAccessKey)) + { + kmsProvidersMap.Add(KmsType.Aws, new AwsKmsCredentials((string)secretAccessKey, (string)accessKeyId)); + } + } + if (_kmsProviders.TryGetValue("local", out var localProvider)) + { + if (localProvider.TryGetValue("key", out var keyObject) && keyObject is byte[] key) + { + kmsProvidersMap.Add(KmsType.Local, new LocalKmsCredentials(key)); + } + } + } + else + { + throw new ArgumentException("At least one kms provider must be specified"); + } + + byte[] schemaBytes = null; + if (_schemaMap != null) + { + var schemaMapElements = _schemaMap.Select(c => new BsonElement(c.Key, c.Value)); + var schemaDocument = new BsonDocument(schemaMapElements); + var writerSettings = new BsonBinaryWriterSettings { GuidRepresentation = GuidRepresentation.Unspecified }; + schemaBytes = schemaDocument.ToBson(writerSettings: writerSettings); + } + + return new CryptOptions(kmsProvidersMap, schemaBytes); + } + } +} diff --git a/src/MongoDB.Driver.Core/Core/Clusters/ICluster.cs b/src/MongoDB.Driver.Core/Core/Clusters/ICluster.cs index ca47a1936fc..5114db4c398 100644 --- a/src/MongoDB.Driver.Core/Core/Clusters/ICluster.cs +++ b/src/MongoDB.Driver.Core/Core/Clusters/ICluster.cs @@ -20,6 +20,7 @@ using MongoDB.Driver.Core.Clusters.ServerSelectors; using MongoDB.Driver.Core.Configuration; using MongoDB.Driver.Core.Servers; +using MongoDB.Libmongocrypt; namespace MongoDB.Driver.Core.Clusters { @@ -66,6 +67,14 @@ public interface ICluster : IDisposable /// A core server session. ICoreServerSession AcquireServerSession(); + /// + /// Gets the crypt client. + /// + /// A crypt client. +#pragma warning disable CS3003 + CryptClient CryptClient { get; } +#pragma warning restore + /// /// Initializes the cluster. /// diff --git a/src/MongoDB.Driver.Core/Core/Configuration/ClusterSettings.cs b/src/MongoDB.Driver.Core/Core/Configuration/ClusterSettings.cs index 791491c54f0..383edc1c0c6 100644 --- a/src/MongoDB.Driver.Core/Core/Configuration/ClusterSettings.cs +++ b/src/MongoDB.Driver.Core/Core/Configuration/ClusterSettings.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using MongoDB.Bson; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Clusters.ServerSelectors; using MongoDB.Driver.Core.Misc; @@ -36,8 +37,10 @@ public class ClusterSettings // fields private readonly ClusterConnectionMode _connectionMode; private readonly IReadOnlyList _endPoints; + private readonly IReadOnlyDictionary> _kmsProviders; private readonly int _maxServerSelectionWaitQueueSize; private readonly string _replicaSetName; + private readonly IReadOnlyDictionary _schemaMap; private readonly ConnectionStringScheme _scheme; private readonly TimeSpan _serverSelectionTimeout; private readonly IServerSelector _preServerSelector; @@ -49,30 +52,36 @@ public class ClusterSettings /// /// The connection mode. /// The end points. + /// The kms providers. /// Maximum size of the server selection wait queue. /// Name of the replica set. /// The server selection timeout. /// The pre server selector. /// The post server selector. + /// The schema map. /// The connection string scheme. public ClusterSettings( Optional connectionMode = default(Optional), Optional> endPoints = default(Optional>), + Optional>> kmsProviders = default(Optional>>), Optional maxServerSelectionWaitQueueSize = default(Optional), Optional replicaSetName = default(Optional), Optional serverSelectionTimeout = default(Optional), Optional preServerSelector = default(Optional), Optional postServerSelector = default(Optional), + Optional> schemaMap = default(Optional>), Optional scheme = default(Optional)) { _connectionMode = connectionMode.WithDefault(ClusterConnectionMode.Automatic); _endPoints = Ensure.IsNotNull(endPoints.WithDefault(__defaultEndPoints), "endPoints").ToList(); + _kmsProviders = kmsProviders.WithDefault(null); _maxServerSelectionWaitQueueSize = Ensure.IsGreaterThanOrEqualToZero(maxServerSelectionWaitQueueSize.WithDefault(500), "maxServerSelectionWaitQueueSize"); _replicaSetName = replicaSetName.WithDefault(null); _serverSelectionTimeout = Ensure.IsGreaterThanOrEqualToZero(serverSelectionTimeout.WithDefault(TimeSpan.FromSeconds(30)), "serverSelectionTimeout"); _preServerSelector = preServerSelector.WithDefault(null); _postServerSelector = postServerSelector.WithDefault(null); _scheme = scheme.WithDefault(ConnectionStringScheme.MongoDB); + _schemaMap = schemaMap.WithDefault(null); } // properties @@ -98,6 +107,17 @@ public IReadOnlyList EndPoints get { return _endPoints; } } + /// + /// Gets the kms providers. + /// + /// + /// The kms providers. + /// + public IReadOnlyDictionary> KmsProviders + { + get { return _kmsProviders; } + } + /// /// Gets the maximum size of the server selection wait queue. /// @@ -120,6 +140,17 @@ public string ReplicaSetName get { return _replicaSetName; } } + /// + /// Gets the schema map. + /// + /// + /// The schema map. + /// + public IReadOnlyDictionary SchemaMap + { + get { return _schemaMap; } + } + /// /// Gets the connection string scheme. /// @@ -170,31 +201,37 @@ public IServerSelector PostServerSelector /// /// The connection mode. /// The end points. + /// The kms providers. /// Maximum size of the server selection wait queue. /// Name of the replica set. /// The server selection timeout. /// The pre server selector. /// The post server selector. + /// The schema map. /// The connection string scheme. /// A new ClusterSettings instance. public ClusterSettings With( Optional connectionMode = default(Optional), Optional> endPoints = default(Optional>), + Optional>> kmsProviders = default(Optional>>), Optional maxServerSelectionWaitQueueSize = default(Optional), Optional replicaSetName = default(Optional), Optional serverSelectionTimeout = default(Optional), Optional preServerSelector = default(Optional), Optional postServerSelector = default(Optional), + Optional> schemaMap = default(Optional>), Optional scheme = default(Optional)) { return new ClusterSettings( connectionMode: connectionMode.WithDefault(_connectionMode), endPoints: Optional.Enumerable(endPoints.WithDefault(_endPoints)), + kmsProviders: Optional.Create(kmsProviders.WithDefault(_kmsProviders)), maxServerSelectionWaitQueueSize: maxServerSelectionWaitQueueSize.WithDefault(_maxServerSelectionWaitQueueSize), replicaSetName: replicaSetName.WithDefault(_replicaSetName), serverSelectionTimeout: serverSelectionTimeout.WithDefault(_serverSelectionTimeout), preServerSelector: Optional.Create(preServerSelector.WithDefault(_preServerSelector)), postServerSelector: Optional.Create(postServerSelector.WithDefault(_postServerSelector)), + schemaMap: Optional.Create(schemaMap.WithDefault(_schemaMap)), scheme: scheme.WithDefault(_scheme)); } } diff --git a/src/MongoDB.Driver.Core/Core/Misc/Feature.cs b/src/MongoDB.Driver.Core/Core/Misc/Feature.cs index c7450f5a73d..90b038813d6 100644 --- a/src/MongoDB.Driver.Core/Core/Misc/Feature.cs +++ b/src/MongoDB.Driver.Core/Core/Misc/Feature.cs @@ -41,6 +41,7 @@ public class Feature private static readonly Feature __bypassDocumentValidation = new Feature("BypassDocumentValidation", new SemanticVersion(3, 2, 0)); private static readonly Feature __changeStreamStage = new Feature("ChangeStreamStage", new SemanticVersion(3, 5, 11)); private static readonly Feature __changeStreamPostBatchResumeToken = new Feature("ChangeStreamPostBatchResumeToken", new SemanticVersion(4, 0 ,7)); + private static readonly Feature __clientSideEncryption = new Feature("ClientSideEncryption", new SemanticVersion(4, 1, 9)); private static readonly CollationFeature __collation = new CollationFeature("Collation", new SemanticVersion(3, 3, 11)); private static readonly Feature __commandMessage = new Feature("CommandMessage", new SemanticVersion(3, 6, 0)); private static readonly CommandsThatWriteAcceptWriteConcernFeature __commandsThatWriteAcceptWriteConcern = new CommandsThatWriteAcceptWriteConcernFeature("CommandsThatWriteAcceptWriteConcern", new SemanticVersion(3, 3, 11)); @@ -170,6 +171,11 @@ public class Feature /// public static Feature ChangeStreamPostBatchResumeToken => __changeStreamPostBatchResumeToken; + /// + /// Gets the client side encryption feature. + /// + public static Feature ClientSideEncryption => __clientSideEncryption; + /// /// Gets the collation feature. /// diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldDecryptor.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldDecryptor.cs new file mode 100644 index 00000000000..6e1bc9bbea9 --- /dev/null +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldDecryptor.cs @@ -0,0 +1,79 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver.Core.WireProtocol.Messages; +using MongoDB.Driver.Core.WireProtocol.Messages.Encoders; + +namespace MongoDB.Driver.Core.WireProtocol +{ + internal class CommandMessageFieldDecryptor + { + // private fields + private readonly IBinaryDocumentFieldDecryptor _documentFieldDecryptor; + private readonly MessageEncoderSettings _messageEncoderSettings; + + // constructors + public CommandMessageFieldDecryptor(IBinaryDocumentFieldDecryptor documentFieldDecryptor, MessageEncoderSettings messageEncoderSettings) + { + _documentFieldDecryptor = documentFieldDecryptor; + _messageEncoderSettings = messageEncoderSettings; + } + + // public methods + public CommandResponseMessage DecryptFields(CommandResponseMessage encryptedResponseMessage, CancellationToken cancellationToken) + { + var encryptedDocumentBytes = GetEncryptedDocumentBytes(encryptedResponseMessage); + var unencryptedDocumentBytes = _documentFieldDecryptor.DecryptFields(encryptedDocumentBytes, cancellationToken); + return CreateUnencryptedResponseMessage(encryptedResponseMessage, unencryptedDocumentBytes); + } + + public async Task DecryptFieldsAsync(CommandResponseMessage encryptedResponseMessage, CancellationToken cancellationToken) + { + var encryptedDocumentBytes = GetEncryptedDocumentBytes(encryptedResponseMessage); + var unencryptedDocumentBytes = await _documentFieldDecryptor.DecryptFieldsAsync(encryptedDocumentBytes, cancellationToken).ConfigureAwait(false); + return CreateUnencryptedResponseMessage(encryptedResponseMessage, unencryptedDocumentBytes); + } + + // private methods + private CommandResponseMessage CreateUnencryptedResponseMessage(CommandResponseMessage encryptedResponseMessage, byte[] unencryptedDocumentBytes) + { + var unencryptedDocument = new RawBsonDocument(unencryptedDocumentBytes); + var unencryptedSections = new[] { new Type0CommandMessageSection(unencryptedDocument, RawBsonDocumentSerializer.Instance) }; + var encryptedCommandMessage = encryptedResponseMessage.WrappedMessage; + var unencryptedCommandMessage = new CommandMessage( + encryptedCommandMessage.RequestId, + encryptedCommandMessage.ResponseTo, + unencryptedSections, + encryptedCommandMessage.MoreToCome); + return new CommandResponseMessage(unencryptedCommandMessage); + } + + private byte[] GetEncryptedDocumentBytes(CommandResponseMessage encryptedResponseMessage) + { + var encryptedCommandMessage = encryptedResponseMessage.WrappedMessage; + var encryptedSections = encryptedCommandMessage.Sections; + var encryptedType0Section = (Type0CommandMessageSection)encryptedSections.Single(); + var encryptedDocumentSlice = encryptedType0Section.Document.Slice; + var encryptedDocumentBytes = new byte[encryptedDocumentSlice.Length]; + encryptedDocumentSlice.GetBytes(0, encryptedDocumentBytes, 0, encryptedDocumentBytes.Length); + return encryptedDocumentBytes; + } + } +} diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldEncryptor.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldEncryptor.cs new file mode 100644 index 00000000000..8f083f7362e --- /dev/null +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/CommandMessageFieldEncryptor.cs @@ -0,0 +1,183 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver.Core.WireProtocol.Messages; +using MongoDB.Driver.Core.WireProtocol.Messages.Encoders; +using MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders; + +namespace MongoDB.Driver.Core.WireProtocol +{ + internal class CommandMessageFieldEncryptor + { + // private fields + private readonly byte[] _buffer = new byte[1024]; + private readonly IBinaryCommandFieldEncryptor _commandFieldEncryptor; + private readonly MessageEncoderSettings _messageEncoderSettings; + + // constructors + public CommandMessageFieldEncryptor(IBinaryCommandFieldEncryptor commandFieldEncryptor, MessageEncoderSettings messageEncoderSettings) + { + _commandFieldEncryptor = commandFieldEncryptor; + _messageEncoderSettings = messageEncoderSettings; + } + + // public static methods + public CommandRequestMessage EncryptFields(string databaseName, CommandRequestMessage unencryptedRequestMessage, CancellationToken cancellationToken) + { + var unencryptedCommandBytes = GetUnencryptedCommandBytes(unencryptedRequestMessage); + var encryptedCommandBytes = _commandFieldEncryptor.EncryptFields(databaseName, unencryptedCommandBytes, cancellationToken); + return CreateEncryptedRequestMessage(unencryptedRequestMessage, encryptedCommandBytes); + } + + public async Task EncryptFieldsAsync(string databaseName, CommandRequestMessage unencryptedRequestMessage, CancellationToken cancellationToken) + { + var unencryptedCommandBytes = GetUnencryptedCommandBytes(unencryptedRequestMessage); + var encryptedCommandBytes = await _commandFieldEncryptor.EncryptFieldsAsync(databaseName, unencryptedCommandBytes, cancellationToken).ConfigureAwait(false); + return CreateEncryptedRequestMessage(unencryptedRequestMessage, encryptedCommandBytes); + } + + // private static methods + private byte[] CombineCommandMessageSectionsIntoSingleDocument(Stream stream) + { + using (var inputStream = new BsonStreamAdapter(stream, ownsStream: false)) + using (var memoryStream = new MemoryStream()) + using (var outputStream = new BsonStreamAdapter(memoryStream, ownsStream: false)) + { + var messageStartPosition = inputStream.Position; + var messageLength = inputStream.ReadInt32(); + var messageEndPosition = messageStartPosition + messageLength; + var requestId = inputStream.ReadInt32(); + var responseTo = inputStream.ReadInt32(); + var opcode = inputStream.ReadInt32(); + var flags = (OpMsgFlags)inputStream.ReadInt32(); + if (flags.HasFlag(OpMsgFlags.ChecksumPresent)) + { + messageEndPosition -= 4; // ignore checksum + } + + CopyType0Section(inputStream, outputStream); + outputStream.Position -= 1; + while (inputStream.Position < messageEndPosition) + { + CopyType1Section(inputStream, outputStream); + } + outputStream.WriteByte(0); + outputStream.BackpatchSize(0); + + return memoryStream.ToArray(); + } + } + + private void CopyBsonDocument(BsonStream inputStream, BsonStream outputStream) + { + var documentLength = inputStream.ReadInt32(); + inputStream.Position -= 4; + CopyBytes(inputStream, outputStream, documentLength); + } + + private void CopyBytes(BsonStream inputStream, BsonStream outputStream, int count) + { + while (count > 0) + { + var chunkSize = Math.Min(count, _buffer.Length); + inputStream.ReadBytes(_buffer, 0, chunkSize); + outputStream.WriteBytes(_buffer, 0, chunkSize); + count -= chunkSize; + } + } + + private void CopyType0Section(BsonStream inputStream, BsonStream outputStream) + { + var payloadType = (PayloadType)inputStream.ReadByte(); + if (payloadType != PayloadType.Type0) + { + throw new FormatException("Expected first section to be of type 0."); + } + + CopyBsonDocument(inputStream, outputStream); + } + + private void CopyType1Section(BsonStream inputStream, BsonStream outputStream) + { + var payloadType = (PayloadType)inputStream.ReadByte(); + if (payloadType != PayloadType.Type1) + { + throw new FormatException("Expected subsequent sections to be of type 1."); + } + + var sectionStartPosition = inputStream.Position; + var sectionSize = inputStream.ReadInt32(); + var sectionEndPosition = sectionStartPosition + sectionSize; + var identifier = inputStream.ReadCString(Utf8Encodings.Lenient); + + outputStream.WriteByte((byte)BsonType.Array); + outputStream.WriteCString(identifier); + var arrayStartPosition = outputStream.Position; + outputStream.WriteInt32(0); // array length will be backpatched + var index = 0; + while (inputStream.Position < sectionEndPosition) + { + outputStream.WriteByte((byte)BsonType.Document); + outputStream.WriteCString(index.ToString()); + CopyBsonDocument(inputStream, outputStream); + index++; + } + outputStream.WriteByte(0); + outputStream.BackpatchSize(arrayStartPosition); + } + + private CommandRequestMessage CreateEncryptedRequestMessage(CommandRequestMessage unencryptedRequestMessage, byte[] encryptedDocumentBytes) + { + var encryptedDocument = new RawBsonDocument(encryptedDocumentBytes); + var encryptedSections = new[] { new Type0CommandMessageSection(encryptedDocument, RawBsonDocumentSerializer.Instance) }; + var unencryptedCommandMessage = unencryptedRequestMessage.WrappedMessage; + var encryptedCommandMessage = new CommandMessage( + unencryptedCommandMessage.RequestId, + unencryptedCommandMessage.ResponseTo, + encryptedSections, + unencryptedCommandMessage.MoreToCome); + return new CommandRequestMessage(encryptedCommandMessage, unencryptedRequestMessage.ShouldBeSent); + } + + private byte[] GetUnencryptedCommandBytes(CommandRequestMessage unencryptedRequestMessage) + { + using (var stream = new MemoryStream()) + { + WriteUnencryptedRequestMessageToStream(stream, unencryptedRequestMessage); + stream.Position = 0; + return CombineCommandMessageSectionsIntoSingleDocument(stream); + } + } + + private void WriteUnencryptedRequestMessageToStream( + Stream stream, + CommandRequestMessage unencryptedRequestMessage) + { + var clonedMessageEncoderSettings = _messageEncoderSettings.Clone(); + clonedMessageEncoderSettings.Set(MessageEncoderSettingsName.MaxDocumentSize, 2097152); + clonedMessageEncoderSettings.Set(MessageEncoderSettingsName.MaxMessageSize, 2097152 + 16384); + var encoderFactory = new BinaryMessageEncoderFactory(stream, clonedMessageEncoderSettings, compressorSource: null); + var encoder = encoderFactory.GetCommandRequestMessageEncoder(); + encoder.WriteMessage(unencryptedRequestMessage); + } + } +} diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs index 6a1543e621c..bd5ea7936cf 100644 --- a/src/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs @@ -41,6 +41,8 @@ internal class CommandUsingCommandMessageWireProtocol : IWirePro private readonly List _commandPayloads; private readonly IElementNameValidator _commandValidator; // TODO: how can this be supported when using CommandMessage? private readonly DatabaseNamespace _databaseNamespace; + private readonly IBinaryDocumentFieldDecryptor _documentFieldDecryptor; + private readonly IBinaryCommandFieldEncryptor _documentFieldEncryptor; private readonly MessageEncoderSettings _messageEncoderSettings; private readonly Action _postWriteAction; private readonly ReadPreference _readPreference; @@ -78,6 +80,12 @@ internal class CommandUsingCommandMessageWireProtocol : IWirePro _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer)); _messageEncoderSettings = messageEncoderSettings; _postWriteAction = postWriteAction; // can be null + + if (messageEncoderSettings != null) + { + _documentFieldDecryptor = messageEncoderSettings.GetOrDefault(MessageEncoderSettingsName.BinaryDocumentFieldDecryptor, null); + _documentFieldEncryptor = messageEncoderSettings.GetOrDefault(MessageEncoderSettingsName.BinaryDocumentFieldEncryptor, null); + } } // public methods @@ -86,6 +94,7 @@ public TCommandResult Execute(IConnection connection, CancellationToken cancella try { var message = CreateCommandMessage(connection.Description); + message = AutoEncryptFieldsIfNecessary(message, connection, cancellationToken); try { @@ -100,6 +109,7 @@ public TCommandResult Execute(IConnection connection, CancellationToken cancella { var encoderSelector = new CommandResponseMessageEncoderSelector(); var response = (CommandResponseMessage)connection.ReceiveMessage(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken); + response = AutoDecryptFieldsIfNecessary(response, cancellationToken); return ProcessResponse(connection.ConnectionId, response.WrappedMessage); } else @@ -123,6 +133,7 @@ public async Task ExecuteAsync(IConnection connection, Cancellat try { var message = CreateCommandMessage(connection.Description); + message = await AutoEncryptFieldsIfNecessaryAsync(message, connection, cancellationToken).ConfigureAwait(false); try { @@ -137,6 +148,7 @@ public async Task ExecuteAsync(IConnection connection, Cancellat { var encoderSelector = new CommandResponseMessageEncoderSelector(); var response = (CommandResponseMessage)await connection.ReceiveMessageAsync(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken).ConfigureAwait(false); + response = await AutoDecryptFieldsIfNecessaryAsync(response, cancellationToken).ConfigureAwait(false); return ProcessResponse(connection.ConnectionId, response.WrappedMessage); } else @@ -156,6 +168,68 @@ public async Task ExecuteAsync(IConnection connection, Cancellat } // private methods + private CommandResponseMessage AutoDecryptFieldsIfNecessary(CommandResponseMessage encryptedResponseMessage, CancellationToken cancellationToken) + { + if (_documentFieldDecryptor == null) + { + return encryptedResponseMessage; + } + else + { + var messageFieldDecryptor = new CommandMessageFieldDecryptor(_documentFieldDecryptor, _messageEncoderSettings); + return messageFieldDecryptor.DecryptFields(encryptedResponseMessage, cancellationToken); + } + } + + private async Task AutoDecryptFieldsIfNecessaryAsync(CommandResponseMessage encryptedResponseMessage, CancellationToken cancellationToken) + { + if (_documentFieldDecryptor == null) + { + return encryptedResponseMessage; + } + else + { + var messageFieldDecryptor = new CommandMessageFieldDecryptor(_documentFieldDecryptor, _messageEncoderSettings); + return await messageFieldDecryptor.DecryptFieldsAsync(encryptedResponseMessage, cancellationToken).ConfigureAwait(false); + } + } + + private CommandRequestMessage AutoEncryptFieldsIfNecessary(CommandRequestMessage unencryptedRequestMessage, IConnection connection, CancellationToken cancellationToken) + { + if (_documentFieldEncryptor == null) + { + return unencryptedRequestMessage; + } + else + { + if (connection.Description.IsMasterResult.MaxWireVersion < 8) + { + throw new NotSupportedException("Auto-encryption requires a minimum MongoDB version of 4.2."); + } + + var helper = new CommandMessageFieldEncryptor(_documentFieldEncryptor, _messageEncoderSettings); + return helper.EncryptFields(_databaseNamespace.DatabaseName, unencryptedRequestMessage, cancellationToken); + } + } + + private async Task AutoEncryptFieldsIfNecessaryAsync(CommandRequestMessage unencryptedRequestMessage, IConnection connection, CancellationToken cancellationToken) + { + if (_documentFieldEncryptor == null) + { + return unencryptedRequestMessage; + } + else + { + if (connection.Description.IsMasterResult.MaxWireVersion < 8) + { + throw new NotSupportedException("Auto-encryption requires a minimum MongoDB version of 4.2."); + } + + var helper = new CommandMessageFieldEncryptor(_documentFieldEncryptor, _messageEncoderSettings); + return await helper.EncryptFieldsAsync(_databaseNamespace.DatabaseName, unencryptedRequestMessage, cancellationToken).ConfigureAwait(false); + } + } + private CommandRequestMessage CreateCommandMessage(ConnectionDescription connectionDescription) { var requestId = RequestMessage.GetNextRequestId(); @@ -188,28 +262,24 @@ private Type0CommandMessageSection CreateType0Section(ConnectionDe { var extraElements = new List(); - var dbElement = new BsonElement("$db", _databaseNamespace.DatabaseName); - extraElements.Add(dbElement); + addIfNotAlreadyAdded("$db", _databaseNamespace.DatabaseName); if (connectionDescription.IsMasterResult.ServerType != ServerType.Standalone && _readPreference != null && _readPreference != ReadPreference.Primary) { var readPreferenceDocument = QueryHelper.CreateReadPreferenceDocument(_readPreference); - var readPreferenceElement = new BsonElement("$readPreference", readPreferenceDocument); - extraElements.Add(readPreferenceElement); + addIfNotAlreadyAdded("$readPreference", readPreferenceDocument); } if (_session.Id != null) { - var lsidElement = new BsonElement("lsid", _session.Id); - extraElements.Add(lsidElement); + addIfNotAlreadyAdded("lsid", _session.Id); } if (_session.ClusterTime != null) { - var clusterTimeElement = new BsonElement("$clusterTime", _session.ClusterTime); - extraElements.Add(clusterTimeElement); + addIfNotAlreadyAdded("$clusterTime", _session.ClusterTime); } Action writerSettingsConfigurator = s => s.GuidRepresentation = GuidRepresentation.Unspecified; @@ -217,21 +287,29 @@ private Type0CommandMessageSection CreateType0Section(ConnectionDe if (_session.IsInTransaction) { var transaction = _session.CurrentTransaction; - extraElements.Add(new BsonElement("txnNumber", transaction.TransactionNumber)); + addIfNotAlreadyAdded("txnNumber", transaction.TransactionNumber); if (transaction.State == CoreTransactionState.Starting) { - extraElements.Add(new BsonElement("startTransaction", true)); + addIfNotAlreadyAdded("startTransaction", true); var readConcern = ReadConcernHelper.GetReadConcernForFirstCommandInTransaction(_session, connectionDescription); if (readConcern != null) { - extraElements.Add(new BsonElement("readConcern", readConcern)); + addIfNotAlreadyAdded("readConcern", readConcern); } } - extraElements.Add(new BsonElement("autocommit", false)); + addIfNotAlreadyAdded("autocommit", false); } var elementAppendingSerializer = new ElementAppendingSerializer(BsonDocumentSerializer.Instance, extraElements, writerSettingsConfigurator); return new Type0CommandMessageSection(_command, elementAppendingSerializer); + + void addIfNotAlreadyAdded(string key, BsonValue value) + { + if (!_command.Contains(key)) + { + extraElements.Add(new BsonElement(key, value)); + } + } } private bool IsRetryableWriteExceptionAndDeploymentDoesNotSupportRetryableWrites(MongoCommandException exception) diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryCommandFieldEncryptor.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryCommandFieldEncryptor.cs new file mode 100644 index 00000000000..66eec78143e --- /dev/null +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryCommandFieldEncryptor.cs @@ -0,0 +1,44 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Threading; +using System.Threading.Tasks; + +namespace MongoDB.Driver.Core.WireProtocol +{ + /// + /// Interface for decrypting fields in a binary document. + /// + public interface IBinaryCommandFieldEncryptor + { + /// + /// Encrypts the fields. + /// + /// The database name. + /// The unencrypted command bytes. + /// The cancellation token. + /// An encrypted document. + byte[] EncryptFields(string databaseName, byte[] unencryptedCommandBytes, CancellationToken cancellationToken); + + /// + /// Encrypts the fields asynchronously. + /// + /// The database name. + /// The unencrypted command bytes. + /// The cancellation token. + /// An encrypted document. + Task EncryptFieldsAsync(string databaseName, byte[] unencryptedCommandBytes, CancellationToken cancellationToken); + } +} diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryDocumentFieldDecryptor.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryDocumentFieldDecryptor.cs new file mode 100644 index 00000000000..4b9c99e97ab --- /dev/null +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/IBinaryDocumentFieldDecryptor.cs @@ -0,0 +1,42 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Threading; +using System.Threading.Tasks; + +namespace MongoDB.Driver.Core.WireProtocol +{ + /// + /// Interface for decrypting fields in a binary document. + /// + public interface IBinaryDocumentFieldDecryptor + { + /// + /// Decrypts the fields. + /// + /// The encrypted document bytes. + /// The cancellation token. + /// An unencrypted document. + byte[] DecryptFields(byte[] encryptedDocumentBytes, CancellationToken cancellationToken); + + /// + /// Decrypts the fields asynchronously. + /// + /// The encrypted document bytes. + /// The cancellation token. + /// An unencrypted document. + Task DecryptFieldsAsync(byte[] encryptedDocumentBytes, CancellationToken cancellationToken); + } +} diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs index 97ef64359ce..6d37bb3b113 100644 --- a/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs @@ -296,7 +296,10 @@ private void WriteType1Section(BsonBinaryWriter writer, Type1CommandMessageSecti stream.WriteCString(section.Identifier); var batch = section.Documents; - var maxDocumentSize = section.MaxDocumentSize ?? writer.Settings.MaxDocumentSize; + var maxDocumentSize = + IsEncryptionConfigured && MaxDocumentSize.HasValue + ? MaxDocumentSize.Value + : section.MaxDocumentSize ?? writer.Settings.MaxDocumentSize; writer.PushSettings(s => ((BsonBinaryWriterSettings)s).MaxDocumentSize = maxDocumentSize); writer.PushElementNameValidator(section.ElementNameValidator); try diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs index d4ac861a779..6735d5954ec 100644 --- a/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs @@ -68,6 +68,20 @@ protected UTF8Encoding Encoding } } + /// + /// Gets a flag whether encryption has been configured. + /// + /// + /// The flag whether encryption is configured or not. + /// + protected bool IsEncryptionConfigured + { + get + { + return _encoderSettings?.GetOrDefault(MessageEncoderSettingsName.BinaryDocumentFieldEncryptor, null) != null; + } + } + /// /// Gets the maximum size of the document. /// diff --git a/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs b/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs index 2c7122aba05..a669475cc9d 100644 --- a/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs +++ b/src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs @@ -13,12 +13,8 @@ * limitations under the License. */ -using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders { @@ -28,6 +24,16 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders public static class MessageEncoderSettingsName { // encoder settings used by the binary encoders + /// + /// The name of the binary document field decryptor setting. + /// + public const string BinaryDocumentFieldDecryptor = "BinaryDocumentFieldDecryptor"; + + /// + /// The name of the binary document field encryptor setting. + /// + public const string BinaryDocumentFieldEncryptor = "BinaryDocumentFieldEncryptor"; + /// /// The name of the FixOldBinarySubTypeOnInput setting. /// @@ -173,5 +179,15 @@ public T GetOrDefault(string name, T defaultValue) return defaultValue; } } + + /// + /// Sets the specified setting. + /// + /// The name. + /// The value. + public void Set(string name, object value) + { + _settings[name] = value; + } } } diff --git a/src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj b/src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj index dada86120dc..acf591fc50f 100644 --- a/src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj +++ b/src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj @@ -45,6 +45,7 @@ + diff --git a/src/MongoDB.Driver.Legacy/MongoServerSettings.cs b/src/MongoDB.Driver.Legacy/MongoServerSettings.cs index 2b01f48ce7c..df9c6ae0358 100644 --- a/src/MongoDB.Driver.Legacy/MongoServerSettings.cs +++ b/src/MongoDB.Driver.Legacy/MongoServerSettings.cs @@ -1062,6 +1062,7 @@ internal ClusterKey ToClusterKey() _heartbeatInterval, _heartbeatTimeout, _ipv6, + kmsProviders: null, // not supported for legacy _localThreshold, _maxConnectionIdleTime, _maxConnectionLifeTime, @@ -1069,6 +1070,7 @@ internal ClusterKey ToClusterKey() _minConnectionPoolSize, MongoDefaults.TcpReceiveBufferSize, _replicaSetName, + schemaMap: null, // not supported for legacy _scheme, _sdamLogFilename, MongoDefaults.TcpSendBufferSize, diff --git a/src/MongoDB.Driver/ClusterKey.cs b/src/MongoDB.Driver/ClusterKey.cs index 7e09a441e26..8f42a81b40b 100644 --- a/src/MongoDB.Driver/ClusterKey.cs +++ b/src/MongoDB.Driver/ClusterKey.cs @@ -16,7 +16,9 @@ using System; using System.Collections.Generic; using System.Linq; +using MongoDB.Bson; using MongoDB.Driver.Core.Configuration; +using MongoDB.Driver.Encryption; using MongoDB.Shared; namespace MongoDB.Driver @@ -35,6 +37,7 @@ internal class ClusterKey private readonly TimeSpan _heartbeatInterval; private readonly TimeSpan _heartbeatTimeout; private readonly bool _ipv6; + private readonly IReadOnlyDictionary> _kmsProviders; private readonly TimeSpan _localThreshold; private readonly TimeSpan _maxConnectionIdleTime; private readonly TimeSpan _maxConnectionLifeTime; @@ -42,6 +45,7 @@ internal class ClusterKey private readonly int _minConnectionPoolSize; private readonly int _receiveBufferSize; private readonly string _replicaSetName; + private readonly IReadOnlyDictionary _schemaMap; private readonly ConnectionStringScheme _scheme; private readonly string _sdamLogFilename; private readonly int _sendBufferSize; @@ -65,6 +69,7 @@ internal class ClusterKey TimeSpan heartbeatInterval, TimeSpan heartbeatTimeout, bool ipv6, + IReadOnlyDictionary> kmsProviders, TimeSpan localThreshold, TimeSpan maxConnectionIdleTime, TimeSpan maxConnectionLifeTime, @@ -72,6 +77,7 @@ internal class ClusterKey int minConnectionPoolSize, int receiveBufferSize, string replicaSetName, + IReadOnlyDictionary schemaMap, ConnectionStringScheme scheme, string sdamLogFilename, int sendBufferSize, @@ -93,6 +99,7 @@ internal class ClusterKey _heartbeatInterval = heartbeatInterval; _heartbeatTimeout = heartbeatTimeout; _ipv6 = ipv6; + _kmsProviders = kmsProviders; _localThreshold = localThreshold; _maxConnectionIdleTime = maxConnectionIdleTime; _maxConnectionLifeTime = maxConnectionLifeTime; @@ -100,6 +107,7 @@ internal class ClusterKey _minConnectionPoolSize = minConnectionPoolSize; _receiveBufferSize = receiveBufferSize; _replicaSetName = replicaSetName; + _schemaMap = schemaMap; _scheme = scheme; _sdamLogFilename = sdamLogFilename; _sendBufferSize = sendBufferSize; @@ -125,6 +133,7 @@ internal class ClusterKey public TimeSpan HeartbeatInterval { get { return _heartbeatInterval; } } public TimeSpan HeartbeatTimeout { get { return _heartbeatTimeout; } } public bool IPv6 { get { return _ipv6; } } + public IReadOnlyDictionary> KmsProviders { get { return _kmsProviders; } } public TimeSpan LocalThreshold { get { return _localThreshold; } } public TimeSpan MaxConnectionIdleTime { get { return _maxConnectionIdleTime; } } public TimeSpan MaxConnectionLifeTime { get { return _maxConnectionLifeTime; } } @@ -132,8 +141,9 @@ internal class ClusterKey public int MinConnectionPoolSize { get { return _minConnectionPoolSize; } } public int ReceiveBufferSize { get { return _receiveBufferSize; } } public string ReplicaSetName { get { return _replicaSetName; } } + public IReadOnlyDictionary SchemaMap { get { return _schemaMap; } } public ConnectionStringScheme Scheme { get { return _scheme; } } - public string SdamLogFilename { get { return _sdamLogFilename; }} + public string SdamLogFilename { get { return _sdamLogFilename; } } public int SendBufferSize { get { return _sendBufferSize; } } public IReadOnlyList Servers { get { return _servers; } } public TimeSpan ServerSelectionTimeout { get { return _serverSelectionTimeout; } } @@ -172,6 +182,7 @@ public override bool Equals(object obj) _heartbeatInterval == rhs._heartbeatInterval && _heartbeatTimeout == rhs._heartbeatTimeout && _ipv6 == rhs._ipv6 && + KmsProvidersHelper.Equals(_kmsProviders, rhs.KmsProviders) && _localThreshold == rhs._localThreshold && _maxConnectionIdleTime == rhs._maxConnectionIdleTime && _maxConnectionLifeTime == rhs._maxConnectionLifeTime && @@ -179,6 +190,7 @@ public override bool Equals(object obj) _minConnectionPoolSize == rhs._minConnectionPoolSize && _receiveBufferSize == rhs._receiveBufferSize && _replicaSetName == rhs._replicaSetName && + _schemaMap.IsEquivalentTo(rhs._schemaMap, object.Equals) && _scheme == rhs._scheme && _sdamLogFilename == rhs._sdamLogFilename && _sendBufferSize == rhs._sendBufferSize && diff --git a/src/MongoDB.Driver/ClusterRegistry.cs b/src/MongoDB.Driver/ClusterRegistry.cs index b1085d38a39..91b8f6ad295 100644 --- a/src/MongoDB.Driver/ClusterRegistry.cs +++ b/src/MongoDB.Driver/ClusterRegistry.cs @@ -84,10 +84,12 @@ private ClusterSettings ConfigureCluster(ClusterSettings settings, ClusterKey cl return settings.With( connectionMode: clusterKey.ConnectionMode.ToCore(), endPoints: Optional.Enumerable(endPoints), + kmsProviders: Optional.Create(clusterKey.KmsProviders), replicaSetName: clusterKey.ReplicaSetName, maxServerSelectionWaitQueueSize: clusterKey.WaitQueueSize, serverSelectionTimeout: clusterKey.ServerSelectionTimeout, postServerSelector: new LatencyLimitingServerSelector(clusterKey.LocalThreshold), + schemaMap: Optional.Create(clusterKey.SchemaMap), scheme: clusterKey.Scheme); } diff --git a/src/MongoDB.Driver/Encryption/AutoEncryptionLibMongoController.cs b/src/MongoDB.Driver/Encryption/AutoEncryptionLibMongoController.cs new file mode 100644 index 00000000000..95bca8afb11 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/AutoEncryptionLibMongoController.cs @@ -0,0 +1,227 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Driver.Core.Misc; +using MongoDB.Driver.Core.WireProtocol; +using MongoDB.Libmongocrypt; + +namespace MongoDB.Driver.Encryption +{ + internal sealed class AutoEncryptionLibMongoCryptController : LibMongoCryptControllerBase, IBinaryDocumentFieldDecryptor, IBinaryCommandFieldEncryptor + { + // private fields + private readonly IMongoClient _client; + private readonly IMongoClient _mongocryptdClient; + private readonly MongocryptdFactory _mongocryptdFactory; + + // constructors + public AutoEncryptionLibMongoCryptController( + IMongoClient client, + CryptClient cryptClient, + AutoEncryptionOptions autoEncryptionOptions) + : base( + Ensure.IsNotNull(cryptClient, nameof(cryptClient)), + Ensure.IsNotNull(autoEncryptionOptions, nameof(autoEncryptionOptions)).KeyVaultClient ?? client, + Ensure.IsNotNull(Ensure.IsNotNull(autoEncryptionOptions, nameof(autoEncryptionOptions)).KeyVaultNamespace, nameof(autoEncryptionOptions.KeyVaultNamespace))) + { + _client = Ensure.IsNotNull(client, nameof(client)); // _client might not be fully constructed at this point, don't call any instance methods on it yet + _mongocryptdFactory = new MongocryptdFactory(autoEncryptionOptions.ExtraOptions); + _mongocryptdClient = _mongocryptdFactory.CreateMongocryptdClient(); + } + + // public methods + public byte[] DecryptFields(byte[] encryptedDocumentBytes, CancellationToken cancellationToken) + { + try + { + using (var context = _cryptClient.StartDecryptionContext(encryptedDocumentBytes)) + { + return ProcessStates(context, databaseName: null, cancellationToken); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public async Task DecryptFieldsAsync(byte[] encryptedDocumentBytes, CancellationToken cancellationToken) + { + try + { + using (var context = _cryptClient.StartDecryptionContext(encryptedDocumentBytes)) + { + return await ProcessStatesAsync(context, databaseName: null, cancellationToken).ConfigureAwait(false); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public byte[] EncryptFields(string databaseName, byte[] unencryptedCommandBytes, CancellationToken cancellationToken) + { + try + { + using (var context = _cryptClient.StartEncryptionContext(databaseName, unencryptedCommandBytes)) + { + return ProcessStates(context, databaseName, cancellationToken); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public async Task EncryptFieldsAsync(string databaseName, byte[] unencryptedCommandBytes, CancellationToken cancellationToken) + { + try + { + using (var context = _cryptClient.StartEncryptionContext(databaseName, unencryptedCommandBytes)) + { + return await ProcessStatesAsync(context, databaseName, cancellationToken).ConfigureAwait(false); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + // protected methods + protected override void ProcessState(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + switch (context.State) + { + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: + ProcessNeedCollectionInfoState(context, databaseName, cancellationToken); + break; + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: + ProcessNeedMongoMarkingsState(context, databaseName, cancellationToken); + break; + default: + base.ProcessState(context, databaseName, cancellationToken); + break; + } + } + + protected override async Task ProcessStateAsync(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + switch (context.State) + { + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: + await ProcessNeedCollectionInfoStateAsync(context, databaseName, cancellationToken).ConfigureAwait(false); + break; + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: + await ProcessNeedMongoMarkingsStateAsync(context, databaseName, cancellationToken).ConfigureAwait(false); + break; + default: + await base.ProcessStateAsync(context, databaseName, cancellationToken).ConfigureAwait(false); + break; + } + } + + // private methods + private void ProcessNeedCollectionInfoState(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + var database = _client.GetDatabase(databaseName); + var filterBytes = context.GetOperation().ToArray(); + var filterDocument = new RawBsonDocument(filterBytes); + var filter = new BsonDocumentFilterDefinition(filterDocument); + var options = new ListCollectionsOptions { Filter = filter }; + var cursor = database.ListCollections(options, cancellationToken); + var results = cursor.ToList(cancellationToken); + FeedResults(context, results); + } + + private async Task ProcessNeedCollectionInfoStateAsync(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + var database = _client.GetDatabase(databaseName); + var filterBytes = context.GetOperation().ToArray(); + var filterDocument = new RawBsonDocument(filterBytes); + var filter = new BsonDocumentFilterDefinition(filterDocument); + var options = new ListCollectionsOptions { Filter = filter }; + var cursor = await database.ListCollectionsAsync(options, cancellationToken).ConfigureAwait(false); + var results = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false); + FeedResults(context, results); + } + + private void ProcessNeedMongoMarkingsState(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + var database = _mongocryptdClient.GetDatabase(databaseName); + var commandBytes = context.GetOperation().ToArray(); + var commandDocument = new RawBsonDocument(commandBytes); + var command = new BsonDocumentCommand(commandDocument); + + BsonDocument response = null; + for (var attempt = 1; response == null; attempt++) + { + try + { + response = database.RunCommand(command, cancellationToken: cancellationToken); + } + catch (TimeoutException) when (attempt == 1) + { + _mongocryptdFactory.SpawnMongocryptdProcessIfRequired(); + } + } + + RestoreDbNodeInResponse(commandDocument, response); + FeedResult(context, response); + } + + private async Task ProcessNeedMongoMarkingsStateAsync(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + var database = _mongocryptdClient.GetDatabase(databaseName); + var commandBytes = context.GetOperation().ToArray(); + var commandDocument = new RawBsonDocument(commandBytes); + var command = new BsonDocumentCommand(commandDocument); + + BsonDocument response = null; + for (var attempt = 1; response == null; attempt++) + { + try + { + response = await database.RunCommandAsync(command, cancellationToken: cancellationToken).ConfigureAwait(false); + } + catch (TimeoutException) when (attempt == 1) + { + _mongocryptdFactory.SpawnMongocryptdProcessIfRequired(); + } + } + + RestoreDbNodeInResponse(commandDocument, response); + FeedResult(context, response); + } + + private void RestoreDbNodeInResponse(BsonDocument request, BsonDocument response) + { + if (request.TryGetElement("$db", out var db)) + { + var result = response["result"].AsBsonDocument; + if (!result.Contains("$db")) + { + result.Add(db); + } + } + } + } +} diff --git a/src/MongoDB.Driver/Encryption/AutoEncryptionOptions.cs b/src/MongoDB.Driver/Encryption/AutoEncryptionOptions.cs new file mode 100644 index 00000000000..2c854ca923a --- /dev/null +++ b/src/MongoDB.Driver/Encryption/AutoEncryptionOptions.cs @@ -0,0 +1,229 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MongoDB.Bson; +using MongoDB.Driver.Core.Misc; +using MongoDB.Shared; + +namespace MongoDB.Driver.Encryption +{ + /// + /// Auto encryption options. + /// + public class AutoEncryptionOptions + { + // private fields + private readonly bool _bypassAutoEncryption; + private readonly IReadOnlyDictionary _extraOptions; + private readonly IMongoClient _keyVaultClient; + private readonly CollectionNamespace _keyVaultNamespace; + private readonly IReadOnlyDictionary> _kmsProviders; + private readonly IReadOnlyDictionary _schemaMap; + + // constructors + /// + /// Initializes a new instance of the class. + /// + /// The keyVault namespace. + /// The kms providers. + /// The bypass auto encryption flag. + /// The extra options. + /// The keyVault client. + /// The schema map. + public AutoEncryptionOptions( + CollectionNamespace keyVaultNamespace, + IReadOnlyDictionary> kmsProviders, + Optional bypassAutoEncryption = default, + Optional> extraOptions = default, + Optional keyVaultClient = default, + Optional> schemaMap = default) + { + _keyVaultNamespace = Ensure.IsNotNull(keyVaultNamespace, nameof(keyVaultNamespace)); + _kmsProviders = Ensure.IsNotNull(kmsProviders, nameof(kmsProviders)); + _bypassAutoEncryption = bypassAutoEncryption.WithDefault(false); + _extraOptions = extraOptions.WithDefault(null); + _keyVaultClient = keyVaultClient.WithDefault(null); + _schemaMap = schemaMap.WithDefault(null); + + EncryptionExtraOptionsValidator.EnsureThatExtraOptionsAreValid(_extraOptions); + KmsProvidersHelper.EnsureKmsProvidersAreValid(_kmsProviders); + } + + // public properties + /// + /// Gets a value indicating whether to bypass automatic encryption. + /// + /// + /// true if automatic encryption should be bypasssed; otherwise, false. + /// + public bool BypassAutoEncryption => _bypassAutoEncryption; + + /// + /// Gets the extra options. + /// + /// + /// The extra options. + /// + public IReadOnlyDictionary ExtraOptions => _extraOptions; + + /// + /// Gets the key vault client. + /// + /// + /// The key vault client. + /// + public IMongoClient KeyVaultClient => _keyVaultClient; + + /// + /// Gets the key vault namespace. + /// + /// + /// The key vault namespace. + /// + public CollectionNamespace KeyVaultNamespace => _keyVaultNamespace; + + /// + /// Gets the KMS providers. + /// + /// + /// The KMS providers. + /// + public IReadOnlyDictionary> KmsProviders => _kmsProviders; + + /// + /// Gets the schema map. + /// + /// + /// The schema map. + /// + public IReadOnlyDictionary SchemaMap => _schemaMap; + + /// + /// Returns a new instance of the class. + /// + /// The keyVault namespace. + /// The kms providers. + /// The bypass auto encryption flag. + /// The extra options. + /// The keyVault client. + /// The schema map. + /// A new instance of . + public AutoEncryptionOptions With( + Optional keyVaultNamespace = default, + Optional>> kmsProviders = default, + Optional bypassAutoEncryption = default, + Optional> extraOptions = default, + Optional keyVaultClient = default, + Optional> schemaMap = default) + { + return new AutoEncryptionOptions( + keyVaultNamespace.WithDefault(_keyVaultNamespace), + kmsProviders.WithDefault(_kmsProviders), + bypassAutoEncryption.WithDefault(_bypassAutoEncryption), + Optional.Create(extraOptions.WithDefault(_extraOptions)), + Optional.Create(keyVaultClient.WithDefault(_keyVaultClient)), + Optional.Create(schemaMap.WithDefault(_schemaMap))); + } + + /// + public override bool Equals(object obj) + { + if (object.ReferenceEquals(obj, null) || GetType() != obj.GetType()) { return false; } + var rhs = (AutoEncryptionOptions)obj; + + return + _bypassAutoEncryption.Equals(rhs._bypassAutoEncryption) && + ExtraOptionsEquals(_extraOptions, rhs._extraOptions) && + object.ReferenceEquals(_keyVaultClient, rhs._keyVaultClient) && + _keyVaultNamespace.Equals(rhs._keyVaultNamespace) && + KmsProvidersHelper.Equals(_kmsProviders, rhs._kmsProviders) && + _schemaMap.IsEquivalentTo(rhs._schemaMap, object.Equals); + } + + /// + public override int GetHashCode() + { + return new Hasher() + .Hash(_bypassAutoEncryption) + .HashElements(_extraOptions) + .Hash(_keyVaultClient) + .Hash(_keyVaultNamespace) + .HashElements(_kmsProviders) + .HashElements(_schemaMap) + .GetHashCode(); + } + + /// + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append("{ "); + sb.AppendFormat("BypassAutoEncryption : {0}, ", _bypassAutoEncryption); + sb.AppendFormat("KmsProviders : {0}, ", _kmsProviders.ToJson()); + if (_keyVaultNamespace != null) + { + sb.AppendFormat("KeyVaultNamespace : \"{0}\", ", _keyVaultNamespace.FullName); + } + if (_extraOptions != null) + { + sb.AppendFormat("ExtraOptions : {0}, ", _extraOptions.ToJson()); + } + if (_schemaMap != null) + { + sb.AppendFormat("SchemaMap : {0}, ", _schemaMap.ToJson()); + } + sb.Remove(sb.Length - 2, 2); + sb.Append(" }"); + return sb.ToString(); + } + + // private methods + private bool ExtraOptionsEquals(IReadOnlyDictionary x, IReadOnlyDictionary y) + { + return x.IsEquivalentTo(y, ExtraOptionEquals); + } + + private bool ExtraOptionEquals(object x, object y) + { + if (object.ReferenceEquals(x, y)) + { + return true; + } + + if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null)) + { + return false; + } + + if (x.GetType() != y.GetType()) + { + return false; + } + + if (x is IEnumerable enumerableX) + { + var enumerableY = (IEnumerable)y; + return enumerableX.SequenceEqual(enumerableY); + } + else + { + return x.Equals(y); + } + } + } +} diff --git a/src/MongoDB.Driver/Encryption/ClientEncryption.cs b/src/MongoDB.Driver/Encryption/ClientEncryption.cs new file mode 100644 index 00000000000..1892450f0ea --- /dev/null +++ b/src/MongoDB.Driver/Encryption/ClientEncryption.cs @@ -0,0 +1,151 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Driver.Core.Clusters; +using MongoDB.Libmongocrypt; + +namespace MongoDB.Driver.Encryption +{ + /// + /// Explicit client encryption. + /// + public sealed class ClientEncryption : IDisposable + { + // private fields + private readonly CryptClient _cryptClient; + private bool _disposed; + private readonly ExplicitEncryptionLibMongoCryptController _libMongoCryptController; + + // constructors + /// + /// Initializes a new instance of the class. + /// + /// The client encryption options. + public ClientEncryption(ClientEncryptionOptions clientEncryptionOptions) + { + _cryptClient = CryptClientCreator.CreateCryptClient( + kmsProviders: clientEncryptionOptions.KmsProviders, + schemaMap: null); + _libMongoCryptController = new ExplicitEncryptionLibMongoCryptController( + _cryptClient, + clientEncryptionOptions); + } + + // public methods + /// + /// Creates a data key. + /// + /// The kms provider. + /// The data key options. + /// The cancellation token. + /// A data key. + public Guid CreateDataKey(string kmsProvider, DataKeyOptions dataKeyOptions, CancellationToken cancellationToken) + { + return _libMongoCryptController.CreateDataKey( + kmsProvider, + dataKeyOptions.AlternateKeyNames, + dataKeyOptions.MasterKey, + cancellationToken); + } + + /// + /// Creates a data key. + /// + /// The kms provider. + /// The data key options. + /// The cancellation token. + /// A data key. + public Task CreateDataKeyAsync(string kmsProvider, DataKeyOptions dataKeyOptions, CancellationToken cancellationToken) + { + return _libMongoCryptController.CreateDataKeyAsync( + kmsProvider, + dataKeyOptions.AlternateKeyNames, + dataKeyOptions.MasterKey, + cancellationToken); + } + + /// + /// Decrypts the specified value. + /// + /// The value. + /// The cancellation token. + /// The decrypted value. + public BsonValue Decrypt(BsonBinaryData value, CancellationToken cancellationToken) + { + return _libMongoCryptController.DecryptField(value, cancellationToken); + } + + /// + /// Decrypts the specified value. + /// + /// The value. + /// The cancellation token. + /// The decrypted value. + public Task DecryptAsync(BsonBinaryData value, CancellationToken cancellationToken) + { + return _libMongoCryptController.DecryptFieldAsync(value, cancellationToken); + } + + /// + public void Dispose() + { + if (!_disposed) + { + _cryptClient.Dispose(); + _disposed = true; + } + } + + /// + /// Encrypts the specified value. + /// + /// The value. + /// The encrypt options. + /// The cancellation token. + /// The encrypted value. + public BsonBinaryData Encrypt(BsonValue value, EncryptOptions encryptOptions, CancellationToken cancellationToken) + { + var algorithm = (EncryptionAlgorithm)Enum.Parse(typeof(EncryptionAlgorithm), encryptOptions.Algorithm); + return _libMongoCryptController.EncryptField( + value, + encryptOptions.KeyId, + encryptOptions.AlternateKeyName, + algorithm, + cancellationToken); + } + + /// + /// Encrypts the specified value. + /// + /// The value. + /// The encrypt options. + /// The cancellation token. + /// The encrypted value. + public Task EncryptAsync(BsonValue value, EncryptOptions encryptOptions, CancellationToken cancellationToken) + { + var algorithm = (EncryptionAlgorithm)Enum.Parse(typeof(EncryptionAlgorithm), encryptOptions.Algorithm); + return _libMongoCryptController.EncryptFieldAsync( + value, + encryptOptions.KeyId, + encryptOptions.AlternateKeyName, + algorithm, + cancellationToken); + } + } +} diff --git a/src/MongoDB.Driver/Encryption/ClientEncryptionOptions.cs b/src/MongoDB.Driver/Encryption/ClientEncryptionOptions.cs new file mode 100644 index 00000000000..1a50bc43ee8 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/ClientEncryptionOptions.cs @@ -0,0 +1,92 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Collections.Generic; +using MongoDB.Driver.Core.Misc; + +namespace MongoDB.Driver.Encryption +{ + /// + /// Client encryption options. + /// + public class ClientEncryptionOptions + { + // private fields + private readonly IMongoClient _keyVaultClient; + private readonly CollectionNamespace _keyVaultNamespace; + private readonly IReadOnlyDictionary> _kmsProviders; + + // constructors + /// + /// Initializes a new instance of the class. + /// + /// The key vault client. + /// The key vault namespace. + /// The KMS providers. + public ClientEncryptionOptions( + IMongoClient keyVaultClient, + CollectionNamespace keyVaultNamespace, + IReadOnlyDictionary> kmsProviders) + { + _keyVaultClient = Ensure.IsNotNull(keyVaultClient, nameof(keyVaultClient)); + _keyVaultNamespace = Ensure.IsNotNull(keyVaultNamespace, nameof(keyVaultNamespace)); + _kmsProviders = Ensure.IsNotNull(kmsProviders, nameof(kmsProviders)); + + KmsProvidersHelper.EnsureKmsProvidersAreValid(_kmsProviders); + } + + // public properties + /// + /// Gets the key vault client. + /// + /// + /// The key vault client. + /// + public IMongoClient KeyVaultClient => _keyVaultClient; + + /// + /// Gets the key vault namespace. + /// + /// + /// The key vault namespace. + /// + public CollectionNamespace KeyVaultNamespace => _keyVaultNamespace; + + /// + /// Gets the KMS providers. + /// + /// + /// The KMS providers. + /// + public IReadOnlyDictionary> KmsProviders => _kmsProviders; + + /// + /// Returns a new ClientEncryptionOptions instance with some settings changed. + /// + /// The key vault client. + /// The key vault namespace. + /// The KMS providers. + public ClientEncryptionOptions With( + Optional keyVaultClient = default, + Optional keyVaultNamespace = default, + Optional>> kmsProviders = default) + { + return new ClientEncryptionOptions( + keyVaultClient: keyVaultClient.WithDefault(_keyVaultClient), + keyVaultNamespace: keyVaultNamespace.WithDefault(_keyVaultNamespace), + kmsProviders: kmsProviders.WithDefault(_kmsProviders)); + } + } +} diff --git a/src/MongoDB.Driver/Encryption/DataKeyOptions.cs b/src/MongoDB.Driver/Encryption/DataKeyOptions.cs new file mode 100644 index 00000000000..c564c1b7cc1 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/DataKeyOptions.cs @@ -0,0 +1,76 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Collections.Generic; +using MongoDB.Bson; + +namespace MongoDB.Driver.Encryption +{ + /// + /// Options for creating a data key. + /// + public class DataKeyOptions + { + // private fields + private readonly IReadOnlyList _alternateKeyNames; + private readonly BsonDocument _masterKey; + + // constructors + /// + /// Initializes a new instance of the class. + /// + /// The alternate key names. + /// The master key. + public DataKeyOptions( + Optional> alternateKeyNames = default, + Optional masterKey = default) + { + _alternateKeyNames = alternateKeyNames.WithDefault(null); + _masterKey = masterKey.WithDefault(null); + } + + /// + /// Gets the alternate key names. + /// + /// + /// The alternate key names. + /// + public IReadOnlyList AlternateKeyNames => _alternateKeyNames; + + // public properties + /// + /// Gets the master key. + /// + /// + /// The master key. + /// + public BsonDocument MasterKey => _masterKey; + + /// + /// Returns a new DataKeyOptions instance with some settings changed. + /// + /// The alternate key names. + /// The master key. + /// A new DataKeyOptions instance. + public DataKeyOptions With( + Optional> alternateKeyNames = default, + Optional masterKey = default) + { + return new DataKeyOptions( + alternateKeyNames: Optional.Create(alternateKeyNames.WithDefault(_alternateKeyNames)), + masterKey: Optional.Create(masterKey.WithDefault(_masterKey))); + } + } +} diff --git a/src/MongoDB.Driver/Encryption/EncryptOptions.cs b/src/MongoDB.Driver/Encryption/EncryptOptions.cs new file mode 100644 index 00000000000..d6903989a67 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/EncryptOptions.cs @@ -0,0 +1,99 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using MongoDB.Driver.Core.Misc; +using System; + +namespace MongoDB.Driver.Encryption +{ + /// + /// Encryption options for explicit encryption. + /// + public class EncryptOptions + { + // private fields + private readonly string _algorithm; + private readonly string _alternateKeyName; + private readonly Guid? _keyId; + + // constructors + /// + /// Initializes a new instance of the class. + /// + /// The encryption algorithm. + /// The alternate key name. + /// The key Id. + public EncryptOptions( + string algorithm, + Optional alternateKeyName = default, + Optional keyId = default) + { + _algorithm = Ensure.IsNotNull(algorithm, nameof(algorithm)); + _alternateKeyName = alternateKeyName.WithDefault(null); + _keyId = keyId.WithDefault(null); + EnsureThatOptionsAreValid(); + } + + // public properties + /// + /// Gets the algorithm. + /// + /// + /// The algorithm. + /// + public string Algorithm=> _algorithm; + + /// + /// Gets the alternate key name. + /// + /// + /// The alternate key name. + /// + public string AlternateKeyName => _alternateKeyName; + + /// + /// Gets the key identifier. + /// + /// + /// The key identifier. + /// + public Guid? KeyId => _keyId; + + /// + /// Returns a new EncryptOptions instance with some settings changed. + /// + /// The encryption algorithm. + /// The alternate key name. + /// The keyId. + /// A new EncryptOptions instance. + public EncryptOptions With( + Optional algorithm = default, + Optional alternateKeyName = default, + Optional keyId = default) + { + return new EncryptOptions( + algorithm: algorithm.WithDefault(_algorithm), + alternateKeyName: alternateKeyName.WithDefault(_alternateKeyName), + keyId: keyId.WithDefault(_keyId)); + } + + // private methods + private void EnsureThatOptionsAreValid() + { + Ensure.That(!(!_keyId.HasValue && _alternateKeyName == null), "Key Id and AlternateKeyName may not both be null."); + Ensure.That(!(_keyId.HasValue && _alternateKeyName != null), "Key Id and AlternateKeyName may not both be set."); + } + } +} diff --git a/src/MongoDB.Driver/Encryption/ExplicitEncryptionLibMongoCryptController.cs b/src/MongoDB.Driver/Encryption/ExplicitEncryptionLibMongoCryptController.cs new file mode 100644 index 00000000000..ddc8501c9d2 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/ExplicitEncryptionLibMongoCryptController.cs @@ -0,0 +1,283 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver.Core.Misc; +using MongoDB.Libmongocrypt; + +namespace MongoDB.Driver.Encryption +{ + internal sealed class ExplicitEncryptionLibMongoCryptController : LibMongoCryptControllerBase + { + // constructors + public ExplicitEncryptionLibMongoCryptController( + CryptClient cryptClient, + ClientEncryptionOptions clientEncryptionOptions) + : base( + Ensure.IsNotNull(cryptClient, nameof(cryptClient)), + Ensure.IsNotNull(Ensure.IsNotNull(clientEncryptionOptions, nameof(clientEncryptionOptions)).KeyVaultClient, nameof(clientEncryptionOptions.KeyVaultClient)), + Ensure.IsNotNull(Ensure.IsNotNull(clientEncryptionOptions, nameof(clientEncryptionOptions)).KeyVaultNamespace, nameof(clientEncryptionOptions.KeyVaultNamespace))) + { + } + + // public methods + public Guid CreateDataKey( + string kmsProvider, + IReadOnlyList alternateKeyNames, + BsonDocument masterKey, + CancellationToken cancellationToken) + { + try + { + var kmsKeyId = GetKmsKeyId(kmsProvider, alternateKeyNames, masterKey); + + using (var context = _cryptClient.StartCreateDataKeyContext(kmsKeyId)) + { + var wrappedKeyBytes = ProcessStates(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken); + + var wrappedKeyDocument = new RawBsonDocument(wrappedKeyBytes); + var keyId = UnwrapKeyId(wrappedKeyDocument); + + _keyVaultCollection.Value.InsertOne(wrappedKeyDocument, cancellationToken: cancellationToken); + + return keyId; + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public async Task CreateDataKeyAsync( + string kmsProvider, + IReadOnlyList alternateKeyNames, + BsonDocument masterKey, + CancellationToken cancellationToken) + { + try + { + var kmsKeyId = GetKmsKeyId(kmsProvider, alternateKeyNames, masterKey); + + using (var context = _cryptClient.StartCreateDataKeyContext(kmsKeyId)) + { + var wrappedKeyBytes = await ProcessStatesAsync(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken).ConfigureAwait(false); + + var wrappedKeyDocument = new RawBsonDocument(wrappedKeyBytes); + var keyId = UnwrapKeyId(wrappedKeyDocument); + + await _keyVaultCollection.Value.InsertOneAsync(wrappedKeyDocument, cancellationToken: cancellationToken).ConfigureAwait(false); + + return keyId; + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public BsonValue DecryptField(BsonBinaryData encryptedValue, CancellationToken cancellationToken) + { + try + { + var wrappedValueBytes = GetWrappedValueBytes(encryptedValue); + + using (var context = _cryptClient.StartExplicitDecryptionContext(wrappedValueBytes)) + { + var wrappedBytes = ProcessStates(context, databaseName: null, cancellationToken); + return UnwrapDecryptedValue(wrappedBytes); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public async Task DecryptFieldAsync(BsonBinaryData wrappedBinaryValue, CancellationToken cancellationToken) + { + try + { + var wrappedValueBytes = GetWrappedValueBytes(wrappedBinaryValue); + + using (var context = _cryptClient.StartExplicitDecryptionContext(wrappedValueBytes)) + { + var wrappedBytes = await ProcessStatesAsync(context, databaseName: null, cancellationToken).ConfigureAwait(false); + return UnwrapDecryptedValue(wrappedBytes); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public BsonBinaryData EncryptField( + BsonValue value, + Guid? keyId, + string alternateKeyName, + EncryptionAlgorithm encryptionAlgorithm, + CancellationToken cancellationToken) + { + try + { + var wrappedValueBytes = GetWrappedValueBytes(value); + + CryptContext context; + if (keyId.HasValue && alternateKeyName != null) + { + throw new ArgumentException("keyId and alternateKeyName cannot both be provided."); + } + else if (keyId.HasValue) + { + var keyBytes = GuidConverter.ToBytes(keyId.Value, GuidRepresentation.Standard); + context = _cryptClient.StartExplicitEncryptionContextWithKeyId(keyBytes, encryptionAlgorithm, wrappedValueBytes); + } + else if (alternateKeyName != null) + { + var wrappedAlternateKeyNameBytes = GetWrappedAlternateKeyNameBytes(alternateKeyName); + context = _cryptClient.StartExplicitEncryptionContextWithKeyAltName(wrappedAlternateKeyNameBytes, encryptionAlgorithm, wrappedValueBytes); + } + else + { + throw new ArgumentException("Either keyId or alternateKeyName must be provided."); + } + + using (context) + { + var wrappedBytes = ProcessStates(context, databaseName: null, cancellationToken); + return UnwrapEncryptedValue(wrappedBytes); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + public async Task EncryptFieldAsync( + BsonValue value, + Guid? keyId, + string alternateKeyName, + EncryptionAlgorithm encryptionAlgorithm, + CancellationToken cancellationToken) + { + try + { + var wrappedValueBytes = GetWrappedValueBytes(value); + + CryptContext context; + if (keyId.HasValue && alternateKeyName != null) + { + throw new ArgumentException("keyId and alternateKeyName cannot both be provided."); + } + else if (keyId.HasValue) + { + var bytes = GuidConverter.ToBytes(keyId.Value, GuidRepresentation.Standard); + context = _cryptClient.StartExplicitEncryptionContextWithKeyId(bytes, encryptionAlgorithm, wrappedValueBytes); + } + else if (alternateKeyName != null) + { + var wrappedAlternateKeyNameBytes = GetWrappedAlternateKeyNameBytes(alternateKeyName); + context = _cryptClient.StartExplicitEncryptionContextWithKeyAltName(wrappedAlternateKeyNameBytes, encryptionAlgorithm, wrappedValueBytes); + } + else + { + throw new ArgumentException("Either keyId or alternateKeyName must be provided."); + } + + using (context) + { + var wrappedBytes = await ProcessStatesAsync(context, databaseName: null, cancellationToken).ConfigureAwait(false); + return UnwrapEncryptedValue(wrappedBytes); + } + } + catch (Exception ex) + { + throw new MongoEncryptionException(ex); + } + } + + // private methods + private IKmsKeyId GetKmsKeyId(string kmsProvider, IReadOnlyList alternateKeyNames, BsonDocument masterKey) + { + IEnumerable wrappedAlternateKeyNamesBytes = null; + if (alternateKeyNames != null) + { + wrappedAlternateKeyNamesBytes = alternateKeyNames.Select(GetWrappedAlternateKeyNameBytes); + } + + switch (kmsProvider) + { + case "aws": + var customerMasterKey = masterKey["key"].ToString(); + var region = masterKey["region"].ToString(); + return wrappedAlternateKeyNamesBytes != null + ? new AwsKeyId(customerMasterKey, region, wrappedAlternateKeyNamesBytes) + : new AwsKeyId(customerMasterKey, region); + case "local": + return wrappedAlternateKeyNamesBytes != null ? new LocalKeyId(wrappedAlternateKeyNamesBytes) : new LocalKeyId(); + default: + throw new ArgumentException($"Invalid kmsProvider {kmsProvider}."); + } + } + + private byte[] GetWrappedAlternateKeyNameBytes(string value) + { + return + !string.IsNullOrWhiteSpace(value) + ? new BsonDocument("keyAltName", value).ToBson() + : null; + } + + private byte[] GetWrappedValueBytes(BsonValue value) + { + var wrappedValue = new BsonDocument("v", value); + var writerSettings = BsonBinaryWriterSettings.Defaults.Clone(); + writerSettings.GuidRepresentation = GuidRepresentation.Unspecified; + return wrappedValue.ToBson(writerSettings: writerSettings); + } + + private BsonValue UnwrapDecryptedValue(byte[] wrappedBytes) + { + var wrappedDocument = new RawBsonDocument(wrappedBytes); + return wrappedDocument["v"]; + } + + private BsonBinaryData UnwrapEncryptedValue(byte[] encryptedWrappedBytes) + { + var wrappedDocument = new RawBsonDocument(encryptedWrappedBytes); + return wrappedDocument["v"].AsBsonBinaryData; + } + + private Guid UnwrapKeyId(RawBsonDocument wrappedKeyDocument) + { + var keyId = wrappedKeyDocument["_id"].AsBsonBinaryData; + if (keyId.SubType != BsonBinarySubType.UuidStandard) + { + throw new InvalidOperationException($"KeyId sub type must be UuidStandard, not: {keyId.SubType}."); + } + return GuidConverter.FromBytes(keyId.Bytes, GuidRepresentation.Standard); + } + } +} diff --git a/src/MongoDB.Driver/Encryption/KmsProvidersHelper.cs b/src/MongoDB.Driver/Encryption/KmsProvidersHelper.cs new file mode 100644 index 00000000000..910ebf4665a --- /dev/null +++ b/src/MongoDB.Driver/Encryption/KmsProvidersHelper.cs @@ -0,0 +1,64 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using MongoDB.Driver.Core.Misc; + +namespace MongoDB.Driver.Encryption +{ + internal static class KmsProvidersHelper + { + public static void EnsureKmsProvidersAreValid(IReadOnlyDictionary> kmsProviders) + { + foreach (var kmsProvider in kmsProviders) + { + foreach (var option in Ensure.IsNotNull(kmsProvider.Value, nameof(kmsProvider))) + { + var optionValue = Ensure.IsNotNull(option.Value, "kmsProviderOption"); + var isValid = optionValue is byte[] || optionValue is string; + if (!isValid) + { + throw new ArgumentException($"Invalid kms provider option type: {optionValue.GetType().Name}."); + } + } + } + } + + public static bool Equals(IReadOnlyDictionary> x, IReadOnlyDictionary> y) + { + return x.IsEquivalentTo(y, KmsProviderIsEquivalentTo); + } + + // private methods + private static bool KmsProviderIsEquivalentTo(IReadOnlyDictionary x, IReadOnlyDictionary y) + { + return x.IsEquivalentTo(y, KmsProviderOptionEquals); + } + + private static bool KmsProviderOptionEquals(object x, object y) + { + if (x is byte[] xBytes && y is byte[] yBytes) + { + return xBytes.SequenceEqual(yBytes); + } + else + { + return object.Equals(x, y); + } + } + } +} diff --git a/src/MongoDB.Driver/Encryption/LibMongoCryptControllerBase.cs b/src/MongoDB.Driver/Encryption/LibMongoCryptControllerBase.cs new file mode 100644 index 00000000000..e5beededa25 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/LibMongoCryptControllerBase.cs @@ -0,0 +1,240 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Net.Security; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Libmongocrypt; + +namespace MongoDB.Driver.Encryption +{ + internal abstract class LibMongoCryptControllerBase + { + // protected fields + protected readonly CryptClient _cryptClient; + protected readonly IMongoClient _keyVaultClient; + protected readonly Lazy> _keyVaultCollection; + protected readonly CollectionNamespace _keyVaultNamespace; + + // constructors + protected LibMongoCryptControllerBase( + CryptClient cryptClient, + IMongoClient keyVaultClient, + CollectionNamespace keyVaultNamespace) + { + _cryptClient = cryptClient; + _keyVaultClient = keyVaultClient; // _keyVaultClient might not be fully constructed at this point, don't call any instance methods on it yet + _keyVaultNamespace = keyVaultNamespace; + _keyVaultCollection = new Lazy>(GetKeyVaultCollection); // delay use _keyVaultClient + } + + // protected methods + protected void FeedResult(CryptContext context, BsonDocument document) + { + var writerSettings = new BsonBinaryWriterSettings { GuidRepresentation = GuidRepresentation.Unspecified }; + var documentBytes = document.ToBson(writerSettings: writerSettings); + context.Feed(documentBytes); + context.MarkDone(); + } + + protected void FeedResults(CryptContext context, IEnumerable documents) + { + var writerSettings = new BsonBinaryWriterSettings { GuidRepresentation = GuidRepresentation.Unspecified }; + foreach (var document in documents) + { + var documentBytes = document.ToBson(writerSettings: writerSettings); + context.Feed(documentBytes); + } + context.MarkDone(); + } + + protected virtual void ProcessState(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + switch (context.State) + { + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS: + ProcessNeedKmsState(context, cancellationToken); + break; + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS: + ProcessNeedMongoKeysState(context, cancellationToken); + break; + default: + throw new InvalidOperationException($"Unexpected context state: {context.State}."); + } + } + + protected virtual async Task ProcessStateAsync(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + switch (context.State) + { + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS: + await ProcessNeedKmsStateAsync(context, cancellationToken).ConfigureAwait(false); + break; + case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS: + await ProcessNeedMongoKeysStateAsync(context, cancellationToken).ConfigureAwait(false); + break; + default: + throw new InvalidOperationException($"Unexpected context state: {context.State}."); + } + } + + protected byte[] ProcessStates(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + byte[] result = null; + while (context.State != CryptContext.StateCode.MONGOCRYPT_CTX_DONE) + { + if (context.State == CryptContext.StateCode.MONGOCRYPT_CTX_READY) + { + result = ProcessReadyState(context); + } + else + { + ProcessState(context, databaseName, cancellationToken); + } + } + return result; + } + + protected async Task ProcessStatesAsync(CryptContext context, string databaseName, CancellationToken cancellationToken) + { + byte[] result = null; + while (context.State != CryptContext.StateCode.MONGOCRYPT_CTX_DONE) + { + if (context.State == CryptContext.StateCode.MONGOCRYPT_CTX_READY) + { + result = ProcessReadyState(context); + } + else + { + await ProcessStateAsync(context, databaseName, cancellationToken).ConfigureAwait(false); + } + } + return result; + } + + // private methods + private IMongoCollection GetKeyVaultCollection() + { + var keyVaultDatabase = _keyVaultClient.GetDatabase(_keyVaultNamespace.DatabaseNamespace.DatabaseName); + return keyVaultDatabase.GetCollection(_keyVaultNamespace.CollectionName); + } + + private void ProcessNeedKmsState(CryptContext context, CancellationToken cancellationToken) + { + var requests = context.GetKmsMessageRequests(); + foreach (var request in requests) + { + SendKmsRequest(request, cancellationToken); + } + requests.MarkDone(); + } + + private async Task ProcessNeedKmsStateAsync(CryptContext context, CancellationToken cancellationToken) + { + var requests = context.GetKmsMessageRequests(); + foreach (var request in requests) + { + await SendKmsRequestAsync(request, cancellationToken).ConfigureAwait(false); + } + requests.MarkDone(); + } + + private void ProcessNeedMongoKeysState(CryptContext context, CancellationToken cancellationToken) + { + var filterBytes = context.GetOperation().ToArray(); + var filterDocument = new RawBsonDocument(filterBytes); + var filter = new BsonDocumentFilterDefinition(filterDocument); + var cursor = _keyVaultCollection.Value.FindSync(filter, cancellationToken: cancellationToken); + var results = cursor.ToList(cancellationToken); + FeedResults(context, results); + } + + private async Task ProcessNeedMongoKeysStateAsync(CryptContext context, CancellationToken cancellationToken) + { + var filterBytes = context.GetOperation().ToArray(); + var filterDocument = new RawBsonDocument(filterBytes); + var filter = new BsonDocumentFilterDefinition(filterDocument); + var cursor = await _keyVaultCollection.Value.FindAsync(filter, cancellationToken: cancellationToken).ConfigureAwait(false); + var results = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false); + FeedResults(context, results); + } + + private byte[] ProcessReadyState(CryptContext context) + { + return context.FinalizeForEncryption().ToArray(); + } + + private void SendKmsRequest(KmsRequest request, CancellationToken cancellation) + { + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + socket.Connect(request.Endpoint, 443); + + using (var networkStream = new NetworkStream(socket, ownsSocket: true)) + using (var sslStream = new SslStream(networkStream, leaveInnerStreamOpen: false)) + { +#if NETSTANDARD1_5 + sslStream.AuthenticateAsClientAsync(request.Endpoint).ConfigureAwait(false).GetAwaiter().GetResult(); +#else + sslStream.AuthenticateAsClient(request.Endpoint); +#endif + + var requestBytes = request.Message.ToArray(); + sslStream.Write(requestBytes); + + var buffer = new byte[4096]; + while (request.BytesNeeded > 0) + { + var count = sslStream.Read(buffer, 0, buffer.Length); + var responseBytes = new byte[count]; + Buffer.BlockCopy(buffer, 0, responseBytes, 0, count); + request.Feed(responseBytes); + } + } + } + + private async Task SendKmsRequestAsync(KmsRequest request, CancellationToken cancellation) + { + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); +#if NETSTANDARD1_5 + await socket.ConnectAsync(request.Endpoint, 443).ConfigureAwait(false); +#else + await Task.Factory.FromAsync(socket.BeginConnect(request.Endpoint, 443, null, null), socket.EndConnect).ConfigureAwait(false); +#endif + + using (var networkStream = new NetworkStream(socket, ownsSocket: true)) + using (var sslStream = new SslStream(networkStream, leaveInnerStreamOpen: false)) + { + await sslStream.AuthenticateAsClientAsync(request.Endpoint).ConfigureAwait(false); + + var requestBytes = request.Message.ToArray(); + await sslStream.WriteAsync(requestBytes, 0, requestBytes.Length).ConfigureAwait(false); + + var buffer = new byte[4096]; + while (request.BytesNeeded > 0) + { + var count = await sslStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + var responseBytes = new byte[count]; + Buffer.BlockCopy(buffer, 0, responseBytes, 0, count); + request.Feed(responseBytes); + } + } + } + } +} diff --git a/src/MongoDB.Driver/Encryption/MongoEncryptionException.cs b/src/MongoDB.Driver/Encryption/MongoEncryptionException.cs new file mode 100644 index 00000000000..3c54bfd4ff0 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/MongoEncryptionException.cs @@ -0,0 +1,41 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#if NET452 +using System.Runtime.Serialization; +#endif + +using System; + +namespace MongoDB.Driver.Encryption +{ + /// + /// Represents an encryption exception. + /// +#if NET452 + [Serializable] +#endif + public class MongoEncryptionException : MongoClientException + { + /// + /// Initializes a new instance of the class. + /// + /// The inner exception. + public MongoEncryptionException(Exception innerException) + : base($"Encryption related exception: {innerException.Message}.", innerException) + { + } + } +} diff --git a/src/MongoDB.Driver/Encryption/MongocryptdFactory.cs b/src/MongoDB.Driver/Encryption/MongocryptdFactory.cs new file mode 100644 index 00000000000..965dc239b4a --- /dev/null +++ b/src/MongoDB.Driver/Encryption/MongocryptdFactory.cs @@ -0,0 +1,184 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using MongoDB.Driver.Core.Misc; + +namespace MongoDB.Driver.Encryption +{ + internal static class EncryptionExtraOptionsValidator + { + #region static + private static readonly Dictionary __supportedExtraOptions = new Dictionary + { + { "mongocryptdURI", new [] { typeof(string) } }, + { "mongocryptdBypassSpawn", new [] { typeof(bool) } }, + { "mongocryptdSpawnPath", new [] { typeof(string) } }, + { "mongocryptdSpawnArgs", new [] { typeof(string), typeof(IEnumerable) } } + }; + #endregion + + public static void EnsureThatExtraOptionsAreValid(IReadOnlyDictionary extraOptions) + { + if (extraOptions == null) + { + return; + } + + foreach (var extraOption in extraOptions) + { + if (__supportedExtraOptions.TryGetValue(extraOption.Key, out var validTypes)) + { + var extraOptionValue = Ensure.IsNotNull(extraOption.Value, nameof(extraOptions)); + var extraOptionValueType = extraOptionValue.GetType(); + var isExtraOptionValueTypeValid = validTypes.Any(t => t.GetTypeInfo().IsAssignableFrom(extraOptionValueType)); + if (!isExtraOptionValueTypeValid) + { + throw new ArgumentException($"Extra option {extraOption.Key} has invalid type: {extraOptionValueType}.", nameof(extraOptions)); + } + } + else + { + throw new ArgumentException($"Invalid extra option key: {extraOption.Key}.", nameof(extraOptions)); + } + } + } + } + + internal class MongocryptdFactory + { + private readonly IReadOnlyDictionary _extraOptions; + + public MongocryptdFactory(IReadOnlyDictionary extraOptions) + { + _extraOptions = extraOptions ?? new Dictionary(); + } + + // public methods + public IMongoClient CreateMongocryptdClient() + { + var connectionString = CreateMongocryptdConnectionString(); + var clientSettings = MongoClientSettings.FromConnectionString(connectionString); + clientSettings.ServerSelectionTimeout = TimeSpan.FromMilliseconds(1000); + return new MongoClient(clientSettings); + } + + public void SpawnMongocryptdProcessIfRequired() + { + if (ShouldMongocryptdBeSpawned(out var path, out var args)) + { + StartProcess(path, args); + } + } + + // private methods + private string CreateMongocryptdConnectionString() + { + if (_extraOptions.TryGetValue("mongocryptdURI", out var connectionString)) + { + return (string)connectionString; + } + else + { + return "mongodb://localhost:27020"; + } + } + + private bool ShouldMongocryptdBeSpawned(out string path, out string args) + { + path = null; + args = null; + if (!_extraOptions.TryGetValue("mongocryptdBypassSpawn", out var mongoCryptBypassSpawn) + || !(bool)mongoCryptBypassSpawn) + { + if (_extraOptions.TryGetValue("mongocryptdSpawnPath", out var objPath)) + { + path = (string)objPath; + } + else + { + path = string.Empty; // look at the PATH env variable + } + + if (!Path.HasExtension(path)) + { + string fileName = "mongocryptd.exe"; + path = Path.Combine(path, fileName); + } + + args = string.Empty; + if (_extraOptions.TryGetValue("mongocryptdSpawnArgs", out var mongocryptdSpawnArgs)) + { + string trimStartHyphens(string str) => str.TrimStart('-').TrimStart('-'); + switch (mongocryptdSpawnArgs) + { + case string str: + args += str; + break; + case IEnumerable enumerable: + foreach (var item in enumerable) + { + args += $"--{trimStartHyphens(item.ToString())} "; + } + break; + default: + throw new InvalidCastException($"Invalid type: {mongocryptdSpawnArgs.GetType().Name} of mongocryptdSpawnArgs option."); + } + } + + args = args.Trim(); + if (!args.Contains("idleShutdownTimeoutSecs")) + { + args += " --idleShutdownTimeoutSecs 60"; + } + args = args.Trim(); + + return true; + } + + return false; + } + + private void StartProcess(string path, string args) + { + try + { + using (var process = new Process()) + { + process.StartInfo.Arguments = args; + process.StartInfo.FileName = path; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.UseShellExecute = false; + + if (!process.Start()) + { + // skip it. This case can happen if no new process resource is started + // (for example, if an existing process is reused) + } + } + } + catch (Exception ex) + { + throw new MongoClientException("Exception starting mongocryptd process. Is mongocryptd on the system path?", ex); + } + } + } +} diff --git a/src/MongoDB.Driver/Encryption/NoopBinaryDocumentFieldCryptor.cs b/src/MongoDB.Driver/Encryption/NoopBinaryDocumentFieldCryptor.cs new file mode 100644 index 00000000000..4b080ae81e8 --- /dev/null +++ b/src/MongoDB.Driver/Encryption/NoopBinaryDocumentFieldCryptor.cs @@ -0,0 +1,44 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver.Core.WireProtocol; + +namespace MongoDB.Driver.Encryption +{ + internal class NoopBinaryDocumentFieldCryptor : IBinaryDocumentFieldDecryptor, IBinaryCommandFieldEncryptor + { + public byte[] DecryptFields(byte[] encryptedDocumentBytes, CancellationToken cancellationToken) + { + return encryptedDocumentBytes; + } + + public Task DecryptFieldsAsync(byte[] encryptedDocumentBytes, CancellationToken cancellationToken) + { + return Task.FromResult(encryptedDocumentBytes); + } + + public byte[] EncryptFields(string databaseName, byte[] unencryptedCommandBytes, CancellationToken cancellationToken) + { + return unencryptedCommandBytes; + } + + public Task EncryptFieldsAsync(string databaseName, byte[] unencryptedCommandBytes, CancellationToken cancellationToken) + { + return Task.FromResult(unencryptedCommandBytes); + } + } +} diff --git a/src/MongoDB.Driver/IReadOnlyDictionaryExtensions.cs b/src/MongoDB.Driver/IReadOnlyDictionaryExtensions.cs new file mode 100644 index 00000000000..98894290498 --- /dev/null +++ b/src/MongoDB.Driver/IReadOnlyDictionaryExtensions.cs @@ -0,0 +1,53 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; + +namespace MongoDB.Driver +{ + internal static class IReadOnlyDictionaryExtensions + { + public static bool IsEquivalentTo(this IReadOnlyDictionary x, IReadOnlyDictionary y, Func equals) + { + if (object.ReferenceEquals(x, y)) + { + return true; + } + + if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null)) + { + return false; + } + + if (x.Count != y.Count) + { + return false; + } + + foreach (var keyValuePair in x) + { + var key = keyValuePair.Key; + var xValue = keyValuePair.Value; + if (!y.TryGetValue(key, out var yValue) || !equals(xValue, yValue)) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 0173b448078..a6f55d98617 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -29,6 +29,7 @@ using MongoDB.Driver.Core.Operations; using MongoDB.Driver.Core.Servers; using MongoDB.Driver.Core.WireProtocol.Messages.Encoders; +using MongoDB.Driver.Encryption; namespace MongoDB.Driver { @@ -53,6 +54,7 @@ private static IEnumerable SelectServersThatDetermineWhetherS // private fields private readonly ICluster _cluster; + private readonly AutoEncryptionLibMongoCryptController _libMongoCryptController; private readonly IOperationExecutor _operationExecutor; private readonly MongoClientSettings _settings; @@ -78,6 +80,13 @@ public MongoClient(MongoClientSettings settings) _settings = Ensure.IsNotNull(settings, nameof(settings)).FrozenCopy(); _cluster = ClusterRegistry.Instance.GetOrCreateCluster(_settings.ToClusterKey()); _operationExecutor = new OperationExecutor(this); + if (settings.AutoEncryptionOptions != null) + { + _libMongoCryptController = new AutoEncryptionLibMongoCryptController( + this, + _cluster.CryptClient, + settings.AutoEncryptionOptions); + } } /// @@ -128,10 +137,26 @@ public sealed override MongoClientSettings Settings } // internal properties + internal AutoEncryptionLibMongoCryptController LibMongoCryptController => _libMongoCryptController; internal IOperationExecutor OperationExecutor => _operationExecutor; + + // internal methods + internal void ConfigureAutoEncryptionMessageEncoderSettings(MessageEncoderSettings messageEncoderSettings) + { + var autoEncryptionOptions = _settings.AutoEncryptionOptions; + if (autoEncryptionOptions != null) + { + if (!autoEncryptionOptions.BypassAutoEncryption) + { + messageEncoderSettings.Add(MessageEncoderSettingsName.BinaryDocumentFieldEncryptor, _libMongoCryptController); + } + messageEncoderSettings.Add(MessageEncoderSettingsName.BinaryDocumentFieldDecryptor, _libMongoCryptController); + } + } // private static methods + // public methods /// public sealed override void DropDatabase(string name, CancellationToken cancellationToken = default(CancellationToken)) @@ -479,10 +504,10 @@ private IReadWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle sess ChangeStreamOptions options) { return ChangeStreamHelper.CreateChangeStreamOperation( - pipeline, - options, - _settings.ReadConcern, - GetMessageEncoderSettings(), + pipeline, + options, + _settings.ReadConcern, + GetMessageEncoderSettings(), _settings.RetryReads); } @@ -520,12 +545,16 @@ private async Task ExecuteWriteOperationAsync(IClientSessionHa private MessageEncoderSettings GetMessageEncoderSettings() { - return new MessageEncoderSettings + var messageEncoderSettings = new MessageEncoderSettings { { MessageEncoderSettingsName.GuidRepresentation, _settings.GuidRepresentation }, { MessageEncoderSettingsName.ReadEncoding, _settings.ReadEncoding ?? Utf8Encodings.Strict }, { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict } }; + + ConfigureAutoEncryptionMessageEncoderSettings(messageEncoderSettings); + + return messageEncoderSettings; } private IClientSessionHandle StartImplicitSession(bool areSessionsSupported) diff --git a/src/MongoDB.Driver/MongoClientSettings.cs b/src/MongoDB.Driver/MongoClientSettings.cs index 67be8219274..78e6f297810 100644 --- a/src/MongoDB.Driver/MongoClientSettings.cs +++ b/src/MongoDB.Driver/MongoClientSettings.cs @@ -21,6 +21,7 @@ using MongoDB.Bson; using MongoDB.Driver.Core.Configuration; using MongoDB.Driver.Core.Misc; +using MongoDB.Driver.Encryption; using MongoDB.Shared; namespace MongoDB.Driver @@ -33,6 +34,7 @@ public class MongoClientSettings : IEquatable, IInheritable // private fields private bool _allowInsecureTls; private string _applicationName; + private AutoEncryptionOptions _autoEncryptionOptions; private Action _clusterConfigurator; private IReadOnlyList _compressors; private ConnectionMode _connectionMode; @@ -78,6 +80,7 @@ public MongoClientSettings() { _allowInsecureTls = false; _applicationName = null; + _autoEncryptionOptions = null; _compressors = new CompressorConfiguration[0]; _connectionMode = ConnectionMode.Automatic; _connectTimeout = MongoDefaults.ConnectTimeout; @@ -137,6 +140,19 @@ public string ApplicationName } } + /// + /// Gets or sets the auto encryption options. + /// + public AutoEncryptionOptions AutoEncryptionOptions + { + get { return _autoEncryptionOptions; } + set + { + if (_isFrozen) { throw new InvalidOperationException("MongoClientSettings is frozen."); } + _autoEncryptionOptions = value; + } + } + /// /// Gets or sets the compressors. /// @@ -692,6 +708,7 @@ public static MongoClientSettings FromUrl(MongoUrl url) var clientSettings = new MongoClientSettings(); clientSettings.AllowInsecureTls = url.AllowInsecureTls; clientSettings.ApplicationName = url.ApplicationName; + clientSettings.AutoEncryptionOptions = null; // must be configured via code clientSettings.Compressors = url.Compressors; clientSettings.ConnectionMode = url.ConnectionMode; clientSettings.ConnectTimeout = url.ConnectTimeout; @@ -748,6 +765,7 @@ public MongoClientSettings Clone() var clone = new MongoClientSettings(); clone._allowInsecureTls = _allowInsecureTls; clone._applicationName = _applicationName; + clone._autoEncryptionOptions = _autoEncryptionOptions; clone._compressors = _compressors; clone._clusterConfigurator = _clusterConfigurator; clone._connectionMode = _connectionMode; @@ -808,6 +826,7 @@ public override bool Equals(object obj) return _allowInsecureTls == rhs._allowInsecureTls && _applicationName == rhs._applicationName && + object.Equals(_autoEncryptionOptions, rhs._autoEncryptionOptions) && object.ReferenceEquals(_clusterConfigurator, rhs._clusterConfigurator) && _compressors.SequenceEqual(rhs._compressors) && _connectionMode == rhs._connectionMode && @@ -886,6 +905,7 @@ public override int GetHashCode() return new Hasher() .Hash(_allowInsecureTls) .Hash(_applicationName) + .Hash(_autoEncryptionOptions) .Hash(_clusterConfigurator) .HashElements(_compressors) .Hash(_connectionMode) @@ -936,7 +956,10 @@ public override string ToString() { sb.AppendFormat("ApplicationName={0};", _applicationName); } - + if (_autoEncryptionOptions != null) + { + sb.AppendFormat("AutoEncryptionOptions={0};", _autoEncryptionOptions); + } if (_compressors?.Any() ?? false) { sb.AppendFormat("Compressors=[{0}];", string.Join(",", _compressors)); @@ -1003,6 +1026,7 @@ internal ClusterKey ToClusterKey() _heartbeatInterval, _heartbeatTimeout, _ipv6, + _autoEncryptionOptions?.KmsProviders, _localThreshold, _maxConnectionIdleTime, _maxConnectionLifeTime, @@ -1010,6 +1034,7 @@ internal ClusterKey ToClusterKey() _minConnectionPoolSize, MongoDefaults.TcpReceiveBufferSize, // TODO: add ReceiveBufferSize to MongoClientSettings? _replicaSetName, + _autoEncryptionOptions?.SchemaMap, _scheme, _sdamLogFilename, MongoDefaults.TcpSendBufferSize, // TODO: add SendBufferSize to MongoClientSettings? diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index c7bbcff4866..50befe8b82c 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -55,12 +55,7 @@ private MongoCollectionImpl(IMongoDatabase database, CollectionNamespace collect _operationExecutor = Ensure.IsNotNull(operationExecutor, nameof(operationExecutor)); _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer)); - _messageEncoderSettings = new MessageEncoderSettings - { - { MessageEncoderSettingsName.GuidRepresentation, _settings.GuidRepresentation }, - { MessageEncoderSettingsName.ReadEncoding, _settings.ReadEncoding ?? Utf8Encodings.Strict }, - { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict } - }; + _messageEncoderSettings = GetMessageEncoderSettings(); } // properties @@ -1071,6 +1066,23 @@ private IWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle session) return new ReadWriteBindingHandle(binding); } + private MessageEncoderSettings GetMessageEncoderSettings() + { + var messageEncoderSettings = new MessageEncoderSettings + { + { MessageEncoderSettingsName.GuidRepresentation, _settings.GuidRepresentation }, + { MessageEncoderSettingsName.ReadEncoding, _settings.ReadEncoding ?? Utf8Encodings.Strict }, + { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict } + }; + + if (_database.Client is MongoClient mongoClient) + { + mongoClient.ConfigureAutoEncryptionMessageEncoderSettings(messageEncoderSettings); + } + + return messageEncoderSettings; + } + private IBsonSerializer GetValueSerializerForDistinct(RenderedFieldDefinition renderedField, IBsonSerializerRegistry serializerRegistry) { if (renderedField.UnderlyingSerializer != null) diff --git a/src/MongoDB.Driver/MongoDB.Driver.csproj b/src/MongoDB.Driver/MongoDB.Driver.csproj index 68f875bf2a3..0aa56c0272f 100644 --- a/src/MongoDB.Driver/MongoDB.Driver.csproj +++ b/src/MongoDB.Driver/MongoDB.Driver.csproj @@ -42,6 +42,7 @@ + diff --git a/src/MongoDB.Driver/MongoDatabaseImpl.cs b/src/MongoDB.Driver/MongoDatabaseImpl.cs index d11d179a4e9..31cb40c61d8 100644 --- a/src/MongoDB.Driver/MongoDatabaseImpl.cs +++ b/src/MongoDB.Driver/MongoDatabaseImpl.cs @@ -454,11 +454,12 @@ public override IMongoDatabase WithWriteConcern(WriteConcern writeConcern) // private methods private AggregateOperation CreateAggregateOperation(RenderedPipelineDefinition renderedPipeline, AggregateOptions options) { + var messageEncoderSettings = GetMessageEncoderSettings(); return new AggregateOperation( _databaseNamespace, renderedPipeline.Documents, renderedPipeline.OutputSerializer, - _messageEncoderSettings) + messageEncoderSettings) { AllowDiskUse = options.AllowDiskUse, BatchSize = options.BatchSize, @@ -508,7 +509,12 @@ private FindOperation CreateAggregateToCollectionFindOperation throw new ArgumentException($"Unexpected stage name: {stageName}."); } - return new FindOperation(outputCollectionNamespace, resultSerializer, _messageEncoderSettings) + // because auto encryption is not supported for non-collection commands. + // So, an error will be thrown in the previous CreateAggregateToCollectionOperation step. + // However, since we've added encryption configuration for CreateAggregateToCollectionOperation operation, + // it's not superfluous to also add it here + var messageEncoderSettings = GetMessageEncoderSettings(); + return new FindOperation(outputCollectionNamespace, resultSerializer, messageEncoderSettings) { BatchSize = options.BatchSize, Collation = options.Collation, @@ -520,10 +526,11 @@ private FindOperation CreateAggregateToCollectionFindOperation private AggregateToCollectionOperation CreateAggregateToCollectionOperation(RenderedPipelineDefinition renderedPipeline, AggregateOptions options) { + var messageEncoderSettings = GetMessageEncoderSettings(); return new AggregateToCollectionOperation( _databaseNamespace, renderedPipeline.Documents, - _messageEncoderSettings) + messageEncoderSettings) { AllowDiskUse = options.AllowDiskUse, BypassDocumentValidation = options.BypassDocumentValidation, @@ -751,12 +758,19 @@ private async Task ExecuteWriteOperationAsync(IClientSessionHandle session private MessageEncoderSettings GetMessageEncoderSettings() { - return new MessageEncoderSettings + var messageEncoderSettings = new MessageEncoderSettings { { MessageEncoderSettingsName.GuidRepresentation, _settings.GuidRepresentation }, { MessageEncoderSettingsName.ReadEncoding, _settings.ReadEncoding ?? Utf8Encodings.Strict }, { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict } }; + + if (_client is MongoClient mongoClient) + { + mongoClient.ConfigureAutoEncryptionMessageEncoderSettings(messageEncoderSettings); + } + + return messageEncoderSettings; } private void UsingImplicitSession(Action func, CancellationToken cancellationToken) diff --git a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/AspectAsserter.cs b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/AspectAsserter.cs index f0dcab411f1..559ce62bac2 100644 --- a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/AspectAsserter.cs +++ b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/AspectAsserter.cs @@ -13,6 +13,7 @@ * limitations under the License. */ +using System.Collections.Generic; using FluentAssertions; namespace MongoDB.Bson.TestHelpers.JsonDrivenTests @@ -21,6 +22,11 @@ public abstract class AspectAsserter { // public methods public abstract void AssertAspects(object actualValue, BsonDocument aspects); + + public virtual void ConfigurePlaceholders(KeyValuePair[] placeholders) + { + // do nothing by default + } } public abstract class AspectAsserter : AspectAsserter diff --git a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/EmbeddedResourceJsonFileReader.cs b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/EmbeddedResourceJsonFileReader.cs new file mode 100644 index 00000000000..0d36ba65877 --- /dev/null +++ b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/EmbeddedResourceJsonFileReader.cs @@ -0,0 +1,75 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; + +namespace MongoDB.Bson.TestHelpers.JsonDrivenTests +{ + public abstract class EmbeddedResourceJsonFileReader + { + // protected properties + protected virtual Assembly Assembly => this.GetType().GetTypeInfo().Assembly; + + protected virtual string PathPrefix { get; } = null; + protected virtual string[] PathPrefixes { get; } = null; + + protected virtual BsonDocument ReadJsonDocument(string path) + { + var jsonReaderSettings = new JsonReaderSettings { GuidRepresentation = GuidRepresentation.Unspecified }; + using (var stream = Assembly.GetManifestResourceStream(path)) + using (var streamReader = new StreamReader(stream)) + using (var jsonReader = new JsonReader(streamReader, jsonReaderSettings)) + { + var context = BsonDeserializationContext.CreateRoot(jsonReader); + var document = BsonDocumentSerializer.Instance.Deserialize(context); + document.InsertAt(0, new BsonElement("_path", path)); + return document; + } + } + + protected virtual IEnumerable ReadJsonDocuments() + { + return + Assembly.GetManifestResourceNames() + .Where(path => ShouldReadJsonDocument(path)) + .Select(path => ReadJsonDocument(path)); + } + + protected virtual bool ShouldReadJsonDocument(string path) + { + var prefixes = GetPathPrefixes(); + return prefixes.Any(path.StartsWith) && path.EndsWith(".json"); + } + + private string[] GetPathPrefixes() + { + var prefixes = !string.IsNullOrEmpty(PathPrefix) ? new[] { PathPrefix } : PathPrefixes; + + if (prefixes == null || prefixes.Length == 0) + { + throw new NotImplementedException("At least one path prefix must be specified."); + } + + return prefixes; + } + } +} diff --git a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTest.cs b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTest.cs index 2fbb0a03caa..a3c1352d93a 100644 --- a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTest.cs +++ b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTest.cs @@ -71,9 +71,9 @@ public virtual void Arrange(BsonDocument document) _expectedException = new BsonDocument(); // any exception will do } - if (document.Contains("result")) + if (document.TryGetValue("result", out var result) || document.TryGetValue("results", out result)) { - ParseExpectedResult(document["result"]); + ParseExpectedResult(result); } } diff --git a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCase.cs b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCase.cs index 667d3540079..705cc74c776 100644 --- a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCase.cs +++ b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCase.cs @@ -13,6 +13,10 @@ * limitations under the License. */ +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; +using System.IO; using Xunit.Abstractions; namespace MongoDB.Bson.TestHelpers.JsonDrivenTests @@ -47,20 +51,43 @@ public JsonDrivenTestCase(string name, BsonDocument shared, BsonDocument test) public void Deserialize(IXunitSerializationInfo info) { _name = info.GetValue(nameof(_name)); - _shared = BsonDocument.Parse(info.GetValue(nameof(_shared))); - _test = BsonDocument.Parse(info.GetValue(nameof(_test))); + _shared = DeserializeBsonDocument(info.GetValue(nameof(_shared))); + _test = DeserializeBsonDocument(info.GetValue(nameof(_test))); } public void Serialize(IXunitSerializationInfo info) { info.AddValue(nameof(_name), _name); - info.AddValue(nameof(_shared), _shared.ToJson()); - info.AddValue(nameof(_test), _test.ToJson()); + info.AddValue(nameof(_shared), SerializeBsonDocument(_shared)); + info.AddValue(nameof(_test), SerializeBsonDocument(_test)); } public override string ToString() { return _name; } + + // private methods + private BsonDocument DeserializeBsonDocument(string value) + { + var jsonReaderSettings = new JsonReaderSettings { GuidRepresentation = GuidRepresentation.Unspecified }; + using (var jsonReader = new JsonReader(value, jsonReaderSettings)) + { + var context = BsonDeserializationContext.CreateRoot(jsonReader); + return BsonDocumentSerializer.Instance.Deserialize(context); + } + } + + private string SerializeBsonDocument(BsonDocument value) + { + var jsonWriterSettings = new JsonWriterSettings { GuidRepresentation = GuidRepresentation.Unspecified }; + using (var stringWriter = new StringWriter()) + using (var jsonWriter = new JsonWriter(stringWriter, jsonWriterSettings)) + { + var context = BsonSerializationContext.CreateRoot(jsonWriter); + BsonDocumentSerializer.Instance.Serialize(context, value); + return stringWriter.ToString(); + } + } } } diff --git a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCaseFactory.cs b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCaseFactory.cs index 65937a7c516..d67f5eb8c5c 100644 --- a/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCaseFactory.cs +++ b/tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenTestCaseFactory.cs @@ -16,22 +16,14 @@ using System; using System.Collections; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; using Xunit.Abstractions; namespace MongoDB.Bson.TestHelpers.JsonDrivenTests { - public abstract class JsonDrivenTestCaseFactory : IEnumerable + public abstract class JsonDrivenTestCaseFactory : EmbeddedResourceJsonFileReader, IEnumerable where TTestCase : IXunitSerializable { - // protected properties - protected virtual Assembly Assembly => this.GetType().GetTypeInfo().Assembly; - - protected virtual string PathPrefix { get; } = null; - protected virtual string[] PathPrefixes { get; } = null; - // public methods public IEnumerator GetEnumerator() { @@ -49,39 +41,6 @@ IEnumerator IEnumerable.GetEnumerator() // protected methods protected abstract IEnumerable CreateTestCases(BsonDocument document); - - protected virtual BsonDocument ReadJsonDocument(string path) - { - using (var stream = Assembly.GetManifestResourceStream(path)) - using (var reader = new StreamReader(stream)) - { - var json = reader.ReadToEnd(); - var document = BsonDocument.Parse(json); - document.InsertAt(0, new BsonElement("_path", path)); - return document; - } - } - - protected virtual IEnumerable ReadJsonDocuments() - { - return - Assembly.GetManifestResourceNames() - .Where(path => ShouldReadJsonDocument(path)) - .Select(path => ReadJsonDocument(path)); - } - - protected virtual bool ShouldReadJsonDocument(string path) - { - var prefixes = GetPathPrefixes(); - return prefixes.Any(path.StartsWith) && path.EndsWith(".json"); - } - - private string[] GetPathPrefixes() - { - var prefixes = !string.IsNullOrEmpty(PathPrefix) ? new[] { PathPrefix } : PathPrefixes; - - return prefixes ?? throw new NotImplementedException("A test must have at least one test path."); - } } public abstract class JsonDrivenTestCaseFactory : JsonDrivenTestCaseFactory diff --git a/tests/MongoDB.Bson.TestHelpers/Reflector.cs b/tests/MongoDB.Bson.TestHelpers/Reflector.cs index 600e33fdb71..52fcc89acfe 100644 --- a/tests/MongoDB.Bson.TestHelpers/Reflector.cs +++ b/tests/MongoDB.Bson.TestHelpers/Reflector.cs @@ -70,6 +70,34 @@ public static object Invoke(object obj, string name, T1 arg1) } } + public static object Invoke(object obj, string name, out T1 arg1, out T2 arg2) + { + arg1 = default; + arg2 = default; + var parameterTypes = new[] { typeof(T1), typeof(T2) }.Select(t => t.FullName); + var methodInfo = obj + .GetType() + .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) + .Where(m => + m.Name == name && + m.GetParameters() + .Select(p => p.ParameterType.FullName.TrimEnd('&')) + .SequenceEqual(parameterTypes)) + .Single(); + try + { + var arguments = new object[] { arg1, arg2 }; + var result = methodInfo.Invoke(obj, arguments); + arg1 = (T1)arguments[0]; + arg2 = (T2)arguments[1]; + return result; + } + catch (TargetInvocationException exception) + { + throw exception.InnerException; + } + } + public static object Invoke(object obj, string name, T1 arg1, T2 arg2, T3 arg3) { var parameterTypes = new[] { typeof(T1), typeof(T2), typeof(T3) }; diff --git a/tests/MongoDB.Bson.Tests/IO/JsonReaderTests.cs b/tests/MongoDB.Bson.Tests/IO/JsonReaderTests.cs index 1f8355980ec..823ed0dc1d3 100644 --- a/tests/MongoDB.Bson.Tests/IO/JsonReaderTests.cs +++ b/tests/MongoDB.Bson.Tests/IO/JsonReaderTests.cs @@ -473,6 +473,21 @@ public void TestDateTimeStrictIso8601() Assert.Equal(expected, BsonSerializer.Deserialize(json).ToJson(jsonSettings)); } + [Theory] + [InlineData("{ $date: { \"$numberLong\": \"1552949630483\" } }", 1552949630483L)] + [InlineData("{ $date: { $numberLong: \"1552949630483\" } }", 1552949630483L)] + public void TestDateTimeWithNumberLong(string json, long expectedResult) + { + using (var reader = new JsonReader(json)) + { + var result = reader.ReadDateTime(); + + result.Should().Be(expectedResult); + reader.State.Should().Be(BsonReaderState.Initial); + reader.IsAtEndOfFile().Should().BeTrue(); + } + } + [Theory] [InlineData("NumberDecimal(1)", "1", "NumberDecimal(\"1\")")] [InlineData("NumberDecimal(2147483648)", "2147483648", "NumberDecimal(\"2147483648\")")] diff --git a/tests/MongoDB.Driver.Core.TestHelpers/JsonDrivenTests/CommandStartedEventAsserter.cs b/tests/MongoDB.Driver.Core.TestHelpers/JsonDrivenTests/CommandStartedEventAsserter.cs index fb5b0e371df..56384448f88 100644 --- a/tests/MongoDB.Driver.Core.TestHelpers/JsonDrivenTests/CommandStartedEventAsserter.cs +++ b/tests/MongoDB.Driver.Core.TestHelpers/JsonDrivenTests/CommandStartedEventAsserter.cs @@ -27,6 +27,13 @@ namespace MongoDB.Driver.Core.TestHelpers.JsonDrivenTests { public class CommandStartedEventAsserter : AspectAsserter { + private KeyValuePair[] _placeholders = + { + new KeyValuePair("getMore", 42L), + new KeyValuePair("afterClusterTime", 42), + new KeyValuePair("recoveryToken", 42) + }; + // protected methods protected override void AssertAspect(CommandStartedEvent actualEvent, string name, BsonValue expectedValue) { @@ -62,23 +69,32 @@ private void AdaptExpectedUpdateModels(List actualModels, List().ToList(), expectedValue.AsBsonArray.Cast().ToList()); } - var namesToUseOrderInsensitiveComparisonWith = new[] { "writeConcern", "maxTimeMS" }; + var namesToUseOrderInsensitiveComparisonWith = new[] { "writeConcern", "maxTimeMS", "updates" }; var useOrderInsensitiveComparison = namesToUseOrderInsensitiveComparisonWith.Contains(name); if (!(useOrderInsensitiveComparison ? BsonValueEquivalencyComparer.Compare(actualValue, expectedValue) : actualValue.Equals(expectedValue))) @@ -139,7 +157,7 @@ private void AssertCommandAspect(BsonDocument actualCommand, string name, BsonVa switch (name) { case "out": - if (commandName == "mapReduce") + if (commandName == "mapReduce") { if (expectedValue is BsonString && actualValue.IsBsonDocument && @@ -158,5 +176,10 @@ private void AssertCommandAspect(BsonDocument actualCommand, string name, BsonVa throw new AssertionFailedException($"Expected field '{name}' in command '{commandName}' to be {expectedValue.ToJson()} but found {actualValue.ToJson()}."); } } + + public override void ConfigurePlaceholders(KeyValuePair[] placeholders) + { + _placeholders = placeholders; + } } } diff --git a/tests/MongoDB.Driver.Tests/ClusterKeyTests.cs b/tests/MongoDB.Driver.Tests/ClusterKeyTests.cs index 75a08ed8dd6..0500f848f33 100644 --- a/tests/MongoDB.Driver.Tests/ClusterKeyTests.cs +++ b/tests/MongoDB.Driver.Tests/ClusterKeyTests.cs @@ -15,8 +15,11 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Security.Authentication; using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Bson.TestHelpers.XunitExtensions; using MongoDB.Driver.Core.Compression; using MongoDB.Driver.Core.Configuration; using Xunit; @@ -25,6 +28,9 @@ namespace MongoDB.Driver.Tests { public class ClusterKeyTests { + private const string Key1 = "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk"; + private const string Key2 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + [Fact] public void Equals_should_return_true_if_all_fields_are_equal() { @@ -46,6 +52,7 @@ public void Equals_should_return_true_if_all_fields_are_equal() [InlineData("HeartbeatInterval", true)] [InlineData("HeartbeatTimeout", true)] [InlineData("IPv6", true)] + [InlineData("KmsProviders", true)] [InlineData("MaxConnectionIdleTime", true)] [InlineData("MaxConnectionLifeTime", true)] [InlineData("MaxConnectionPoolSize", true)] @@ -53,6 +60,7 @@ public void Equals_should_return_true_if_all_fields_are_equal() [InlineData("ReceiveBufferSize", true)] [InlineData("ReplicaSetName", true)] [InlineData("LocalThreshold", true)] + [InlineData("SchemaMap", true)] [InlineData("Scheme", true)] [InlineData("SdamLogFileName", true)] [InlineData("SendBufferSize", true)] @@ -72,6 +80,50 @@ public void Equals_should_return_false_if_any_field_is_not_equal(string notEqual subject1.GetHashCode().Equals(subject2.GetHashCode()).Should().Be(expectEqualHashCode); } + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + public void Equals_should_return_true_if_kms_providers_have_different_records_count( + bool skipTheLastMainRecord, + bool skipTheLastNestedRecord) + { + var kmsProvider1 = GetKmsProviders(); + var kmsProvider2 = GetKmsProviders(skipTheLastMainRecord: skipTheLastMainRecord, skipTheLastNestedRecord: skipTheLastNestedRecord); + + var subject1 = CreateSubjectWith(kmsProvidersValue: kmsProvider1); + var subject2 = CreateSubjectWith(kmsProvidersValue: kmsProvider2); + subject1.Should().NotBe(subject2); + } + + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public void Equals_should_return_true_if_kms_providers_have_the_same_items_but_with_different_order( + bool withReverseInMainKeys, + bool withReverseInNestedKeys) + { + var kmsProviders1 = GetKmsProviders(); + var kmsProviders2 = GetKmsProviders(withReverseInMainKeys: withReverseInMainKeys, withReverseInNestedKeys: withReverseInNestedKeys); + + var subject1 = CreateSubjectWith(kmsProvidersValue: kmsProviders1); + var subject2 = CreateSubjectWith(kmsProvidersValue: kmsProviders2); + subject1.Should().Be(subject2); + } + + [Theory] + [ParameterAttributeData] + public void Equals_should_return_true_if_schema_maps_have_the_same_items_but_with_different_order( + [Values(false, true)] bool withReverse) + { + var schemaMap1 = GetSchemaMaps(); + var schemaMap2 = GetSchemaMaps(withReverse: withReverse); + + var subject1 = CreateSubjectWith(schemaMapValue: schemaMap1); + var subject2 = CreateSubjectWith(schemaMapValue: schemaMap2); + subject1.Should().Be(subject2); + } + private ClusterKey CreateSubject(string notEqualFieldName = null) { var allowInsecureTls = true; @@ -86,6 +138,7 @@ private ClusterKey CreateSubject(string notEqualFieldName = null) var heartbeatInterval = TimeSpan.FromSeconds(7); var heartbeatTimeout = TimeSpan.FromSeconds(8); var ipv6 = false; + var kmsProviders = new Dictionary>(); var localThreshold = TimeSpan.FromMilliseconds(20); var maxConnectionIdleTime = TimeSpan.FromSeconds(2); var maxConnectionLifeTime = TimeSpan.FromSeconds(3); @@ -93,6 +146,7 @@ private ClusterKey CreateSubject(string notEqualFieldName = null) var minConnectionPoolSize = 5; var receiveBufferSize = 1; var replicaSetName = "abc"; + var schemaMap = new Dictionary(); var scheme = ConnectionStringScheme.MongoDB; var sdamLogFileName = "stdout"; var sendBufferSize = 1; @@ -124,6 +178,7 @@ private ClusterKey CreateSubject(string notEqualFieldName = null) case "HeartbeatInterval": heartbeatInterval = TimeSpan.FromSeconds(99); break; case "HeartbeatTimeout": heartbeatTimeout = TimeSpan.FromSeconds(99); break; case "IPv6": ipv6 = !ipv6; break; + case "KmsProviders": kmsProviders.Add("local", new Dictionary() { { "key", "test" } }); break; case "LocalThreshold": localThreshold = TimeSpan.FromMilliseconds(99); break; case "MaxConnectionIdleTime": maxConnectionIdleTime = TimeSpan.FromSeconds(99); break; case "MaxConnectionLifeTime": maxConnectionLifeTime = TimeSpan.FromSeconds(99); break; @@ -131,6 +186,7 @@ private ClusterKey CreateSubject(string notEqualFieldName = null) case "MinConnectionPoolSize": minConnectionPoolSize = 99; break; case "ReceiveBufferSize": receiveBufferSize = 2; break; case "ReplicaSetName": replicaSetName = "different"; break; + case "SchemaMap": schemaMap.Add("db.coll", new BsonDocument()); break; case "Scheme": scheme = ConnectionStringScheme.MongoDBPlusSrv; break; case "SdamLogFileName": sdamLogFileName = "different"; break; case "SendBufferSize": sendBufferSize = 2; break; @@ -156,6 +212,7 @@ private ClusterKey CreateSubject(string notEqualFieldName = null) heartbeatInterval, heartbeatTimeout, ipv6, + kmsProviders, localThreshold, maxConnectionIdleTime, maxConnectionLifeTime, @@ -163,6 +220,7 @@ private ClusterKey CreateSubject(string notEqualFieldName = null) minConnectionPoolSize, receiveBufferSize, replicaSetName, + schemaMap, scheme, sdamLogFileName, sendBufferSize, @@ -174,5 +232,150 @@ private ClusterKey CreateSubject(string notEqualFieldName = null) waitQueueSize, waitQueueTimeout); } + + internal ClusterKey CreateSubjectWith( + Dictionary> kmsProvidersValue = null, + Dictionary schemaMapValue = null) + { + var allowInsecureTls = true; + var applicationName = "app1"; + var clusterConfigurator = new Action(b => { }); + var compressors = new CompressorConfiguration[0]; + var connectionMode = ConnectionMode.Direct; + var connectTimeout = TimeSpan.FromSeconds(1); +#pragma warning disable 618 + var credentials = new List { MongoCredential.CreateMongoCRCredential("source", "username", "password") }; +#pragma warning restore 618 + var heartbeatInterval = TimeSpan.FromSeconds(7); + var heartbeatTimeout = TimeSpan.FromSeconds(8); + var ipv6 = false; + var kmsProviders = kmsProvidersValue ?? new Dictionary>(); + var localThreshold = TimeSpan.FromMilliseconds(20); + var maxConnectionIdleTime = TimeSpan.FromSeconds(2); + var maxConnectionLifeTime = TimeSpan.FromSeconds(3); + var maxConnectionPoolSize = 50; + var minConnectionPoolSize = 5; + var receiveBufferSize = 1; + var replicaSetName = "abc"; + var schemaMap = schemaMapValue ?? new Dictionary(); + var scheme = ConnectionStringScheme.MongoDB; + var sdamLogFileName = "stdout"; + var sendBufferSize = 1; + var servers = new[] { new MongoServerAddress("localhost") }; + var serverSelectionTimeout = TimeSpan.FromSeconds(6); + var socketTimeout = TimeSpan.FromSeconds(4); + var sslSettings = new SslSettings + { + CheckCertificateRevocation = true, + EnabledSslProtocols = SslProtocols.Tls + }; + var useTls = false; + var waitQueueSize = 20; + var waitQueueTimeout = TimeSpan.FromSeconds(5); + + return new ClusterKey( + allowInsecureTls, + applicationName, + clusterConfigurator, + compressors, + connectionMode, + connectTimeout, + credentials, + heartbeatInterval, + heartbeatTimeout, + ipv6, + kmsProviders, + localThreshold, + maxConnectionIdleTime, + maxConnectionLifeTime, + maxConnectionPoolSize, + minConnectionPoolSize, + receiveBufferSize, + replicaSetName, + schemaMap, + scheme, + sdamLogFileName, + sendBufferSize, + servers, + serverSelectionTimeout, + socketTimeout, + sslSettings, + useTls, + waitQueueSize, + waitQueueTimeout); + } + + private Dictionary> GetKmsProviders( + bool withReverseInMainKeys = false, + bool withReverseInNestedKeys = false, + bool skipTheLastMainRecord = false, + bool skipTheLastNestedRecord = false) + { + var options1 = new Dictionary + { + { "key1", new BsonBinaryData(Convert.FromBase64String(Key1)).Bytes }, + }; + if (!skipTheLastNestedRecord) + { + options1.Add("key2", new BsonBinaryData(Convert.FromBase64String(Key2)).Bytes); + } + + var options2 = new Dictionary + { + { "key1", "value1" }, + { "key2", "value2" }, + { "key3", "value3" } + }; + + Dictionary> kmsProviders = null; + if (withReverseInNestedKeys) + { + kmsProviders = + new Dictionary>() + { + { "options1", options1.Reverse().ToDictionary(k => k.Key, v => v.Value) }, + }; + + if (!skipTheLastMainRecord) + { + kmsProviders.Add("options2", options2.Reverse().ToDictionary(k => k.Key, v => v.Value)); + } + } + else + { + kmsProviders = + new Dictionary>() + { + { "options1", options1 }, + }; + + if (!skipTheLastMainRecord) + { + kmsProviders.Add("options2", options2); + } + } + + return withReverseInMainKeys + ? kmsProviders.Reverse().ToDictionary(k => k.Key, v => v.Value) + : kmsProviders; + } + + private Dictionary GetSchemaMaps( + bool withReverse = false, + bool skipLastRecord = false) + { + var options = new Dictionary + { + { "key1", new BsonDocument("a", 1) } + }; + if (!skipLastRecord) + { + options.Add("key2", new BsonDocument("b", 2)); + } + + return withReverse + ? options.Reverse().ToDictionary(k => k.Key, v => v.Value) + : options; + } } } \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/ClusterRegistryTests.cs b/tests/MongoDB.Driver.Tests/ClusterRegistryTests.cs index 7f749b06b67..4513324d258 100644 --- a/tests/MongoDB.Driver.Tests/ClusterRegistryTests.cs +++ b/tests/MongoDB.Driver.Tests/ClusterRegistryTests.cs @@ -19,6 +19,7 @@ using System.Net; using System.Security.Authentication; using FluentAssertions; +using MongoDB.Bson; using MongoDB.Bson.TestHelpers; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Compression; @@ -51,6 +52,14 @@ public void GetOrCreateCluster_should_return_a_cluster_with_the_correct_settings CheckCertificateRevocation = true, EnabledSslProtocols = SslProtocols.Tls }; + var kmsProviders = new Dictionary>() + { + { "local", new Dictionary() { { "key" , "test" } } } + }; + var schemaMap = new Dictionary() + { + { "db.coll", new BsonDocument() } + }; var clusterKey = new ClusterKey( allowInsecureTls: false, @@ -63,6 +72,7 @@ public void GetOrCreateCluster_should_return_a_cluster_with_the_correct_settings heartbeatInterval: TimeSpan.FromSeconds(2), heartbeatTimeout: TimeSpan.FromSeconds(3), ipv6: true, + kmsProviders: kmsProviders, localThreshold: TimeSpan.FromSeconds(4), maxConnectionIdleTime: TimeSpan.FromSeconds(5), maxConnectionLifeTime: TimeSpan.FromSeconds(6), @@ -70,6 +80,7 @@ public void GetOrCreateCluster_should_return_a_cluster_with_the_correct_settings minConnectionPoolSize: 8, receiveBufferSize: 9, replicaSetName: "rs", + schemaMap: schemaMap, scheme: ConnectionStringScheme.MongoDB, sdamLogFilename: "sdam.log", sendBufferSize: 10, @@ -92,9 +103,11 @@ public void GetOrCreateCluster_should_return_a_cluster_with_the_correct_settings new IPEndPoint(IPAddress.Parse("[::1]"), 27018) }; cluster.Settings.ConnectionMode.Should().Be(clusterKey.ConnectionMode.ToCore()); + cluster.Settings.KmsProviders.Should().BeEquivalentTo(kmsProviders); cluster.Settings.EndPoints.Should().Equal(expectedEndPoints); cluster.Settings.MaxServerSelectionWaitQueueSize.Should().Be(clusterKey.WaitQueueSize); cluster.Settings.ReplicaSetName.Should().Be(clusterKey.ReplicaSetName); + cluster.Settings.SchemaMap.Should().BeEquivalentTo(schemaMap); cluster.Settings.Scheme.Should().Be(clusterKey.Scheme); cluster.Settings.ServerSelectionTimeout.Should().Be(clusterKey.ServerSelectionTimeout); diff --git a/tests/MongoDB.Driver.Tests/EncryptionTests.cs b/tests/MongoDB.Driver.Tests/EncryptionTests.cs new file mode 100644 index 00000000000..178e5e0a05e --- /dev/null +++ b/tests/MongoDB.Driver.Tests/EncryptionTests.cs @@ -0,0 +1,274 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Bson.TestHelpers; +using MongoDB.Bson.TestHelpers.XunitExtensions; +using MongoDB.Driver.Core.Misc; +using MongoDB.Driver.Core.TestHelpers.XunitExtensions; +using MongoDB.Driver.Encryption; +using MongoDB.Driver.TestHelpers; +using MongoDB.Libmongocrypt; +using System; +using System.Collections.Generic; +using Moq; +using Xunit; + +namespace MongoDB.Driver.Tests +{ + public class EncryptionTests + { + #region static + private static readonly CollectionNamespace __keyVaultCollectionNamespace = CollectionNamespace.FromFullName("db.coll"); + #endregion + + private const string LocalMasterKey = "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk"; + + [Theory] + [InlineData("mongocryptdBypassSpawn", typeof(int), typeof(ArgumentException))] + [InlineData("mongocryptdBypassSpawn", typeof(string), typeof(ArgumentException))] + [InlineData("mongocryptdBypassSpawn", typeof(bool), null)] + + [InlineData("mongocryptdSpawnArgs", typeof(Dictionary), typeof(ArgumentException))] + [InlineData("mongocryptdSpawnArgs", typeof(int), typeof(ArgumentException))] + [InlineData("mongocryptdSpawnArgs", typeof(List), null)] + [InlineData("mongocryptdSpawnArgs", typeof(string[]), null)] + [InlineData("mongocryptdSpawnArgs", typeof(string), null)] + + [InlineData("mongocryptdURI", typeof(object), typeof(ArgumentException))] + [InlineData("mongocryptdURI", typeof(int), typeof(ArgumentException))] + [InlineData("mongocryptdURI", typeof(List), typeof(ArgumentException))] + [InlineData("mongocryptdURI", typeof(string), null)] + + [InlineData("mongocryptdSpawnPath", typeof(object), typeof(ArgumentException))] + [InlineData("mongocryptdSpawnPath", typeof(int), typeof(ArgumentException))] + [InlineData("mongocryptdSpawnPath", typeof(string), null)] + + [InlineData("mongocryptdURI1", typeof(object), typeof(ArgumentException))] + [InlineData("test", typeof(object), typeof(ArgumentException))] + public void Constructor_of_auto_encryption_should_validate_extra_options(string extraOptionKey, Type extraOptionValueType, Type expectedException) + { + var extraOptions = new Dictionary + { + { extraOptionKey, CreateInstance(extraOptionValueType) } + }; + + var exception = Record.Exception(() => + new AutoEncryptionOptions( + __keyVaultCollectionNamespace, + new Dictionary>(), + extraOptions: extraOptions)); + if (expectedException != null) + { + exception.GetType().Should().Be(expectedException); + } + else + { + exception.Should().BeNull(); + } + } + + [Theory] + [InlineData(typeof(int), typeof(ArgumentException))] + [InlineData(typeof(int[]), typeof(ArgumentException))] + [InlineData(typeof(string[]), typeof(ArgumentException))] + [InlineData(null, typeof(ArgumentNullException))] + [InlineData(typeof(string), null)] + [InlineData(typeof(byte[]), null)] + public void Constructor_of_encryption_options_should_validate_kms_providers(Type valueType, Type expectedExceptionType) + { + var kmsProviders = new Dictionary>(); + var options = valueType != null ? CreateInstance(valueType) : null; + kmsProviders.Add( + "testKey", + new Dictionary + { + { "nestedTestKey", options } + }); + + testCase(() => + new AutoEncryptionOptions( + keyVaultNamespace: __keyVaultCollectionNamespace, + kmsProviders: kmsProviders)); + + testCase(() => + new ClientEncryptionOptions( + Mock.Of(), + kmsProviders: kmsProviders, + keyVaultNamespace: __keyVaultCollectionNamespace)); + + void testCase(Action testCode) + { + var testCaseException = Record.Exception(testCode); + if (expectedExceptionType != null) + { + testCaseException.GetType().Should().Be(expectedExceptionType); + } + else + { + testCaseException.Should().BeNull(); + } + } + } + + [SkippableTheory] + [ParameterAttributeData] + public void CryptClient_should_be_initialized([Values(false, true)] bool withAutoEncryption) + { + RequireServer.Check().Supports(Feature.ClientSideEncryption); + + using (var client1 = GetClient(withAutoEncryption)) + using (var client2 = GetClient(withAutoEncryption)) + { + var libMongoCryptController1 = ((MongoClient)client1.Wrapped).LibMongoCryptController; + var libMongoCryptController2 = ((MongoClient)client2.Wrapped).LibMongoCryptController; + if (withAutoEncryption) + { + var cryptClient1 = libMongoCryptController1._cryptClient(); + var cryptClient2 = libMongoCryptController2._cryptClient(); + var areTheSame = object.ReferenceEquals(cryptClient1, cryptClient2); + areTheSame.Should().BeTrue(); + } + else + { + libMongoCryptController1.Should().BeNull(); + libMongoCryptController2.Should().BeNull(); + } + + var kmsProviders = GetKmsProviders(); + var clientEncryption = GetClientEncryption((MongoClient)client1.Wrapped, kmsProviders); + clientEncryption._libMongoCryptController()._cryptClient().Should().NotBeNull(); + } + } + + [SkippableTheory] + [ParameterAttributeData] + public void Mongocryptd_should_be_initialized_only_for_auto_encryption([Values(false, true)] bool withAutoEncryption) + { + RequireServer.Check().Supports(Feature.ClientSideEncryption); + + using (var disposableClient = GetClient(withAutoEncryption)) + { + var kmsProviders = GetKmsProviders(); + var client = (MongoClient)disposableClient.Wrapped; + var clientEncryption = GetClientEncryption(client, kmsProviders); + if (withAutoEncryption) + { + client.LibMongoCryptController.Should().NotBeNull(); + var clientController = client.LibMongoCryptController; + clientController._mongocryptdClient().Should().NotBeNull(); + + var clientEncryptionController = clientEncryption._libMongoCryptController(); + clientEncryptionController.Should().NotBeNull(); + } + else + { + client.LibMongoCryptController.Should().BeNull(); + + var clientEncryptionController = clientEncryption._libMongoCryptController(); + clientEncryptionController.Should().NotBeNull(); + } + } + } + + // private methods + private object CreateInstance(Type type) + { + if (type.IsArray) + { + return Array.CreateInstance(type.GetElementType(), 0); + } + else + { + return type == typeof(string) ? string.Empty : Activator.CreateInstance(type); + } + } + + private DisposableMongoClient GetClient(bool withAutoEncryption = false, Dictionary extraOptions = null) + { + var mongoClientSettings = new MongoClientSettings(); + + if (withAutoEncryption) + { + if (extraOptions == null) + { + extraOptions = new Dictionary() + { + { "mongocryptdSpawnPath", Environment.GetEnvironmentVariable("MONGODB_BINARIES") ?? string.Empty } + }; + } + + var kmsProviders = GetKmsProviders(); + var autoEncryptionOptions = new AutoEncryptionOptions( + keyVaultNamespace: __keyVaultCollectionNamespace, + kmsProviders: kmsProviders, + extraOptions: extraOptions); + mongoClientSettings.AutoEncryptionOptions = autoEncryptionOptions; + } + + return new DisposableMongoClient(new MongoClient(mongoClientSettings)); + } + + private ClientEncryption GetClientEncryption( + MongoClient mongoClient, + IReadOnlyDictionary> kmsProviders) + { + var clientEncryptionOptions = new ClientEncryptionOptions( + keyVaultClient: mongoClient, + keyVaultNamespace: __keyVaultCollectionNamespace, + kmsProviders: kmsProviders); + + return new ClientEncryption(clientEncryptionOptions); + } + + private Dictionary> GetKmsProviders() + { + var localOptions = new Dictionary + { + { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } + }; + var kmsProviders = new Dictionary>() + { + { "local", localOptions } + }; + return kmsProviders; + } + } + + internal static class ClientEncryptionReflector + { + public static ExplicitEncryptionLibMongoCryptController _libMongoCryptController(this ClientEncryption clientEncryption) + { + return (ExplicitEncryptionLibMongoCryptController)Reflector.GetFieldValue(clientEncryption, nameof(_libMongoCryptController)); + } + } + + internal static class LibMongoCryptControllerBaseReflector + { + public static CryptClient _cryptClient(this LibMongoCryptControllerBase libMongoCryptController) + { + return (CryptClient)Reflector.GetFieldValue(libMongoCryptController, nameof(_cryptClient)); + } + } + + internal static class AutoEncryptionLibMongoCryptControllerReflector + { + public static IMongoClient _mongocryptdClient(this AutoEncryptionLibMongoCryptController libMongoCryptController) + { + return (IMongoClient)Reflector.GetFieldValue(libMongoCryptController, nameof(_mongocryptdClient)); + } + } +} diff --git a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenBulkWriteTest.cs b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenBulkWriteTest.cs index a20dd1b2d07..912d060dcdc 100644 --- a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenBulkWriteTest.cs +++ b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenBulkWriteTest.cs @@ -82,6 +82,14 @@ protected override void SetArgument(string name, BsonValue value) { switch (name) { + case "options": + SetArguments(value.AsBsonDocument); + return; + + case "ordered": + _options.IsOrdered = value.ToBoolean(); + return; + case "requests": _requests = ParseWriteModels(value.AsBsonArray.Cast()); return; diff --git a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenDatabaseAggregateTest.cs b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenDatabaseAggregateTest.cs new file mode 100644 index 00000000000..f69a7863ebd --- /dev/null +++ b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenDatabaseAggregateTest.cs @@ -0,0 +1,98 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Bson.TestHelpers.JsonDrivenTests; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MongoDB.Driver.Tests.JsonDrivenTests +{ + public class JsonDrivenDatabaseAggregateTest : JsonDrivenDatabaseTest + { + // private fields + private AggregateOptions _options = new AggregateOptions(); + private PipelineDefinition _pipeline; + private List _result; + private IClientSessionHandle _session; + + public JsonDrivenDatabaseAggregateTest(IMongoDatabase database, Dictionary objectMap) : base(database, objectMap) + { + } + + public override void Arrange(BsonDocument document) + { + JsonDrivenHelper.EnsureAllFieldsAreValid(document, "name", "object", "arguments", "result", "error"); + base.Arrange(document); + } + + // protected methods + protected override void AssertResult() + { + _result.Should().Equal(_expectedResult.AsBsonArray.Cast()); + } + + protected override void CallMethod(CancellationToken cancellationToken) + { + IAsyncCursor cursor; + if (_session == null) + { + cursor = _database.Aggregate(_pipeline, _options, cancellationToken); + } + else + { + cursor = _database.Aggregate(_session, _pipeline, _options, cancellationToken); + } + _result = cursor.ToList(); + } + + protected override async Task CallMethodAsync(CancellationToken cancellationToken) + { + IAsyncCursor cursor; + if (_session == null) + { + cursor = await _database.AggregateAsync(_pipeline, _options, cancellationToken).ConfigureAwait(false); + } + else + { + cursor = await _database.AggregateAsync(_session, _pipeline, _options, cancellationToken).ConfigureAwait(false); + } + _result = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false); + } + + protected override void SetArgument(string name, BsonValue value) + { + switch (name) + { + case "batchSize": + _options.BatchSize = value.ToInt32(); + return; + + case "pipeline": + _pipeline = new BsonDocumentStagePipelineDefinition(value.AsBsonArray.Cast()); + return; + + case "session": + _session = (IClientSessionHandle)_objectMap[value.AsString]; + return; + } + + base.SetArgument(name, value); + } + } +} diff --git a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenFindTest.cs b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenFindTest.cs index d5c35839f1e..68e6585d708 100644 --- a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenFindTest.cs +++ b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenFindTest.cs @@ -40,14 +40,21 @@ public JsonDrivenFindTest(IMongoCollection collection, Dictionary< // public methods public override void Arrange(BsonDocument document) { - JsonDrivenHelper.EnsureAllFieldsAreValid(document, "name", "object", "collectionOptions", "arguments", "result", "error"); + JsonDrivenHelper.EnsureAllFieldsAreValid(document, "name", "object", "collectionOptions", "arguments", "result", "results", "error"); base.Arrange(document); } // protected methods protected override void AssertResult() { - _result.Should().Equal(_expectedResult.AsBsonArray.Cast()); + if (_expectedResult is BsonDocument resultDocument && _result.Count == 1) + { + _result[0].Should().Be(resultDocument); + } + else + { + _result.Should().Equal(_expectedResult.AsBsonArray.Cast()); + } } protected override void CallMethod(CancellationToken cancellationToken) @@ -94,6 +101,10 @@ protected override void SetArgument(string name, BsonValue value) _options.Limit = value.ToInt32(); return; + case "result": + ParseExpectedResult(value.IsBsonArray ? value.AsBsonArray : new BsonArray(new[] { value })); + return; + case "session": _session = (IClientSessionHandle)_objectMap[value.AsString]; return; diff --git a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenInsertOneTest.cs b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenInsertOneTest.cs index 86849517409..7ff520741b1 100644 --- a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenInsertOneTest.cs +++ b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenInsertOneTest.cs @@ -14,10 +14,8 @@ */ using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using FluentAssertions; using MongoDB.Bson; using MongoDB.Bson.TestHelpers.JsonDrivenTests; @@ -77,6 +75,10 @@ protected override void SetArgument(string name, BsonValue value) { switch (name) { + case "bypassDocumentValidation": + _options.BypassDocumentValidation = value.ToBoolean(); + return; + case "document": _document = value.AsBsonDocument; return; diff --git a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenTestFactory.cs b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenTestFactory.cs index edb2c164520..a3909992027 100644 --- a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenTestFactory.cs +++ b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenTestFactory.cs @@ -85,6 +85,7 @@ public JsonDrivenTest CreateTest(string receiver, string name) database = _client.GetDatabase(_databaseName); switch (name) { + case "aggregate": return new JsonDrivenDatabaseAggregateTest(database, _objectMap); case "listCollectionNames": return new JsonDrivenListCollectionNamesTest(database, _objectMap); case "listCollections": return new JsonDrivenListCollectionsTest(database, _objectMap); case "runCommand": return new JsonDrivenRunCommandTest(database, _objectMap); @@ -104,7 +105,9 @@ public JsonDrivenTest CreateTest(string receiver, string name) case "deleteOne": return new JsonDrivenDeleteOneTest(collection, _objectMap); case "distinct": return new JsonDrivenDistinctTest(collection, _objectMap); case "estimatedDocumentCount": return new JsonDrivenEstimatedCountTest(collection, _objectMap); - case "find": return new JsonDrivenFindTest(collection, _objectMap); + case "find": + case "findOne": + return new JsonDrivenFindTest(collection, _objectMap); case "findOneAndDelete": return new JsonDrivenFindOneAndDeleteTest(collection, _objectMap); case "findOneAndReplace": return new JsonDrivenFindOneAndReplaceTest(collection, _objectMap); case "findOneAndUpdate": return new JsonDrivenFindOneAndUpdateTest(collection, _objectMap); diff --git a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenUpdateOneTest.cs b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenUpdateOneTest.cs index 7ce2fdb392b..81a06f301f7 100644 --- a/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenUpdateOneTest.cs +++ b/tests/MongoDB.Driver.Tests/JsonDrivenTests/JsonDrivenUpdateOneTest.cs @@ -82,6 +82,10 @@ protected override void SetArgument(string name, BsonValue value) { switch (name) { + case "arrayFilters": + _options.ArrayFilters = ParseArrayFilters(value.AsBsonArray); + return; + case "filter": _filter = new BsonDocumentFilterDefinition(value.AsBsonDocument); return; @@ -128,5 +132,15 @@ private void AssertResultAspect(string name, BsonValue expectedValue) throw new FormatException($"Invalid UpdateOne result aspect: {name}."); } } + + private IEnumerable> ParseArrayFilters(BsonArray arrayFilters) + { + var arrayFilter = new List>(); + foreach (var item in arrayFilters) + { + arrayFilter.Add(item.AsBsonDocument); + } + return arrayFilter; + } } } diff --git a/tests/MongoDB.Driver.Tests/MongoDB.Driver.Tests.csproj b/tests/MongoDB.Driver.Tests/MongoDB.Driver.Tests.csproj index c19c307477d..94c40753682 100644 --- a/tests/MongoDB.Driver.Tests/MongoDB.Driver.Tests.csproj +++ b/tests/MongoDB.Driver.Tests/MongoDB.Driver.Tests.csproj @@ -60,11 +60,19 @@ - + + + + + + + + + PreserveNewest diff --git a/tests/MongoDB.Driver.Tests/MongocryptdFactoryTests.cs b/tests/MongoDB.Driver.Tests/MongocryptdFactoryTests.cs new file mode 100644 index 00000000000..e59a990cd36 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/MongocryptdFactoryTests.cs @@ -0,0 +1,112 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Bson.TestHelpers; +using MongoDB.Driver.Encryption; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace MongoDB.Driver.Tests +{ + public class MongocryptdFactoryTests + { + [Theory] + [InlineData("mongocryptdURI", "mongodb://localhost:11111", "mongodb://localhost:11111")] + [InlineData(null, null, "mongodb://localhost:27020")] + public void CreateMongocryptdConnectionString_should_create_expected_connection_string(string optionKey, string optionValue, string expectedConnectionString) + { + var extraOptions = new Dictionary(); + if (optionKey != null) + { + extraOptions.Add(optionKey, optionValue); + } + var subject = new MongocryptdFactory(extraOptions); + var connectionString = subject.CreateMongocryptdConnectionString(); + connectionString.Should().Be(expectedConnectionString); + } + + [SkippableTheory] + [InlineData("{ mongocryptdBypassSpawn : true }", null, null, false)] + [InlineData(null, "mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)] + [InlineData("{ mongocryptdBypassSpawn : false }", "mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)] + [InlineData("{ mongocryptdBypassSpawn : false }", "mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)] + [InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/' }", "c:/mongocryptd.exe", "--idleShutdownTimeoutSecs 60", true)] + [InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/mgcr.exe' }", "c:/mgcr.exe", "--idleShutdownTimeoutSecs 60", true)] + [InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnPath : 'c:/mgcr.exe' }", "c:/mgcr.exe", "--idleShutdownTimeoutSecs 60", true)] + // args string + [InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B' }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 60", true)] + [InlineData("{ mongocryptdSpawnArgs : '--arg1 A --arg2 B --idleShutdownTimeoutSecs 50' }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)] + // args list + [InlineData("{ mongocryptdSpawnArgs : [ 'arg1 A', 'arg2 B'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 60", true)] + [InlineData("{ mongocryptdSpawnArgs : [ 'arg1 A', 'arg2 B', 'idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)] + [InlineData("{ mongocryptdSpawnArgs : [ '--arg1 A', '--arg2 B', '--idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)] + + [InlineData("{ mongocryptdBypassSpawn : false, mongocryptdSpawnArgs : [ '--arg1 A', '--arg2 B', '--idleShutdownTimeoutSecs 50'] }", "mongocryptd.exe", "--arg1 A --arg2 B --idleShutdownTimeoutSecs 50", true)] + public void Mongocryptd_should_be_spawned_with_correct_extra_arguments( + string stringExtraOptions, + string expectedPath, + string expectedArgs, + bool shouldBeSpawned) + { + var bsonDocumentExtraOptions = + stringExtraOptions != null + ? BsonDocument.Parse(stringExtraOptions) + : new BsonDocument(); + + var extraOptions = bsonDocumentExtraOptions + .Elements + .ToDictionary(k => k.Name, v => CreateTypedExtraOptions(v.Value)); + + var subject = new MongocryptdFactory(extraOptions); + + var result = subject.ShouldMongocryptdBeSpawned(out var path, out var args); + result.Should().Be(shouldBeSpawned); + path.Should().Be(expectedPath); + args.Should().Be(expectedArgs); + + object CreateTypedExtraOptions(BsonValue value) + { + if (value.IsBsonArray) + { + return value.AsBsonArray; // IEnumerable + } + else if (value.IsBoolean) + { + return (bool)value; // bool + } + else + { + return (string)value; // string + } + } + } + } + + internal static class MongocryptdFactoryReflector + { + public static string CreateMongocryptdConnectionString(this MongocryptdFactory mongocryptdHelper) + { + return (string)Reflector.Invoke(mongocryptdHelper, nameof(CreateMongocryptdConnectionString)); + } + + public static bool ShouldMongocryptdBeSpawned(this MongocryptdFactory mongocryptdHelper, out string path, out string args) + { + return (bool)Reflector.Invoke(mongocryptdHelper, nameof(ShouldMongocryptdBeSpawned), out path, out args); + } + } +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenSessionsTestRunner.cs b/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenSessionsTestRunner.cs index e5f89c3ff0f..99a06bceecf 100644 --- a/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenSessionsTestRunner.cs +++ b/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenSessionsTestRunner.cs @@ -28,21 +28,21 @@ public abstract class MongoClientJsonDrivenSessionsTestRunner : MongoClientJsonD protected override string[] ExpectedTestColumns => new[] { "description", "clientOptions", "useMultipleMongoses", "failPoint", "sessionOptions", "operations", "expectations", "outcome", "async" }; // protected methods` - protected override void TestInitialize() + protected override void TestInitialize(MongoClient client, BsonDocument test, BsonDocument shared) { - base.TestInitialize(); + base.TestInitialize(client, test, shared); KillAllSessions(); } - protected override void AssertEvents(EventCapturer actualEvents, BsonDocument test) + protected override void AssertEvent(object actualEvent, BsonDocument expectedEvent) { - base.AssertEvents( - actualEvents, - test, - document => + base.AssertEvent( + actualEvent, + expectedEvent, + (actual, expected) => { RecursiveFieldSetter.SetAll( - document, + expected, "lsid", value => { diff --git a/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenTestRunnerBase.cs b/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenTestRunnerBase.cs index e7a0faedb3c..000164573d5 100644 --- a/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenTestRunnerBase.cs +++ b/tests/MongoDB.Driver.Tests/Specifications/Runner/MongoClientJsonDrivenTestRunnerBase.cs @@ -22,7 +22,6 @@ using MongoDB.Bson.TestHelpers.JsonDrivenTests; using MongoDB.Driver.Core; using MongoDB.Driver.Core.Bindings; -using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Clusters.ServerSelectors; using MongoDB.Driver.Core.Events; using MongoDB.Driver.Core.Misc; @@ -94,12 +93,31 @@ public abstract class MongoClientJsonDrivenTestRunnerBase protected IDictionary ObjectMap => _objectMap; // Virtual methods - protected virtual void AssertEvents(EventCapturer actualEvents, BsonDocument test) + protected virtual void AssertEvent(object actualEvent, BsonDocument expectedEvent) { - AssertEvents(actualEvents, test, null); + AssertEvent(actualEvent, expectedEvent, null); } - protected virtual void AssertEvents(EventCapturer eventCapturer, BsonDocument test, Action prepareEventResult) + protected virtual void AssertEvent(object actualEvent, BsonDocument expectedEvent, Action prepareEventResult, Func[]> getPlaceholders = null) + { + if (expectedEvent.ElementCount != 1) + { + throw new FormatException("Expected event must be a document with a single element with a name the specifies the type of the event."); + } + + prepareEventResult?.Invoke(actualEvent, expectedEvent); + + var eventType = expectedEvent.GetElement(0).Name; + var eventAsserter = EventAsserterFactory.CreateAsserter(eventType); + if (getPlaceholders != null) + { + eventAsserter.ConfigurePlaceholders(getPlaceholders()); + } + + eventAsserter.AssertAspects(actualEvent, expectedEvent[0].AsBsonDocument); + } + + protected virtual void AssertEvents(EventCapturer eventCapturer, BsonDocument test) { if (test.Contains(ExpectationsKey)) { @@ -110,9 +128,7 @@ protected virtual void AssertEvents(EventCapturer eventCapturer, BsonDocument te for (var index = 0; index < n; index++) { var actualEvent = actualEvents[index]; - var expectedEvent = expectedEvents[index]; - prepareEventResult?.Invoke(expectedEvent); AssertEvent(actualEvent, expectedEvent); } if (actualEvents.Count < expectedEvents.Count) @@ -152,7 +168,7 @@ protected virtual void CheckServerRequirements(BsonDocument document) { RequireServer.Check().RunOn(runOn.AsBsonArray); } - } + } protected virtual void ConfigureClientSettings(MongoClientSettings settings, BsonDocument test) { @@ -160,44 +176,36 @@ protected virtual void ConfigureClientSettings(MongoClientSettings settings, Bso { foreach (var option in test["clientOptions"].AsBsonDocument) { - switch (option.Name) + if (!TryConfigureClientOption(settings, option)) { - case "readConcernLevel": - var level = (ReadConcernLevel)Enum.Parse(typeof(ReadConcernLevel), option.Value.AsString, ignoreCase: true); - settings.ReadConcern = new ReadConcern(level); - break; - - case "readPreference": - settings.ReadPreference = ReadPreferenceFromBsonValue(option.Value); - break; - - case "retryWrites": - settings.RetryWrites = option.Value.ToBoolean(); - break; - - case "w": - if (option.Value.IsString) - { - settings.WriteConcern = new WriteConcern(option.Value.AsString); - } - else - { - settings.WriteConcern = new WriteConcern(option.Value.ToInt32()); - } - break; - - default: - throw new FormatException($"Unexpected client option: \"{option.Name}\"."); + throw new FormatException($"Unexpected client option: \"{option.Name}\"."); } } } } + protected virtual void CreateCollection(IMongoClient client, string databaseName, string collectionName, BsonDocument test, BsonDocument shared) + { + var database = client.GetDatabase(databaseName).WithWriteConcern(WriteConcern.WMajority); + database.CreateCollection(collectionName); + } + + protected virtual MongoClient CreateClientForTestSetup() + { + return DriverTestConfiguration.Client; + } + protected virtual void CustomDataValidation(BsonDocument shared, BsonDocument test) { // do nothing by default. } + protected virtual void DropCollection(MongoClient client, string databaseName, string collectionName, BsonDocument test, BsonDocument shared) + { + var database = client.GetDatabase(databaseName).WithWriteConcern(WriteConcern.WMajority); + database.DropCollection(collectionName); + } + protected virtual void ExecuteOperations(IMongoClient client, Dictionary objectMap, BsonDocument test) { _objectMap = objectMap; @@ -206,6 +214,7 @@ protected virtual void ExecuteOperations(IMongoClient client, Dictionary()) { + ModifyOperationIfNeeded(operation); var receiver = operation["object"].AsString; var name = operation["name"].AsString; var jsonDrivenTest = factory.CreateTest(receiver, name); @@ -223,13 +232,78 @@ protected virtual void ExecuteOperations(IMongoClient client, Dictionary().ToList(); + if (documents.Count > 0) + { + var database = client.GetDatabase(databaseName); + var collection = database.GetCollection(collectionName).WithWriteConcern(WriteConcern.WMajority); + collection.InsertMany(documents); + } + } + } + + protected virtual void ModifyOperationIfNeeded(BsonDocument operation) + { + // do nothing by default + } + + protected virtual void RunTest(BsonDocument shared, BsonDocument test, EventCapturer eventCapturer) + { + using (var client = CreateDisposableClient(test, eventCapturer)) + { + ExecuteOperations(client, null, test); + } + } - protected virtual void TestInitialize() + protected virtual void TestInitialize(MongoClient client, BsonDocument test, BsonDocument shared) { // do nothing by default. } + protected virtual bool TryConfigureClientOption(MongoClientSettings settings, BsonElement option) + { + switch (option.Name) + { + case "readConcernLevel": + var level = (ReadConcernLevel)Enum.Parse(typeof(ReadConcernLevel), option.Value.AsString, ignoreCase: true); + settings.ReadConcern = new ReadConcern(level); + break; + + case "readPreference": + settings.ReadPreference = ReadPreferenceFromBsonValue(option.Value); + break; + + case "retryWrites": + settings.RetryWrites = option.Value.ToBoolean(); + break; + + case "w": + if (option.Value.IsString) + { + settings.WriteConcern = new WriteConcern(option.Value.AsString); + } + else + { + settings.WriteConcern = new WriteConcern(option.Value.ToInt32()); + } + break; + + default: + return false; + } + + return true; + } + + protected virtual void VerifyCollectionData(IEnumerable expectedDocuments) + { + VerifyCollectionData(expectedDocuments, null); + } + protected virtual void VerifyCollectionOutcome(BsonDocument outcome) { foreach (var aspect in outcome) @@ -260,13 +334,6 @@ protected FailPoint ConfigureFailPoint(BsonDocument test) return null; } - protected void CreateCollection() - { - var client = DriverTestConfiguration.Client; - var database = client.GetDatabase(DatabaseName).WithWriteConcern(WriteConcern.WMajority); - database.CreateCollection(CollectionName); - } - protected DisposableMongoClient CreateDisposableClient(BsonDocument test, EventCapturer eventCapturer) { var useMultipleShardRouters = test.GetValue("useMultipleMongoses", false).AsBoolean; @@ -284,56 +351,32 @@ protected DisposableMongoClient CreateDisposableClient(BsonDocument test, EventC useMultipleShardRouters); } - protected void DropCollection() - { - var client = DriverTestConfiguration.Client; - var database = client.GetDatabase(DatabaseName).WithWriteConcern(WriteConcern.WMajority); - database.DropCollection(CollectionName); - } - - protected void InsertData(BsonDocument shared) - { - if (shared.Contains(DataKey)) - { - var documents = shared[DataKey].AsBsonArray.Cast().ToList(); - if (documents.Count > 0) - { - var client = DriverTestConfiguration.Client; - var database = client.GetDatabase(DatabaseName); - var collection = database.GetCollection(CollectionName).WithWriteConcern(WriteConcern.WMajority); - collection.InsertMany(documents); - } - } - } - protected void SetupAndRunTest(JsonDrivenTestCase testCase) { CheckServerRequirements(testCase.Shared); SetupAndRunTest(testCase.Shared, testCase.Test); } - protected void VerifyCollectionData(IEnumerable expectedDocuments) + protected void VerifyCollectionData(IEnumerable expectedDocuments, Action prepareExpectedResult) { var database = DriverTestConfiguration.Client.GetDatabase(DatabaseName).WithReadConcern(ReadConcern.Local); var collection = database.GetCollection(CollectionName); var actualDocuments = collection.Find("{}").ToList(); - actualDocuments.Should().BeEquivalentTo(expectedDocuments); - } - - - // private methods - private void AssertEvent(object actualEvent, BsonDocument expectedEvent) - { - if (expectedEvent.ElementCount != 1) + if (prepareExpectedResult != null) { - throw new FormatException("Expected event must be a document with a single element with a name the specifies the type of the event."); - } + var n = Math.Min(actualDocuments.Count, expectedDocuments.Count()); + for (var index = 0; index < n; index++) + { + var actualEvent = actualDocuments.ElementAt(index); - var eventType = expectedEvent.GetElement(0).Name; - var eventAsserter = EventAsserterFactory.CreateAsserter(eventType); - eventAsserter.AssertAspects(actualEvent, expectedEvent[0].AsBsonDocument); + var expectedEvent = expectedDocuments.ElementAt(index); + prepareExpectedResult(actualEvent, expectedEvent); + } + } + actualDocuments.Should().BeEquivalentTo(expectedDocuments); } + // private methods private List GetEvents(EventCapturer eventCapturer) { var events = new List(); @@ -375,10 +418,11 @@ private void SetupAndRunTest(BsonDocument shared, BsonDocument test) DatabaseName = shared[DatabaseNameKey].AsString; CollectionName = shared[CollectionNameKey].AsString; - TestInitialize(); - DropCollection(); - CreateCollection(); - InsertData(shared); + var client = CreateClientForTestSetup(); + TestInitialize(client, test, shared); + DropCollection(client, DatabaseName, CollectionName, test, shared); + CreateCollection(client, DatabaseName, CollectionName, test, shared); + InsertData(client, DatabaseName, CollectionName, shared); using (ConfigureFailPoint(test)) { diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/ClientSideEncryptionTestRunner.cs b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/ClientSideEncryptionTestRunner.cs new file mode 100644 index 00000000000..991ee512864 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/ClientSideEncryptionTestRunner.cs @@ -0,0 +1,316 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using MongoDB.Bson; +using MongoDB.Bson.TestHelpers.JsonDrivenTests; +using MongoDB.Driver.Core.Events; +using MongoDB.Driver.Encryption; +using MongoDB.Driver.Tests.Specifications.Runner; +using Xunit; + +namespace MongoDB.Driver.Tests.Specifications.client_side_encryption +{ + public class ClientSideEncryptionTestRunner : MongoClientJsonDrivenTestRunnerBase + { + [SkippableTheory] + [ClassData(typeof(TestCaseFactory))] + public void Run(JsonDrivenTestCase testCase) + { + SetupAndRunTest(testCase); + } + + protected override string[] ExpectedTestColumns => new[] { "description", "clientOptions", "operations", "expectations", "skipReason", "async", "outcome" }; + + protected override string[] ExpectedSharedColumns + { + get + { + var expectedSharedColumns = new List(base.ExpectedSharedColumns); + expectedSharedColumns.AddRange(new[] { "json_schema", "key_vault_data" }); + return expectedSharedColumns.ToArray(); + } + } + + protected override void AssertEvent(object actualEvent, BsonDocument expectedEvent) + { + base.AssertEvent( + actualEvent, + expectedEvent, + (actual, expected) => + { + if (actualEvent is CommandStartedEvent commandStartedEvent) + { + var expectedCommand = expected + .GetValue("command_started_event") + .AsBsonDocument + .GetValue("command") + .AsBsonDocument; + ReplaceTypeAssertionWithActual(commandStartedEvent.Command, expectedCommand); + } + }, + getPlaceholders: () => new KeyValuePair[0]); // do not use placeholders + } + + protected override MongoClient CreateClientForTestSetup() + { + var clientSettings = DriverTestConfiguration.GetClientSettings().Clone(); + clientSettings.GuidRepresentation = GuidRepresentation.Unspecified; + return new MongoClient(clientSettings); + } + + protected override void CreateCollection(IMongoClient client, string databaseName, string collectionName, BsonDocument test, BsonDocument shared) + { + if (shared.TryGetElement("json_schema", out var jsonSchema)) + { + var database = client.GetDatabase(databaseName).WithWriteConcern(WriteConcern.WMajority); + var validatorSchema = new BsonDocument("$jsonSchema", jsonSchema.Value.ToBsonDocument()); + database.CreateCollection( + collectionName, + new CreateCollectionOptions + { + Validator = new BsonDocumentFilterDefinition(validatorSchema) + }); + } + else + { + base.CreateCollection(client, databaseName, collectionName, test, shared); + } + } + + protected override void DropCollection(MongoClient client, string databaseName, string collectionName, BsonDocument test, BsonDocument shared) + { + base.DropCollection(client, databaseName, collectionName, test, shared); + + if (shared.Contains("key_vault_data")) + { + var adminDatabase = client.GetDatabase("admin").WithWriteConcern(WriteConcern.WMajority); + adminDatabase.DropCollection("datakeys"); + } + } + + protected override void InsertData(IMongoClient client, string databaseName, string collectionName, BsonDocument shared) + { + base.InsertData(client, databaseName, collectionName, shared); + + if (shared.TryGetValue("key_vault_data", out var keyVaultData)) + { + var adminDatabase = client.GetDatabase("admin"); + var keyVaultCollection = adminDatabase.GetCollection( + "datakeys", + new MongoCollectionSettings + { + AssignIdOnInsert = false + }); + var keyVaultDocuments = keyVaultData.AsBsonArray.Select(c => c.AsBsonDocument); + keyVaultCollection.InsertMany(keyVaultDocuments); + } + } + + protected override void ModifyOperationIfNeeded(BsonDocument operation) + { + base.ModifyOperationIfNeeded(operation); + if (!operation.Contains("object")) + { + operation.Add(new BsonElement("object", "collection")); + } + } + + protected override bool TryConfigureClientOption(MongoClientSettings settings, BsonElement option) + { + switch (option.Name) + { + case "autoEncryptOpts": + settings.AutoEncryptionOptions = ConfigureAutoEncryptionOptions(option.Value.AsBsonDocument); + break; + default: + return false; + } + + return true; + } + + protected override void VerifyCollectionData(IEnumerable expectedDocuments) + { + base.VerifyCollectionData(expectedDocuments, ReplaceTypeAssertionWithActual); + } + + // private methods + private AutoEncryptionOptions ConfigureAutoEncryptionOptions(BsonDocument autoEncryptOpts) + { + var keyVaultCollectionNamespace = new CollectionNamespace("admin", "datakeys"); + var extraOptions = new Dictionary() + { + { "mongocryptdSpawnPath", Environment.GetEnvironmentVariable("MONGODB_BINARIES") ?? string.Empty } + }; + + var kmsProviders = new ReadOnlyDictionary>(new Dictionary>()); + var autoEncryptionOptions = new AutoEncryptionOptions( + keyVaultNamespace: keyVaultCollectionNamespace, + kmsProviders: kmsProviders, + extraOptions: extraOptions); + + foreach (var option in autoEncryptOpts.Elements) + { + switch (option.Name) + { + case "kmsProviders": + kmsProviders = ParseKmsProviders(option.Value.AsBsonDocument); + autoEncryptionOptions = autoEncryptionOptions + .With(kmsProviders: kmsProviders); + break; + case "schemaMap": + var schemaMaps = new Dictionary(); + var schemaMapsDocument = option.Value.AsBsonDocument; + foreach (var schemaMapElement in schemaMapsDocument.Elements) + { + schemaMaps.Add(schemaMapElement.Name, schemaMapElement.Value.AsBsonDocument); + } + autoEncryptionOptions = autoEncryptionOptions.With(schemaMap: schemaMaps); + break; + case "bypassAutoEncryption": + autoEncryptionOptions = autoEncryptionOptions.With(bypassAutoEncryption: option.Value.ToBoolean()); + break; + case "keyVaultNamespace": + autoEncryptionOptions = autoEncryptionOptions.With(keyVaultNamespace: CollectionNamespace.FromFullName(option.Value.AsString)); + break; + + default: + throw new Exception($"Unexpected auto encryption option {option.Name}."); + } + } + + return autoEncryptionOptions; + } + + private ReadOnlyDictionary> ParseKmsProviders(BsonDocument kmsProviders) + { + var providers = new Dictionary>(); + foreach (var kmsProvider in kmsProviders.Elements) + { + var kmsOptions = new Dictionary(); + switch (kmsProvider.Name) + { + case "aws": + { + var awsRegion = Environment.GetEnvironmentVariable("FLE_AWS_REGION") ?? "us-east-1"; + var awsAccessKey = Environment.GetEnvironmentVariable("FLE_AWS_ACCESS_KEY_ID") ?? throw new Exception("The FLE_AWS_ACCESS_KEY_ID system variable should be configured on the machine."); + var awsSecretAccessKey = Environment.GetEnvironmentVariable("FLE_AWS_SECRET_ACCESS_KEY") ?? throw new Exception("The FLE_AWS_SECRET_ACCESS_KEY system variable should be configured on the machine."); + kmsOptions.Add("region", awsRegion); + kmsOptions.Add("accessKeyId", awsAccessKey); + kmsOptions.Add("secretAccessKey", awsSecretAccessKey); + } + providers.Add(kmsProvider.Name, kmsOptions); + break; + case "local": + if (kmsProvider.Value.AsBsonDocument.TryGetElement("key", out var key)) + { + var binary = key.Value.AsBsonBinaryData; + kmsOptions.Add(key.Name, binary.Bytes); + } + providers.Add(kmsProvider.Name, kmsOptions); + break; + default: + throw new Exception($"Unexpected kms provider type {kmsProvider.Name}."); + } + } + + return new ReadOnlyDictionary>(providers); + } + + public void ReplaceTypeAssertionWithActual(BsonDocument actual, BsonDocument expected) + { + for (int i = 0; i < expected.ElementCount; i++) + { + var expectedElement = expected.ElementAt(i); + var value = expectedElement.Value; + if (value.IsBsonDocument) + { + var valueDocument = value.AsBsonDocument; + var actualValue = actual.GetValue(expectedElement.Name, null); + if (valueDocument.ElementCount == 1 && valueDocument.Select(c => c.Name).Single().Equals("$$type")) + { + var type = valueDocument["$$type"].AsString; + if (type.Equals("binData")) + { + expected[expectedElement.Name] = actualValue; + } + else if (type.Equals("long")) + { + expected[expectedElement.Name] = actualValue; + } + } + else if (actualValue != null && actualValue.IsBsonDocument) + { + ReplaceTypeAssertionWithActual(actualValue.AsBsonDocument, valueDocument); + } + } + else if (value.IsBsonArray) + { + ReplaceTypeAssertionWithActual(actual[expectedElement.Name].AsBsonArray, value.AsBsonArray); + } + } + } + + private void ReplaceTypeAssertionWithActual(BsonArray actual, BsonArray expected) + { + for (int i = 0; i < expected.Count; i++) + { + var value = expected[i]; + if (value.IsBsonDocument) + { + ReplaceTypeAssertionWithActual(actual[i].AsBsonDocument, value.AsBsonDocument); + } + else if (value.IsBsonArray) + { + ReplaceTypeAssertionWithActual(actual[i].AsBsonArray, value.AsBsonArray); + } + } + } + } + + // nested types + public class TestCaseFactory : JsonDrivenTestCaseFactory + { + #region static + private static readonly string[] __ignoredTestNames = + { + // https://jira.mongodb.org/browse/SPEC-1403 + "maxWireVersion.json:operation fails with maxWireVersion < 8" + }; + #endregion + + // protected properties + protected override string PathPrefix => "MongoDB.Driver.Tests.Specifications.client_side_encryption.tests."; + + // protected methods + protected override IEnumerable CreateTestCases(BsonDocument document) + { + var testCases = base.CreateTestCases(document).Where(test => !__ignoredTestNames.Any(ignoredName => test.Name.EndsWith(ignoredName))); + foreach (var testCase in testCases) + { + foreach (var async in new[] { false, true }) + { + var name = $"{testCase.Name}:async={async}"; + var test = testCase.Test.DeepClone().AsBsonDocument.Add("async", async); + yield return new JsonDrivenTestCase(name, testCase.Shared, test); + } + } + } + } +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs new file mode 100644 index 00000000000..103302dbe61 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs @@ -0,0 +1,835 @@ +/* Copyright 2019-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Bson.TestHelpers.JsonDrivenTests; +using MongoDB.Bson.TestHelpers.XunitExtensions; +using MongoDB.Driver.Core; +using MongoDB.Driver.Core.Bindings; +using MongoDB.Driver.Core.Clusters; +using MongoDB.Driver.Core.Configuration; +using MongoDB.Driver.Core.Events; +using MongoDB.Driver.Core.Misc; +using MongoDB.Driver.Core.Operations; +using MongoDB.Driver.Core.TestHelpers.XunitExtensions; +using MongoDB.Driver.Encryption; +using MongoDB.Driver.TestHelpers; +using MongoDB.Libmongocrypt; +using Xunit; + +namespace MongoDB.Driver.Tests.Specifications.client_side_encryption.prose_tests +{ + public class ClientEncryptionProseTests + { + #region static + private static readonly CollectionNamespace __collCollectionNamespace = CollectionNamespace.FromFullName("db.coll"); + private static readonly CollectionNamespace __keyVaultCollectionNamespace = CollectionNamespace.FromFullName("admin.datakeys"); + #endregion + + private const string LocalMasterKey = "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk"; + private const string SchemaMap = + @"{ + ""db.coll"": { + ""bsonType"": ""object"", + ""properties"": { + ""encrypted_placeholder"": { + ""encrypt"": { + ""keyId"": ""/placeholder"", + ""bsonType"": ""string"", + ""algorithm"": ""AEAD_AES_256_CBC_HMAC_SHA_512-Random"" + } + } + } + } + }"; + + private readonly ICluster _cluster; + + public ClientEncryptionProseTests() + { + _cluster = CoreTestConfiguration.Cluster; + } + + [SkippableTheory] + [ParameterAttributeData] + public void BsonSizeLimitAndBatchSizeSplittingTest( + [Values(false, true)] bool async) + { + RequireServer.Check().Supports(Feature.ClientSideEncryption); + + var eventCapturer = new EventCapturer().Capture(e => e.CommandName == "insert"); + using (var client = ConfigureClient()) + using (var clientEncrypted = ConfigureClientEncrypted(kmsProviderFilter: "local", eventCapturer: eventCapturer)) + { + var collLimitSchema = JsonFileReader.Instance.Documents["limits.limits-schema.json"]; + CreateCollection(client, __collCollectionNamespace, new BsonDocument("$jsonSchema", collLimitSchema)); + var datakeysLimitsKey = JsonFileReader.Instance.Documents["limits.limits-key.json"]; + var keyVaultCollection = GetCollection(client, __keyVaultCollectionNamespace); + Insert(keyVaultCollection, async, datakeysLimitsKey); + + var coll = GetCollection(clientEncrypted, __collCollectionNamespace); + + var exception = Record.Exception( + () => Insert( + coll, + async, + new BsonDocument + { + { "_id", "no_encryption_under_2mib" }, + { "unencrypted", new string('a', 2097152 - 1000) } + })); + exception.Should().BeNull(); + eventCapturer.Clear(); + + exception = Record.Exception( + () => Insert( + coll, + async, + new BsonDocument + { + { "_id", "no_encryption_over_2mib" }, + { "unencrypted", new string('a', 2097152) } + })); + exception.Should().NotBeNull(); + eventCapturer.Clear(); + + var limitsDoc = JsonFileReader.Instance.Documents["limits.limits-doc.json"]; + limitsDoc.AddRange( + new BsonDocument + { + {"_id", "encryption_exceeds_2mib"}, + {"unencrypted", new string('a', 2097152 - 2000)} + }); + exception = Record.Exception( + () => Insert( + coll, + async, + limitsDoc)); + exception.Should().BeNull(); + eventCapturer.Clear(); + + exception = Record.Exception( + () => Insert( + coll, + async, + new BsonDocument + { + { "_id", "no_encryption_under_2mib_1" }, + { "unencrypted", new string('a', 2097152 - 1000) } + }, + new BsonDocument + { + { "_id", "no_encryption_under_2mib_2" }, + { "unencrypted", new string('a', 2097152 - 1000) } + })); + exception.Should().BeNull(); + eventCapturer.Count.Should().Be(2); + eventCapturer.Clear(); + + var limitsDoc1 = JsonFileReader.Instance.Documents["limits.limits-doc.json"]; + limitsDoc1.AddRange( + new BsonDocument + { + { "_id", "encryption_exceeds_2mib_1" }, + { "unencrypted", new string('a', 2097152 - 2000) } + }); + var limitsDoc2 = JsonFileReader.Instance.Documents["limits.limits-doc.json"]; + limitsDoc2.AddRange( + new BsonDocument + { + { "_id", "encryption_exceeds_2mib_2" }, + { "unencrypted", new string('a', 2097152 - 2000) } + }); + exception = Record.Exception( + () => Insert( + coll, + async, + limitsDoc1, + limitsDoc2)); + exception.Should().BeNull(); + eventCapturer.Count.Should().Be(2); + eventCapturer.Clear(); + } + } + + [SkippableTheory] + [ParameterAttributeData] + public void CorpusTest( + [Values(false, true)] bool useLocalSchema, + [Values(false, true)] bool async) + { + RequireServer.Check().Supports(Feature.ClientSideEncryption); + + var corpusSchema = JsonFileReader.Instance.Documents["corpus.corpus-schema.json"]; + var schemaMap = useLocalSchema ? new BsonDocument("db.coll", corpusSchema) : null; + using (var client = ConfigureClient()) + using (var clientEncrypted = ConfigureClientEncrypted(schemaMap)) + using (var clientEncryption = ConfigureClientEncryption(clientEncrypted.Wrapped as MongoClient)) + { + CreateCollection(client, __collCollectionNamespace, new BsonDocument("$jsonSchema", corpusSchema)); + + var corpusKeyLocal = JsonFileReader.Instance.Documents["corpus.corpus-key-local.json"]; + var corpusKeyAws = JsonFileReader.Instance.Documents["corpus.corpus-key-aws.json"]; + var keyVaultCollection = GetCollection(client, __keyVaultCollectionNamespace); + Insert(keyVaultCollection, async, corpusKeyLocal, corpusKeyAws); + + var corpus = JsonFileReader.Instance.Documents["corpus.corpus.json"]; + var corpusCopied = new BsonDocument + { + corpus.GetElement("_id"), + corpus.GetElement("altname_aws"), + corpus.GetElement("altname_local") + }; + + foreach (var corpusElement in corpus.Elements.Where(c => c.Value.IsBsonDocument)) + { + var corpusValue = corpusElement.Value.DeepClone(); + var kms = corpusValue["kms"].AsString; + var abbreviatedAlgorithmName = corpusValue["algo"].AsString; + var identifier = corpusValue["identifier"].AsString; + var allowed = corpusValue["allowed"].ToBoolean(); + var value = corpusValue["value"]; + var method = corpusValue["method"].AsString; + switch (method) + { + case "auto": + corpusCopied.Add(corpusElement); + continue; + case "explicit": + { + var encryptionOptions = CreateEncryptOptions(abbreviatedAlgorithmName, identifier, kms); + BsonBinaryData encrypted = null; + var exception = Record.Exception(() => + { + encrypted = ExplicitEncrypt( + clientEncryption, + encryptionOptions, + value, + async); + }); + if (allowed) + { + exception.Should().BeNull(); + encrypted.Should().NotBeNull(); + corpusValue["value"] = encrypted; + } + else + { + exception.Should().NotBeNull(); + } + corpusCopied.Add(new BsonElement(corpusElement.Name, corpusValue)); + } + break; + default: + throw new ArgumentException($"Unsupported method name {method}.", nameof(method)); + } + } + + var coll = GetCollection(clientEncrypted, __collCollectionNamespace); + Insert(coll, async, corpusCopied); + + var corpusDecrypted = Find(coll, new BsonDocument(), async).Single(); + corpusDecrypted.Should().Be(corpus); + + var corpusEncryptedExpected = JsonFileReader.Instance.Documents["corpus.corpus-encrypted.json"]; + coll = GetCollection(client, __collCollectionNamespace); + var corpusEncryptedActual = Find(coll, new BsonDocument(), async).Single(); + foreach (var expectedElement in corpusEncryptedExpected.Elements.Where(c => c.Value.IsBsonDocument)) + { + var expectedElementValue = expectedElement.Value; + var expectedAlgorithm = ParseAlgorithm(expectedElementValue["algo"].AsString); + var expectedAllowed = expectedElementValue["allowed"].ToBoolean(); + var expectedValue = expectedElementValue["value"]; + var actualValue = corpusEncryptedActual.GetValue(expectedElement.Name)["value"]; + + switch (expectedAlgorithm) + { + case EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic: + actualValue.Should().Be(expectedValue); + break; + case EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random: + if (expectedAllowed) + { + actualValue.Should().NotBe(expectedValue); + } + break; + default: + throw new ArgumentException($"Unsupported expected algorithm {expectedAllowed}.", nameof(expectedAlgorithm)); + } + + if (expectedAllowed) + { + var actualDecryptedValue = ExplicitDecrypt(clientEncryption, actualValue.AsBsonBinaryData, async); + var expectedDecryptedValue = ExplicitDecrypt(clientEncryption, expectedValue.AsBsonBinaryData, async); + actualDecryptedValue.Should().Be(expectedDecryptedValue); + } + else + { + actualValue.Should().Be(expectedValue); + } + } + } + + EncryptOptions CreateEncryptOptions(string algorithm, string identifier, string kms) + { + Guid? keyId = null; + string alternateName = null; + if (identifier == "id") + { + switch (kms) + { + case "local": + keyId = GuidConverter.FromBytes(Convert.FromBase64String("LOCALAAAAAAAAAAAAAAAAA=="), GuidRepresentation.Standard); + break; + case "aws": + keyId = GuidConverter.FromBytes(Convert.FromBase64String("AWSAAAAAAAAAAAAAAAAAAA=="), GuidRepresentation.Standard); + break; + default: + throw new ArgumentException($"Unsupported kms type {kms}."); + } + } + else if (identifier == "altname") + { + alternateName = kms; + } + else + { + throw new ArgumentException($"Unsupported identifier {identifier}.", nameof(identifier)); + } + + return new EncryptOptions(ParseAlgorithm(algorithm).ToString(), alternateName, keyId); + } + + EncryptionAlgorithm ParseAlgorithm(string algorithm) + { + switch (algorithm) + { + case "rand": + return EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random; + case "det": + return EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic; + default: + throw new ArgumentException($"Unsupported algorithm {algorithm}."); + } + } + } + + [SkippableTheory] + [ParameterAttributeData] + public void CreateDataKeyAndDoubleEncryptionTest( + [Values("local", "aws")] string kmsProvider, + [Values(false, true)] bool async) + { + RequireServer.Check().Supports(Feature.ClientSideEncryption); + + using (var client = ConfigureClient()) + using (var clientEncrypted = ConfigureClientEncrypted(BsonDocument.Parse(SchemaMap))) + using (var clientEncryption = ConfigureClientEncryption(clientEncrypted.Wrapped as MongoClient)) + { + var dataKeyOptions = CreateDataKeyOptions(kmsProvider); + + Guid dataKey; + if (async) + { + dataKey = clientEncryption + .CreateDataKeyAsync(kmsProvider, dataKeyOptions, CancellationToken.None) + .GetAwaiter() + .GetResult(); + } + else + { + dataKey = clientEncryption.CreateDataKey(kmsProvider, dataKeyOptions, CancellationToken.None); + } + + var keyVaultCollection = GetCollection(client, __keyVaultCollectionNamespace); + var keyVaultDocument = + Find( + keyVaultCollection, + new BsonDocument("_id", new BsonBinaryData(dataKey, GuidRepresentation.Standard)), + async) + .Single(); + keyVaultDocument["masterKey"]["provider"].Should().Be(BsonValue.Create(kmsProvider)); + + var encryptOptions = new EncryptOptions( + EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic.ToString(), + keyId: dataKey); + + var encryptedValue = ExplicitEncrypt( + clientEncryption, + encryptOptions, + $"hello {kmsProvider}", + async); + encryptedValue.SubType.Should().Be(BsonBinarySubType.Encrypted); + + var coll = GetCollection(clientEncrypted, __collCollectionNamespace); + Insert( + coll, + async, + new BsonDocument + { + {"_id", kmsProvider}, + {"value", encryptedValue} + }); + + var findResult = Find(coll, new BsonDocument("_id", kmsProvider), async).Single(); + findResult["value"].ToString().Should().Be($"hello {kmsProvider}"); + + encryptOptions = new EncryptOptions( + EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic.ToString(), + alternateKeyName: $"{kmsProvider}_altname"); + var encryptedValueWithAlternateKeyName = ExplicitEncrypt( + clientEncryption, + encryptOptions, + $"hello {kmsProvider}", + async); + encryptedValueWithAlternateKeyName.SubType.Should().Be(BsonBinarySubType.Encrypted); + encryptedValueWithAlternateKeyName.Should().Be(encryptedValue); + + if (kmsProvider == "local") // the test description expects this assert only once for a local kms provider + { + coll = GetCollection(clientEncrypted, __collCollectionNamespace); + var exception = Record.Exception(() => Insert(coll, async, new BsonDocument("encrypted_placeholder", encryptedValue))); + exception.Should().BeOfType(); + } + } + } + + [SkippableTheory] + [ParameterAttributeData] + public void ExternalKeyVaultTest( + [Values(false, true)] bool withExternalKeyVault, + [Values(false, true)] bool async) + { + RequireServer.Check().Supports(Feature.ClientSideEncryption); + + var clientEncryptedSchema = new BsonDocument("db.coll", JsonFileReader.Instance.Documents["external.external-schema.json"]); + using (var client = ConfigureClient()) + using (var clientEncrypted = ConfigureClientEncrypted(clientEncryptedSchema, withExternalKeyVault)) + using (var clientEncryption = ConfigureClientEncryption(clientEncrypted.Wrapped as MongoClient)) + { + var datakeys = GetCollection(client, __keyVaultCollectionNamespace); + var externalKey = JsonFileReader.Instance.Documents["external.external-key.json"]; + Insert(datakeys, async, externalKey); + + var coll = GetCollection(clientEncrypted, __collCollectionNamespace); + var exception = Record.Exception(() => Insert(coll, async, new BsonDocument("encrypted", "test"))); + if (withExternalKeyVault) + { + exception.InnerException.Should().BeOfType(); + } + else + { + exception.Should().BeNull(); + } + + var encryptionOptions = new EncryptOptions( + algorithm: EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic.ToString(), + keyId: GuidConverter.FromBytes(Convert.FromBase64String("LOCALAAAAAAAAAAAAAAAAA=="), GuidRepresentation.Standard)); + exception = Record.Exception(() => ExplicitEncrypt(clientEncryption, encryptionOptions, "test", async)); + if (withExternalKeyVault) + { + exception.InnerException.Should().BeOfType(); + } + else + { + exception.Should().BeNull(); + } + } + } + + [SkippableTheory] + [ParameterAttributeData] + public void ViewAreProhibitedTest([Values(false, true)] bool async) + { + RequireServer.Check().Supports(Feature.ClientSideEncryption); + + var viewName = CollectionNamespace.FromFullName("db.view"); + using (var client = ConfigureClient(false)) + using (var clientEncrypted = ConfigureClientEncrypted(kmsProviderFilter: "local")) + { + DropView(viewName); + client + .GetDatabase(viewName.DatabaseNamespace.DatabaseName) + .CreateView( + viewName.CollectionName, + __collCollectionNamespace.CollectionName, + new EmptyPipelineDefinition()); + + var view = GetCollection(clientEncrypted, viewName); + var exception = Record.Exception( + () => Insert( + view, + async, + documents: new BsonDocument("test", 1))); + exception.Message.Should().Be("Encryption related exception: cannot auto encrypt a view."); + } + } + + // private methods + private DisposableMongoClient ConfigureClient(bool clearCollections = true) + { + var client = CreateMongoClient(); + if (clearCollections) + { + var clientAdminDatabase = client.GetDatabase(__keyVaultCollectionNamespace.DatabaseNamespace.DatabaseName); + clientAdminDatabase.DropCollection(__keyVaultCollectionNamespace.CollectionName); + var clientDbDatabase = client.GetDatabase(__collCollectionNamespace.DatabaseNamespace.DatabaseName); + clientDbDatabase.DropCollection(__collCollectionNamespace.CollectionName); + } + return client; + } + + private DisposableMongoClient ConfigureClientEncrypted( + BsonDocument schemaMap = null, + bool withExternalKeyVault = false, + string kmsProviderFilter = null, + EventCapturer eventCapturer = null) + { + var kmsProviders = GetKmsProviders(); + + var clientEncrypted = + CreateMongoClient( + keyVaultNamespace: __keyVaultCollectionNamespace, + schemaMapDocument: schemaMap, + kmsProviders: + kmsProviderFilter == null + ? kmsProviders + : kmsProviders + .Where(c => c.Key == kmsProviderFilter) + .ToDictionary(key => key.Key, value => value.Value), + withExternalKeyVault: withExternalKeyVault, + clusterConfigurator: + eventCapturer != null + ? c => c.Subscribe(eventCapturer) + : (Action)null); + return clientEncrypted; + } + + private ClientEncryption ConfigureClientEncryption(MongoClient client) + { + var clientEncryptionOptions = new ClientEncryptionOptions( + keyVaultClient: client.Settings.AutoEncryptionOptions.KeyVaultClient ?? client, + keyVaultNamespace: __keyVaultCollectionNamespace, + kmsProviders: GetKmsProviders()); + + return new ClientEncryption(clientEncryptionOptions); + } + + private void CreateCollection(IMongoClient client, CollectionNamespace collectionNamespace, BsonDocument validatorSchema) + { + client + .GetDatabase(collectionNamespace.DatabaseNamespace.DatabaseName) + .CreateCollection( + collectionNamespace.CollectionName, + new CreateCollectionOptions() + { + Validator = new BsonDocumentFilterDefinition(validatorSchema) + }); + } + + private DataKeyOptions CreateDataKeyOptions(string kmsProvider) + { + var alternateKeyNames = new[] { $"{kmsProvider}_altname" }; + switch (kmsProvider) + { + case "local": + return new DataKeyOptions(alternateKeyNames: alternateKeyNames); + case "aws": + var masterKey = new BsonDocument + { + { "region", "us-east-1" }, + { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" } + }; + return new DataKeyOptions( + alternateKeyNames: alternateKeyNames, + masterKey: masterKey); + default: + throw new ArgumentException($"Incorrect kms provider {kmsProvider}", nameof(kmsProvider)); + } + } + + private DisposableMongoClient CreateMongoClient( + CollectionNamespace keyVaultNamespace = null, + BsonDocument schemaMapDocument = null, + IReadOnlyDictionary> kmsProviders = null, + bool withExternalKeyVault = false, + Action clusterConfigurator = null) + { + var mongoClientSettings = DriverTestConfiguration.GetClientSettings().Clone(); + mongoClientSettings.GuidRepresentation = GuidRepresentation.Unspecified; + mongoClientSettings.ClusterConfigurator = clusterConfigurator; + + if (keyVaultNamespace != null || schemaMapDocument != null || kmsProviders != null || withExternalKeyVault) + { + var extraOptions = new Dictionary() + { + { "mongocryptdSpawnPath", Environment.GetEnvironmentVariable("MONGODB_BINARIES") ?? string.Empty } + }; + + var schemaMap = GetSchemaMapIfNotNull(schemaMapDocument); + + if (kmsProviders == null) + { + kmsProviders = new ReadOnlyDictionary>(new Dictionary>()); + } + + var autoEncryptionOptions = new AutoEncryptionOptions( + keyVaultNamespace: keyVaultNamespace, + kmsProviders: kmsProviders, + schemaMap: schemaMap, + extraOptions: extraOptions); + + if (withExternalKeyVault) + { + var externalKeyVaultClientSettings = DriverTestConfiguration.GetClientSettings().Clone(); + externalKeyVaultClientSettings.Credential = MongoCredential.FromComponents(null, null, "fake-user", "fake-pwd"); + var externalKeyVaultClient = new MongoClient(externalKeyVaultClientSettings); + autoEncryptionOptions = autoEncryptionOptions.With(keyVaultClient: externalKeyVaultClient); + } + mongoClientSettings.AutoEncryptionOptions = autoEncryptionOptions; + } + + return new DisposableMongoClient(new MongoClient(mongoClientSettings)); + } + + private void DropView(CollectionNamespace viewNamespace) + { + var operation = new DropCollectionOperation(viewNamespace, CoreTestConfiguration.MessageEncoderSettings); + using (var session = CoreTestConfiguration.StartSession(_cluster)) + using (var binding = new WritableServerBinding(_cluster, session.Fork())) + using (var bindingHandle = new ReadWriteBindingHandle(binding)) + { + operation.Execute(bindingHandle, CancellationToken.None); + } + } + + private BsonValue ExplicitDecrypt( + ClientEncryption clientEncryption, + BsonBinaryData value, + bool async) + { + BsonValue decryptedValue; + if (async) + { + decryptedValue = clientEncryption + .DecryptAsync( + value, + CancellationToken.None) + .GetAwaiter() + .GetResult(); + } + else + { + decryptedValue = clientEncryption.Decrypt( + value, + CancellationToken.None); + } + + return decryptedValue; + } + + private BsonBinaryData ExplicitEncrypt( + ClientEncryption clientEncryption, + EncryptOptions encryptOptions, + BsonValue value, + bool async) + { + BsonBinaryData encryptedValue; + if (async) + { + encryptedValue = clientEncryption + .EncryptAsync( + value, + encryptOptions, + CancellationToken.None) + .GetAwaiter() + .GetResult(); + } + else + { + encryptedValue = clientEncryption.Encrypt( + value, + encryptOptions, + CancellationToken.None); + } + + return encryptedValue; + } + + private IAsyncCursor Find( + IMongoCollection collection, + BsonDocument filter, + bool async) + { + if (async) + { + return collection + .FindAsync(new BsonDocumentFilterDefinition(filter)) + .GetAwaiter() + .GetResult(); + } + else + { + return collection + .FindSync(new BsonDocumentFilterDefinition(filter)); + } + } + + private IMongoCollection GetCollection(IMongoClient client, CollectionNamespace collectionNamespace) + { + return client + .GetDatabase(collectionNamespace.DatabaseNamespace.DatabaseName) + .GetCollection(collectionNamespace.CollectionName); + } + + private IReadOnlyDictionary> GetKmsProviders() + { + var kmsProviders = new Dictionary>(); + + var awsRegion = Environment.GetEnvironmentVariable("FLE_AWS_REGION") ?? "us-east-1"; + var awsAccessKey = Environment.GetEnvironmentVariable("FLE_AWS_ACCESS_KEY_ID") ?? throw new Exception("The AWS_ACCESS_KEY_ID system variable should be configured on the machine."); + var awsSecretAccessKey = Environment.GetEnvironmentVariable("FLE_AWS_SECRET_ACCESS_KEY") ?? throw new Exception("The AWS_SECRET_ACCESS_KEY system variable should be configured on the machine."); + var kmsOptions = new Dictionary + { + { "region", awsRegion }, + { "accessKeyId", awsAccessKey }, + { "secretAccessKey", awsSecretAccessKey } + }; + kmsProviders.Add("aws", kmsOptions); + + var localOptions = new Dictionary + { + { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } + }; + kmsProviders.Add("local", localOptions); + + return new ReadOnlyDictionary>(kmsProviders); + } + + private Dictionary GetSchemaMapIfNotNull(BsonDocument schemaMapDocument) + { + Dictionary schemaMap = null; + if (schemaMapDocument != null) + { + var element = schemaMapDocument.Single(); + schemaMap = new Dictionary + { + { element.Name, element.Value.AsBsonDocument } + }; + } + return schemaMap; + } + + private void Insert( + IMongoCollection collection, + bool async, + params BsonDocument[] documents) + { + if (async) + { + collection + .InsertManyAsync(documents) + .GetAwaiter() + .GetResult(); + } + else + { + collection.InsertMany(documents); + } + } + + public class JsonFileReader : EmbeddedResourceJsonFileReader + { + #region static + // private static fields + private static readonly string[] __ignoreKeyNames = + { + "dbPointer" // not supported + }; + private static readonly Lazy __instance = new Lazy(() => new JsonFileReader(), isThreadSafe: true); + + // public static properties + public static JsonFileReader Instance => __instance.Value; + #endregion + + private readonly IReadOnlyDictionary _documents; + + public JsonFileReader() + { + _documents = new ReadOnlyDictionary(ReadDocuments()); + } + + protected override string[] PathPrefixes => new[] + { + "MongoDB.Driver.Tests.Specifications.client_side_encryption.prose_tests.corpus.", + "MongoDB.Driver.Tests.Specifications.client_side_encryption.prose_tests.external.", + "MongoDB.Driver.Tests.Specifications.client_side_encryption.prose_tests.limits." + }; + + public IReadOnlyDictionary Documents + { + get + { + return _documents.ToDictionary(k => k.Key, v => v.Value.DeepClone().AsBsonDocument); + } + } + + // private methods + private IDictionary ReadDocuments() + { + var documents = ReadJsonDocuments(); + return new Dictionary( + documents.ToDictionary( + key => + { + var path = key["_path"].ToString(); + var testTitle = "MongoDB.Driver.Tests.Specifications.client_side_encryption.prose_tests"; + var startIndex = path.IndexOf(testTitle, StringComparison.Ordinal); + if (startIndex != -1) + { + return path.Substring(startIndex + testTitle.Length + 1); + } + else + { + throw new ArgumentException($"Unexpected test file: {path}."); + } + }, + value => + { + RemoveIgnoredElements(value); + return value; + })); + } + + private void RemoveIgnoredElements(BsonDocument document) + { + document.Remove("_path"); + var ignoredElements = document + .Where(c => __ignoreKeyNames.Any(i => c.Name.Contains(i))) + .ToList(); + foreach (var ignored in ignoredElements.Where(c => c.Value.IsBsonDocument)) + { + document.RemoveElement(ignored); + } + } + } + } +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-encrypted.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-encrypted.json new file mode 100644 index 00000000000..998b058b0f6 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-encrypted.json @@ -0,0 +1,4025 @@ +{ + "_id": "client_side_encryption_corpus", + "altname_aws": "aws", + "altname_local": "local", + "aws_double_rand_auto_id": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAABchrWPF5OPeuFpk4tUV325TmoNpGW+L5iPSXcLQIr319WJFIp3EDy5QiAHBfz2rThI7imU4eLXndIUrsjM0S/vg==", + "subType": "06" + } + } + }, + "aws_double_rand_auto_altname": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAABga5hXFiFvH/wOr0wOHSHFWRZ4pEs/UCC1XJWf46Dod3GY9Ry5j1ZyzeHueJxc4Ym5M8UHKSmJuXmNo9m9ZnkiA==", + "subType": "06" + } + } + }, + "aws_double_rand_explicit_id": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAABjTYZbsro/YxLWBb88qPXEIDQdzY7UZyK4UaZZ8h62OTxp43Zp9j6WvOEzKhXt4oJPMxlAxyTdqO6MllX5bsDrw==", + "subType": "06" + } + } + }, + "aws_double_rand_explicit_altname": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAABqkyXdeS3aWH2tRFoKxsIIL3ZH05gkiAEbutrjrdfw0b110iPhuCCOb0gP/nX/NRNCg1kCFZ543Vu0xZ0BRXlvQ==", + "subType": "06" + } + } + }, + "aws_double_det_explicit_id": { + "kms": "aws", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "aws_double_det_explicit_altname": { + "kms": "aws", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "aws_string_rand_auto_id": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAACAsI5E0rVT8TpIONY3TnbRvIxUjKsiy9ynVd/fE7U1lndE7KR6dTzs8QWK13kdKxO+njKPeC2ObBX904QmJ65Sw==", + "subType": "06" + } + } + }, + "aws_string_rand_auto_altname": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAACgBE6J6MRxPSDe+gfJPL8nBvuEIRBYxNS/73LqBTDJYyN/lsHQ6UlFDT5B4EkIPmHPTe+UBMOhZQ1bsP+DK8Aog==", + "subType": "06" + } + } + }, + "aws_string_rand_explicit_id": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAACbdTVDBWn35M5caKZgLFoiSVeFGKRj5K/QtupKNc8/dPIyCE+/a4PU51G/YIzFpYmp91nLpyq7lD/eJ/V0q66Zw==", + "subType": "06" + } + } + }, + "aws_string_rand_explicit_altname": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAACa4O+kE2BaqM0E+yiBrbCuE0YEGTrZ7L/+SuWm9gN3UupxwAQpRfxXAuUCTc9u1CXnvL+ga+VJMcWD2bawnn/Rg==", + "subType": "06" + } + } + }, + "aws_string_det_auto_id": { + "kms": "aws", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAACyvOW8NcqRkZYzujivwVmYptJkic27PWr3Nq3Yv5Njz8cJdoyesVaQan6mn+U3wdfGEH8zbUUISdCx5qgvXEpvw==", + "subType": "06" + } + } + }, + "aws_string_det_explicit_id": { + "kms": "aws", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAACyvOW8NcqRkZYzujivwVmYptJkic27PWr3Nq3Yv5Njz8cJdoyesVaQan6mn+U3wdfGEH8zbUUISdCx5qgvXEpvw==", + "subType": "06" + } + } + }, + "aws_string_det_explicit_altname": { + "kms": "aws", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAACyvOW8NcqRkZYzujivwVmYptJkic27PWr3Nq3Yv5Njz8cJdoyesVaQan6mn+U3wdfGEH8zbUUISdCx5qgvXEpvw==", + "subType": "06" + } + } + }, + "aws_object_rand_auto_id": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAADI+/afY6Eka8j1VNThWIeGkDZ7vo4/l66a01Z+lVUFFnVLeUV/nz9kM6uTTplNRUa+RXmNmwkoR/BHRnGc7wRNA==", + "subType": "06" + } + } + }, + "aws_object_rand_auto_altname": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAADzN4hVXWXKerhggRRtwWnDu2W2wQ5KIWb/X1WCZJKTjQSQ5LNHVasabBCa4U1q46PQ5pDDM1PkVjW6o+zzl/4xw==", + "subType": "06" + } + } + }, + "aws_object_rand_explicit_id": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAADhSs5zKFMuuux3fqFFuPito3N+bp5TgmkUtJtFXjmA/EnLuexGARvEeGUsMJ/n0VzKbbsiE8+AsUNY3o9YXutqQ==", + "subType": "06" + } + } + }, + "aws_object_rand_explicit_altname": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAADpj8MSov16h26bFDrHepsNkW+tOLOjRP7oj1Tnj75qZ+uqxxVkQ5B/t/Ihk5fikHTJGAcRBR5Vv6kJ/ulMaDnvQ==", + "subType": "06" + } + } + }, + "aws_object_det_explicit_id": { + "kms": "aws", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_object_det_explicit_altname": { + "kms": "aws", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_array_rand_auto_id": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAETWDOZ6zV39H2+W+BkwZIoxI3BNF6phKoiBZ9+i4T9uEoyU3TmoTPjuI0YNwR1v/p5/9rlVCG0KLZd16eeMb3zxZXjqh6IAJqfhsBQ7bzBYI=", + "subType": "06" + } + } + }, + "aws_array_rand_auto_altname": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAE1xeHbld2JjUiPB1k+xMZuIzNSai7mv1iusCswxKEfYCZ7YtR0GDQTxN4676CwhcodSDiysjgOxSFIGlptKCvl0k46LNq0EGypP9yWBLvdjQ=", + "subType": "06" + } + } + }, + "aws_array_rand_explicit_id": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAEFVa4U2uW65MGihhdOmpZFgnwGTs3VeN5TXXbXJ5cfm0CwXF3EPlzAVjy5WO/+lbvFufpQnIiLH59/kVygmwn+2P9zPNJnSGIJW9gaV8Vye8=", + "subType": "06" + } + } + }, + "aws_array_rand_explicit_altname": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAE11VXbfg7DJQ5/CB9XdBO0hCrxOkK3RrEjPGJ0FXlUo76IMna1uo+NVmDnM63CRlGE3/TEbZPpp0w0jn4vZLKvBmGr7o7WQusRY4jnRf5oH4=", + "subType": "06" + } + } + }, + "aws_array_det_explicit_id": { + "kms": "aws", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_array_det_explicit_altname": { + "kms": "aws", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_binData=00_rand_auto_id": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFpZYSktIHzGLZ6mcBFxywICqxdurqLVJcQR34ngix5YIOOulCYEhBSDzzSEyixEPCuU6cEzeuafpZRHX4qgcr9Q==", + "subType": "06" + } + } + }, + "aws_binData=00_rand_auto_altname": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFshzESR9SyR++9r2yeaEjJYScMDez414s8pZkB3C8ihDa+rsyaxNy4yrF7qNEWjFrdFaH7zD2LdlPx+TKZgROlg==", + "subType": "06" + } + } + }, + "aws_binData=00_rand_explicit_id": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFpYwZRPDom7qyAe5WW/QNSq97/OYgRT8xUEaaR5pkbQEFd/Cwtl8Aib/3Bs1CT3MVaHVWna2u5Gcc4s/v18zLhg==", + "subType": "06" + } + } + }, + "aws_binData=00_rand_explicit_altname": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFBq1RIU1YGHKAS1SAtS42fKtQBHQ/BCQzRutirNdvWlrXxF81LSaS7QgQyycZ2ePiOLsSm2vZS4xaQETeCgRC4g==", + "subType": "06" + } + } + }, + "aws_binData=00_det_auto_id": { + "kms": "aws", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAF6SJGmfD3hLVc4tLPm4v2zFuHoRxUDLumBR8Q0AlKK2nQPyvuHEPVBD3vQdDi+Q7PwFxmovJsHccr59VnzvpJeg==", + "subType": "06" + } + } + }, + "aws_binData=00_det_explicit_id": { + "kms": "aws", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAF6SJGmfD3hLVc4tLPm4v2zFuHoRxUDLumBR8Q0AlKK2nQPyvuHEPVBD3vQdDi+Q7PwFxmovJsHccr59VnzvpJeg==", + "subType": "06" + } + } + }, + "aws_binData=00_det_explicit_altname": { + "kms": "aws", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAF6SJGmfD3hLVc4tLPm4v2zFuHoRxUDLumBR8Q0AlKK2nQPyvuHEPVBD3vQdDi+Q7PwFxmovJsHccr59VnzvpJeg==", + "subType": "06" + } + } + }, + "aws_binData=04_rand_auto_id": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFM5685zqlM8pc3xubtCFuf724g/bWXsebpNzw5E5HrxUqSBBVOvjs3IJH74+Supe169qejY358nOG41mLZvO2wJByvT14qmgUGpgBaLaxPR0=", + "subType": "06" + } + } + }, + "aws_binData=04_rand_auto_altname": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFfLqOzpfjz/XYHDLnliUAA5ehi6s+OIjvrLa59ubqEf8DuoCEWlO13Dl8X42IBB4hoSsO2RUeWtc9MeH4SdIUh/xJN3qS7qzjh/H+GvZRdAM=", + "subType": "06" + } + } + }, + "aws_binData=04_rand_explicit_id": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFkmKfKAbz9tqVaiM9MRhYttiY3vgDwXpdYLQ4uUgWX89KRayLADWortYL+Oq+roFhO3oiwB9vjeWGIdgbj5wSh/50JT/2Gs85TXFe1GFjfWs=", + "subType": "06" + } + } + }, + "aws_binData=04_rand_explicit_altname": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAFKbufv83ddN+07Q5Ocq0VxUEV+BesSrVM7Bol3cMlWjHi7P+MrdwhNEa94xlxlDwU3b+RD6kW+AuNEQ2byA3CX2JjZE1gHwN7l0ukXuqpD0A=", + "subType": "06" + } + } + }, + "aws_binData=04_det_auto_id": { + "kms": "aws", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAFlg7ceq9w/JMhHcNzQks6UrKYAffpUyeWuBIpcuLoB7YbFO61Dphseh77pzZbk3OvmveUq6EtCP2pmsq7hA+QV4hkv6BTn4m6wnXw6ss/qfE=", + "subType": "06" + } + } + }, + "aws_binData=04_det_explicit_id": { + "kms": "aws", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAFlg7ceq9w/JMhHcNzQks6UrKYAffpUyeWuBIpcuLoB7YbFO61Dphseh77pzZbk3OvmveUq6EtCP2pmsq7hA+QV4hkv6BTn4m6wnXw6ss/qfE=", + "subType": "06" + } + } + }, + "aws_binData=04_det_explicit_altname": { + "kms": "aws", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAFlg7ceq9w/JMhHcNzQks6UrKYAffpUyeWuBIpcuLoB7YbFO61Dphseh77pzZbk3OvmveUq6EtCP2pmsq7hA+QV4hkv6BTn4m6wnXw6ss/qfE=", + "subType": "06" + } + } + }, + "aws_undefined_rand_explicit_id": { + "kms": "aws", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_undefined_rand_explicit_altname": { + "kms": "aws", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_undefined_det_explicit_id": { + "kms": "aws", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_undefined_det_explicit_altname": { + "kms": "aws", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_objectId_rand_auto_id": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAHASE+V+LlkmwgF9QNjBK8QBvC973NaTMk6wbd57VB2EpQzrgxMtR5gYzVeqq4xaaHqrncyZCOIxDJkFlaim2NqA==", + "subType": "06" + } + } + }, + "aws_objectId_rand_auto_altname": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAHf/+9Qj/ozcDoUb8RNBnajU1d9hJ/6fE17IEZnw+ma6v5yH8LqZk9w3dtm6Sfw1unMhcMKrmIgs6kxqRWhNREJg==", + "subType": "06" + } + } + }, + "aws_objectId_rand_explicit_id": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAHzX8ejVLhoarQ5xgWsJitU/9eBm/Hlt2IIbZtS0SBc80qzkkWTaP9Zl9wrILH/Hwwx8RFnts855eKII3NJFa3BA==", + "subType": "06" + } + } + }, + "aws_objectId_rand_explicit_altname": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAHG5l6nUCY8f/6xO6TsPDrZHcdPRyMe3muMlY2DxHwv9GJNDR5Ne5VEAzUjnbgoy+B29SX4oY8cXJ6XhVz8mt3Eg==", + "subType": "06" + } + } + }, + "aws_objectId_det_auto_id": { + "kms": "aws", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAHTMY2l+gY8glm4HeSsGfCSfOsTVTzYU8qnQV8iqEFHrO5SBJac59gv3N/jukMwAnt0j6vIIQrROkVetU24YY7sQ==", + "subType": "06" + } + } + }, + "aws_objectId_det_explicit_id": { + "kms": "aws", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAHTMY2l+gY8glm4HeSsGfCSfOsTVTzYU8qnQV8iqEFHrO5SBJac59gv3N/jukMwAnt0j6vIIQrROkVetU24YY7sQ==", + "subType": "06" + } + } + }, + "aws_objectId_det_explicit_altname": { + "kms": "aws", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAHTMY2l+gY8glm4HeSsGfCSfOsTVTzYU8qnQV8iqEFHrO5SBJac59gv3N/jukMwAnt0j6vIIQrROkVetU24YY7sQ==", + "subType": "06" + } + } + }, + "aws_bool_rand_auto_id": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAISm4UFt1HC2j0ObpTBg7SvF2Dq31i9To2ED4F3JcTihhq0fVzaSCsUz9VTJ0ziHmeNPNdfPPZO6qA/CDEZBO4jg==", + "subType": "06" + } + } + }, + "aws_bool_rand_auto_altname": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAIj93KeAa96DmZXdB8boFvW19jhJSMmtSs5ag5FDSkH8MdKG2d2VoBOdUlBrL+LHYELqeDHCszY7qCirvb5mIgZg==", + "subType": "06" + } + } + }, + "aws_bool_rand_explicit_id": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAIMbDFEuHIl5MNEsWnYLIand1vpK6EMv7Mso6qxrN4wHSVVwmxK+GCPgrKoUQsNuTssFWNCu0IhwrXOagDEfmlxw==", + "subType": "06" + } + } + }, + "aws_bool_rand_explicit_altname": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAIkIaWfmPdxgAV5Rtb6on6T0NGt9GPFDScQD5I/Ch0ngiTCCKceJOjU0ljd3YTgfWRA1p/MlMIV0I5YAWZXKTHlg==", + "subType": "06" + } + } + }, + "aws_bool_det_explicit_id": { + "kms": "aws", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "aws_bool_det_explicit_altname": { + "kms": "aws", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "aws_date_rand_auto_id": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAJz1VG4+QnQXEE+TGu/pzfPugGMVTiC1xnenG1ByRdPvsERVw9WComWl1tb9tt9oblD7H/q0y1+y8HevkDqohB2Q==", + "subType": "06" + } + } + }, + "aws_date_rand_auto_altname": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAJa1kI2mIIYWjf7zjf5dD9+psvAQpjZ3nnsoXA5upcIwEtZaC8bxKKHVpOLOP3rTbvT5EV6vLhXkferGoyaqd/8w==", + "subType": "06" + } + } + }, + "aws_date_rand_explicit_id": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAJ9Q5Xe4UuOLQTUwosk47A6xx40XJcNoICCNtKrHqsUYy0QLCFRc5v4nA0160BVghURizbUtX8iuIp11pnsDyRtA==", + "subType": "06" + } + } + }, + "aws_date_rand_explicit_altname": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAJkHOdUc/4U82wxWJZ0SYABkJjQqNApkH2Iy/5S+PoatPgynoeSFTU9FmAbuWV/gbtIfBiaCOIjlsdonl/gf9+5w==", + "subType": "06" + } + } + }, + "aws_date_det_auto_id": { + "kms": "aws", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAJEEpQNsiqMWPqD4lhMkiOJHGE8FxOeYrKPiiAp/bZTrLKyCSS0ZL1WT9H3cGzxWPm5veihCjKqWhjatC/pjtzbQ==", + "subType": "06" + } + } + }, + "aws_date_det_explicit_id": { + "kms": "aws", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAJEEpQNsiqMWPqD4lhMkiOJHGE8FxOeYrKPiiAp/bZTrLKyCSS0ZL1WT9H3cGzxWPm5veihCjKqWhjatC/pjtzbQ==", + "subType": "06" + } + } + }, + "aws_date_det_explicit_altname": { + "kms": "aws", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAJEEpQNsiqMWPqD4lhMkiOJHGE8FxOeYrKPiiAp/bZTrLKyCSS0ZL1WT9H3cGzxWPm5veihCjKqWhjatC/pjtzbQ==", + "subType": "06" + } + } + }, + "aws_null_rand_explicit_id": { + "kms": "aws", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "aws_null_rand_explicit_altname": { + "kms": "aws", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "aws_null_det_explicit_id": { + "kms": "aws", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "aws_null_det_explicit_altname": { + "kms": "aws", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "aws_regex_rand_auto_id": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAALnhViSt3HqTDzyLN4mWO9srBU8TjRvPWsAJYfj/5sgI/yFuWdrggMs3Aq6G+K3tRrX3Yb+osy5CLiFCxq9WIvAA==", + "subType": "06" + } + } + }, + "aws_regex_rand_auto_altname": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAALbL2RS2tGQLBZ+6LtXLKAWFKcoKui+u4+gMIlFemLgpdO2eLqrMJB53ccqZImX8ons9UgAwDkiD68hWy8e7KHfg==", + "subType": "06" + } + } + }, + "aws_regex_rand_explicit_id": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAALa0+ftF6W/0Ul4J9VT/3chXFktE1o+OK4S14h2kyOqDVNA8yMKuyCK5nWl1yZvjJ76TuhEABte23oxcBP5QwalQ==", + "subType": "06" + } + } + }, + "aws_regex_rand_explicit_altname": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAALS4Yo9Fwk6OTx2CWdnObFT2L4rHngeIbdCyT4/YMJYd+jLU3mph14M1ptZZg+TBIgSPHq+BkvpRDifbMmOVr/Hg==", + "subType": "06" + } + } + }, + "aws_regex_det_auto_id": { + "kms": "aws", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAALpwNlokiTCUtTa2Kx9NVGvXR/aKPGhR5iaCT7nHEk4BOiZ9Kr4cRHdPCeZ7A+gjG4cKoT62sm3Fj1FwSOl8J8aQ==", + "subType": "06" + } + } + }, + "aws_regex_det_explicit_id": { + "kms": "aws", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAALpwNlokiTCUtTa2Kx9NVGvXR/aKPGhR5iaCT7nHEk4BOiZ9Kr4cRHdPCeZ7A+gjG4cKoT62sm3Fj1FwSOl8J8aQ==", + "subType": "06" + } + } + }, + "aws_regex_det_explicit_altname": { + "kms": "aws", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAALpwNlokiTCUtTa2Kx9NVGvXR/aKPGhR5iaCT7nHEk4BOiZ9Kr4cRHdPCeZ7A+gjG4cKoT62sm3Fj1FwSOl8J8aQ==", + "subType": "06" + } + } + }, + "aws_dbPointer_rand_auto_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAMfCVAnMNbRGsThnoVGb2KDsCIU2ehcPtebk/TFG4GZvEmculscLLih813lEz5NHS2sAXBn721EzUS7d0TKAPbmEYFwUBnijIQIPvUoUO8AQM=", + "subType": "06" + } + } + }, + "aws_dbPointer_rand_auto_altname": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAMvYJ5BtaMLVXV+qj85q5WqKRlzlHOBIIxZfUE/BBXUwqSTpJLdQQD++DDh6F2dtorBeYa3oUv2ef3ImASk5j23joU35Pm3Zt9Ci1pMNGodWs=", + "subType": "06" + } + } + }, + "aws_dbPointer_rand_explicit_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAMdsmYtPDw8kKjfB2kWfx5W1oNEkWWct1lRpesN303pUWsawDJpfBx40lg18So2X/g4yGIwpY3qfEKQZA4vCJeT+MTjhRXFjXA7eS/mxv8f3E=", + "subType": "06" + } + } + }, + "aws_dbPointer_rand_explicit_altname": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAM0hcvS5zmY3mlTp0SfME/rINlflF/sx2KvP0eJTdH+Uk0WHuTkFIJAza+bXvV/gB7iNC350qyzUX3M6NHx/9s/5yBpY8MawTZTZ7WCQIA+ZI=", + "subType": "06" + } + } + }, + "aws_dbPointer_det_auto_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAMp4QxbaEOij66L+RtaMekrDSm6QbfJBTQ8lQFhxfq9n7SVuQ9Zwdy14Ja8tyI3cGgQzQ/73rHUJ3CKA4+OYr63skYUkkkdlHxUrIMd5j5woc=", + "subType": "06" + } + } + }, + "aws_dbPointer_det_explicit_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAMp4QxbaEOij66L+RtaMekrDSm6QbfJBTQ8lQFhxfq9n7SVuQ9Zwdy14Ja8tyI3cGgQzQ/73rHUJ3CKA4+OYr63skYUkkkdlHxUrIMd5j5woc=", + "subType": "06" + } + } + }, + "aws_dbPointer_det_explicit_altname": { + "kms": "aws", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAMp4QxbaEOij66L+RtaMekrDSm6QbfJBTQ8lQFhxfq9n7SVuQ9Zwdy14Ja8tyI3cGgQzQ/73rHUJ3CKA4+OYr63skYUkkkdlHxUrIMd5j5woc=", + "subType": "06" + } + } + }, + "aws_javascript_rand_auto_id": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAN3HzAC9BTD7Jgi0PR4RS/Z6L6QtAQ7VhbKRbX+1smmnYniH6jVBM6zyxMDM8h9YjMPNs8EJrGDnisuf33w5KI/A==", + "subType": "06" + } + } + }, + "aws_javascript_rand_auto_altname": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAANJpw+znlu3ecSiNyZ0EerVsow4aDRF2auI3Wy69EVexJkQlHO753PjRn8hG/x2kY8ROy5IUU43jaugP5AN1bwNQ==", + "subType": "06" + } + } + }, + "aws_javascript_rand_explicit_id": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAANzoDiq8uI0+l8COY8YdM9S3rpLvPOHOWmJqJNtOyS0ZXUx1SB5paRJ4W3Eg8KuXEeoFwvBDe9cW9YT66CzkjlBw==", + "subType": "06" + } + } + }, + "aws_javascript_rand_explicit_altname": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAN/JhtRongJweLC5SdrXHhsFz3p82q3cwXf8Sru21DK6S39S997y3uhVLn0xlX5d94PxK1XVYSjz1oVuMxZouZ7Q==", + "subType": "06" + } + } + }, + "aws_javascript_det_auto_id": { + "kms": "aws", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAANE39aEGiuUZ1WyakVEBgkGzLp5whkIjJ4uiaFLXniRszJL70FRkcf+aFXlA5Y4So9/ODKF76qbSsH4Jk6L+3mog==", + "subType": "06" + } + } + }, + "aws_javascript_det_explicit_id": { + "kms": "aws", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAANE39aEGiuUZ1WyakVEBgkGzLp5whkIjJ4uiaFLXniRszJL70FRkcf+aFXlA5Y4So9/ODKF76qbSsH4Jk6L+3mog==", + "subType": "06" + } + } + }, + "aws_javascript_det_explicit_altname": { + "kms": "aws", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAANE39aEGiuUZ1WyakVEBgkGzLp5whkIjJ4uiaFLXniRszJL70FRkcf+aFXlA5Y4So9/ODKF76qbSsH4Jk6L+3mog==", + "subType": "06" + } + } + }, + "aws_symbol_rand_auto_id": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAOBv1T9tleM0xwNe7efg/MlShyzvXe3Pmg1GzPl3gjFRHZGWXR578KqX+8oiz65eXGzNuyOFvcpnR2gYCs3NeKeQfctO5plEiIva6nzCI5SK8=", + "subType": "06" + } + } + }, + "aws_symbol_rand_auto_altname": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAOwLgGws8CMh+GgkEJFAx8tDIflyjsgG+/1FmZZobKAg8NOKqfXjtbnNCbvR28OCk6g/8SqBm8m53G6JciwvthJ0DirdfEexiUqu7IPtaeeyw=", + "subType": "06" + } + } + }, + "aws_symbol_rand_explicit_id": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAORQi3dNkXzZeruWu19kEhDu6fFD/h47ILzk+OVKQMoriAQC5YFyVRp1yAkIaWsrsPcyCHlfZ99FySSQeqSYbZZNj5FqyonWvDuPTduHDy3CI=", + "subType": "06" + } + } + }, + "aws_symbol_rand_explicit_altname": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAOj+Yl1pQPiJ6mESOISOyUYsKN/VIvC8f0derhxIPakXkwn57U0sxv+geUkrl3JZDxY3+cX5M1JZmY+PfjaYQhbTorf9RZaVC2Wwo2lMftWi0=", + "subType": "06" + } + } + }, + "aws_symbol_det_auto_id": { + "kms": "aws", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAO5IHripygBGEsVK8RFWZ1rIIVUap8KVDuqOspZpERaj+5ZEfqIcyrP/WK9KdvwOfdOWXfP/mOwuImYgNdbaQe+ejkYe4W0Y0uneCuw88k95Q=", + "subType": "06" + } + } + }, + "aws_symbol_det_explicit_id": { + "kms": "aws", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAO5IHripygBGEsVK8RFWZ1rIIVUap8KVDuqOspZpERaj+5ZEfqIcyrP/WK9KdvwOfdOWXfP/mOwuImYgNdbaQe+ejkYe4W0Y0uneCuw88k95Q=", + "subType": "06" + } + } + }, + "aws_symbol_det_explicit_altname": { + "kms": "aws", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAO5IHripygBGEsVK8RFWZ1rIIVUap8KVDuqOspZpERaj+5ZEfqIcyrP/WK9KdvwOfdOWXfP/mOwuImYgNdbaQe+ejkYe4W0Y0uneCuw88k95Q=", + "subType": "06" + } + } + }, + "aws_javascriptWithScope_rand_auto_id": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAPT31GSNkY1RM43miv1XPYtDX1vU/xORiM3U0pumjqA+JLU/HMhH++75OcMhcAQqMjm2nZtZScxdGJsJJPEEzqjbFNMJgYc9sqR5uLnzk+2dg=", + "subType": "06" + } + } + }, + "aws_javascriptWithScope_rand_auto_altname": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAPUxgaKAxSQ1uzOZtzsbtrxtDT2P/zWY6lYsbChXuRUooqvyjXSkNDqKBBA7Gp5BdGiVB/JLR47Tihpbcw1s1yGhwQRvnqeDvPrf91nvElXRY=", + "subType": "06" + } + } + }, + "aws_javascriptWithScope_rand_explicit_id": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAPv8W0ZtquFCLTG0TqvRjdzKa/4mvqT2FuEGQ0mXG2k2BZh2LY5APr/kgW0tP4eLjHzVld6OLiM9ZKAvENCZ6/fKOvqSwpIfkdLWUIeB4REQg=", + "subType": "06" + } + } + }, + "aws_javascriptWithScope_rand_explicit_altname": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAPMVhWjaxLffdAOkVgIJpjgNIldMS451NQs3C1jb+pzopHp3DlfZ+AHQpK9reMVVKjaqanhWBpL25q+feA60XVgZPCUDroiRYqMFqU//y0amw=", + "subType": "06" + } + } + }, + "aws_javascriptWithScope_det_explicit_id": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_javascriptWithScope_det_explicit_altname": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_int_rand_auto_id": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAQFV5b3vsoZe+MT4z8soetpmrWJpm7be41FNu/rdEqHWTG32jCym6762PCNYH5+vA7ldCWQkdt+ncneHsxzPrm9w==", + "subType": "06" + } + } + }, + "aws_int_rand_auto_altname": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAQY9+QenvU1Tk/dEGZP11uOZJLHAJ9hWHbEhxbtxItt1LsdU/8gOZfypilIO5BUkLT/15PUuXV28GISNh6yIuWhw==", + "subType": "06" + } + } + }, + "aws_int_rand_explicit_id": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAQruCugbneumhcinuXm89WW1PXVuSOewttp9cpsPPsCRVqe/uAkZOdJnZ2KaEZ9zki2GeqaJTs1qDmaJofc6GMEA==", + "subType": "06" + } + } + }, + "aws_int_rand_explicit_altname": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAQb15qXl/tejk4pmgkc4pUxzt4eJrv/cetgzgcPVaROAQSzd8ptbgCjaV8vP46uqozRoaDFZbQ06t65c3f0x/Ucw==", + "subType": "06" + } + } + }, + "aws_int_det_auto_id": { + "kms": "aws", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAQCXo6ieWvfoqkG+rP7J2BV013AVf/oNMmmGWe44VEHahF+qZHzW5I/F2qIA+xgKkk172pFq0iTSOpe+K2WHMKFw==", + "subType": "06" + } + } + }, + "aws_int_det_explicit_id": { + "kms": "aws", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAQCXo6ieWvfoqkG+rP7J2BV013AVf/oNMmmGWe44VEHahF+qZHzW5I/F2qIA+xgKkk172pFq0iTSOpe+K2WHMKFw==", + "subType": "06" + } + } + }, + "aws_int_det_explicit_altname": { + "kms": "aws", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAAQCXo6ieWvfoqkG+rP7J2BV013AVf/oNMmmGWe44VEHahF+qZHzW5I/F2qIA+xgKkk172pFq0iTSOpe+K2WHMKFw==", + "subType": "06" + } + } + }, + "aws_timestamp_rand_auto_id": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAR63xXG8mrlixkQzD5VBIPE6NHicaWcS5CBhiIJDcZ0x8D9c5TgRJUfCeWhKvWFD4o0DoxcBQ2opPormFDpvmq/g==", + "subType": "06" + } + } + }, + "aws_timestamp_rand_auto_altname": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAARAgY9LsUxP6gP4gYRvvzZ4iaHVQRNbycATiVag1YNSiDmEr4LYserYuBscdrIy4v3zgGaulFM9KV86bx0ItycZA==", + "subType": "06" + } + } + }, + "aws_timestamp_rand_explicit_id": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAARLneAZqPcHdzGGnXz2Ne5E7HP9cDC1+yoIwcA8OSF/IlzEjrrMAi3z6Izol6gWDlD7VOh7QYL3sASJOXyzF1hPQ==", + "subType": "06" + } + } + }, + "aws_timestamp_rand_explicit_altname": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAARH2bU7KNo5SHxiO8JFEcT9wryuHNXyM7ADop1oPcESyay1Nc0WHPD3nr0yMAK481NxOkE3qXyaslu7bcP/744WA==", + "subType": "06" + } + } + }, + "aws_timestamp_det_auto_id": { + "kms": "aws", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAARG7kGfx0ky+d4Hl/fRBu8oUR1Mph26Dkv3J7fxGYanpzOFMiHIfVO0uwYMvsfzG54y0DDNlS3FmmS13DzepbzGQ==", + "subType": "06" + } + } + }, + "aws_timestamp_det_explicit_id": { + "kms": "aws", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAARG7kGfx0ky+d4Hl/fRBu8oUR1Mph26Dkv3J7fxGYanpzOFMiHIfVO0uwYMvsfzG54y0DDNlS3FmmS13DzepbzGQ==", + "subType": "06" + } + } + }, + "aws_timestamp_det_explicit_altname": { + "kms": "aws", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAARG7kGfx0ky+d4Hl/fRBu8oUR1Mph26Dkv3J7fxGYanpzOFMiHIfVO0uwYMvsfzG54y0DDNlS3FmmS13DzepbzGQ==", + "subType": "06" + } + } + }, + "aws_long_rand_auto_id": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAASZbes2EdR78crt2pXVElW2YwAQh8HEBapYYeav2VQeg2syXaV/qZuD8ofnAVn4v/DydTTMVMmK+sVU/TlnAu2eA==", + "subType": "06" + } + } + }, + "aws_long_rand_auto_altname": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAASt+7fmMYH+fLHgybc+sng8/UmKP3YPUEPCz1SXVQljQp6orsCILSgtgGPsdeGnN5NSxh3XzerHs6zlR92fWpZCw==", + "subType": "06" + } + } + }, + "aws_long_rand_explicit_id": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAS01fF1uo6zYDToJnOT/EbDipzk7YZ6I+IspZF+avjU3XYfpRxT9NdAgKr0euWJwyAsdpWqqCwFummfrPeZOy04A==", + "subType": "06" + } + } + }, + "aws_long_rand_explicit_altname": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAS6tpH796bqy58mXf38rJvVtA1uBcxBE5yIGQ4RN44oypc/pvw0ouhFI1dkoneKMtAFU/5RygZV+RvQhRtgKn76A==", + "subType": "06" + } + } + }, + "aws_long_det_auto_id": { + "kms": "aws", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAASC7O/8JeB4WTqQFPuMpFRsAuonPS3yu7IAPZeRPIr03CmM6HNndYIKMoFM13eELNZTdJSgg9u9ItGqRw+/XMHzQ==", + "subType": "06" + } + } + }, + "aws_long_det_explicit_id": { + "kms": "aws", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAASC7O/8JeB4WTqQFPuMpFRsAuonPS3yu7IAPZeRPIr03CmM6HNndYIKMoFM13eELNZTdJSgg9u9ItGqRw+/XMHzQ==", + "subType": "06" + } + } + }, + "aws_long_det_explicit_altname": { + "kms": "aws", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQFkgAAAAAAAAAAAAAAAAAASC7O/8JeB4WTqQFPuMpFRsAuonPS3yu7IAPZeRPIr03CmM6HNndYIKMoFM13eELNZTdJSgg9u9ItGqRw+/XMHzQ==", + "subType": "06" + } + } + }, + "aws_decimal_rand_auto_id": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAATgf5zW9EgnWHPxj4HAGt472eN9UXP41TaF8V2J7S2zqSpiBZGKDuOIjw2FBSqaNp53vvfl9HpwAuQBJZhrwkBCKRkKV/AAR3/pTpuoqhSKaM=", + "subType": "06" + } + } + }, + "aws_decimal_rand_auto_altname": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAATPRfvZWdupE2N0W1DXUx7X8Zz7g43jawJL7PbQtTYetI78xRETkMdygwSEHgs+cvnUBBtYIeKRVkOGZQkwf568OclhDiPxUeD38cR5blBq/U=", + "subType": "06" + } + } + }, + "aws_decimal_rand_explicit_id": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAAT+ZnCg2lSMIohZ9RJ4CNs3LZ0g+nV04cYAmrxTSrTSBPGlZ7Ywh5A2rCss7AUijYZiKiYyZbuAzukbOuVRhdCtm+xo9+DyLAwTezF18okk6Y=", + "subType": "06" + } + } + }, + "aws_decimal_rand_explicit_altname": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgFkgAAAAAAAAAAAAAAAAAATlnQYASsTZRRHzFjcbCClXartcXBVRrYv7JImMkDmAj6EAjf/ZqpjeykkS/wohMhXaNwyZBdREr+n+GDV7imYoL4WRBOLnqB6hrYidlWqNzE=", + "subType": "06" + } + } + }, + "aws_decimal_det_explicit_id": { + "kms": "aws", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "aws_decimal_det_explicit_altname": { + "kms": "aws", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "aws_minKey_rand_explicit_id": { + "kms": "aws", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_minKey_rand_explicit_altname": { + "kms": "aws", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_minKey_det_explicit_id": { + "kms": "aws", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_minKey_det_explicit_altname": { + "kms": "aws", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_maxKey_rand_explicit_id": { + "kms": "aws", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "aws_maxKey_rand_explicit_altname": { + "kms": "aws", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "aws_maxKey_det_explicit_id": { + "kms": "aws", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "aws_maxKey_det_explicit_altname": { + "kms": "aws", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_double_rand_auto_id": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAABGF195CB8nRmK9+KxYO7T96MeXucC/ILQtEEQAS4zrwj3Qz7YEQrf/apvbKTCkn3siN2XSDLQ/7dmddZa9xa9yQ==", + "subType": "06" + } + } + }, + "local_double_rand_auto_altname": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAABY8g18z6ZOjGtfNxaAmU95tXMdoM6qbtDMpB72paqiHZTW1UGB22HPXiEnVz05JTBzzX4fc6tOldX6aJel812Zg==", + "subType": "06" + } + } + }, + "local_double_rand_explicit_id": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAABDlHwN8hYyScEhhx64TdJ2Qp2rmKRg8983zdqIL1914tyPwRQq7ySCOhmFif2S7v4KT+r0uOfimYvKD1n9rKHlg==", + "subType": "06" + } + } + }, + "local_double_rand_explicit_altname": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAB2VnTFlaCRzAZZTQiMWQORFNgXIuAJlHJXIHiYow2eO6JbVghWTpH+MsdafBNPVnc0zKuZBL0Qs2Nuk1xiQaqhA==", + "subType": "06" + } + } + }, + "local_double_det_explicit_id": { + "kms": "local", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "local_double_det_explicit_altname": { + "kms": "local", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "local_string_rand_auto_id": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAC5NBAPM8q2n9fnkwQfE9so/XcO51plPBNs5VlBRbDw68k9T6/uZ2TWsAvTYtVooY59zHHr2QS3usKbGQB6J61rA==", + "subType": "06" + } + } + }, + "local_string_rand_auto_altname": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACM/EjGMrkYHvSZra26m74upuvLkfKXTs+tTWquGzrgWYLnLt8I6XBIwx1VymS9EybrCU/ewmtgjLUNUFQacIeXA==", + "subType": "06" + } + } + }, + "local_string_rand_explicit_id": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACn4tD26UG8lO9gTZaxen6yXzHo/a2lokeY1ClxHMtJODoJr2JZzIDHP3A9aZ8L4+Vu+nyqphaWyGaGONKu8gpcQ==", + "subType": "06" + } + } + }, + "local_string_rand_explicit_altname": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACZfoO2LjY+IB31FZ1Tq7pHr0DCFKGJqWcXcOrnZ7bV9Euc9f101motJc31sp8nF5CTCfd83VQE0319eQrxDDaSw==", + "subType": "06" + } + } + }, + "local_string_det_auto_id": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACW0cZMYWOY3eoqQQkSdBtS9iHC4CSQA27dy6XJGcmTV8EDuhGNnPmbx0EKFTDb0PCSyCjMyuE4nsgmNYgjTaSuw==", + "subType": "06" + } + } + }, + "local_string_det_explicit_id": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACW0cZMYWOY3eoqQQkSdBtS9iHC4CSQA27dy6XJGcmTV8EDuhGNnPmbx0EKFTDb0PCSyCjMyuE4nsgmNYgjTaSuw==", + "subType": "06" + } + } + }, + "local_string_det_explicit_altname": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACW0cZMYWOY3eoqQQkSdBtS9iHC4CSQA27dy6XJGcmTV8EDuhGNnPmbx0EKFTDb0PCSyCjMyuE4nsgmNYgjTaSuw==", + "subType": "06" + } + } + }, + "local_object_rand_auto_id": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAADlekcUsETAkkKTjCVx5EISJN+sftrQax/VhaWXLyRgRz97adXXmwZkMyt+035SHZsF91i2LaXziMA4RHoP+nKFw==", + "subType": "06" + } + } + }, + "local_object_rand_auto_altname": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAADpaQmy5r6q9gLqEm+FIi/OyQgcuUnrICCP9rC4S3wR6qUHd82IW/3dFQUzwTkaXxgStjopamQMuZ4ESRj0xx0bA==", + "subType": "06" + } + } + }, + "local_object_rand_explicit_id": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAADCHRJCINzWY0u4gZPWEmHg/JoQ8IW4yMfUyzYJCQrEMp4rUeupIuxqSuq2QyLBYZBBv0r7t3lNH49I5qDeav2vA==", + "subType": "06" + } + } + }, + "local_object_rand_explicit_altname": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAADrHQQUnLF1jdNmFY/V266cS28XAB4nOKetHAcSbwkeUxNzgZT1g+XMQaYfcNMMv/ywypKU1KpgLMsEOpm4qcPkQ==", + "subType": "06" + } + } + }, + "local_object_det_explicit_id": { + "kms": "local", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "local_object_det_explicit_altname": { + "kms": "local", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "local_array_rand_auto_id": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAEXa7bQ5vGPNsLdklM/H+sop8aCL4vlDiVUoVjTAGjTngn2WLcdKLWxaNSyMdJpsI/NsxQJ58YrcwP+yHzi9rZVtRdbg7m8p+CYcq1vUm6UoQ=", + "subType": "06" + } + } + }, + "local_array_rand_auto_altname": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAEVlZlOvtRmGIhcYi/qPl3HKi/qf0yRQrkbVo9rScYkxDCBN9wA55pAWHDQ/5Sjy4d0DwL57k+M1G9e7xSIrv8xXKwoIuuabhSWaIX2eJHroY=", + "subType": "06" + } + } + }, + "local_array_rand_explicit_id": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAEYBLSYHHt2rohezMF4lMjNdqy9CY33EHf+pgRbJwVXZScLDgn9CcqeRsdU8bW5h2qgNpQvoSMBB7pW+Dgp1RauTHZSOd4PcZpAGjwoFDWSSM=", + "subType": "06" + } + } + }, + "local_array_rand_explicit_altname": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAES1IJ8S2NxWekolQockxLJvzFSGfKQ9Xbi55vO8LyWo0sIG9ZgPQXtVQkZ301CsdFduvx9A0vDqQ0MGYc4plxNnpUTizJPRUDyez5dOgZ9tI=", + "subType": "06" + } + } + }, + "local_array_det_explicit_id": { + "kms": "local", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_array_det_explicit_altname": { + "kms": "local", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_binData=00_rand_auto_id": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAF+hgWs4ZCo9GnmhSM9SDSWzWX4E7Tlp4TwlEy3zfO/rrMREECGB4u8LD8Ju9b8YP+xcZhMI1tcz/vrQS87NffUg==", + "subType": "06" + } + } + }, + "local_binData=00_rand_auto_altname": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAFtEvaXWpGfXC1GlKu0AeRDaeBKHryGoS0tAUr48vfYk7umCr+fJKyXCY9vSv7wCiQxWLe8V/EZWkHsu0zqhJw9w==", + "subType": "06" + } + } + }, + "local_binData=00_rand_explicit_id": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAF/1L5bvmMX3Bk2nAw8KvvRd/7nZ82XHVasT0jrlPhSiJU7ehJMeUCOb7HCHU6KgCzZB9C2W3NoVhLKIhE9ZnYdg==", + "subType": "06" + } + } + }, + "local_binData=00_rand_explicit_altname": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAFK0W5IWKzggR4UU+fhwA2p8YCHLfmx5y1OEtHc/9be9eEYTORACDmWY6207Vd4LhBJCedd+Q5qMm7NRZjjhyLEQ==", + "subType": "06" + } + } + }, + "local_binData=00_det_auto_id": { + "kms": "local", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAF1ofBnK9+ERP29P/i14GQ/y3muic6tNKY532zCkzQkJSktYCOeXS8DdY1DdaOP/asZWzPTdgwby6/iZcAxJU+xQ==", + "subType": "06" + } + } + }, + "local_binData=00_det_explicit_id": { + "kms": "local", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAF1ofBnK9+ERP29P/i14GQ/y3muic6tNKY532zCkzQkJSktYCOeXS8DdY1DdaOP/asZWzPTdgwby6/iZcAxJU+xQ==", + "subType": "06" + } + } + }, + "local_binData=00_det_explicit_altname": { + "kms": "local", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAF1ofBnK9+ERP29P/i14GQ/y3muic6tNKY532zCkzQkJSktYCOeXS8DdY1DdaOP/asZWzPTdgwby6/iZcAxJU+xQ==", + "subType": "06" + } + } + }, + "local_binData=04_rand_auto_id": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAFxq38aA4k/tYHPwJFRK0pahlo/3zjCe3VHJRqURRA+04lbJCvdkQTawxWlf8o+3Pcetl1UcPTQigdYp5KbIkstuPstLbT+TZXHVD1os9LTRw=", + "subType": "06" + } + } + }, + "local_binData=04_rand_auto_altname": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAFTXNWchCPmCSY0+AL22/kCBmAoDJDX5T18jpJHLdvZtHs0zwD64b9hLvfRK268BlNu4P37KDFE6LT0QzjG7brqzFJf3ZaadDCKeIw1q7DWQs=", + "subType": "06" + } + } + }, + "local_binData=04_rand_explicit_id": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAF7XgMgKjQmWYWmobrYWKiGYCKsy5kTgVweFBuzvFISaZjFsq2hrZB2DwUaOeT6XUPH/Onrdjc3fNElf3FdQDHif4rt+1lh9jEX+nMbRw9i3s=", + "subType": "06" + } + } + }, + "local_binData=04_rand_explicit_altname": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAFGoA/1H0waFLor6LbkUCLC2Wm9j/ZT7yifPbf0G7WvO0+gBLlffr3aJIQ9ik5vxPbmDDMCoYlbEYgb8i9I5tKC17WPhjVH2N2+4l9y7aEmS4=", + "subType": "06" + } + } + }, + "local_binData=04_det_auto_id": { + "kms": "local", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAFwO3hsD8ee/uwgUiHWem8fGe54LsTJWqgbRCacIe6sxrsyLT6EsVIqg4Sn7Ou+FC3WJbFld5kx8euLe/MHa8FGYjxD97z5j+rUx5tt3T6YbA=", + "subType": "06" + } + } + }, + "local_binData=04_det_explicit_id": { + "kms": "local", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAFwO3hsD8ee/uwgUiHWem8fGe54LsTJWqgbRCacIe6sxrsyLT6EsVIqg4Sn7Ou+FC3WJbFld5kx8euLe/MHa8FGYjxD97z5j+rUx5tt3T6YbA=", + "subType": "06" + } + } + }, + "local_binData=04_det_explicit_altname": { + "kms": "local", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAFwO3hsD8ee/uwgUiHWem8fGe54LsTJWqgbRCacIe6sxrsyLT6EsVIqg4Sn7Ou+FC3WJbFld5kx8euLe/MHa8FGYjxD97z5j+rUx5tt3T6YbA=", + "subType": "06" + } + } + }, + "local_undefined_rand_explicit_id": { + "kms": "local", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "local_undefined_rand_explicit_altname": { + "kms": "local", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "local_undefined_det_explicit_id": { + "kms": "local", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "local_undefined_det_explicit_altname": { + "kms": "local", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "local_objectId_rand_auto_id": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAHfvxWRZOzfao3faE3RglL0IcDpBcNwqiGL5KgSokmRxWjjWeiel88Mbo5Plo0SswwNQ2H7C5GVG21L+UbvcW63g==", + "subType": "06" + } + } + }, + "local_objectId_rand_auto_altname": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAHhd9lSOO7bHE7PM+Uxa2v3X1FF66IwyEr0wqnyTaOM+cHQLmec/RlEaRIQ1x2AiW7LwmmVgZ0xBMK9CMh0Lhbyw==", + "subType": "06" + } + } + }, + "local_objectId_rand_explicit_id": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAHETwT9bo+JtboBVW/8GzzMQCpn22iiNJnlxYfyO45jvYJQRs29RRIouCsnFkmC7cfAO3GlVxv113euYjIO7AlAg==", + "subType": "06" + } + } + }, + "local_objectId_rand_explicit_altname": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAHhsguAMBzQUFBAitpJDzKEaMDGUGfvCzmUUhf4rnp8xeall/p91TUudaSMcU11XEgJ0Mym4IbYRd8+TfUai0nvw==", + "subType": "06" + } + } + }, + "local_objectId_det_auto_id": { + "kms": "local", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAH4ElF4AvQ+kkGfhadgKNy3GcYrDZPN6RpzaMYIhcCGDvC9W+cIS9dH1aJbPU7vTPmEZnnynPTDWjw3rAj2+9mOA==", + "subType": "06" + } + } + }, + "local_objectId_det_explicit_id": { + "kms": "local", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAH4ElF4AvQ+kkGfhadgKNy3GcYrDZPN6RpzaMYIhcCGDvC9W+cIS9dH1aJbPU7vTPmEZnnynPTDWjw3rAj2+9mOA==", + "subType": "06" + } + } + }, + "local_objectId_det_explicit_altname": { + "kms": "local", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAH4ElF4AvQ+kkGfhadgKNy3GcYrDZPN6RpzaMYIhcCGDvC9W+cIS9dH1aJbPU7vTPmEZnnynPTDWjw3rAj2+9mOA==", + "subType": "06" + } + } + }, + "local_bool_rand_auto_id": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAIxGld4J/2vSWg5tjQulpkm9C6WeUcLbv2yfKRXPAbmLpv3u4Yrmr5qisJtqmDPTcb993WosvCYAh0UGW+zpsdEg==", + "subType": "06" + } + } + }, + "local_bool_rand_auto_altname": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAIpUFPiS2uoW1Aqs0WQkBa201OBmsuJ8WUKcv5aBPASkcwfaw9qSWs3QrbEDR2GyoU4SeYOByCAQMzXCPoIYAFdQ==", + "subType": "06" + } + } + }, + "local_bool_rand_explicit_id": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAIJuzu1a60meYlU3LMjw/7G4Vh/lqKopxdpGWoLXEmY/NoHgX6Fkv9iTwxv/Nv8rZwtawpFV+mQUG/6A1IHMBASQ==", + "subType": "06" + } + } + }, + "local_bool_rand_explicit_altname": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAIn9VjxL5TdGgJLckNHRrIaL32L31q5OERRZG2M5OYKk66TnrlfEs+ykcDvGwMGKpr/PYjY5kBHDc/oELGJJbWRQ==", + "subType": "06" + } + } + }, + "local_bool_det_explicit_id": { + "kms": "local", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "local_bool_det_explicit_altname": { + "kms": "local", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "local_date_rand_auto_id": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAJPPv4MC5xzt2uxPGBHH9g2z03o9SQjjmuxt97Ub1UcKCCHsGED3bx6YSrocuEMiFFI4d5Fqgl8HNeS4j0PR0tYA==", + "subType": "06" + } + } + }, + "local_date_rand_auto_altname": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAJ6i2A9Hi4xWlOMjFMGpwaRctR1VFnb4El166n18RvjKic46V+WoadvLHS32RhPOvkLVYwIeU4C+vrO5isBNoUdw==", + "subType": "06" + } + } + }, + "local_date_rand_explicit_id": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAJHcniV7Q0C8ZTWrE0hp5i5bUPlrrRdNLZckfODw8XNVtVPDjbznglccQmI7w1t8kOVp65eKzVzUOXN0YkqA+1QA==", + "subType": "06" + } + } + }, + "local_date_rand_explicit_altname": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAJKCUCjC3hsmEKKYwGP3ceh3zR+ArE8LYFOQfN87aEsTr60VrzHXmsE8PvizRhhMnrp07ljzQkuat39L+0QSR2qQ==", + "subType": "06" + } + } + }, + "local_date_det_auto_id": { + "kms": "local", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAJ1GMYQTruoKr6fv9XCbcVkx/3yivymPSMEkPCRDYxQv45w4TqBKMDfpRd1TOLOv1qvcb+gjH+z5IfVBMp2IpG/Q==", + "subType": "06" + } + } + }, + "local_date_det_explicit_id": { + "kms": "local", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAJ1GMYQTruoKr6fv9XCbcVkx/3yivymPSMEkPCRDYxQv45w4TqBKMDfpRd1TOLOv1qvcb+gjH+z5IfVBMp2IpG/Q==", + "subType": "06" + } + } + }, + "local_date_det_explicit_altname": { + "kms": "local", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAJ1GMYQTruoKr6fv9XCbcVkx/3yivymPSMEkPCRDYxQv45w4TqBKMDfpRd1TOLOv1qvcb+gjH+z5IfVBMp2IpG/Q==", + "subType": "06" + } + } + }, + "local_null_rand_explicit_id": { + "kms": "local", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "local_null_rand_explicit_altname": { + "kms": "local", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "local_null_det_explicit_id": { + "kms": "local", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "local_null_det_explicit_altname": { + "kms": "local", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "local_regex_rand_auto_id": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAALXKw7zSgqQj1AKoWO0MoMxsBuu0cMB6KdJQCRKdupoLV/Y22owwsVpDDMv5sgUpkG5YIV+Fz7taHodXE07qHopw==", + "subType": "06" + } + } + }, + "local_regex_rand_auto_altname": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAALntOLXq7VW1+jwba/dSbidMo2bewNo7AtK9A1CPwk9XrjUQaEOQxfRpho3BYQEo2U67fQdsY/tyhaj4jduHn9JQ==", + "subType": "06" + } + } + }, + "local_regex_rand_explicit_id": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAALlMMG2iS/gEOEsVKR7sxBJP2IUzZ+aRbozDSkqADncresBvaPBSE17lng5NG7H1JRCAcP1rH/Te+0CrMd7JpRAQ==", + "subType": "06" + } + } + }, + "local_regex_rand_explicit_altname": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAL1YNnlVu5+njDLxh1LMhIPOH19RykAXhxrUbCy6TI5MLQsAOSgAJbXOTXeKr0D8/Ff0phToWOKl193gOOIp8yZQ==", + "subType": "06" + } + } + }, + "local_regex_det_auto_id": { + "kms": "local", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAALiZbL5nFIZl7cSLH5E3wK3jJeAeFc7hLHNITtLAu+o10raEs5i/UCihMHmkf8KHZxghs056pfm5BjPzlL9x7IHQ==", + "subType": "06" + } + } + }, + "local_regex_det_explicit_id": { + "kms": "local", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAALiZbL5nFIZl7cSLH5E3wK3jJeAeFc7hLHNITtLAu+o10raEs5i/UCihMHmkf8KHZxghs056pfm5BjPzlL9x7IHQ==", + "subType": "06" + } + } + }, + "local_regex_det_explicit_altname": { + "kms": "local", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAALiZbL5nFIZl7cSLH5E3wK3jJeAeFc7hLHNITtLAu+o10raEs5i/UCihMHmkf8KHZxghs056pfm5BjPzlL9x7IHQ==", + "subType": "06" + } + } + }, + "local_dbPointer_rand_auto_id": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAMUdAA9uOSk1tXJVe/CG3Ps6avYTEF1eHj1wSlCHkFxqlMtTO+rIQpikpjH0MrcXvEEdAO8g5hFZ01I7DWyK5AAxTxDqVF+kOaQ2VfKs6hyuo=", + "subType": "06" + } + } + }, + "local_dbPointer_rand_auto_altname": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAMiNqvqLwZrPnsF235z+Obl1K9iEXdJ5GucMGpJdRG4lRvRE0Oy1vh6ztNTpYPY/tXyUFTBWlzl/lITalSEm/dT1Bnlh0iPAFrAiNySf662og=", + "subType": "06" + } + } + }, + "local_dbPointer_rand_explicit_id": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAM+Tn31YcKiowBTJWRYCYAEO7UARDE2/jTVGEKXCpiwEqqP3JSAS0b80zYt8dxo5mVhUo2a02ClKrB8vs+B6sU1kXrahSaVSEHZlRSGN9fWgo=", + "subType": "06" + } + } + }, + "local_dbPointer_rand_explicit_altname": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAMdOZZUvpJIqG9qiOLy5x4BdftyHipPDZn/eeLEc7ir3v4jJsY3dsv6fQERo5U9lMynNGA9PJePVzq5tWsIMX0EcCQcMfGmosfkYDzN1OX99A=", + "subType": "06" + } + } + }, + "local_dbPointer_det_auto_id": { + "kms": "local", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAMQWace2C1w3yqtmo/rgz3YtIDnx1Ia/oDsoHnnMZlEy5RoK3uosi1hvNAZCSg3Sen0H7MH3XVhGGMCL4cS69uJ0ENSvh+K6fiZzAXCKUPfvM=", + "subType": "06" + } + } + }, + "local_dbPointer_det_explicit_id": { + "kms": "local", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAMQWace2C1w3yqtmo/rgz3YtIDnx1Ia/oDsoHnnMZlEy5RoK3uosi1hvNAZCSg3Sen0H7MH3XVhGGMCL4cS69uJ0ENSvh+K6fiZzAXCKUPfvM=", + "subType": "06" + } + } + }, + "local_dbPointer_det_explicit_altname": { + "kms": "local", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAMQWace2C1w3yqtmo/rgz3YtIDnx1Ia/oDsoHnnMZlEy5RoK3uosi1hvNAZCSg3Sen0H7MH3XVhGGMCL4cS69uJ0ENSvh+K6fiZzAXCKUPfvM=", + "subType": "06" + } + } + }, + "local_javascript_rand_auto_id": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAANNL2AMKwTDyMIvxLKhBxZKx50C0tBdkLwuXmuMcrUqZeH8bsvjtttoM9LWkkileMyeTWgxblJ1b+uQ+V+4VT6fA==", + "subType": "06" + } + } + }, + "local_javascript_rand_auto_altname": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAANBjBlHGw3K3TWQHpvfa1z0bKhNnVFC/lZArIexo3wjdGq3MdkGA5cuBIp87HHmOIv6o/pvQ9K74v48RQl+JH44A==", + "subType": "06" + } + } + }, + "local_javascript_rand_explicit_id": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAANjvM7u3vNVyKpyI7g5kbzBpHPzXzOQToDSng5/c9yjMG+qi4TPtOyassobJOnMmDYBLyqRXCl/GsDLprbg5jxuA==", + "subType": "06" + } + } + }, + "local_javascript_rand_explicit_altname": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAANMtO7KneuVx4gSOjX4MQjKL80zJhnt+efDBylkpNsqKyxBXB60nkiredGzwaK3/4QhIfGJrC1fQpwUwu/v1L17g==", + "subType": "06" + } + } + }, + "local_javascript_det_auto_id": { + "kms": "local", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAANmQsg9E/BzGJVNVhSNyunS/TH0332oVFdPS6gjX0Cp/JC0YhB97DLz3N4e/q8ECaz7tTdQt9JacNUgxo+YCULUA==", + "subType": "06" + } + } + }, + "local_javascript_det_explicit_id": { + "kms": "local", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAANmQsg9E/BzGJVNVhSNyunS/TH0332oVFdPS6gjX0Cp/JC0YhB97DLz3N4e/q8ECaz7tTdQt9JacNUgxo+YCULUA==", + "subType": "06" + } + } + }, + "local_javascript_det_explicit_altname": { + "kms": "local", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAANmQsg9E/BzGJVNVhSNyunS/TH0332oVFdPS6gjX0Cp/JC0YhB97DLz3N4e/q8ECaz7tTdQt9JacNUgxo+YCULUA==", + "subType": "06" + } + } + }, + "local_symbol_rand_auto_id": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAOOuO2b23mekwI8b6gWeEgRy1lLOCsNyBKvdmizK7/oOVKCvd+3kwUn9a6TxygooiVAN/Aohr1cjb8jRlMPWpkP0iO0+Tt6+vkizgFsQW4iio=", + "subType": "06" + } + } + }, + "local_symbol_rand_auto_altname": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAOhN4QPOcmGnFKGvTfhz6TQleDA02X6oWULLHTnOUJYfE3OUSyf2ULEQh1yhdKdwXMuYVgGl28pMosiwkBShrXYe5ZlMjiZCIMZWSdUMV0tXk=", + "subType": "06" + } + } + }, + "local_symbol_rand_explicit_id": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAO9aWi9RliwQHdXHoJME9VyN6XgyGd95Eclx+ZFYfLxBGAuUnPNjSfVuNZwYdyKC8JX79+mYhk7IXmcGV4z+4486sxyLk3idi4Kmpz2ESqV5g=", + "subType": "06" + } + } + }, + "local_symbol_rand_explicit_altname": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAO/qev3DPfpkQoSW9aHOyalwfI/VYDQVN5VMINx4kw2vEqHiI1HRdZRPOz3q74TlQEy3TMNMTYdCvh5bpN/PptRZCTQbzP6ugz9dTp79w5/Ok=", + "subType": "06" + } + } + }, + "local_symbol_det_auto_id": { + "kms": "local", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAOsg5cs6VpZWoTOFg4ztZmpj8kSTeCArVcI1Zz2pOnmMqNv/vcKQGhKSBbfniMripr7iuiYtlgkHGsdO2FqUp6Jb8NEWm5uWqdNU21zR9SRkE=", + "subType": "06" + } + } + }, + "local_symbol_det_explicit_id": { + "kms": "local", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAOsg5cs6VpZWoTOFg4ztZmpj8kSTeCArVcI1Zz2pOnmMqNv/vcKQGhKSBbfniMripr7iuiYtlgkHGsdO2FqUp6Jb8NEWm5uWqdNU21zR9SRkE=", + "subType": "06" + } + } + }, + "local_symbol_det_explicit_altname": { + "kms": "local", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAOsg5cs6VpZWoTOFg4ztZmpj8kSTeCArVcI1Zz2pOnmMqNv/vcKQGhKSBbfniMripr7iuiYtlgkHGsdO2FqUp6Jb8NEWm5uWqdNU21zR9SRkE=", + "subType": "06" + } + } + }, + "local_javascriptWithScope_rand_auto_id": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAP5gLMvLOAc6vGAvC7bGmEC4eweptAiX3A7L0iCoHps/wm0FBLkfpF6F4pCjVYiY1lTID38wliRLPyhntCj+cfvlMfKSjouNgXMIWyQ8GKZ2c=", + "subType": "06" + } + } + }, + "local_javascriptWithScope_rand_auto_altname": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAPVsw9Opn/P5SAdJhX4MTxIcsmaG8isIN4NKPi9k1u/Vj7AVkcxYqwurAghaJpmfoAgMruvzi1hcKvd05yHd9Nk0vkvODwDgnjJB6QO+qUce8=", + "subType": "06" + } + } + }, + "local_javascriptWithScope_rand_explicit_id": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAPLUa+nsrqiHkVdE5K1xl/ZsiZqQznG2yVXyA3b3loBylbcL2NEBp1JUeGnPZ0y5ZK4AmoL6NMH2Io313rW3V8FTArs/OOQWPRJSe6h0M3wXk=", + "subType": "06" + } + } + }, + "local_javascriptWithScope_rand_explicit_altname": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAPzUKaXCH0JImSlY73HVop9g9c0YssNEiA7Dy7Vji61avxvnuJJfghDchdwwaY7Vc8+0bymoanUWcErRctLzjm+1uKeMnFQokR8wFtnS3PgpQ=", + "subType": "06" + } + } + }, + "local_javascriptWithScope_det_explicit_id": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_javascriptWithScope_det_explicit_altname": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_int_rand_auto_id": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAQHXpXb3KlHA2KFTBgl0VoLCu0CUf1ae4DckkwDorbredVSqxvA5e+NvVudY5yuea6bC9F57JlbjI8NWYAUw4q0Q==", + "subType": "06" + } + } + }, + "local_int_rand_auto_altname": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAQSxXMF4+TKV+a3lcxXky8VepEqdg5wI/jg+C4CAUgNurq2XhgrxyqiMjkU8z07tfyoLYyX6P+dTrwj6nzvvchCw==", + "subType": "06" + } + } + }, + "local_int_rand_explicit_id": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAQmzteYnshCI8HBGd7UYUKvcg4xl6M8PRyi1xX/WHbjyQkAJXxczS8hO91wuqStE3tBNSmulUejz9S691ufTd6ZA==", + "subType": "06" + } + } + }, + "local_int_rand_explicit_altname": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAQLCHLru//++QSoWVEyw2v6TUfCnlrPJXrpLLezWf16vK85jTfm8vJbb2X2UzX04wGzVL9tCFFsWX6Z5gHXhgSBg==", + "subType": "06" + } + } + }, + "local_int_det_auto_id": { + "kms": "local", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAQIxWjLBromNUgiOoeoZ4RUJUYIfhfOmab0sa4qYlS9bgYI41FU6BtzaOevR16O9i+uACbiHL0X6FMXKjOmiRAug==", + "subType": "06" + } + } + }, + "local_int_det_explicit_id": { + "kms": "local", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAQIxWjLBromNUgiOoeoZ4RUJUYIfhfOmab0sa4qYlS9bgYI41FU6BtzaOevR16O9i+uACbiHL0X6FMXKjOmiRAug==", + "subType": "06" + } + } + }, + "local_int_det_explicit_altname": { + "kms": "local", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAQIxWjLBromNUgiOoeoZ4RUJUYIfhfOmab0sa4qYlS9bgYI41FU6BtzaOevR16O9i+uACbiHL0X6FMXKjOmiRAug==", + "subType": "06" + } + } + }, + "local_timestamp_rand_auto_id": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAARntIycg0Xkd16GEa//VSJI4Rkl7dT6MpRa+D3MiTEeio5Yy8zGK0u2BtEP/9MCRQw2hJDYj5znVqwhdduM0OTiA==", + "subType": "06" + } + } + }, + "local_timestamp_rand_auto_altname": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAARWA9Ox5ejDPeWxfjbRgcGCtF/G5yrPMbBJD9ESDFc0NaVe0sdNNTisEVxsSkn7M/S4FCibKh+C8femr7xhu1iTw==", + "subType": "06" + } + } + }, + "local_timestamp_rand_explicit_id": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAARrEfOL4+4Qh7IkhHnHcBEANGfMF8n2wUDnsZ0lXEb0fACKzaN5OKaxMIQBs/3pFBw721qRfCHY+ByKeaQuABbzg==", + "subType": "06" + } + } + }, + "local_timestamp_rand_explicit_altname": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAARW8nwmnBt+LFIAcFWvOzX8llrGcveQKFhyYUIth9d7wtpTyc9myFp8GBQCnjDpKzA6lPmbqVYeLU0L9q0h6SHGQ==", + "subType": "06" + } + } + }, + "local_timestamp_det_auto_id": { + "kms": "local", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAR6uMylGytMq8QDr5Yz3w9HlW2MkGt6yIgUKcXYSaXru8eer+EkLv66/vy5rHqTfV0+8ryoi+d+PWO5U6b3Ng5Gg==", + "subType": "06" + } + } + }, + "local_timestamp_det_explicit_id": { + "kms": "local", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAR6uMylGytMq8QDr5Yz3w9HlW2MkGt6yIgUKcXYSaXru8eer+EkLv66/vy5rHqTfV0+8ryoi+d+PWO5U6b3Ng5Gg==", + "subType": "06" + } + } + }, + "local_timestamp_det_explicit_altname": { + "kms": "local", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAR6uMylGytMq8QDr5Yz3w9HlW2MkGt6yIgUKcXYSaXru8eer+EkLv66/vy5rHqTfV0+8ryoi+d+PWO5U6b3Ng5Gg==", + "subType": "06" + } + } + }, + "local_long_rand_auto_id": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAASrinKUOpHIB7MNRmCAPWcP4CjZwfr5JaRT3G/GqY9B/6csj3+N9jmo1fYvM8uHcnmf5hzDDOamaE2FF1jDKkrHw==", + "subType": "06" + } + } + }, + "local_long_rand_auto_altname": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAShWMPYDkCpTC2XLYyykPJMihASLKn6HHcB2Eh7jFwQb/8D1HCQoPmOHMyXaN4AtIKm1oqEfma6FSnEPENQoledQ==", + "subType": "06" + } + } + }, + "local_long_rand_explicit_id": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAASd2h34ZLib+GiYayrm/FIZ/weg8wF41T0PfF8NCLTJCoT7gIkdpNRz2zkkQgZMR31efNKtsM8Bs4wgZbkrXsXWg==", + "subType": "06" + } + } + }, + "local_long_rand_explicit_altname": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAASPAvdjz+a3FvXqDSjazaGqwZxrfXlfFB5/VjQFXQB0gpodCEaz1qaLSKfCWBg83ftrYKa/1sa44gU5NBthDfDwQ==", + "subType": "06" + } + } + }, + "local_long_det_auto_id": { + "kms": "local", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAASQk372m/hW3WX82/GH+ikPv3QUwK7Hh/RBpAguiNxMdNhkgA/y2gznVNm17t6djyub7+d5zN4P5PLS/EOm2kjtw==", + "subType": "06" + } + } + }, + "local_long_det_explicit_id": { + "kms": "local", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAASQk372m/hW3WX82/GH+ikPv3QUwK7Hh/RBpAguiNxMdNhkgA/y2gznVNm17t6djyub7+d5zN4P5PLS/EOm2kjtw==", + "subType": "06" + } + } + }, + "local_long_det_explicit_altname": { + "kms": "local", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAASQk372m/hW3WX82/GH+ikPv3QUwK7Hh/RBpAguiNxMdNhkgA/y2gznVNm17t6djyub7+d5zN4P5PLS/EOm2kjtw==", + "subType": "06" + } + } + }, + "local_decimal_rand_auto_id": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAATLnMMDZhnGSn5F5xHhsJXxiTGXd61Eq6fgppOlxUNVlsZNYyr5tZ3owfTTqRuD9yRg97x65WiHewBBnJJSeirCTAy9zZxWPVlJSiC0gO7rbM=", + "subType": "06" + } + } + }, + "local_decimal_rand_auto_altname": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAATenMh7NKQioGjpuEojIrYKFaJhbuGxUgu2yTTbe3TndhgHryhW9GXiUqo8WTpnXqpC5E/z03ZYLWfCbe7qGdL6T7bbrTpaTaWZnnAm3XaCqY=", + "subType": "06" + } + } + }, + "local_decimal_rand_explicit_id": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAT9vqXuKRh+2HxeCMr+pQYdhYNw7xrTdU4dySWz0X6tCK7LZO5AV72utmRJxID7Bqv1ZlXAk00V92oDLyKG9kHeG5+S34QE/aLCPsAWcppfxY=", + "subType": "06" + } + } + }, + "local_decimal_rand_explicit_altname": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAATtqOCFMbOkls3LikQNXlnlkRr5gJns1+5Kvbt7P7texMa/QlXkYSHhtwESyfOcCQ2sw1T0eZ9DDuNaznpdK2KIqZBkVEC9iMoxqIqXF7Nab0=", + "subType": "06" + } + } + }, + "local_decimal_det_explicit_id": { + "kms": "local", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "local_decimal_det_explicit_altname": { + "kms": "local", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "local_minKey_rand_explicit_id": { + "kms": "local", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_minKey_rand_explicit_altname": { + "kms": "local", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_minKey_det_explicit_id": { + "kms": "local", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_minKey_det_explicit_altname": { + "kms": "local", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_maxKey_rand_explicit_id": { + "kms": "local", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_maxKey_rand_explicit_altname": { + "kms": "local", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_maxKey_det_explicit_id": { + "kms": "local", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_maxKey_det_explicit_altname": { + "kms": "local", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "payload=0,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACcsBdT93ivCyvtkfQz9qb1A9Ll+I6hnGE0kFy3rmVG6xAvipmRJSoVq3iv7iUEDvaqmPXfjeH8h8cPYT86v3XSg==", + "subType": "06" + } + } + }, + "payload=1,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACQOzpNBEGSrANr3Wl8uYpqeIc7pjc8e2LS2FaSrb8tM9F3mR1FqGgfJtn3eD+HZf3Y3WEDGK8975a/1BufkMqIQ==", + "subType": "06" + } + } + }, + "payload=2,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACyGJEcuN1pG5oSEyxuKFwqddGHVU5Untbib7LkmtoJe9HngTofkOpeHZH/hV6Z3CFxLu6WFliJoySsFFbnFy9ag==", + "subType": "06" + } + } + }, + "payload=3,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACLbp4w6mx45lR1vvgmeRja/y8U+WnR2oH4IpfrDi4lKM+JPVnJweiN3/1wAy+sXSy0S1Yh9yxmhh9ISoTkAuVxw==", + "subType": "06" + } + } + }, + "payload=4,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACG0qMY/GPZ/2CR61cxbuizywefyMZVdeTCn5KFjqwejgxeBwX0JmGNHKKWbQIDQykRFv0q0WHUgsRmRhaotNCyQ==", + "subType": "06" + } + } + }, + "payload=5,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACJI1onNpQfZhaYWrPEzHvNaJRqUDZK2xoyonB5E473BPgp3zvn0Jmz1deL8GzS+HlkjCrx39OvHyVt3+3S0kYYw==", + "subType": "06" + } + } + }, + "payload=6,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAClyKY9tZBjl7SewSXr3MdoWRDUNgLaXDUjENpjyYvi/54EQ9a+J/LAAh1892i+mLpYxEUAmcftPyfX3VhbCgUQw==", + "subType": "06" + } + } + }, + "payload=7,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACAMbEA+kNvnVV7B//ds2/QoVot061kbazoMwB/psB5eFdLVB5qApAXEWgQEMwkNnsTUYbtSduQz6uGwdagtNBRw==", + "subType": "06" + } + } + }, + "payload=8,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACzdSK/d7Ni6D8qUgNopnEU5ia1K5llhBGk3O1Tf71t4ThnQjYW9eI/rIohWmev5CGWLHhwuvvKUtFcTAe+NMQww==", + "subType": "06" + } + } + }, + "payload=9,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACzQcEa+ktF2EZf35TtyatnSGGaIVvFhZNuo5P3VwQvoONJrK2cSad7PBDAv3xDAB+VPZAigXAGQvd051sHooOHg==", + "subType": "06" + } + } + }, + "payload=10,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACpfoDmApsR5xOD3TDhcHeD7Jco3kPFuuWjDpHtMepMOJ3S0c+ngGGhzPGZtEz2xuD/E7AQn1ryp/WAQ+WwkaJkQ==", + "subType": "06" + } + } + }, + "payload=11,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACICMRXmx3oKqYv0IpmzkSMBIGT4Li3MPBF4Lw1s5F69WvZApD58glIKB6b7koIrF5qc2Wrb1/Nw+stRv0zvQ8Y9CcFV4OHm6WoEw+XDlWXJ4=", + "subType": "06" + } + } + }, + "payload=12,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACTArUn0WUTojQC4fSvq3TwJVTsZNhWAK2WB057u2EnkUzMC0xsbU6611W6Okx6idZ7pMudXpBC34fRDrJPXOu3BxK+ZLCOWS2FqsvWq3HeTY=", + "subType": "06" + } + } + }, + "payload=13,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACU1Ojn7EM2i+5KK2Beh1gPLhryK3Y7PtaZ/v4JvstxuAV4OHOR9yROP7pwenHXxczkWXvcyMY9OCdmHO8pkQkXO21798IPkDDN/ejJUFI0Uw=", + "subType": "06" + } + } + }, + "payload=14,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAAC0ZLwSliCbcr/e1uiYWk6gRuD/5qiyulQ7IUNWjhpBR6SLUfX2+yExLzps9hoOp53j9zRSKIzyleZ8yGLTLeN+Lz9BUe2ZT+sV8NiqZz3pkA=", + "subType": "06" + } + } + }, + "payload=15,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACQ9pmlQeFDr+jEhFwjL/eGVxdv70JdnkLaKdJ3/jkvCX1VPU5HmQIi+JWY3Rrw844E/6sBR6zIODn5aM0WfyP8a2zKRAWaVQZ7n+QE9hDN/8=", + "subType": "06" + } + } + }, + "payload=16,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AizggCwAAAAAAAAAAAAAAAACiOcItInDGHqvkH0I3udp5nnX32XzDeqya/3KDjgZPT5GHek1vFTZ4924JVxFqFQz+No9rOVmyxm8O2fxjTK2vsjtADzKGnMTtFYZqghYCuc=", + "subType": "06" + } + } + }, + "payload=0,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACijFptWQy7a1Y0rpXEvamXWI9v9dnx0Qj84/mKUsVpc3agkQ0B04uPYeROdt2MeEeiZoEKVWV0NjBocAQCEz7dw==", + "subType": "06" + } + } + }, + "payload=1,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAChR90taVWsZk+++sgibX6CnFeQQHNoB8V+n2gmDe3CIT/t+WvhMf9D+mQipbAlrUyHgGihKMHcvAZ5RZ/spaH4Q==", + "subType": "06" + } + } + }, + "payload=2,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAC67wemDv1Xdu7+EMR9LMBTOxfyAqsGaxQibwamZItzplslL/Dp3t9g9vPuNzq0dWwhnfxQ9GBe8OA3dtRaifYCA==", + "subType": "06" + } + } + }, + "payload=3,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACVLxch+uC7weXrbtylCo1m4HYZmh0sd9JCrlTECO2M56JK1X9a30i2BDUdhPuoTvvODv74CGXkZKdist3o0mGAQ==", + "subType": "06" + } + } + }, + "payload=4,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACexfIZGkOYaCGktOUc6cgAYg7Bd/C5ZYmdb7b8+rd5BKWbthW6N6CxhDIyh/DHvkPAeIzfTYA2/9w6tsjfD/TPQ==", + "subType": "06" + } + } + }, + "payload=5,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACjUH/dPW4egOvFMJJnpWK8v27MeLkbXC4GFl1j+wPqTsIEeIWkzEmcXjHLTQGE2GplHHc/zxwRwD2dXdbzvsCDw==", + "subType": "06" + } + } + }, + "payload=6,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACzvS+QkGlvb05pNn+vBMml09yKmE8yM6lwccNIST5uZSsUxXf2hrxPtO7Ylc4lmBAJt/9bcM59JIeT9fpYMc75w==", + "subType": "06" + } + } + }, + "payload=7,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACSf2RxHJpRuh4j8nS1dfonUtsJEwgqfWrwOsfuT/tAGXgDN0ObUpzL2K7G2vmePjP4dwycCSIL3+2j34bqBJK1Q==", + "subType": "06" + } + } + }, + "payload=8,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACu96YYeLXXoYdEZYNU9UAZjSd6G4fOE1edrA6/RjZKVGWKxftmvj5g1VAOiom0XuTZUe1ihbnwhvKexeoa3Vc8Q==", + "subType": "06" + } + } + }, + "payload=9,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACX+UjBKo9+N0Z+mbyqZqkQv2ETMSn6aPTONWgJtw5nWklcxKjUSSLI+8LW/6M6Xf9a7177GsqmV2f/yCRF58Xtw==", + "subType": "06" + } + } + }, + "payload=10,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACL6TVscFzIJ9+Zj6LsCZ9xhaZuTZdvz1nJe4l69nKyj9hCjnyuiV6Ve4AXwQ5W1wiPfkJ0fCZS33NwiHw7QQ/vg==", + "subType": "06" + } + } + }, + "payload=11,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACPLq7IcWhTVwkKmy0flN7opoQzx7tTe1eD9JIc25FC9B6KGQkdcRDglDDR7/m6+kBtTnq88y63vBgomTxA8ZxQE+3pB7zCiBhX0QznuXvP44=", + "subType": "06" + } + } + }, + "payload=12,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACxv7v4pKtom5z1g9FUuyjEWAbdzJ3ytPNZlOfVr6KZnUPhIH7PfCz3/lTdYYWBTj01+SUZiC/7ruof9QDhsSiNWP7nUyHpQ/C3joI/BBjtDA=", + "subType": "06" + } + } + }, + "payload=13,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACZhiElQ/MvyVMwMkZPu8pT54Ap6TlpVSEbE4nIQzzeU3XKVuspMdI5IXvvgfULXKXc+AOu6oQXZ+wAJ1tErVOsb48HF1g0wbXbBA31C5qLEM=", + "subType": "06" + } + } + }, + "payload=14,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACdp8mDOeDuDLhE0LzTOT2p0CMaUsAQrGCzmiK6Ab9xvaIcPPcejUcpdO3XXAS/pPab4+TUwO5GbI5pDJ29zwaOiOz2H3OJ2m2p5BHQp9mCys=", + "subType": "06" + } + } + }, + "payload=15,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAACmtLohoP/gotuon2IvnGeLEfCWHRMhG9Wp4tPu/vbJJkJkbQTP35HRG9VrMV7KKrEQbOsJ2Y6UDBra4tyjn0fIkwwc/0X9i+xaP+TrwpNabE=", + "subType": "06" + } + } + }, + "payload=16,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASzggCwAAAAAAAAAAAAAAAAC6s9eUtSneKWj3/A7S+bPZLj3t1WtUh7ltW80b8jCRzA+kOI26j1MEb1tt68HgcnH1IJ3YQ/+UHlV95OgwSnIxlib/HJn3U0s8mpuCWe1Auo=", + "subType": "06" + } + } + } +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-aws.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-aws.json new file mode 100644 index 00000000000..eca6cf912ef --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-aws.json @@ -0,0 +1,33 @@ +{ + "status": { + "$numberInt": "1" + }, + "_id": { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "region": "us-east-1", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "provider": "aws" + }, + "updateDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyAltNames": ["aws"] +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-local.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-local.json new file mode 100644 index 00000000000..b3fe0723b06 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-key-local.json @@ -0,0 +1,31 @@ +{ + "status": { + "$numberInt": "1" + }, + "_id": { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "local" + }, + "updateDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyMaterial": { + "$binary": { + "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyAltNames": [ "local" ] +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-schema.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-schema.json new file mode 100644 index 00000000000..e4838d8aaea --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus-schema.json @@ -0,0 +1,2057 @@ +{ + "bsonType": "object", + "properties": { + "aws_double_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "aws_double_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "aws_double_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_double_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_string_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "aws_string_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "aws_string_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_string_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_string_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "string" + } + } + } + }, + "aws_string_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_string_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_object_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "aws_object_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "aws_object_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_object_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_array_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "aws_array_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "aws_array_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_array_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=00_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "aws_binData=00_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "aws_binData=00_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=00_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=00_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "aws_binData=00_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=00_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=04_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "aws_binData=04_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "aws_binData=04_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=04_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=04_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "aws_binData=04_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_binData=04_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_objectId_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "aws_objectId_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "aws_objectId_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_objectId_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_objectId_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "objectId" + } + } + } + }, + "aws_objectId_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_objectId_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_bool_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "aws_bool_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "aws_bool_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_bool_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_date_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "aws_date_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "aws_date_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_date_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_date_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "date" + } + } + } + }, + "aws_date_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_date_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_regex_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "aws_regex_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "aws_regex_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_regex_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_regex_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "regex" + } + } + } + }, + "aws_regex_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_regex_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_dbPointer_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "aws_dbPointer_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "aws_dbPointer_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_dbPointer_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_dbPointer_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "dbPointer" + } + } + } + }, + "aws_dbPointer_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_dbPointer_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_javascript_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "aws_javascript_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "aws_javascript_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_javascript_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_javascript_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "javascript" + } + } + } + }, + "aws_javascript_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_javascript_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_symbol_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "aws_symbol_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "aws_symbol_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_symbol_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_symbol_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "symbol" + } + } + } + }, + "aws_symbol_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_symbol_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_javascriptWithScope_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "aws_javascriptWithScope_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "aws_javascriptWithScope_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_javascriptWithScope_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_int_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "aws_int_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "aws_int_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_int_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_int_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "int" + } + } + } + }, + "aws_int_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_int_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_timestamp_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "aws_timestamp_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "aws_timestamp_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_timestamp_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_timestamp_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "timestamp" + } + } + } + }, + "aws_timestamp_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_timestamp_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_long_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "aws_long_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "aws_long_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_long_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_long_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "long" + } + } + } + }, + "aws_long_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_long_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_decimal_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "aws_decimal_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_aws", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "aws_decimal_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "aws_decimal_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_double_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "local_double_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "local_double_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_double_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_string_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "local_string_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "local_string_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_string_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_string_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "string" + } + } + } + }, + "local_string_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_string_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_object_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "local_object_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "local_object_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_object_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_array_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "local_array_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "local_array_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_array_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=00_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "local_binData=00_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "local_binData=00_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=00_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=00_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "local_binData=00_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=00_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=04_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "local_binData=04_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "local_binData=04_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=04_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=04_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "local_binData=04_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_binData=04_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_objectId_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "local_objectId_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "local_objectId_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_objectId_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_objectId_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "objectId" + } + } + } + }, + "local_objectId_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_objectId_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_bool_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "local_bool_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "local_bool_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_bool_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_date_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "local_date_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "local_date_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_date_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_date_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "date" + } + } + } + }, + "local_date_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_date_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_regex_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "local_regex_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "local_regex_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_regex_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_regex_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "regex" + } + } + } + }, + "local_regex_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_regex_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_dbPointer_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "local_dbPointer_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "local_dbPointer_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_dbPointer_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_dbPointer_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "dbPointer" + } + } + } + }, + "local_dbPointer_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_dbPointer_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_javascript_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "local_javascript_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "local_javascript_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_javascript_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_javascript_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "javascript" + } + } + } + }, + "local_javascript_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_javascript_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_symbol_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "local_symbol_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "local_symbol_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_symbol_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_symbol_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "symbol" + } + } + } + }, + "local_symbol_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_symbol_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_javascriptWithScope_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "local_javascriptWithScope_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "local_javascriptWithScope_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_javascriptWithScope_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_int_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "local_int_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "local_int_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_int_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_int_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "int" + } + } + } + }, + "local_int_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_int_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_timestamp_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "local_timestamp_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "local_timestamp_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_timestamp_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_timestamp_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "timestamp" + } + } + } + }, + "local_timestamp_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_timestamp_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_long_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "local_long_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "local_long_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_long_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_long_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "long" + } + } + } + }, + "local_long_det_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_long_det_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_decimal_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "local_decimal_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_local", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "local_decimal_rand_explicit_id": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + }, + "local_decimal_rand_explicit_altname": { + "bsonType": "object", + "properties": { "value": { "bsonType": "binData" } } + } + } +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus.json new file mode 100644 index 00000000000..cbf7a091a1a --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/corpus/corpus.json @@ -0,0 +1,2905 @@ +{ + "_id": "client_side_encryption_corpus", + "altname_aws": "aws", + "altname_local": "local", + "aws_double_rand_auto_id": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "aws_double_rand_auto_altname": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "aws_double_rand_explicit_id": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "aws_double_rand_explicit_altname": { + "kms": "aws", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "aws_double_det_explicit_id": { + "kms": "aws", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "aws_double_det_explicit_altname": { + "kms": "aws", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "aws_string_rand_auto_id": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "aws_string_rand_auto_altname": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "aws_string_rand_explicit_id": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "aws_string_rand_explicit_altname": { + "kms": "aws", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "aws_string_det_auto_id": { + "kms": "aws", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "aws_string_det_explicit_id": { + "kms": "aws", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "aws_string_det_explicit_altname": { + "kms": "aws", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "aws_object_rand_auto_id": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_object_rand_auto_altname": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_object_rand_explicit_id": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_object_rand_explicit_altname": { + "kms": "aws", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_object_det_explicit_id": { + "kms": "aws", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_object_det_explicit_altname": { + "kms": "aws", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "aws_array_rand_auto_id": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_array_rand_auto_altname": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_array_rand_explicit_id": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_array_rand_explicit_altname": { + "kms": "aws", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_array_det_explicit_id": { + "kms": "aws", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_array_det_explicit_altname": { + "kms": "aws", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "aws_binData=00_rand_auto_id": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "aws_binData=00_rand_auto_altname": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "aws_binData=00_rand_explicit_id": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "aws_binData=00_rand_explicit_altname": { + "kms": "aws", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "aws_binData=00_det_auto_id": { + "kms": "aws", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "aws_binData=00_det_explicit_id": { + "kms": "aws", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "aws_binData=00_det_explicit_altname": { + "kms": "aws", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "aws_binData=04_rand_auto_id": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "aws_binData=04_rand_auto_altname": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "aws_binData=04_rand_explicit_id": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "aws_binData=04_rand_explicit_altname": { + "kms": "aws", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "aws_binData=04_det_auto_id": { + "kms": "aws", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "aws_binData=04_det_explicit_id": { + "kms": "aws", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "aws_binData=04_det_explicit_altname": { + "kms": "aws", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "aws_undefined_rand_explicit_id": { + "kms": "aws", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_undefined_rand_explicit_altname": { + "kms": "aws", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_undefined_det_explicit_id": { + "kms": "aws", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_undefined_det_explicit_altname": { + "kms": "aws", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "aws_objectId_rand_auto_id": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "aws_objectId_rand_auto_altname": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "aws_objectId_rand_explicit_id": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "aws_objectId_rand_explicit_altname": { + "kms": "aws", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "aws_objectId_det_auto_id": { + "kms": "aws", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "aws_objectId_det_explicit_id": { + "kms": "aws", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "aws_objectId_det_explicit_altname": { + "kms": "aws", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "aws_bool_rand_auto_id": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": true + }, + "aws_bool_rand_auto_altname": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": true + }, + "aws_bool_rand_explicit_id": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": true + }, + "aws_bool_rand_explicit_altname": { + "kms": "aws", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": true + }, + "aws_bool_det_explicit_id": { + "kms": "aws", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "aws_bool_det_explicit_altname": { + "kms": "aws", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "aws_date_rand_auto_id": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "aws_date_rand_auto_altname": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "aws_date_rand_explicit_id": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "aws_date_rand_explicit_altname": { + "kms": "aws", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "aws_date_det_auto_id": { + "kms": "aws", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "aws_date_det_explicit_id": { + "kms": "aws", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "aws_date_det_explicit_altname": { + "kms": "aws", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "aws_null_rand_explicit_id": { + "kms": "aws", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "aws_null_rand_explicit_altname": { + "kms": "aws", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "aws_null_det_explicit_id": { + "kms": "aws", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "aws_null_det_explicit_altname": { + "kms": "aws", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "aws_regex_rand_auto_id": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "aws_regex_rand_auto_altname": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "aws_regex_rand_explicit_id": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "aws_regex_rand_explicit_altname": { + "kms": "aws", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "aws_regex_det_auto_id": { + "kms": "aws", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "aws_regex_det_explicit_id": { + "kms": "aws", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "aws_regex_det_explicit_altname": { + "kms": "aws", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "aws_dbPointer_rand_auto_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "aws_dbPointer_rand_auto_altname": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "aws_dbPointer_rand_explicit_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "aws_dbPointer_rand_explicit_altname": { + "kms": "aws", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "aws_dbPointer_det_auto_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "aws_dbPointer_det_explicit_id": { + "kms": "aws", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "aws_dbPointer_det_explicit_altname": { + "kms": "aws", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "aws_javascript_rand_auto_id": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "aws_javascript_rand_auto_altname": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1" } + }, + "aws_javascript_rand_explicit_id": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "aws_javascript_rand_explicit_altname": { + "kms": "aws", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1" } + }, + "aws_javascript_det_auto_id": { + "kms": "aws", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "aws_javascript_det_explicit_id": { + "kms": "aws", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "aws_javascript_det_explicit_altname": { + "kms": "aws", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1" } + }, + "aws_symbol_rand_auto_id": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "aws_symbol_rand_auto_altname": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "aws_symbol_rand_explicit_id": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "aws_symbol_rand_explicit_altname": { + "kms": "aws", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "aws_symbol_det_auto_id": { + "kms": "aws", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "aws_symbol_det_explicit_id": { + "kms": "aws", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "aws_symbol_det_explicit_altname": { + "kms": "aws", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "aws_javascriptWithScope_rand_auto_id": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_javascriptWithScope_rand_auto_altname": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_javascriptWithScope_rand_explicit_id": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_javascriptWithScope_rand_explicit_altname": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_javascriptWithScope_det_explicit_id": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_javascriptWithScope_det_explicit_altname": { + "kms": "aws", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "aws_int_rand_auto_id": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "aws_int_rand_auto_altname": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "aws_int_rand_explicit_id": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "aws_int_rand_explicit_altname": { + "kms": "aws", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "aws_int_det_auto_id": { + "kms": "aws", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "aws_int_det_explicit_id": { + "kms": "aws", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "aws_int_det_explicit_altname": { + "kms": "aws", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "aws_timestamp_rand_auto_id": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "aws_timestamp_rand_auto_altname": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "aws_timestamp_rand_explicit_id": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "aws_timestamp_rand_explicit_altname": { + "kms": "aws", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "aws_timestamp_det_auto_id": { + "kms": "aws", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "aws_timestamp_det_explicit_id": { + "kms": "aws", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "aws_timestamp_det_explicit_altname": { + "kms": "aws", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "aws_long_rand_auto_id": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "aws_long_rand_auto_altname": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "aws_long_rand_explicit_id": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "aws_long_rand_explicit_altname": { + "kms": "aws", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "aws_long_det_auto_id": { + "kms": "aws", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "aws_long_det_explicit_id": { + "kms": "aws", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "aws_long_det_explicit_altname": { + "kms": "aws", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "aws_decimal_rand_auto_id": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "aws_decimal_rand_auto_altname": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "aws_decimal_rand_explicit_id": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "aws_decimal_rand_explicit_altname": { + "kms": "aws", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "aws_decimal_det_explicit_id": { + "kms": "aws", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "aws_decimal_det_explicit_altname": { + "kms": "aws", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "aws_minKey_rand_explicit_id": { + "kms": "aws", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_minKey_rand_explicit_altname": { + "kms": "aws", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_minKey_det_explicit_id": { + "kms": "aws", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_minKey_det_explicit_altname": { + "kms": "aws", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "aws_maxKey_rand_explicit_id": { + "kms": "aws", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "aws_maxKey_rand_explicit_altname": { + "kms": "aws", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "aws_maxKey_det_explicit_id": { + "kms": "aws", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "aws_maxKey_det_explicit_altname": { + "kms": "aws", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_double_rand_auto_id": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "local_double_rand_auto_altname": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "local_double_rand_explicit_id": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "local_double_rand_explicit_altname": { + "kms": "local", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberDouble": "1.234" } + }, + "local_double_det_explicit_id": { + "kms": "local", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "local_double_det_explicit_altname": { + "kms": "local", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDouble": "1.234" } + }, + "local_string_rand_auto_id": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "local_string_rand_auto_altname": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "local_string_rand_explicit_id": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "local_string_rand_explicit_altname": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "local_string_det_auto_id": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "local_string_det_explicit_id": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "local_string_det_explicit_altname": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "local_object_rand_auto_id": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "local_object_rand_auto_altname": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "local_object_rand_explicit_id": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "local_object_rand_explicit_altname": { + "kms": "local", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "x": { "$numberInt": "1" } } + }, + "local_object_det_explicit_id": { + "kms": "local", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "local_object_det_explicit_altname": { + "kms": "local", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "x": { "$numberInt": "1" } } + }, + "local_array_rand_auto_id": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_array_rand_auto_altname": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_array_rand_explicit_id": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_array_rand_explicit_altname": { + "kms": "local", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_array_det_explicit_id": { + "kms": "local", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_array_det_explicit_altname": { + "kms": "local", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { "$numberInt": "1" }, + { "$numberInt": "2" }, + { "$numberInt": "3" } + ] + }, + "local_binData=00_rand_auto_id": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "local_binData=00_rand_auto_altname": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "local_binData=00_rand_explicit_id": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "local_binData=00_rand_explicit_altname": { + "kms": "local", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "local_binData=00_det_auto_id": { + "kms": "local", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "local_binData=00_det_explicit_id": { + "kms": "local", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "local_binData=00_det_explicit_altname": { + "kms": "local", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + }, + "local_binData=04_rand_auto_id": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "local_binData=04_rand_auto_altname": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "local_binData=04_rand_explicit_id": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "local_binData=04_rand_explicit_altname": { + "kms": "local", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "local_binData=04_det_auto_id": { + "kms": "local", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "local_binData=04_det_explicit_id": { + "kms": "local", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "local_binData=04_det_explicit_altname": { + "kms": "local", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + } + }, + "local_undefined_rand_explicit_id": { + "kms": "local", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "local_undefined_rand_explicit_altname": { + "kms": "local", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "local_undefined_det_explicit_id": { + "kms": "local", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$undefined": true } + }, + "local_undefined_det_explicit_altname": { + "kms": "local", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$undefined": true } + }, + "local_objectId_rand_auto_id": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "local_objectId_rand_auto_altname": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "local_objectId_rand_explicit_id": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "local_objectId_rand_explicit_altname": { + "kms": "local", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "local_objectId_det_auto_id": { + "kms": "local", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "local_objectId_det_explicit_id": { + "kms": "local", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "local_objectId_det_explicit_altname": { + "kms": "local", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$oid": "01234567890abcdef0123456" } + }, + "local_bool_rand_auto_id": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": true + }, + "local_bool_rand_auto_altname": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": true + }, + "local_bool_rand_explicit_id": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": true + }, + "local_bool_rand_explicit_altname": { + "kms": "local", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": true + }, + "local_bool_det_explicit_id": { + "kms": "local", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "local_bool_det_explicit_altname": { + "kms": "local", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "local_date_rand_auto_id": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "local_date_rand_auto_altname": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "local_date_rand_explicit_id": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "local_date_rand_explicit_altname": { + "kms": "local", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "local_date_det_auto_id": { + "kms": "local", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "local_date_det_explicit_id": { + "kms": "local", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "local_date_det_explicit_altname": { + "kms": "local", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$date": { "$numberLong": "12345" } } + }, + "local_null_rand_explicit_id": { + "kms": "local", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "local_null_rand_explicit_altname": { + "kms": "local", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "local_null_det_explicit_id": { + "kms": "local", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "local_null_det_explicit_altname": { + "kms": "local", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "local_regex_rand_auto_id": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "local_regex_rand_auto_altname": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "local_regex_rand_explicit_id": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "local_regex_rand_explicit_altname": { + "kms": "local", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "local_regex_det_auto_id": { + "kms": "local", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "local_regex_det_explicit_id": { + "kms": "local", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "local_regex_det_explicit_altname": { + "kms": "local", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + }, + "local_dbPointer_rand_auto_id": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "local_dbPointer_rand_auto_altname": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "local_dbPointer_rand_explicit_id": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "local_dbPointer_rand_explicit_altname": { + "kms": "local", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "local_dbPointer_det_auto_id": { + "kms": "local", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "local_dbPointer_det_explicit_id": { + "kms": "local", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "local_dbPointer_det_explicit_altname": { + "kms": "local", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { "$oid": "01234567890abcdef0123456" } + } + } + }, + "local_javascript_rand_auto_id": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "local_javascript_rand_auto_altname": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1" } + }, + "local_javascript_rand_explicit_id": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "local_javascript_rand_explicit_altname": { + "kms": "local", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1" } + }, + "local_javascript_det_auto_id": { + "kms": "local", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "local_javascript_det_explicit_id": { + "kms": "local", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1" } + }, + "local_javascript_det_explicit_altname": { + "kms": "local", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1" } + }, + "local_symbol_rand_auto_id": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "local_symbol_rand_auto_altname": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "local_symbol_rand_explicit_id": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "local_symbol_rand_explicit_altname": { + "kms": "local", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "local_symbol_det_auto_id": { + "kms": "local", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "local_symbol_det_explicit_id": { + "kms": "local", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "local_symbol_det_explicit_altname": { + "kms": "local", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$symbol": "mongodb-symbol" } + }, + "local_javascriptWithScope_rand_auto_id": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_javascriptWithScope_rand_auto_altname": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_javascriptWithScope_rand_explicit_id": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_javascriptWithScope_rand_explicit_altname": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_javascriptWithScope_det_explicit_id": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_javascriptWithScope_det_explicit_altname": { + "kms": "local", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$code": "x=1", "$scope": {} } + }, + "local_int_rand_auto_id": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "local_int_rand_auto_altname": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "local_int_rand_explicit_id": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "local_int_rand_explicit_altname": { + "kms": "local", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "local_int_det_auto_id": { + "kms": "local", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "local_int_det_explicit_id": { + "kms": "local", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "local_int_det_explicit_altname": { + "kms": "local", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberInt": "123" } + }, + "local_timestamp_rand_auto_id": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "local_timestamp_rand_auto_altname": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "local_timestamp_rand_explicit_id": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "local_timestamp_rand_explicit_altname": { + "kms": "local", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "local_timestamp_det_auto_id": { + "kms": "local", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "local_timestamp_det_explicit_id": { + "kms": "local", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "local_timestamp_det_explicit_altname": { + "kms": "local", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$timestamp": { "t": 0, "i": 12345 } } + }, + "local_long_rand_auto_id": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "local_long_rand_auto_altname": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "local_long_rand_explicit_id": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "local_long_rand_explicit_altname": { + "kms": "local", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "local_long_det_auto_id": { + "kms": "local", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "local_long_det_explicit_id": { + "kms": "local", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "local_long_det_explicit_altname": { + "kms": "local", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberLong": "456" } + }, + "local_decimal_rand_auto_id": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "local_decimal_rand_auto_altname": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "local_decimal_rand_explicit_id": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "local_decimal_rand_explicit_altname": { + "kms": "local", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { "$numberDecimal": "1.234" } + }, + "local_decimal_det_explicit_id": { + "kms": "local", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "local_decimal_det_explicit_altname": { + "kms": "local", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$numberDecimal": "1.234" } + }, + "local_minKey_rand_explicit_id": { + "kms": "local", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_minKey_rand_explicit_altname": { + "kms": "local", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_minKey_det_explicit_id": { + "kms": "local", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_minKey_det_explicit_altname": { + "kms": "local", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$minKey": 1 } + }, + "local_maxKey_rand_explicit_id": { + "kms": "local", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_maxKey_rand_explicit_altname": { + "kms": "local", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_maxKey_det_explicit_id": { + "kms": "local", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "local_maxKey_det_explicit_altname": { + "kms": "local", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { "$maxKey": 1 } + }, + "payload=0,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "" + }, + "payload=1,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "a" + }, + "payload=2,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aa" + }, + "payload=3,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaa" + }, + "payload=4,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaa" + }, + "payload=5,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaa" + }, + "payload=6,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaa" + }, + "payload=7,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaa" + }, + "payload=8,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaa" + }, + "payload=9,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaa" + }, + "payload=10,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaa" + }, + "payload=11,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaa" + }, + "payload=12,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaa" + }, + "payload=13,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaa" + }, + "payload=14,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaaa" + }, + "payload=15,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaaaa" + }, + "payload=16,algo=rand": { + "kms": "local", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaaaaa" + }, + "payload=0,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "" + }, + "payload=1,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "a" + }, + "payload=2,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aa" + }, + "payload=3,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaa" + }, + "payload=4,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaa" + }, + "payload=5,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaa" + }, + "payload=6,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaa" + }, + "payload=7,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaa" + }, + "payload=8,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaa" + }, + "payload=9,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaa" + }, + "payload=10,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaa" + }, + "payload=11,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaa" + }, + "payload=12,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaa" + }, + "payload=13,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaa" + }, + "payload=14,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaaa" + }, + "payload=15,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaaaa" + }, + "payload=16,algo=det": { + "kms": "local", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "aaaaaaaaaaaaaaaa" + } +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-key.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-key.json new file mode 100644 index 00000000000..6da5fc3c6d7 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-key.json @@ -0,0 +1,31 @@ +{ + "status": { + "$numberInt": "1" + }, + "_id": { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "local" + }, + "updateDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyMaterial": { + "$binary": { + "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyAltNames": [ "local" ] +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-schema.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-schema.json new file mode 100644 index 00000000000..4e99e4c5c42 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/external/external-schema.json @@ -0,0 +1,19 @@ +{ + "properties": { + "encrypted": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-doc.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-doc.json new file mode 100644 index 00000000000..7df58785484 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-doc.json @@ -0,0 +1,102 @@ +{ + "00": "a", + "01": "a", + "02": "a", + "03": "a", + "04": "a", + "05": "a", + "06": "a", + "07": "a", + "08": "a", + "09": "a", + "10": "a", + "11": "a", + "12": "a", + "13": "a", + "14": "a", + "15": "a", + "16": "a", + "17": "a", + "18": "a", + "19": "a", + "20": "a", + "21": "a", + "22": "a", + "23": "a", + "24": "a", + "25": "a", + "26": "a", + "27": "a", + "28": "a", + "29": "a", + "30": "a", + "31": "a", + "32": "a", + "33": "a", + "34": "a", + "35": "a", + "36": "a", + "37": "a", + "38": "a", + "39": "a", + "40": "a", + "41": "a", + "42": "a", + "43": "a", + "44": "a", + "45": "a", + "46": "a", + "47": "a", + "48": "a", + "49": "a", + "50": "a", + "51": "a", + "52": "a", + "53": "a", + "54": "a", + "55": "a", + "56": "a", + "57": "a", + "58": "a", + "59": "a", + "60": "a", + "61": "a", + "62": "a", + "63": "a", + "64": "a", + "65": "a", + "66": "a", + "67": "a", + "68": "a", + "69": "a", + "70": "a", + "71": "a", + "72": "a", + "73": "a", + "74": "a", + "75": "a", + "76": "a", + "77": "a", + "78": "a", + "79": "a", + "80": "a", + "81": "a", + "82": "a", + "83": "a", + "84": "a", + "85": "a", + "86": "a", + "87": "a", + "88": "a", + "89": "a", + "90": "a", + "91": "a", + "92": "a", + "93": "a", + "94": "a", + "95": "a", + "96": "a", + "97": "a", + "98": "a", + "99": "a" +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-key.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-key.json new file mode 100644 index 00000000000..0ff20048a8e --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-key.json @@ -0,0 +1,31 @@ +{ + "status": { + "$numberInt": "1" + }, + "_id": { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "local" + }, + "updateDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyMaterial": { + "$binary": { + "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1557827033449" + } + }, + "keyAltNames": [ "local" ] +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-schema.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-schema.json new file mode 100644 index 00000000000..8f9a9f0085a --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/limits/limits-schema.json @@ -0,0 +1,1405 @@ +{ + "properties": { + "00": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "01": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "02": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "03": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "04": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "05": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "06": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "07": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "08": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "09": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "10": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "11": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "12": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "13": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "14": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "15": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "16": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "17": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "18": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "19": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "20": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "21": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "22": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "23": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "24": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "25": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "26": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "27": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "28": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "29": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "30": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "31": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "32": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "33": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "34": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "35": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "36": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "37": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "38": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "39": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "40": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "41": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "42": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "43": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "44": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "45": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "46": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "47": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "48": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "49": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "50": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "51": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "52": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "53": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "54": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "55": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "56": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "57": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "58": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "59": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "60": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "61": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "62": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "63": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "64": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "65": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "66": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "67": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "68": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "69": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "70": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "71": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "72": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "73": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "74": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "75": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "76": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "77": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "78": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "79": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "80": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "81": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "82": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "83": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "84": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "85": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "86": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "87": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "88": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "89": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "90": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "91": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "92": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "93": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "94": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "95": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "96": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "97": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "98": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "99": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/README.rst b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/README.rst new file mode 100644 index 00000000000..7a8e53bb681 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/README.rst @@ -0,0 +1,491 @@ +============================ +Client Side Encryption Tests +============================ + +.. contents:: + +---- + +Introduction +============ + +This document describes the format of the driver spec tests included in the JSON +and YAML files included in this directory. + +Additional prose tests, that are not represented in the spec tests, are described +and MUST be implemented by all drivers. + +Spec Test Format +================ + +The spec tests format is an extension of `transactions spec tests `_ with some additions: + +- A ``json_schema`` to set on the collection used for operations. + +- A ``key_vault_data`` of data that should be inserted in the key vault collection before each test. + +- Introduction ``autoEncryptOpts`` to `clientOptions` + +- Addition of `$db` to command in `command_started_event` + +- Addition of `$$type` to command_started_event and outcome. + +The semantics of `$$type` is that any actual value matching the BSON type indicated by the BSON type string is considered a match. + +For example, the following matches a command_started_event for an insert of a document where `random` must be of type ``binData``:: + + - command_started_event: + command: + insert: *collection_name + documents: + - { random: { $$type: "binData" } } + ordered: true + command_name: insert + + +The values of `$$type` correspond to `these documented string representations of BSON types `_. + + +Each YAML file has the following keys: + +.. |txn| replace:: Unchanged from Transactions spec tests. + +- ``runOn`` |txn| + +- ``database_name`` |txn| + +- ``collection_name`` |txn| + +- ``data`` |txn| + +- ``json_schema`` A JSON Schema that should be set on the collection (using ``createCollection``) before each test run. + +- ``key_vault_data`` The data that should exist in the key vault collection under test before each test run. + +- ``tests``: An array of tests that are to be run independently of each other. + Each test will have some or all of the following fields: + + - ``description``: |txn| + + - ``skipReason``: |txn| + + - ``clientOptions``: Optional, parameters to pass to MongoClient(). + + - ``auto_encrypt_opts``: Optional + + - ``kms_providers`` A dictionary of KMS providers to set on the key vault ("aws" or "local") + + - ``aws`` The AWS KMS provider. An empty object. Drivers MUST fill in AWS credentials from the environment. + + - ``local`` The local KMS provider. + + - ``key`` A 96 byte local key. + + - ``schema_map``: Optional, a map from namespaces to local JSON schemas. + + - ``keyVaultNamespace``: Optional, a namespace to the key vault collection. Defaults to "admin.datakeys". + + - ``operations``: Array of documents, each describing an operation to be + executed. Each document has the following fields: + + - ``name``: |txn| + + - ``object``: |txn| + + - ``collectionOptions``: |txn| + + - ``command_name``: |txn| + + - ``arguments``: |txn| + + - ``result``: |txn| + + - ``expectations``: |txn| + + - ``outcome``: |txn| + + + +Use as integration tests +======================== + +Do the following before running spec tests: + +- Start the mongocryptd process. +- Start a mongod process with **server version 4.1.9 or later**. +- Place credentials to an AWS IAM user (access key ID + secret access key) somewhere in the environment outside of tracked code. (If testing on evergreen, project variables are a good place). + +Load each YAML (or JSON) file using a Canonical Extended JSON parser. + +Then for each element in ``tests``: + +#. If the ``skipReason`` field is present, skip this test completely. +#. If the ``key_vault_data`` field is present: + + #. Drop the ``admin.datakeys`` collection using writeConcern "majority". + #. Insert the data specified into the ``admin.datakeys`` with write concern "majority". + +#. Create a MongoClient using ``clientOptions``. + + #. If ``autoEncryptOpts`` includes ``aws`` as a KMS provider, pass in AWS credentials from the environment. + #. If ``autoEncryptOpts`` does not include ``keyVaultNamespace``, default it to ``admin.datakeys`` + +#. Create a collection object from the MongoClient, using the ``database_name`` + and ``collection_name`` fields from the YAML file. +#. Drop the test collection, using writeConcern "majority". +#. If the YAML file contains a ``data`` array, insert the documents in ``data`` + into the test collection, using writeConcern "majority". + +#. Set Command Monitoring listeners on the MongoClient. +#. For each element in ``operations``: + + - Enter a "try" block or your programming language's closest equivalent. + - Create a Database object from the MongoClient, using the ``database_name`` + field at the top level of the test file. + - Create a Collection object from the Database, using the + ``collection_name`` field at the top level of the test file. + If ``collectionOptions`` is present create the Collection object with the + provided options. Otherwise create the object with the default options. + - Execute the named method on the provided ``object``, passing the + arguments listed. + - If the driver throws an exception / returns an error while executing this + series of operations, store the error message and server error code. + - If the result document has an "errorContains" field, verify that the + method threw an exception or returned an error, and that the value of the + "errorContains" field matches the error string. "errorContains" is a + substring (case-insensitive) of the actual error message. + + If the result document has an "errorCodeName" field, verify that the + method threw a command failed exception or returned an error, and that + the value of the "errorCodeName" field matches the "codeName" in the + server error response. + + If the result document has an "errorLabelsContain" field, verify that the + method threw an exception or returned an error. Verify that all of the + error labels in "errorLabelsContain" are present in the error or exception + using the ``hasErrorLabel`` method. + + If the result document has an "errorLabelsOmit" field, verify that the + method threw an exception or returned an error. Verify that none of the + error labels in "errorLabelsOmit" are present in the error or exception + using the ``hasErrorLabel`` method. + - If the operation returns a raw command response, eg from ``runCommand``, + then compare only the fields present in the expected result document. + Otherwise, compare the method's return value to ``result`` using the same + logic as the CRUD Spec Tests runner. + +#. If the test includes a list of command-started events in ``expectations``, + compare them to the actual command-started events using the + same logic as the Command Monitoring Spec Tests runner. + +#. For each element in ``outcome``: + + - If ``name`` is "collection", create a new MongoClient *without encryption* + and verify that the test collection contains exactly the documents in the + ``data`` array. Ensure this find reads the latest data by using + **primary read preference** with **local read concern** even when the + MongoClient is configured with another read preference or read concern. + +The spec test MUST be run with *and* without auth. + +Prose Tests +=========== + +Tests for the ClientEncryption type are not included as part of the YAML tests. + +In the prose tests LOCAL_MASTERKEY refers to the following base64: + +.. code:: javascript + + Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk + +Data key and double encryption +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +First, perform the setup. + +#. Create a MongoClient without encryption enabled (referred to as ``client``). + +#. Using ``client``, drop the collections ``admin.datakeys`` and ``db.coll``. + +#. Create the following: + + - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) + - A ``ClientEncryption`` object (referred to as ``client_encryption``) + + Configure both objects with ``aws`` and the ``local`` KMS providers as follows: + + .. code:: javascript + + { + "aws": { }, + "local": { "key": } + } + + Configure both objects with ``keyVaultNamespace`` set to ``admin.datakeys``. + + Configure the ``MongoClient`` with the following ``schema_map``: + + .. code:: javascript + + { + "db.coll": { + "bsonType": "object", + "properties": { + "encrypted_placeholder": { + "encrypt": { + "keyId": "/placeholder", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + } + } + } + } + +Then, test creating and using data keys from a ``local`` KMS provider: + +#. Call ``client_encryption.createDataKey()`` with the ``local`` KMS provider and keyAltNames set to ``["local_altname"]``. + + - Expect a BSON binary with subtype 4 to be returned, referred to as ``local_datakey_id``. + - Use ``client`` to run a ``find`` on ``admin.datakeys`` by querying with the ``_id`` set to the ``local_datakey_id``. + - Expect that exactly one document is returned with the "masterKey.provider" equal to "local". + +#. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``local_datakey_id``. + + - Expect the return value to be a BSON binary subtype 6, referred to as ``local_encrypted``. + - Use ``client_encrypted`` to insert ``{ _id: "local", "value": }`` into ``db.coll``. + - Use ``client_encrypted`` to run a find querying with ``_id`` of "local" and expect ``value`` to be "hello local". + +#. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``local_altname``. + + - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``local_encrypted``. + +Then, repeat the above tests with the ``aws`` KMS provider: + +#. Call ``client_encryption.createDataKey()`` with the ``aws`` KMS provider, keyAltNames set to ``["aws_altname"]``, and ``masterKey`` as follows: + + .. code:: javascript + + { + region: "us-east-1", + key: "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" + } + + + - Expect a BSON binary with subtype 4 to be returned, referred to as ``aws_datakey_id``. + - Use ``client`` to run a ``find`` on ``admin.datakeys`` by querying with the ``_id`` set to the ``aws_datakey_id``. + - Expect that exactly one document is returned with the "masterKey.provider" equal to "aws". + +#. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``aws_datakey_id``. + + - Expect the return value to be a BSON binary subtype 6, referred to as ``aws_encrypted``. + - Use ``client_encrypted`` to insert ``{ _id: "aws", "value": }`` into ``db.coll``. + - Use ``client_encrypted`` to run a find querying with ``_id`` of "aws" and expect ``value`` to be "hello aws". + +#. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``aws_altname``. + + - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``aws_encrypted``. + + +Then, run the following final tests: + +#. Test explicit encrypting an auto encrypted field. + + - Use ``client_encrypted`` to attempt to insert ``{ "encrypted_placeholder": (local_encrypted) }`` + - Expect an exception to be thrown, since this is an attempt to auto encrypt an already encrypted value. + + + +External Key Vault Test +~~~~~~~~~~~~~~~~~~~~~~~ + +Run the following tests twice, parameterized by a boolean ``withExternalKeyVault``. + +#. Create a MongoClient without encryption enabled (referred to as ``client``). + +#. Using ``client``, drop the collections ``admin.datakeys`` and ``db.coll``. + Insert the document `external/external-key.json <../external/external-key.json>`_ into ``admin.datakeys``. + +#. Create the following: + + - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) + - A ``ClientEncryption`` object (referred to as ``client_encryption``) + + Configure both objects with the ``local`` KMS providers as follows: + + .. code:: javascript + + { "local": { "key": } } + + Configure both objects with ``keyVaultNamespace`` set to ``admin.datakeys``. + + Configure ``client_encrypted`` to use the schema `external/external-schema.json <../external/external-schema.json>`_ for ``db.coll`` by setting a schema map like: ``{ "db.coll": }`` + + If ``withExternalKeyVault == true``, configure both objects with an external key vault client. The external client MUST connect to the same + MongoDB cluster that is being tested against, except it MUST use the username ``fake-user`` and password ``fake-pwd``. + +#. Use ``client_encrypted`` to insert the document ``{"encrypted": "test"}`` into ``db.coll``. + If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. + +#. Use ``client_encryption`` to explicitly encrypt the string ``"test"`` with key ID ``LOCALAAAAAAAAAAAAAAAAA==`` and deterministic algorithm. + If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. + + +BSON size limits and batch splitting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +First, perform the setup. + +#. Create a MongoClient without encryption enabled (referred to as ``client``). + +#. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `limits/limits-schema.json <../limits/limits-schema.json>`_. + +#. Using ``client``, drop the collection ``admin.datakeys``. Insert the document `limits/limits-key.json <../limits/limits-key.json>`_ + +#. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``) + + Configure with the ``local`` KMS provider as follows: + + .. code:: javascript + + { "local": { "key": } } + + Configure with the ``keyVaultNamespace`` set to ``admin.datakeys``. + +Using ``client_encrypted`` perform the following operations: + +#. Insert ``{ "_id": "no_encryption_under_2mib", "unencrypted": }``. (Note 2097152 is 2^21 bytes, or 2 MiB). + + Expect this to succeed. + +#. Insert ``{ "_id": "no_encryption_over_2mib", "unencrypted": }``. + + Expect this to throw an exception due to exceeding the reduced maximum BSON document size. + +#. Insert the document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_2mib", "unencrypted": < the string "a" repeated (2097152 - 2000) times > }`` + Note: limits-doc.json is a 1005 byte BSON document that encrypts to a ~10,000 byte document. + + Expect this to succeed since after encryption this still is below the normal maximum BSON document size. + Note, before auto encryption this document is under the 2 MiB limit. After encryption it exceeds the 2 MiB limit, but does NOT exceed the 16 MiB limit. + +#. Bulk insert the following: + + - ``{ "_id": "no_encryption_under_2mib_1", "unencrypted": }`` + + - ``{ "_id": "no_encryption_under_2mib_2", "unencrypted": }`` + + Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. + +#. Bulk insert the following: + + - The document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_2mib_1", "unencrypted": < the string "a" repeated (2097152 - 2000) times > }`` + + - The document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_2mib_2", "unencrypted": < the string "a" repeated (2097152 - 2000) times > }`` + + Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). + +Optionally, if it is possible to mock the maxWriteBatchSize (i.e. the maximum number of documents in a batch) test that setting maxWriteBatchSize=1 and inserting the two documents ``{ "_id": "a" }, { "_id": "b" }`` with ``client_encrypted`` splits the operation into two inserts. + + +Views are prohibited +~~~~~~~~~~~~~~~~~~~~ + +#. Create a MongoClient without encryption enabled (referred to as ``client``). + +#. Using ``client``, drop and create a view named ``db.view`` with an empty pipeline. E.g. using the command ``{ "create": "view", "viewOn": "coll" }``. + +#. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``) + + Configure with the ``local`` KMS provider as follows: + + .. code:: javascript + + { "local": { "key": } } + + Configure with the ``keyVaultNamespace`` set to ``admin.datakeys``. + +#. Using ``client_encrypted``, attempt to insert a document into ``db.view``. Expect an exception to be thrown containing the message: "cannot auto encrypt a view". + + +Corpus Test +=========== + +The corpus test exhaustively enumerates all ways to encrypt all BSON value types. Note, the test data includes BSON binary subtype 4 (or standard UUID), which MUST be decoded and encoded as subtype 4. Run the test as follows. + +1. Create a MongoClient without encryption enabled (referred to as ``client``). + +2. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `corpus/corpus-schema.json <../corpus/corpus-schema.json>`_. + +3. Using ``client``, drop the collection ``admin.datakeys``. Insert the documents `corpus/corpus-key-local.json <../corpus/corpus-key-local.json>`_ and `corpus/corpus-key-aws.json <../corpus/corpus-key-aws.json>`_. + +4. Create the following: + + - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) + - A ``ClientEncryption`` object (referred to as ``client_encryption``) + + Configure both objects with ``aws`` and the ``local`` KMS providers as follows: + + .. code:: javascript + + { + "aws": { }, + "local": { "key": } + } + + Where LOCAL_MASTERKEY is the following base64: + + .. code:: javascript + + Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk + + Configure both objects with ``keyVaultNamespace`` set to ``admin.datakeys``. + +5. Load `corpus/corpus.json <../corpus/corpus.json>`_ to a variable named ``corpus``. The corpus contains subdocuments with the following fields: + + - ``kms`` is either ``aws`` or ``local`` + - ``type`` is a BSON type string `names coming from here `_) + - ``algo`` is either ``rand`` or ``det`` for random or deterministic encryption + - ``method`` is either ``auto``, for automatic encryption or ``explicit`` for explicit encryption + - ``identifier`` is either ``id`` or ``altname`` for the key identifier + - ``allowed`` is a boolean indicating whether the encryption for the given parameters is permitted. + - ``value`` is the value to be tested. + + Create a new BSON document, named ``corpus_copied``. + Iterate over each field of ``corpus``. + + - If the field name is ``_id``, ``altname_aws`` and ``altname_local``, copy the field to ``corpus_copied``. + - If ``method`` is ``auto``, copy the field to ``corpus_copied``. + - If ``method`` is ``explicit``, use ``client_encryption`` to explicitly encrypt the value. + + - Encrypt with the algorithm described by ``algo``. + - If ``identifier`` is ``id`` + + - If ``kms`` is ``local`` set the key_id to the UUID with base64 value ``LOCALAAAAAAAAAAAAAAAAA==``. + - If ``kms`` is ``aws`` set the key_id to the UUID with base64 value ``AWSAAAAAAAAAAAAAAAAAAA==``. + + - If ``identifier`` is ``altname`` + + - If ``kms`` is ``local`` set the key_alt_name to "local". + - If ``kms`` is ``aws`` set the key_alt_name to "aws". + + If ``allowed`` is true, copy the field and encrypted value to ``corpus_copied``. + If ``allowed`` is false. verify that an exception is thrown. Copy the unencrypted value to to ``corpus_copied``. + + +6. Using ``client_encrypted``, insert ``corpus_copied`` into ``db.coll``. + +7. Using ``client_encrypted``, find the inserted document from ``db.coll`` to a variable named ``corpus_decrypted``. Since it should have been automatically decrypted, assert the document exactly matches ``corpus``. + +8. Load `corpus/corpus_encrypted.json <../corpus/corpus-encrypted.json>`_ to a variable named ``corpus_encrypted_expected``. + Using ``client`` find the inserted document from ``db.coll`` to a variable named ``corpus_encrypted_actual``. + + Iterate over each field of ``corpus_encrypted_expected`` and check the following: + + - If the ``algo`` is ``det``, that the value equals the value of the corresponding field in ``corpus_encrypted_actual``. + - If the ``algo`` is ``rand`` and ``allowed`` is true, that the value does not equal the value of the corresponding field in ``corpus_encrypted_actual``. + - If ``allowed`` is true, decrypt the value with ``client_encryption``. Decrypt the value of the corresponding field of ``corpus_encrypted`` and validate that they are both equal. + - If ``allowed`` is false, validate the value exactly equals the value of the corresponding field of ``corpus`` (neither was encrypted). + +9. Repeat steps 1-8 with a local JSON schema. I.e. amend step 4 to configure the schema on ``client_encrypted`` and ``client_encryption`` with the ``schema_map`` option. + diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.json new file mode 100644 index 00000000000..fbb837e1dea --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.json @@ -0,0 +1,416 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Aggregate with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "encrypted_string": { "$eq" : "string0" } + } + } + ] + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "default", + "pipeline": [ + { + "$match": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + } + } + ] + }, + "command_name": "aggregate" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "Aggregate with empty pipeline", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [] + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "default", + "pipeline": [], + "cursor": {} + }, + "command_name": "aggregate" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "Aggregate should fail with random encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "random": "abc" + } + } + ] + }, + "result": { + "errorContains": "Cannot query on fields encrypted with the randomized encryption" + } + } + ] + }, + { + "description": "Database aggregate should fail", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "aggregate", + "object": "database", + "arguments": { + "pipeline": [ + { + "$currentOp": { + "allUsers": false, + "idleConnections": false, + "localOps": true + } + }, + { + "$match": { + "command.aggregate": { + "$eq": 1 + } + } + }, + { + "$project": { + "command": 1 + } + }, + { + "$project": { + "command.lsid": 0 + } + } + ] + }, + "result": { + "errorContains": "non-collection command not supported for auto encryption: aggregate" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.yml new file mode 100644 index 00000000000..24d47dbd572 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/aggregate.yml @@ -0,0 +1,136 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Aggregate with deterministic encryption" + skipReason: "SERVER-39395" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: aggregate + arguments: + pipeline: + - { $match: { encrypted_string: "457-55-5642" } } + result: + - &doc0 { _id: 1, encrypted_string: "string0" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + aggregate: *collection_name + pipeline: + - { $match: { encrypted_string: "457-55-5642" } } + command_name: aggregate + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - description: "Aggregate with empty pipeline" + skipReason: "SERVER-40829 hides agg support behind enableTestCommands flag." + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: aggregate + arguments: + pipeline: [] + result: + - { _id: 1, encrypted_string: "string0" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + aggregate: *collection_name + pipeline: [] + cursor: {} + command_name: aggregate + # Needs to fetch key when decrypting results + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - description: "Aggregate should fail with random encryption" + skipReason: "SERVER-39395" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: aggregate + arguments: + pipeline: + - { $match: { random: "abc" } } + result: + errorContains: "Cannot query on fields encrypted with the randomized encryption" + - description: "Database aggregate should fail" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: aggregate + object: database + arguments: + pipeline: + - $currentOp: { allUsers: false, idleConnections: false, localOps: true } + - $match: { command.aggregate: { $eq: 1 } } + - $project: { command: 1 } + - $project: { command.lsid: 0 } + result: + errorContains: "non-collection command not supported for auto encryption: aggregate" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.json new file mode 100644 index 00000000000..824a53c00b1 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.json @@ -0,0 +1,1446 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "$text unconditionally fails", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "$text": { + "$search": "search text" + } + } + }, + "result": { + "errorContains": "Unsupported match expression operator for encryption" + } + } + ] + }, + { + "description": "$where unconditionally fails", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "$where": { + "$code": "function() { return true }" + } + } + }, + "result": { + "errorContains": "Unsupported match expression operator for encryption" + } + } + ] + }, + { + "description": "$bit operators succeed on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$bitsAllClear": 35 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$bitsAllClear": 35 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$bitsAllSet": 35 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$bitsAllSet": 35 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$bitsAnyClear": 35 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$bitsAnyClear": 35 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$bitsAnySet": 35 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$bitsAnySet": 35 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + } + ] + }, + { + "description": "geo operators succeed on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$near": [ + 0, + 0 + ] + } + } + }, + "result": { + "errorContains": "unable to find index" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$near": [ + 0, + 0 + ] + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$nearSphere": [ + 0, + 0 + ] + } + } + }, + "result": { + "errorContains": "unable to find index" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$nearSphere": [ + 0, + 0 + ] + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$geoIntersects": { + "$geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 1, + 1 + ], + [ + 0, + 0 + ] + ] + ] + } + } + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$geoIntersects": { + "$geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 1, + 1 + ], + [ + 0, + 0 + ] + ] + ] + } + } + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$geoWithin": { + "$geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 1, + 1 + ], + [ + 0, + 0 + ] + ] + ] + } + } + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$geoWithin": { + "$geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 1, + 1 + ], + [ + 0, + 0 + ] + ] + ] + } + } + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + } + ] + }, + { + "description": "inequality operators succeed on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$gt": 1 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$gt": 1 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$lt": 1 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$lt": 1 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$gte": 1 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$gte": 1 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$lte": 1 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$lte": 1 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + } + ] + }, + { + "description": "other misc operators succeed on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$mod": [ + 3, + 1 + ] + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$mod": [ + 3, + 1 + ] + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$regex": "pattern", + "$options": "" + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$regex": "pattern", + "$options": "" + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$size": 2 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$size": 2 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$type": 2 + } + } + }, + "result": [] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$type": 2 + } + } + }, + "result": { + "errorContains": "Invalid match expression operator on encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$eq": null + } + } + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + }, + { + "_id": 2, + "encrypted_string": "string1" + } + ] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$eq": null + } + } + }, + "result": { + "errorContains": "Illegal equality to null predicate for encrypted field" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "unencrypted": { + "$in": [ + null + ] + } + } + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + }, + { + "_id": 2, + "encrypted_string": "string1" + } + ] + }, + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$in": [ + null + ] + } + } + }, + "result": { + "errorContains": "Illegal equality to null inside $in against an encrypted field" + } + } + ] + }, + { + "description": "$addToSet succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$addToSet": { + "unencrypted": [ + "a" + ] + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$addToSet": { + "encrypted_string": [ + "a" + ] + } + } + }, + "result": { + "errorContains": "$addToSet not allowed on encrypted values" + } + } + ] + }, + { + "description": "$inc succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$inc": { + "unencrypted": 1 + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$inc": { + "encrypted_string": 1 + } + } + }, + "result": { + "errorContains": "$inc and $mul not allowed on encrypted values" + } + } + ] + }, + { + "description": "$mul succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$mul": { + "unencrypted": 1 + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$mul": { + "encrypted_string": 1 + } + } + }, + "result": { + "errorContains": "$inc and $mul not allowed on encrypted values" + } + } + ] + }, + { + "description": "$max succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$max": { + "unencrypted": 1 + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$max": { + "encrypted_string": 1 + } + } + }, + "result": { + "errorContains": "$max and $min not allowed on encrypted values" + } + } + ] + }, + { + "description": "$min succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$min": { + "unencrypted": 1 + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$min": { + "encrypted_string": 1 + } + } + }, + "result": { + "errorContains": "$max and $min not allowed on encrypted values" + } + } + ] + }, + { + "description": "$currentDate succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$currentDate": { + "unencrypted": true + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$currentDate": { + "encrypted_string": true + } + } + }, + "result": { + "errorContains": "$currentDate not allowed on encrypted values" + } + } + ] + }, + { + "description": "$pop succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$pop": { + "unencrypted": 1 + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 0, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$pop": { + "encrypted_string": 1 + } + } + }, + "result": { + "errorContains": "$pop not allowed on encrypted values" + } + } + ] + }, + { + "description": "$pull succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$pull": { + "unencrypted": 1 + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 0, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$pull": { + "encrypted_string": 1 + } + } + }, + "result": { + "errorContains": "$pull not allowed on encrypted values" + } + } + ] + }, + { + "description": "$pullAll succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$pullAll": { + "unencrypted": [ + 1 + ] + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 0, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$pullAll": { + "encrypted_string": [ + 1 + ] + } + } + }, + "result": { + "errorContains": "$pullAll not allowed on encrypted values" + } + } + ] + }, + { + "description": "$push succeeds on unencrypted, error on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$push": { + "unencrypted": 1 + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$push": { + "encrypted_string": 1 + } + } + }, + "result": { + "errorContains": "$push not allowed on encrypted values" + } + } + ] + }, + { + "description": "array filters on encrypted fields does not error in mongocryptd, but errors in mongod", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$set": { + "encrypted_string.$[i].x": 1 + } + }, + "arrayFilters": [ + { + "i.x": 1 + } + ] + }, + "result": { + "errorContains": "Array update operations not allowed on encrypted values" + } + } + ] + }, + { + "description": "positional operator succeeds on unencrypted, errors on encrypted", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": { + "unencrypted": 1 + }, + "update": { + "$set": { + "unencrypted.$": 1 + } + } + }, + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0 + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "encrypted_string": "abc" + }, + "update": { + "$set": { + "encrypted_string.$": "abc" + } + } + }, + "result": { + "errorContains": "Cannot encrypt fields below '$' positional update operator" + } + } + ] + }, + { + "description": "an update that would produce an array on an encrypted field errors", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$set": { + "encrypted_string": [ + 1, + 2 + ] + } + } + }, + "result": { + "errorContains": "Cannot encrypt element of type array" + } + } + ] + }, + { + "description": "an insert with encrypted field on _id errors", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "schemaMap": { + "default.default": { + "properties": { + "_id": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1 + } + }, + "result": { + "errorContains": "Invalid schema containing the 'encrypt' keyword." + } + } + ] + }, + { + "description": "an insert with an array value for an encrypted field fails", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "encrypted_string": [ + "123", + "456" + ] + } + }, + "result": { + "errorContains": "Cannot encrypt element of type array" + } + } + ] + }, + { + "description": "an insert with a Timestamp(0,0) value in the top-level fails", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "random": { + "$timestamp": { + "t": 0, + "i": 0 + } + } + } + }, + "result": { + "errorContains": "A command that inserts cannot supply Timestamp(0, 0) for an encrypted" + } + } + ] + }, + { + "description": "distinct with the key referring to a field where the keyID is a JSON Pointer errors", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "distinct", + "arguments": { + "filter": {}, + "fieldName": "encrypted_w_altname" + }, + "result": { + "errorContains": "The distinct key is not allowed to be marked for encryption with a non-UUID keyId" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.yml new file mode 100644 index 00000000000..6b0a28c6111 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badQueries.yml @@ -0,0 +1,526 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +# TODO: I could see an argument against having these tests of mongocryptd as part +# of driver tests. When mongocryptd introduces support for these operators, these +# tests will fail. But it's also easy enough to remove these tests when that happens. + +tests: + - description: "$text unconditionally fails" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: + { $text: { $search: "search text" } } + result: + errorContains: "Unsupported match expression operator for encryption" + - description: "$where unconditionally fails" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: + { $where: { $code: "function() { return true }" } } + result: + errorContains: "Unsupported match expression operator for encryption" + - description: "$bit operators succeed on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: { unencrypted: { $bitsAllClear: 35 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $bitsAllClear: 35 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $bitsAllSet: 35 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $bitsAllSet: 35 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $bitsAnyClear: 35 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $bitsAnyClear: 35 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $bitsAnySet: 35 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $bitsAnySet: 35 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - description: "geo operators succeed on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: { unencrypted: { $near: [0,0] }} + result: + # Still an error because no geo index, but from mongod - not mongocryptd. + errorContains: "unable to find index" + - name: find + arguments: + filter: { encrypted_string: { $near: [0,0] }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $nearSphere: [0,0] }} + result: + # Still an error because no geo index, but from mongod - not mongocryptd. + errorContains: "unable to find index" + - name: find + arguments: + filter: { encrypted_string: { $nearSphere: [0,0] }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $geoIntersects: { $geometry: { type: "Polygon", coordinates: [[ [0,0], [1,0], [1,1], [0,0] ]] }} }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $geoIntersects: { $geometry: { type: "Polygon", coordinates: [[ [0,0], [1,0], [1,1], [0,0] ]] }} }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $geoWithin: { $geometry: { type: "Polygon", coordinates: [[ [0,0], [1,0], [1,1], [0,0] ]] }} }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $geoWithin: { $geometry: { type: "Polygon", coordinates: [[ [0,0], [1,0], [1,1], [0,0] ]] }} }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - description: "inequality operators succeed on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: { unencrypted: { $gt: 1 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $gt: 1 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $lt: 1 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $lt: 1 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $gte: 1 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $gte: 1 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $lte: 1 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $lte: 1 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - description: "other misc operators succeed on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: { unencrypted: { $mod: [3, 1] }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $mod: [3, 1] }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $regex: "pattern", $options: "" }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $regex: "pattern", $options: "" }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $size: 2 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $size: 2 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $type: 2 }} + result: [] + - name: find + arguments: + filter: { encrypted_string: { $type: 2 }} + result: + errorContains: "Invalid match expression operator on encrypted field" + - name: find + arguments: + filter: { unencrypted: { $eq: null }} + result: + - &doc0 { _id: 1, encrypted_string: "string0" } + - &doc1 { _id: 2, encrypted_string: "string1" } + - name: find + arguments: + filter: { encrypted_string: { $eq: null }} + result: + errorContains: "Illegal equality to null predicate for encrypted field" + - name: find + arguments: + filter: { unencrypted: { $in: [null] }} + result: + - *doc0 + - *doc1 + - name: find + arguments: + filter: { encrypted_string: { $in: [null] }} + result: + errorContains: "Illegal equality to null inside $in against an encrypted field" + - description: "$addToSet succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $addToSet: { "unencrypted": ["a"]}} + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $addToSet: { "encrypted_string": ["a"]}} + result: + errorContains: "$addToSet not allowed on encrypted values" + - description: "$inc succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $inc: { "unencrypted": 1}} + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $inc: { "encrypted_string": 1}} + result: + errorContains: "$inc and $mul not allowed on encrypted values" + - description: "$mul succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $mul: { "unencrypted": 1}} + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $mul: { "encrypted_string": 1}} + result: + errorContains: "$inc and $mul not allowed on encrypted values" + - description: "$max succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $max: { "unencrypted": 1}} + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $max: { "encrypted_string": 1}} + result: + errorContains: "$max and $min not allowed on encrypted values" + - description: "$min succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $min: { "unencrypted": 1}} + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $min: { "encrypted_string": 1}} + result: + errorContains: "$max and $min not allowed on encrypted values" + - description: "$currentDate succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $currentDate: { "unencrypted": true}} + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $currentDate: { "encrypted_string": true }} + result: + errorContains: "$currentDate not allowed on encrypted values" + - description: "$pop succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $pop: { "unencrypted": 1}} + result: + matchedCount: 1 + modifiedCount: 0 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $pop: { "encrypted_string": 1 }} + result: + errorContains: "$pop not allowed on encrypted values" + - description: "$pull succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $pull: { "unencrypted": 1}} + result: + matchedCount: 1 + modifiedCount: 0 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $pull: { "encrypted_string": 1 }} + result: + errorContains: "$pull not allowed on encrypted values" + - description: "$pullAll succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $pullAll: { "unencrypted": [1] }} + result: + matchedCount: 1 + modifiedCount: 0 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $pullAll: { "encrypted_string": [1] }} + result: + errorContains: "$pullAll not allowed on encrypted values" + - description: "$push succeeds on unencrypted, error on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $push: { "unencrypted": 1}} + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { } + update: { $push: { "encrypted_string": 1 }} + result: + errorContains: "$push not allowed on encrypted values" + - description: "array filters on encrypted fields does not error in mongocryptd, but errors in mongod" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $set : { "encrypted_string.$[i].x": 1 }} + arrayFilters: [{ i.x: 1 }] + result: + errorContains: "Array update operations not allowed on encrypted values" + - description: "positional operator succeeds on unencrypted, errors on encrypted" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { "unencrypted": 1 } + update: { $set : { "unencrypted.$": 1 }} + result: + matchedCount: 0 + modifiedCount: 0 + upsertedCount: 0 + - name: updateOne + arguments: + filter: { "encrypted_string": "abc" } + update: { $set : { "encrypted_string.$": "abc" }} + result: + errorContains: "Cannot encrypt fields below '$' positional update operator" + - description: "an update that would produce an array on an encrypted field errors" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $set : { "encrypted_string": [1,2] }} + result: + errorContains: "Cannot encrypt element of type array" + - description: "an insert with encrypted field on _id errors" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + schemaMap: + "default.default": {'properties': {'_id': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}} + operations: + - name: insertOne + arguments: + document: { _id: 1 } + result: + errorContains: "Invalid schema containing the 'encrypt' keyword." + - description: "an insert with an array value for an encrypted field fails" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: { encrypted_string: [ "123", "456"] } + result: + errorContains: "Cannot encrypt element of type array" + - description: "an insert with a Timestamp(0,0) value in the top-level fails" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: { random: {"$timestamp": {"t": 0, "i": 0 }} } + result: + errorContains: "A command that inserts cannot supply Timestamp(0, 0) for an encrypted" + - description: "distinct with the key referring to a field where the keyID is a JSON Pointer errors" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: distinct + arguments: + filter: {} + fieldName: "encrypted_w_altname" + result: + errorContains: "The distinct key is not allowed to be marked for encryption with a non-UUID keyId" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.json new file mode 100644 index 00000000000..1fd0f8ed3f9 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.json @@ -0,0 +1,254 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Schema with an encrypted field in an array", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + } + }, + "bsonType": "array" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + }, + "result": { + "errorContains": "Invalid schema" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + }, + { + "description": "Schema without specifying parent object types", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "foo": { + "properties": { + "bar": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + } + } + } + } + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + }, + "result": { + "errorContains": "Invalid schema" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + }, + { + "description": "Schema with siblings of encrypt document", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + }, + "bsonType": "object" + } + } + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + }, + "result": { + "errorContains": "'encrypt' cannot be used in conjunction with 'bsonType'" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + }, + { + "description": "Schema with logical keywords", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "anyOf": [ + { + "properties": { + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + } + } + } + ] + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + }, + "result": { + "errorContains": "Invalid schema" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.yml new file mode 100644 index 00000000000..035774de594 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/badSchema.yml @@ -0,0 +1,73 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Schema with an encrypted field in an array" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}}, 'bsonType': 'array'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string: "string0" } + result: + errorContains: "Invalid schema" + outcome: + collection: + data: [] + - description: "Schema without specifying parent object types" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'foo': {'properties': {'bar': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}}}}} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: *doc0 + result: + errorContains: "Invalid schema" + outcome: + collection: + data: [] + - description: "Schema with siblings of encrypt document" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}, 'bsonType': 'object'}}} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: *doc0 + result: + errorContains: "'encrypt' cannot be used in conjunction with 'bsonType'" + outcome: + collection: + data: [] + - description: "Schema with logical keywords" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'anyOf': [{'properties': {'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}}}]} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: *doc0 + result: + errorContains: "Invalid schema" + outcome: + collection: + data: [] \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.json new file mode 100644 index 00000000000..99408ae066d --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.json @@ -0,0 +1,372 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Insert with deterministic encryption, then find it", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "Insert with randomized encryption, then find it", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "random": "123" + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "random": "123" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "random": { + "$$type": "binData" + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "random": { + "$$type": "binData" + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.yml new file mode 100644 index 00000000000..83fa3c1dc9e --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/basic.yml @@ -0,0 +1,118 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Insert with deterministic encryption, then find it" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string: "string0" } + - name: find + arguments: + filter: { _id: 1 } + result: [*doc0] + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: { _id: 1 } + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - description: "Insert with randomized encryption, then find it" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc1 { _id: 1, random: "123" } + - name: find + arguments: + filter: { _id: 1 } + result: [*doc1] + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - { _id: 1, random: { $$type: "binData" } } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: { _id: 1 } + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, random: { $$type: "binData" } } \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.json new file mode 100644 index 00000000000..5e71b593bb6 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.json @@ -0,0 +1,338 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Bulk write with encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0", + "random": "abc" + } + } + }, + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 2, + "encrypted_string": "string1" + } + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "encrypted_string": "string0" + }, + "update": { + "$set": { + "encrypted_string": "string1" + } + } + } + }, + { + "name": "deleteOne", + "arguments": { + "filter": { + "encrypted_string": "string1", + "_id": 2 + } + } + } + ], + "options": { + "ordered": true + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + }, + "u": { + "$set": { + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + } + } + ], + "ordered": true + }, + "command_name": "update" + } + }, + { + "command_started_event": { + "command": { + "delete": "default", + "deletes": [ + { + "q": { + "$and": [ + { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + }, + { + "_id": { + "$eq": 2 + } + } + ] + }, + "limit": 1 + } + ], + "ordered": true + }, + "command_name": "delete" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.yml new file mode 100644 index 00000000000..b8dc060af01 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bulk.yml @@ -0,0 +1,86 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Bulk write with encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: bulkWrite + arguments: + requests: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string: "string0", random: "abc" } + - name: insertOne + arguments: + document: &doc1 { _id: 2, encrypted_string: "string1" } + - name: updateOne + arguments: + filter: { encrypted_string: "string0" } + update: { $set: { encrypted_string: "string1" } } + - name: deleteOne + arguments: + filter: { encrypted_string: "string1", _id: 2 } + options: { ordered: true } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}}, random: { $$type: "binData" } } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + update: *collection_name + updates: + - q: { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} }} + u: {$set: { encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} }} + ordered: true + command_name: update + - command_started_event: + command: + delete: *collection_name + deletes: + - q: { "$and": [ { "encrypted_string": { "$eq": {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} }}, { "_id": { "$eq": 2 }} ] } + limit: 1 + ordered: true + command_name: delete + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}}, random: { $$type: "binData" } } \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.json new file mode 100644 index 00000000000..97a61651a43 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.json @@ -0,0 +1,396 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Insert with bypassAutoEncryption", + "clientOptions": { + "autoEncryptOpts": { + "bypassAutoEncryption": true, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 2, + "encrypted_string": "string0" + }, + "bypassDocumentValidation": true + } + }, + { + "name": "find", + "arguments": { + "filter": {} + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + }, + { + "_id": 2, + "encrypted_string": "string0" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 2, + "encrypted_string": "string0" + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": {} + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": "string0" + } + ] + } + } + }, + { + "description": "Insert with bypassAutoEncryption for local schema", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "bypassAutoEncryption": true, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 2, + "encrypted_string": "string0" + }, + "bypassDocumentValidation": true + } + }, + { + "name": "find", + "arguments": { + "filter": {} + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + }, + { + "_id": 2, + "encrypted_string": "string0" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 2, + "encrypted_string": "string0" + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": {} + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": "string0" + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.yml new file mode 100644 index 00000000000..f4f08227184 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassAutoEncryption.yml @@ -0,0 +1,98 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [{_id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} }] +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Insert with bypassAutoEncryption" + clientOptions: + autoEncryptOpts: + bypassAutoEncryption: true + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: { _id: 2, encrypted_string: "string0" } + bypassDocumentValidation: true + - name: find + arguments: + filter: { } + result: + - { _id: 1, encrypted_string: "string0" } + - { _id: 2, encrypted_string: "string0" } + expectations: + - command_started_event: + command: + insert: *collection_name + documents: + # No encryption. + - { _id: 2, encrypted_string: "string0" } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: { } + command_name: find + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - { _id: 2, encrypted_string: "string0" } + - description: "Insert with bypassAutoEncryption for local schema" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + bypassAutoEncryption: true + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: { _id: 2, encrypted_string: "string0" } + bypassDocumentValidation: true + - name: find + arguments: + filter: { } + result: + - { _id: 1, encrypted_string: "string0" } + - { _id: 2, encrypted_string: "string0" } + expectations: + - command_started_event: + command: + insert: *collection_name + documents: + # No encryption. + - { _id: 2, encrypted_string: "string0" } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: { } + command_name: find + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - { _id: 2, encrypted_string: "string0" } \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.json new file mode 100644 index 00000000000..bd0b1c565d7 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.json @@ -0,0 +1,106 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": {}, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "ping is bypassed", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "runCommand", + "object": "database", + "command_name": "ping", + "arguments": { + "command": { + "ping": 1 + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "ping": 1 + }, + "command_name": "ping" + } + } + ] + }, + { + "description": "current op is not bypassed", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "runCommand", + "object": "database", + "command_name": "currentOp", + "arguments": { + "command": { + "currentOp": 1 + } + }, + "result": { + "errorContains": "command not supported for auto encryption: currentOp" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.yml new file mode 100644 index 00000000000..7057abd5925 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/bypassedCommand.yml @@ -0,0 +1,42 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "ping is bypassed" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: runCommand + object: database + command_name: ping + arguments: + command: + ping: 1 + expectations: + # No listCollections, no mongocryptd command, just the ping. + - command_started_event: + command: + ping: 1 + command_name: ping + - description: "current op is not bypassed" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: runCommand + object: database + command_name: currentOp + arguments: + command: + currentOp: 1 + result: + errorContains: "command not supported for auto encryption: currentOp" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.json new file mode 100644 index 00000000000..38ece606d7d --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.json @@ -0,0 +1,240 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Count with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "count", + "arguments": { + "filter": { + "encrypted_string": "string0" + } + }, + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "count": "default", + "query": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + } + }, + "command_name": "count" + } + } + ] + }, + { + "description": "Count fails when filtering on a random encrypted field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "count", + "arguments": { + "filter": { + "random": "abc" + } + }, + "result": { + "errorContains": "Cannot query on fields encrypted with the randomized encryption" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.yml new file mode 100644 index 00000000000..28caaf9d1d7 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/count.yml @@ -0,0 +1,62 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Count with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: count + arguments: + filter: { encrypted_string: "string0" } + result: 2 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + count: *collection_name + query: { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + command_name: count + - description: "Count fails when filtering on a random encrypted field" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment + operations: + - name: count + arguments: + filter: { random: "abc" } + result: + errorContains: "Cannot query on fields encrypted with the randomized encryption" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.json new file mode 100644 index 00000000000..01e62cd18da --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.json @@ -0,0 +1,257 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "countDocuments with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "countDocuments", + "arguments": { + "filter": { + "encrypted_string": "string0" + } + }, + "result": 1 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "default", + "pipeline": [ + { + "$match": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + } + }, + { + "$group": { + "_id": { + "$const": 1 + }, + "n": { + "$sum": { + "$const": 1 + } + } + } + } + ] + }, + "command_name": "aggregate" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.yml new file mode 100644 index 00000000000..6f16fde4675 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/countDocuments.yml @@ -0,0 +1,60 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "countDocuments with deterministic encryption" + skipReason: "waiting on SERVER-39395" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: countDocuments + arguments: + filter: { encrypted_string: "string0" } + result: 1 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + aggregate: *collection_name + pipeline: + - { $match: { encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} }} + - { $group: { _id: 1, n: { $sum: 1 }}} + command_name: aggregate + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - *doc1_encrypted \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.json new file mode 100644 index 00000000000..aadd1e3019e --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.json @@ -0,0 +1,362 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "deleteOne with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "deleteOne", + "arguments": { + "filter": { + "encrypted_string": "string0" + } + }, + "result": { + "deletedCount": 1 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "delete": "default", + "deletes": [ + { + "q": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + }, + "limit": 1 + } + ], + "ordered": true + }, + "command_name": "delete" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "deleteMany with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "deleteMany", + "arguments": { + "filter": { + "encrypted_string": { + "$in": [ + "string0", + "string1" + ] + } + } + }, + "result": { + "deletedCount": 2 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "delete": "default", + "deletes": [ + { + "q": { + "encrypted_string": { + "$in": [ + { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + ] + } + }, + "limit": 0 + } + ], + "ordered": true + }, + "command_name": "delete" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.yml new file mode 100644 index 00000000000..40441b722df --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/delete.yml @@ -0,0 +1,107 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "deleteOne with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: deleteOne + arguments: + filter: { encrypted_string: "string0" } + result: + deletedCount: 1 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + delete: *collection_name + deletes: + - q: { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + limit: 1 + ordered: true + command_name: delete + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc1_encrypted + - description: "deleteMany with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: deleteMany + arguments: + filter: { encrypted_string: { $in: [ "string0", "string1" ] } } + result: + deletedCount: 2 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + delete: *collection_name + deletes: + - q: { encrypted_string: { $in : [ {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}}, {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} ] } } + limit: 0 + ordered: true + command_name: delete + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: [] \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.json new file mode 100644 index 00000000000..4a24aa77977 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.json @@ -0,0 +1,287 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 3, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "distinct with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "distinct", + "arguments": { + "filter": { + "encrypted_string": "string0" + }, + "fieldName": "encrypted_string" + }, + "result": [ + "string0" + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "distinct": "default", + "key": "encrypted_string", + "query": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + } + }, + "command_name": "distinct" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 3, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "Distinct fails when filtering on a random encrypted field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "distinct", + "arguments": { + "filter": { + "random": "abc" + }, + "fieldName": "encrypted_string" + }, + "result": { + "errorContains": "Cannot query on fields encrypted with the randomized encryption" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.yml new file mode 100644 index 00000000000..4e76280157e --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/distinct.yml @@ -0,0 +1,74 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc2_encrypted { _id: 3, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "distinct with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: distinct + arguments: + filter: { encrypted_string: "string0" } + fieldName: "encrypted_string" + result: + - "string0" + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + distinct: *collection_name + key: encrypted_string + query: { encrypted_string: {$eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + command_name: distinct + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - *doc1_encrypted + - *doc2_encrypted + - description: "Distinct fails when filtering on a random encrypted field" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment + operations: + - name: distinct + arguments: + filter: { random: "abc" } + fieldName: "encrypted_string" + result: + errorContains: "Cannot query on fields encrypted with the randomized encryption" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.json new file mode 100644 index 00000000000..1253b7f581f --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.json @@ -0,0 +1,250 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Explain a find with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "runCommand", + "object": "database", + "command_name": "explain", + "arguments": { + "command": { + "explain": { + "find": "default", + "filter": { + "encrypted_string": "string1" + } + } + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "explain": { + "find": "default", + "filter": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + } + }, + "verbosity": "allPlansExecution" + }, + "command_name": "explain" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.yml new file mode 100644 index 00000000000..18832ca9435 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/explain.yml @@ -0,0 +1,65 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Explain a find with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: runCommand + object: database + command_name: explain + arguments: + command: + explain: + find: *collection_name + filter: { encrypted_string : "string1" } + + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + explain: + find: *collection_name + filter: + { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } } + verbosity: "allPlansExecution" + command_name: explain + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - *doc1_encrypted \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.json new file mode 100644 index 00000000000..e754fa17093 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.json @@ -0,0 +1,430 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$binary": { + "base64": "AgAAAAAAAAAAAAAAAAAAAAACyfp+lXvKOi7f5vh6ZsCijLEaXFKq1X06RmyS98ZvmMQGixTw8HM1f/bGxZjGwvYwjXOkIEb7Exgb8p2KCDI5TQ==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Find with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": "string0" + } + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$binary": { + "base64": "AgAAAAAAAAAAAAAAAAAAAAACyfp+lXvKOi7f5vh6ZsCijLEaXFKq1X06RmyS98ZvmMQGixTw8HM1f/bGxZjGwvYwjXOkIEb7Exgb8p2KCDI5TQ==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "Find with $in with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "encrypted_string": { + "$in": [ + "string0", + "string1" + ] + } + } + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + }, + { + "_id": 2, + "encrypted_string": "string1", + "random": "abc" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "encrypted_string": { + "$in": [ + { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + ] + } + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$binary": { + "base64": "AgAAAAAAAAAAAAAAAAAAAAACyfp+lXvKOi7f5vh6ZsCijLEaXFKq1X06RmyS98ZvmMQGixTw8HM1f/bGxZjGwvYwjXOkIEb7Exgb8p2KCDI5TQ==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "Find fails when filtering on a random encrypted field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "random": "abc" + } + }, + "result": { + "errorContains": "Cannot query on fields encrypted with the randomized encryption" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.yml new file mode 100644 index 00000000000..82e610d1f5f --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/find.yml @@ -0,0 +1,121 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} , random: {'$binary': {'base64': 'AgAAAAAAAAAAAAAAAAAAAAACyfp+lXvKOi7f5vh6ZsCijLEaXFKq1X06RmyS98ZvmMQGixTw8HM1f/bGxZjGwvYwjXOkIEb7Exgb8p2KCDI5TQ==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Find with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: + { encrypted_string: "string0" } + result: + - &doc0 { _id: 1, encrypted_string: "string0" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + find: *collection_name + filter: + { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - *doc1_encrypted + - description: "Find with $in with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: + { encrypted_string: { $in: [ "string0", "string1" ] } } + result: + - { _id: 1, encrypted_string: "string0" } + - &doc1 { _id: 2, encrypted_string: "string1", random: "abc" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + find: *collection_name + filter: + # Note, the values are re-ordered, but this is logically equivalent. + { encrypted_string: { $in: [ {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}}, {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} ] } } + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - *doc1_encrypted + - description: "Find fails when filtering on a random encrypted field" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment + operations: + - name: find + arguments: + filter: { random: "abc" } + result: + errorContains: "Cannot query on fields encrypted with the randomized encryption" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.json new file mode 100644 index 00000000000..5459b8c21e7 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.json @@ -0,0 +1,232 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "findOneAndDelete with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "encrypted_string": "string0" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "findAndModify": "default", + "query": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + }, + "remove": true + }, + "command_name": "findAndModify" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.yml new file mode 100644 index 00000000000..f796bfd0e1e --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndDelete.yml @@ -0,0 +1,58 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "findOneAndDelete with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: findOneAndDelete + arguments: + filter: + { encrypted_string: "string0" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + findAndModify: *collection_name + query: + { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + remove: true + command_name: findAndModify + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc1_encrypted \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.json new file mode 100644 index 00000000000..fbc1632e4c2 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.json @@ -0,0 +1,238 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "findOneAndReplace with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "encrypted_string": "string0" + }, + "replacement": { + "encrypted_string": "string1" + }, + "returnDocument": "Before" + }, + "result": { + "_id": 1, + "encrypted_string": "string0" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "findAndModify": "default", + "query": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + }, + "update": { + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + }, + "command_name": "findAndModify" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.yml new file mode 100644 index 00000000000..f6deaf2835b --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndReplace.yml @@ -0,0 +1,58 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "findOneAndReplace with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: findOneAndReplace + arguments: + filter: { encrypted_string: "string0" } + replacement: { encrypted_string: "string1" } + returnDocument: Before + result: { _id: 1, encrypted_string: "string0" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + findAndModify: *collection_name + query: { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + update: { encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } + command_name: findAndModify + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.json new file mode 100644 index 00000000000..d342472be01 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.json @@ -0,0 +1,242 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "findOneAndUpdate with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "encrypted_string": "string0" + }, + "update": { + "$set": { + "encrypted_string": "string1" + } + }, + "returnDocument": "Before" + }, + "result": { + "_id": 1, + "encrypted_string": "string0" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "findAndModify": "default", + "query": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + }, + "update": { + "$set": { + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + } + }, + "command_name": "findAndModify" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.yml new file mode 100644 index 00000000000..4ec0c71f342 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/findOneAndUpdate.yml @@ -0,0 +1,58 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "findOneAndUpdate with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: findOneAndUpdate + arguments: + filter: { encrypted_string: "string0" } + update: { $set: { encrypted_string: "string1" } } + returnDocument: Before + result: { _id: 1, encrypted_string: "string0" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + findAndModify: *collection_name + query: { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + update: { $set: { encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } } + command_name: findAndModify + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.json new file mode 100644 index 00000000000..353aa6d1bec --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.json @@ -0,0 +1,274 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + }, + { + "_id": 3, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "getMore with encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "batchSize": 2, + "filter": {} + }, + "results": [ + { + "_id": 1, + "encrypted_string": "string0" + }, + { + "_id": 2, + "encrypted_string": "string1" + }, + { + "_id": 3, + "encrypted_string": "string2" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "batchSize": 2 + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "default", + "batchSize": 2 + }, + "command_name": "getMore" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + }, + { + "_id": 3, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.yml new file mode 100644 index 00000000000..b68e03551e2 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/getMore.yml @@ -0,0 +1,69 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } + - &doc2_encrypted { _id: 3, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "getMore with encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + batchSize: 2 + filter: {} + results: + - { _id: 1, encrypted_string: "string0" } + - { _id: 2, encrypted_string: "string1" } + - { _id: 3, encrypted_string: "string2" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + find: *collection_name + batchSize: 2 + command_name: find + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + getMore: { $$type: "long" } + collection: *collection_name + batchSize: 2 + command_name: getMore + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - *doc1_encrypted + - *doc2_encrypted \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.json new file mode 100644 index 00000000000..12471eb691f --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.json @@ -0,0 +1,366 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "insertOne with encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0", + "random": "abc" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ] + } + } + }, + { + "description": "insertMany with encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 1, + "encrypted_string": "string0", + "random": "abc" + }, + { + "_id": 2, + "encrypted_string": "string1" + } + ] + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.yml new file mode 100644 index 00000000000..9bd1762d34f --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/insert.yml @@ -0,0 +1,104 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "insertOne with encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string: "string0", random: "abc" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}}, random: { $$type: "binData" } } + ordered: true + command_name: insert + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - description: "insertMany with encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertMany + arguments: + documents: + - *doc0 + - &doc1 { _id: 2, encrypted_string: "string1" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - *doc0_encrypted + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } + ordered: true + command_name: insert + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - *doc1_encrypted \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.json new file mode 100644 index 00000000000..ae753baac6a --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.json @@ -0,0 +1,239 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Insert with encryption using key alt name", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_w_altname": "string0", + "altname": "altname" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [] + } + }, + { + "keyAltNames": { + "$in": [ + "altname" + ] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_w_altname": { + "$$type": "binData" + }, + "altname": "altname" + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_w_altname": { + "$$type": "binData" + }, + "altname": "altname" + } + ] + } + } + }, + { + "description": "Replace with key alt name fails", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$set": { + "encrypted_w_altname": "string0" + } + }, + "upsert": true + }, + "result": { + "errorContains": "A non-static (JSONPointer) keyId is not supported" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.yml new file mode 100644 index 00000000000..ba49a5fac36 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/keyAltName.yml @@ -0,0 +1,72 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Insert with encryption using key alt name" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_w_altname: "string0", altname: "altname" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {$or: [ { _id: { $in: [] } }, { keyAltNames: { $in: [ "altname" ] } } ] } + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_w_altname: { $$type: "binData" }, altname: "altname" } + ordered: true + command_name: insert + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - description: "Replace with key alt name fails" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: {} + update: { $set: { encrypted_w_altname: "string0" } } + upsert: true + result: + errorContains: "A non-static (JSONPointer) keyId is not supported" + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: [] \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.json new file mode 100644 index 00000000000..1506076b0c8 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.json @@ -0,0 +1,205 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "Insert a document with auto encryption using local KMS provider", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {}, + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0", + "random": "abc" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACV/+zJmpqMU47yxS/xIVAviGi7wHDuFwaULAixEAoIh0xHz73UYOM3D8D44gcJn67EROjbz4ITpYzzlCJovDL0Q==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACV/+zJmpqMU47yxS/xIVAviGi7wHDuFwaULAixEAoIh0xHz73UYOM3D8D44gcJn67EROjbz4ITpYzzlCJovDL0Q==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.yml new file mode 100644 index 00000000000..2ca4ef22e0c --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localKMS.yml @@ -0,0 +1,56 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {'properties': {'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}}, 'bsonType': 'object'} +key_vault_data: [{'_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'keyMaterial': {'$binary': {'base64': 'Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'status': {'$numberInt': '0'}, 'masterKey': {'provider': 'local'}}] + +tests: + - description: "Insert a document with auto encryption using local KMS provider" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + local: {'key': {'$binary': {'base64': 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk', 'subType': '00'}}} + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string: "string0", random: "abc" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: { $or: [ { _id: { $in: [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] } }, { keyAltNames: { $in: [] } } ] } + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACV/+zJmpqMU47yxS/xIVAviGi7wHDuFwaULAixEAoIh0xHz73UYOM3D8D44gcJn67EROjbz4ITpYzzlCJovDL0Q==', 'subType': '06'}}, random: { $$type: "binData" } } + ordered: true + command_name: insert + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.json new file mode 100644 index 00000000000..9de47f066ce --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.json @@ -0,0 +1,268 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": {}, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "A local schema should override", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "encrypted_string": "string0" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "A local schema with no encryption is an error", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "test": { + "bsonType": "string" + } + }, + "bsonType": "object", + "required": [ + "test" + ] + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + }, + "result": { + "errorContains": "JSON schema keyword 'required' is only allowed with a remote schema" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.yml new file mode 100644 index 00000000000..c4ce8e3679b --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/localSchema.yml @@ -0,0 +1,72 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +# configure an empty schema +json_schema: {} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "A local schema should override" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string: "string0" } + - name: find + arguments: + filter: { _id: 1 } + result: [*doc0] + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: { _id: 1 } + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - description: "A local schema with no encryption is an error" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'test': {'bsonType': 'string'}}, 'bsonType': 'object', 'required': ['test']} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: { _id: 1, encrypted_string: "string0" } + result: + errorContains: "JSON schema keyword 'required' is only allowed with a remote schema" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.json new file mode 100644 index 00000000000..c81330ce833 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.json @@ -0,0 +1,321 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "00" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQ==", + "subType": "06" + } + } + }, + { + "_id": 3, + "encrypted_string": { + "$binary": { + "base64": "AQAAa2V2aW4gYWxiZXJ0c29uCg==", + "subType": "06" + } + } + } + ], + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Wrong subtype", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "Empty data", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "_id": 2 + } + }, + "result": { + "errorContains": "malformed ciphertext" + } + } + ] + }, + { + "description": "Malformed data", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "_id": 3 + } + }, + "result": { + "errorContains": "not all keys requested were satisfied" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.yml new file mode 100644 index 00000000000..e27c1dfdc22 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/malformedCiphertext.yml @@ -0,0 +1,69 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0 + _id: 1 + encrypted_string: + $binary: + base64: AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg== + subType: "00" + - _id: 2 + encrypted_string: + $binary: + base64: "AQ==" + subType: "06" + - _id: 3 + encrypted_string: + $binary: + base64: "AQAAa2V2aW4gYWxiZXJ0c29uCg==" + subType: "06" + +# Since test requires invalid data to be inserted, use a local schema. +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Wrong subtype" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: { _id: 1 } + result: + # gets returned without decryption + - *doc0 + - description: "Empty data" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: { _id: 2 } + result: + errorContains: "malformed ciphertext" + - description: "Malformed data" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: find + arguments: + filter: { _id: 3 } + result: + # ciphertext can only validate subtype (which is correct) + # but takes the 16 byte UUID to look up key. Fails to find. + errorContains: "not all keys requested were satisfied" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.json new file mode 100644 index 00000000000..144786290dc --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.json @@ -0,0 +1,71 @@ +{ + "runOn": [ + { + "maxServerVersion": "4.0" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "operation fails with maxWireVersion < 8", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "encrypted_string": "string0" + } + }, + "result": { + "errorContains": "Auto-encryption requires a minimum MongoDB version of 4.2" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.yml new file mode 100644 index 00000000000..bbd181b5614 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/maxWireVersion.yml @@ -0,0 +1,20 @@ +runOn: + - maxServerVersion: "4.0" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "operation fails with maxWireVersion < 8" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: { encrypted_string: "string0" } + result: + errorContains: "Auto-encryption requires a minimum MongoDB version of 4.2" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.json new file mode 100644 index 00000000000..4a4b1fd4d7f --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.json @@ -0,0 +1,190 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Insert with encryption on a missing key", + "clientOptions": { + "autoEncryptOpts": { + "keyVaultNamespace": "admin.different", + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0", + "random": "abc" + } + }, + "result": { + "errorContains": "not all keys requested were satisfied" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + }, + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "different" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "different", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.yml new file mode 100644 index 00000000000..bf2c163e255 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/missingKey.yml @@ -0,0 +1,50 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "Insert with encryption on a missing key" + clientOptions: + autoEncryptOpts: + keyVaultNamespace: "admin.different" + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string: "string0", random: "abc" } + result: + errorContains: "not all keys requested were satisfied" + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: [] + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "different" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: different + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.json new file mode 100644 index 00000000000..b8c2ffc1906 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.json @@ -0,0 +1,250 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "replaceOne with encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "replaceOne", + "arguments": { + "filter": { + "encrypted_string": "string0" + }, + "replacement": { + "encrypted_string": "string1", + "random": "abc" + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + }, + "u": { + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + } + ], + "ordered": true + }, + "command_name": "update" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ] + } + } + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.yml new file mode 100644 index 00000000000..a9142cdbf86 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/replaceOne.yml @@ -0,0 +1,62 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "replaceOne with encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: replaceOne + arguments: + filter: { encrypted_string: "string0" } + replacement: { encrypted_string: "string1", random: "abc" } + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + update: *collection_name + updates: + - q: { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + u: { encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}}, random: { $$type: "binData" } } + ordered: true + command_name: update + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}}, random: { $$type: "binData" } } \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.json new file mode 100644 index 00000000000..26ec8ea82f7 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.json @@ -0,0 +1,1726 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": {}, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "type=objectId", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_objectId": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "objectId", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_objectId": { + "$oid": "AAAAAAAAAAAAAAAAAAAAAAAA" + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_objectId": { + "$oid": "AAAAAAAAAAAAAAAAAAAAAAAA" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_objectId": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAHmkTPqvzfHMWpvS1mEsrjOxVQ2dyihEgIFWD5E0eNEsiMBQsC0GuvjdqYRL5DHLFI1vKuGek7EYYp0Qyii/tHqA==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_objectId": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAHmkTPqvzfHMWpvS1mEsrjOxVQ2dyihEgIFWD5E0eNEsiMBQsC0GuvjdqYRL5DHLFI1vKuGek7EYYp0Qyii/tHqA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=symbol", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_symbol": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "symbol", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_symbol": { + "$symbol": "test" + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_symbol": { + "$symbol": "test" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_symbol": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAOOmvDmWjcuKsSCO7U/7t9HJ8eI73B6wduyMbdkvn7n7V4uTJes/j+BTtneSdyG2JHKHGkevWAJSIU2XoO66BSXw==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_symbol": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAOOmvDmWjcuKsSCO7U/7t9HJ8eI73B6wduyMbdkvn7n7V4uTJes/j+BTtneSdyG2JHKHGkevWAJSIU2XoO66BSXw==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=int", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_int": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "int", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_int": { + "$numberInt": "123" + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_int": { + "$numberInt": "123" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_int": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAQPNXJVXMEjGZnftMuf2INKufXCtQIRHdw5wTgn6QYt3ejcoAXyiwI4XIUizkpsob494qpt2in4tWeiO7b9zkA8Q==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_int": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAQPNXJVXMEjGZnftMuf2INKufXCtQIRHdw5wTgn6QYt3ejcoAXyiwI4XIUizkpsob494qpt2in4tWeiO7b9zkA8Q==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=double", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_double": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "double", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_double": { + "$numberDouble": "1.23" + } + } + }, + "result": { + "errorContains": "Cannot use deterministic encryption for element of type: double" + } + } + ] + }, + { + "description": "type=decimal", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_decimal": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "decimal", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_decimal": { + "$numberDecimal": "1.23" + } + } + }, + "result": { + "errorContains": "Cannot use deterministic encryption for element of type: decimal" + } + } + ] + }, + { + "description": "type=binData", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_binData": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "binData", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_binData": { + "$binary": { + "base64": "AAAA", + "subType": "00" + } + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_binData": { + "$binary": { + "base64": "AAAA", + "subType": "00" + } + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_binData": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAFB/KHZQHaHHo8fctcl7v6kR+sLkJoTRx2cPSSck9ya+nbGROSeFhdhDRHaCzhV78fDEqnMDSVPNi+ZkbaIh46GQ==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_binData": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAFB/KHZQHaHHo8fctcl7v6kR+sLkJoTRx2cPSSck9ya+nbGROSeFhdhDRHaCzhV78fDEqnMDSVPNi+ZkbaIh46GQ==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=javascript", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_javascript": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "javascript", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_javascript": { + "$code": "var x = 1;" + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_javascript": { + "$code": "var x = 1;" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_javascript": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAANrvMgJkTKWGMc9wt3E2RBR2Hu5gL9p+vIIdHe9FcOm99t1W480/oX1Gnd87ON3B399DuFaxi/aaIiQSo7gTX6Lw==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_javascript": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAANrvMgJkTKWGMc9wt3E2RBR2Hu5gL9p+vIIdHe9FcOm99t1W480/oX1Gnd87ON3B399DuFaxi/aaIiQSo7gTX6Lw==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=javascriptWithScope", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_javascriptWithScope": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "javascriptWithScope", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_javascriptWithScope": { + "$code": "var x = 1;", + "$scope": {} + } + } + }, + "result": { + "errorContains": "Cannot use deterministic encryption for element of type: javascriptWithScope" + } + } + ] + }, + { + "description": "type=object", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_object": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "object", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_object": {} + } + }, + "result": { + "errorContains": "Cannot use deterministic encryption for element of type: object" + } + } + ] + }, + { + "description": "type=timestamp", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_timestamp": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "timestamp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_timestamp": { + "$timestamp": { + "t": 123, + "i": 456 + } + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_timestamp": { + "$timestamp": { + "t": 123, + "i": 456 + } + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_timestamp": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAARJHaM4Gq3MpDTdBasBsEolQaOmxJQU1wsZVaSFAOLpEh1QihDglXI95xemePFMKhg+KNpFg7lw1ChCs2Wn/c26Q==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_timestamp": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAARJHaM4Gq3MpDTdBasBsEolQaOmxJQU1wsZVaSFAOLpEh1QihDglXI95xemePFMKhg+KNpFg7lw1ChCs2Wn/c26Q==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=regex", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_regex": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "regex", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_regex": { + "$regularExpression": { + "pattern": "test", + "options": "" + } + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_regex": { + "$regularExpression": { + "pattern": "test", + "options": "" + } + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_regex": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAALVnxM4UqGhqf5eXw6nsS08am3YJrTf1EvjKitT8tyyMAbHsICIU3GUjuC7EBofCHbusvgo7pDyaClGostFz44nA==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_regex": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAALVnxM4UqGhqf5eXw6nsS08am3YJrTf1EvjKitT8tyyMAbHsICIU3GUjuC7EBofCHbusvgo7pDyaClGostFz44nA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=date", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_date": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "date", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_date": { + "$date": { + "$numberLong": "123" + } + } + } + } + }, + { + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": { + "_id": 1, + "encrypted_date": { + "$date": { + "$numberLong": "123" + } + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_date": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAJ5sN7u6l97+DswfKTqZAijSTSOo5htinGKQKUD7pHNJYlLXGOkB4glrCu7ibu0g3344RHQ5yUp4YxMEa8GD+Snw==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_date": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAAJ5sN7u6l97+DswfKTqZAijSTSOo5htinGKQKUD7pHNJYlLXGOkB4glrCu7ibu0g3344RHQ5yUp4YxMEa8GD+Snw==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "type=minKey", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_minKey": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "minKey", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_minKey": { + "$minKey": 1 + } + } + }, + "result": { + "errorContains": "Cannot encrypt element of type: minKey" + } + } + ] + }, + { + "description": "type=maxKey", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_maxKey": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "maxKey", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_maxKey": { + "$maxKey": 1 + } + } + }, + "result": { + "errorContains": "Cannot encrypt element of type: maxKey" + } + } + ] + }, + { + "description": "type=undefined", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_undefined": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "undefined", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_undefined": { + "$undefined": true + } + } + }, + "result": { + "errorContains": "Cannot encrypt element of type: undefined" + } + } + ] + }, + { + "description": "type=array", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_array": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "array", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_array": [] + } + }, + "result": { + "errorContains": "Cannot use deterministic encryption for element of type: array" + } + } + ] + }, + { + "description": "type=bool", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_bool": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "bool", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_bool": true + } + }, + "result": { + "errorContains": "Cannot use deterministic encryption for element of type: bool" + } + } + ] + }, + { + "description": "type=null", + "clientOptions": { + "autoEncryptOpts": { + "schemaMap": { + "default.default": { + "properties": { + "encrypted_null": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "null", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + }, + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_null": true + } + }, + "result": { + "errorContains": "Cannot encrypt element of type: null" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.yml new file mode 100644 index 00000000000..114c27071ae --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/types.yml @@ -0,0 +1,527 @@ +# Attempt to round trip some BSON types. +# Note: db pointer is excluded since it is deprecated and numberlong is excluded due to different driver interpretations of { $numberLong: '123' } in relaxed JSON parsing. + +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "type=objectId" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_objectId': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'objectId', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_objectId: {"$oid": "AAAAAAAAAAAAAAAAAAAAAAAA"} } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc0 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_objectId: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAAHmkTPqvzfHMWpvS1mEsrjOxVQ2dyihEgIFWD5E0eNEsiMBQsC0GuvjdqYRL5DHLFI1vKuGek7EYYp0Qyii/tHqA==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted + - description: "type=symbol" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_symbol': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'symbol', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc1 { _id: 1, encrypted_symbol: {"$symbol": "test"} } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc1 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc1_encrypted { _id: 1, encrypted_symbol: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAAOOmvDmWjcuKsSCO7U/7t9HJ8eI73B6wduyMbdkvn7n7V4uTJes/j+BTtneSdyG2JHKHGkevWAJSIU2XoO66BSXw==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc1_encrypted + - description: "type=int" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_int': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'int', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc2 { _id: 1, encrypted_int: {"$numberInt": "123"} } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc2 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc2_encrypted { _id: 1, encrypted_int: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAAQPNXJVXMEjGZnftMuf2INKufXCtQIRHdw5wTgn6QYt3ejcoAXyiwI4XIUizkpsob494qpt2in4tWeiO7b9zkA8Q==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc2_encrypted + - description: "type=double" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_double': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'double', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc4 { _id: 1, encrypted_double: {"$numberDouble": "1.23"} } + result: + errorContains: "Cannot use deterministic encryption for element of type: double" + - description: "type=decimal" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_decimal': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'decimal', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc5 { _id: 1, encrypted_decimal: {"$numberDecimal": "1.23"} } + result: + errorContains: "Cannot use deterministic encryption for element of type: decimal" + - description: "type=binData" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_binData': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'binData', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc6 { _id: 1, encrypted_binData: {"$binary": { base64: "AAAA", subType: "00" } } } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc6 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc6_encrypted { _id: 1, encrypted_binData: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAAFB/KHZQHaHHo8fctcl7v6kR+sLkJoTRx2cPSSck9ya+nbGROSeFhdhDRHaCzhV78fDEqnMDSVPNi+ZkbaIh46GQ==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc6_encrypted + - description: "type=javascript" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_javascript': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'javascript', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc7 { _id: 1, encrypted_javascript: {"$code": "var x = 1;" } } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc7 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc7_encrypted { _id: 1, encrypted_javascript: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAANrvMgJkTKWGMc9wt3E2RBR2Hu5gL9p+vIIdHe9FcOm99t1W480/oX1Gnd87ON3B399DuFaxi/aaIiQSo7gTX6Lw==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc7_encrypted + - description: "type=javascriptWithScope" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_javascriptWithScope': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'javascriptWithScope', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc8 { _id: 1, encrypted_javascriptWithScope: {"$code": "var x = 1;", "$scope": {} } } + result: + errorContains: "Cannot use deterministic encryption for element of type: javascriptWithScope" + - description: "type=object" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_object': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'object', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc9 { _id: 1, encrypted_object: {} } + result: + errorContains: "Cannot use deterministic encryption for element of type: object" + - description: "type=timestamp" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_timestamp': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'timestamp', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc10 { _id: 1, encrypted_timestamp: {$timestamp: {t: 123, i: 456}} } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc10 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc10_encrypted { _id: 1, encrypted_timestamp: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAARJHaM4Gq3MpDTdBasBsEolQaOmxJQU1wsZVaSFAOLpEh1QihDglXI95xemePFMKhg+KNpFg7lw1ChCs2Wn/c26Q==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc10_encrypted + - description: "type=regex" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_regex': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'regex', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc11 { _id: 1, encrypted_regex: {$regularExpression: { pattern: "test", options: ""}} } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc11 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc11_encrypted { _id: 1, encrypted_regex: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAALVnxM4UqGhqf5eXw6nsS08am3YJrTf1EvjKitT8tyyMAbHsICIU3GUjuC7EBofCHbusvgo7pDyaClGostFz44nA==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc11_encrypted + - description: "type=date" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_date': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'date', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc13 { _id: 1, encrypted_date: {$date: { $numberLong: "123" }} } + - name: findOne + arguments: + filter: { _id: 1 } + result: *doc13 + expectations: + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc13_encrypted { _id: 1, encrypted_date: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAAJ5sN7u6l97+DswfKTqZAijSTSOo5htinGKQKUD7pHNJYlLXGOkB4glrCu7ibu0g3344RHQ5yUp4YxMEa8GD+Snw==', 'subType': '06'}} } + ordered: true + command_name: insert + - command_started_event: + command: + find: *collection_name + filter: {_id: 1} + command_name: find + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc13_encrypted + - description: "type=minKey" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_minKey': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'minKey', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc14 { _id: 1, encrypted_minKey: {$minKey: 1} } + result: + errorContains: "Cannot encrypt element of type: minKey" + - description: "type=maxKey" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_maxKey': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'maxKey', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc15 { _id: 1, encrypted_maxKey: {$maxKey: 1} } + result: + errorContains: "Cannot encrypt element of type: maxKey" + - description: "type=undefined" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_undefined': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'undefined', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc16 { _id: 1, encrypted_undefined: {$undefined: true} } + result: + errorContains: "Cannot encrypt element of type: undefined" + - description: "type=array" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_array': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'array', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc17 { _id: 1, encrypted_array: [] } + result: + errorContains: "Cannot use deterministic encryption for element of type: array" + - description: "type=bool" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_bool': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'bool', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc18 { _id: 1, encrypted_bool: true } + result: + errorContains: "Cannot use deterministic encryption for element of type: bool" + - description: "type=null" + clientOptions: + autoEncryptOpts: + schemaMap: + "default.default": {'properties': {'encrypted_null': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'null', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: insertOne + arguments: + document: &doc19 { _id: 1, encrypted_null: true } + result: + errorContains: "Cannot encrypt element of type: null" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.json new file mode 100644 index 00000000000..31887151150 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.json @@ -0,0 +1,152 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "x": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "x": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "mapReduce deterministic encryption (unsupported)", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "mapReduce", + "arguments": { + "map": { + "$code": "function inc() { return emit(0, this.x + 1) }" + }, + "reduce": { + "$code": "function sum(key, values) { return values.reduce((acc, x) => acc + x); }" + }, + "out": { + "inline": 1 + } + }, + "result": { + "errorContains": "command not supported for auto encryption: mapreduce" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.yml new file mode 100644 index 00000000000..e9edb0f58fc --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/unsupportedCommand.yml @@ -0,0 +1,25 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, x: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, x: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "mapReduce deterministic encryption (unsupported)" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: mapReduce + arguments: + map: { $code: "function inc() { return emit(0, this.x + 1) }" } + reduce: { $code: "function sum(key, values) { return values.reduce((acc, x) => acc + x); }" } + out: { inline: 1 } + result: + errorContains: "command not supported for auto encryption: mapreduce" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.json new file mode 100644 index 00000000000..7af4c133d2a --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.json @@ -0,0 +1,318 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "updateMany with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateMany", + "arguments": { + "filter": { + "encrypted_string": { + "$in": [ + "string0", + "string1" + ] + } + }, + "update": { + "$set": { + "encrypted_string": "string2", + "random": "abc" + } + } + }, + "result": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": { + "encrypted_string": { + "$in": [ + { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + }, + { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + } + ] + } + }, + "u": { + "$set": { + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + }, + "multi": true, + "upsert": false + } + ], + "ordered": true + }, + "command_name": "update" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + }, + { + "_id": 2, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ] + } + } + }, + { + "description": "updateMany fails when filtering on a random field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateMany", + "arguments": { + "filter": { + "random": "abc" + }, + "update": { + "$set": { + "encrypted_string": "string1" + } + } + }, + "result": { + "errorContains": "Cannot query on fields encrypted with the randomized encryption" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.yml new file mode 100644 index 00000000000..a346d0f60d4 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateMany.yml @@ -0,0 +1,78 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - &doc1_encrypted { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "updateMany with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateMany + arguments: + filter: { encrypted_string: { $in: [ "string0", "string1" ] } } + update: { $set: { encrypted_string: "string2", random: "abc" } } + result: + matchedCount: 2 + modifiedCount: 2 + upsertedCount: 0 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + update: *collection_name + updates: + - q: { encrypted_string: { $in: [ {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}}, {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}} ] } } + u: { $set: { encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==', 'subType': '06'}}, random: { $$type: "binData" } } } + multi: true + upsert: false + ordered: true + command_name: update + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==', 'subType': '06'}}, random: { $$type: "binData" } } + - { _id: 2, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACQ76HWOut3DZtQuV90hp1aaCpZn95vZIaWmn+wrBehcEtcFwyJlBdlyzDzZTWPZCPgiFq72Wvh6Y7VbpU9NAp3A==', 'subType': '06'}}, random: { $$type: "binData" } } + - description: "updateMany fails when filtering on a random field" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateMany + arguments: + filter: { random: "abc" } + update: { $set: { encrypted_string: "string1" } } + result: + errorContains: "Cannot query on fields encrypted with the randomized encryption" \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.json b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.json new file mode 100644 index 00000000000..9352471c7c0 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.json @@ -0,0 +1,478 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "updateOne with deterministic encryption", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": { + "encrypted_string": "string0" + }, + "update": { + "$set": { + "encrypted_string": "string1", + "random": "abc" + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "datakeys" + }, + "$db": "admin" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "admin" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": { + "encrypted_string": { + "$eq": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + }, + "u": { + "$set": { + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + } + } + ], + "ordered": true + }, + "command_name": "update" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==", + "subType": "06" + } + }, + "random": { + "$$type": "binData" + } + } + ] + } + } + }, + { + "description": "updateOne fails when filtering on a random field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": { + "random": "abc" + }, + "update": { + "$set": { + "encrypted_string": "string1" + } + } + }, + "result": { + "errorContains": "Cannot query on fields encrypted with the randomized encryption" + } + } + ] + }, + { + "description": "$unset works with an encrypted field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$unset": { + "encrypted_string": "" + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": {}, + "u": { + "$unset": { + "encrypted_string": "" + } + } + } + ], + "ordered": true + }, + "command_name": "update" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1 + } + ] + } + } + }, + { + "description": "$rename works if target value has same encryption options", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$rename": { + "encrypted_string": "encrypted_string_equivalent" + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "cursor": {}, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": {}, + "u": { + "$rename": { + "encrypted_string": "encrypted_string_equivalent" + } + } + } + ], + "ordered": true + }, + "command_name": "update" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string_equivalent": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "$rename fails if target value has different encryption options", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$rename": { + "encrypted_string": "random" + } + } + }, + "result": { + "errorContains": "$rename between two encrypted fields must have the same metadata or both be unencrypted" + } + } + ] + }, + { + "description": "an invalid update (no $ operators) is validated and errors", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "encrypted_string": "random" + } + }, + "result": { + "errorContains": "" + } + } + ] + } + ] +} diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.yml b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.yml new file mode 100644 index 00000000000..e012880c17b --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/tests/updateOne.yml @@ -0,0 +1,170 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: + - &doc0_encrypted { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } +json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}] + +tests: + - description: "updateOne with deterministic encryption" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { encrypted_string: "string0" } + update: { $set: { encrypted_string: "string1", random: "abc" } } + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: "datakeys" + $db: admin + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: {"$or": [{"_id": {"$in": [ {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}} ] }}, {"keyAltNames": {"$in": []}}]} + $db: admin + command_name: find + - command_started_event: + command: + update: *collection_name + updates: + - q: { encrypted_string: { $eq: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } } + u: { $set: {encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}}, random: { $$type: "binData" } } } + ordered: true + command_name: update + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACDdw4KFz3ZLquhsbt7RmDjD0N67n0uSXx7IGnQNCLeIKvot6s/ouI21Eo84IOtb6lhwUNPlSEBNY0/hbszWAKJg==', 'subType': '06'}}, random: { $$type: "binData"} } + - description: "updateOne fails when filtering on a random field" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { random: "abc" } + update: { $set: { encrypted_string: "string1" } } + result: + errorContains: "Cannot query on fields encrypted with the randomized encryption" + - description: "$unset works with an encrypted field" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $unset: { encrypted_string: "" } } + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + update: *collection_name + updates: + - q: { } + u: { $unset: {encrypted_string: "" } } + ordered: true + command_name: update + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1 } + - description: "$rename works if target value has same encryption options" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $rename: { encrypted_string: "encrypted_string_equivalent" } } + result: + matchedCount: 1 + modifiedCount: 1 + upsertedCount: 0 + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + cursor: {} + filter: + name: *collection_name + command_name: listCollections + - command_started_event: + command: + update: *collection_name + updates: + - q: { } + u: { $rename: {encrypted_string: "encrypted_string_equivalent" } } + ordered: true + command_name: update + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - { _id: 1, encrypted_string_equivalent: {'$binary': {'base64': 'AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==', 'subType': '06'}} } + - description: "$rename fails if target value has different encryption options" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { $rename: { encrypted_string: "random" } } + result: + errorContains: "$rename between two encrypted fields must have the same metadata or both be unencrypted" + - description: "an invalid update (no $ operators) is validated and errors" + clientOptions: + autoEncryptOpts: + kmsProviders: + aws: {} # Credentials filled in from environment. + operations: + - name: updateOne + arguments: + filter: { } + update: { encrypted_string: "random" } + result: + errorContains: "" # Note, drivers differ in the error message. Just ensure an error is thrown. \ No newline at end of file diff --git a/tests/MongoDB.Driver.Tests/xunit.runner.json b/tests/MongoDB.Driver.Tests/xunit.runner.json index a301c676bdc..0d1e5d22262 100644 --- a/tests/MongoDB.Driver.Tests/xunit.runner.json +++ b/tests/MongoDB.Driver.Tests/xunit.runner.json @@ -1,5 +1,6 @@ { "longRunningTestSeconds": 1800, "parallelizeAssembly": false, - "parallelizeTestCollections": false + "parallelizeTestCollections": false, + "shadowCopy": false } \ No newline at end of file