diff options
-rw-r--r-- | jstests/core/create_encrypted_collection.js | 42 | ||||
-rw-r--r-- | src/mongo/bson/bsontypes.cpp | 10 | ||||
-rw-r--r-- | src/mongo/bson/bsontypes.h | 6 | ||||
-rw-r--r-- | src/mongo/crypto/encryption_fields.idl | 73 | ||||
-rw-r--r-- | src/mongo/crypto/encryption_fields_util.h | 81 | ||||
-rw-r--r-- | src/mongo/db/catalog/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_options.cpp | 47 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_options.h | 7 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_options_test.cpp | 219 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_options_validation.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_options_validation.h | 4 | ||||
-rw-r--r-- | src/mongo/db/catalog/create_collection.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/create.idl | 6 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_create_cmd.cpp | 3 |
14 files changed, 557 insertions, 5 deletions
diff --git a/jstests/core/create_encrypted_collection.js b/jstests/core/create_encrypted_collection.js new file mode 100644 index 00000000000..84187857e78 --- /dev/null +++ b/jstests/core/create_encrypted_collection.js @@ -0,0 +1,42 @@ +// Verify valid and invalid scenarios for create encrypted collection + +/** + * @tags: [ + * featureFlagFLE2, + * assumes_against_mongod_not_mongos + * ] + */ +(function() { +'use strict'; + +const isFLE2Enabled = TestData == undefined || TestData.setParameters.featureFlagFLE2; + +if (!isFLE2Enabled) { + return; +} + +let dbTest = db.getSiblingDB('create_encrypted_collection_db'); + +dbTest.basic.drop(); + +assert.commandWorked(dbTest.createCollection("basic", { + encryptedFields: { + "fields": [ + { + "path": "firstName", + "keyId": UUID("11d58b8a-0c6c-4d69-a0bd-70c6d9befae9"), + "bsonType": "string", + "queries": {"queryType": "equality"} // allow single object or array + }, + + ] + } +})); + +const result = dbTest.getCollectionInfos({name: "basic"}); +print("result" + tojson(result)); +const ef = result[0].options.encryptedFields; +assert.eq(ef.escCollection, "fle2.basic.esc"); +assert.eq(ef.eccCollection, "fle2.basic.ecc"); +assert.eq(ef.ecocCollection, "fle2.basic.ecoc"); +}()); diff --git a/src/mongo/bson/bsontypes.cpp b/src/mongo/bson/bsontypes.cpp index 59fb2abba96..8be3c5e1d04 100644 --- a/src/mongo/bson/bsontypes.cpp +++ b/src/mongo/bson/bsontypes.cpp @@ -137,6 +137,16 @@ BSONType typeFromName(StringData name) { return *typeAlias; } +Status isValidBSONTypeName(StringData typeName) { + try { + typeFromName(typeName); + } catch (const ExceptionFor<ErrorCodes::BadValue>& ex) { + return ex.toStatus(); + } + + return Status::OK(); +} + std::ostream& operator<<(std::ostream& stream, BSONType type) { return stream << typeName(type); } diff --git a/src/mongo/bson/bsontypes.h b/src/mongo/bson/bsontypes.h index 3463285f636..0dc2fe8a4ab 100644 --- a/src/mongo/bson/bsontypes.h +++ b/src/mongo/bson/bsontypes.h @@ -135,6 +135,12 @@ std::ostream& operator<<(std::ostream& stream, BSONType type); */ bool isValidBSONType(int type); +/** + * IDL callback validator + */ +Status isValidBSONTypeName(StringData typeName); + + inline bool isNumericBSONType(BSONType type) { switch (type) { case NumberDouble: diff --git a/src/mongo/crypto/encryption_fields.idl b/src/mongo/crypto/encryption_fields.idl index f9724f16c91..1ba43cde430 100644 --- a/src/mongo/crypto/encryption_fields.idl +++ b/src/mongo/crypto/encryption_fields.idl @@ -31,8 +31,81 @@ global: imports: - "mongo/idl/basic_types.idl" +enums: + QueryType: + description: "query types" + type: string + values: + Equality: "equality" + # Range: "range" + feature_flags: featureFlagFLE2: description: "Enable FLE2 support" cpp_varname: gFeatureFlagFLE2 default: false + +structs: + + QueryTypeConfig: + description: "Information about query support for a field" + strict: true + fields: + queryType: + description: "Type of supported queries" + type: QueryType + unstable: true + contention: + description: "Contention factor for field, 0 means it has extremely high set number of distinct values" + type: long + default: 0 + unstable: true + validator: { gte: 0 } + + EncryptedField: + description: "Information about encrypted fields" + strict: true + fields: + keyId: + description: "UUID of key in key vault to use for encryption" + type: uuid + unstable: true + path: + description: "Path to field to encrypt" + type: string + unstable: true + bsonType: + description: "BSON type of field to encrypt" + type: string + validator: { callback: "isValidBSONTypeName" } + unstable: true + queries: + description: "List of supported query types" + type: + variant: [QueryTypeConfig, array<QueryTypeConfig>] + optional: true + unstable: true + + EncryptedFieldConfig: + description: "Information about encrypted fields and state collections" + strict: true + fields: + escCollection: + description: "Encrypted State Collection name, defaults to <collection>.esc" + type: string + optional: true + unstable: true + eccCollection: + description: "Encrypted Cache Collection name, defaults to <collection>.ecc" + type: string + optional: true + unstable: true + ecocCollection: + description: "Encrypted Compaction Collection name, defaults to <collection>.ecoc" + type: string + optional: true + unstable: true + fields: + description: "Array of encrypted fields" + type: array<EncryptedField> + unstable: true diff --git a/src/mongo/crypto/encryption_fields_util.h b/src/mongo/crypto/encryption_fields_util.h new file mode 100644 index 00000000000..ad4419d6acf --- /dev/null +++ b/src/mongo/crypto/encryption_fields_util.h @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ +#pragma once + +#include "mongo/base/status.h" +#include "mongo/base/string_data.h" +#include "mongo/bson/bsontypes.h" +#include "mongo/util/assert_util.h" + +namespace mongo { + +inline bool isFLE2EqualityIndexedSupportedType(BSONType type) { + switch (type) { + case BinData: + case Code: + case RegEx: + case String: + + case NumberInt: + case NumberLong: + case Bool: + case bsonTimestamp: + case Date: + case jstOID: + return true; + + // Deprecated + case Symbol: + case CodeWScope: + case DBRef: + + // Non-deterministic + case Array: + case Object: + case NumberDecimal: + case NumberDouble: + + // Singletons + case EOO: + case jstNULL: + case MaxKey: + case MinKey: + case Undefined: + return false; + default: + MONGO_UNREACHABLE; + } +} + +// Unindexed is the same as equality +inline bool isFLE2UnindexedSupportedType(BSONType type) { + return isFLE2EqualityIndexedSupportedType(type); +} + +} // namespace mongo diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript index b5bf4ebbe09..384775dd7c2 100644 --- a/src/mongo/db/catalog/SConscript +++ b/src/mongo/db/catalog/SConscript @@ -41,8 +41,10 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/crypto/encrypted_field_config', '$BUILD_DIR/mongo/db/query/collation/collator_interface', '$BUILD_DIR/mongo/db/query/query_knobs', + '$BUILD_DIR/mongo/db/server_options_core', '$BUILD_DIR/mongo/db/timeseries/timeseries_options', '$BUILD_DIR/mongo/idl/basic_types', '$BUILD_DIR/mongo/idl/feature_flag', diff --git a/src/mongo/db/catalog/collection_options.cpp b/src/mongo/db/catalog/collection_options.cpp index 2b2f16bf9ea..2db236f1ecb 100644 --- a/src/mongo/db/catalog/collection_options.cpp +++ b/src/mongo/db/catalog/collection_options.cpp @@ -59,6 +59,24 @@ long long adjustCappedMaxDocs(long long cappedMaxDocs) { } return cappedMaxDocs; } + +void setEncryptedDefaultEncryptedCollectionNames(const NamespaceString& ns, + EncryptedFieldConfig* config) { + auto prefix = std::string("fle2.") + ns.coll(); + + if (!config->getEscCollection()) { + config->setEscCollection(StringData(prefix + ".esc")); + } + + if (!config->getEccCollection()) { + config->setEccCollection(StringData(prefix + ".ecc")); + } + + if (!config->getEcocCollection()) { + config->setEcocCollection(StringData(prefix + ".ecoc")); + } +} + } // namespace bool CollectionOptions::isView() const { @@ -258,6 +276,18 @@ StatusWith<CollectionOptions> CollectionOptions::parse(const BSONObj& options, P } catch (const DBException& ex) { return ex.toStatus(); } + } else if (fieldName == "encryptedFields") { + if (e.type() != mongo::Object) { + return {ErrorCodes::TypeMismatch, "'encryptedFields' must be a document"}; + } + + try { + collectionOptions.encryptedFieldConfig = + collection_options_validation::processAndValidateEncryptedFields( + EncryptedFieldConfig::parse({"CollectionOptions::parse"}, e.Obj())); + } catch (const DBException& ex) { + return ex.toStatus(); + } } else if (!createdOn24OrEarlier && !mongo::isGenericArgument(fieldName)) { return Status(ErrorCodes::InvalidOptions, str::stream() @@ -273,7 +303,8 @@ StatusWith<CollectionOptions> CollectionOptions::parse(const BSONObj& options, P return collectionOptions; } -CollectionOptions CollectionOptions::fromCreateCommand(const CreateCommand& cmd) { +CollectionOptions CollectionOptions::fromCreateCommand(const NamespaceString& nss, + const CreateCommand& cmd) { CollectionOptions options; options.validationLevel = cmd.getValidationLevel(); @@ -345,6 +376,10 @@ CollectionOptions CollectionOptions::fromCreateCommand(const CreateCommand& cmd) if (auto temp = cmd.getTemp()) { options.temp = *temp; } + if (auto encryptedFieldConfig = cmd.getEncryptedFields()) { + options.encryptedFieldConfig = std::move(*encryptedFieldConfig); + setEncryptedDefaultEncryptedCollectionNames(nss, options.encryptedFieldConfig.get_ptr()); + } return options; } @@ -448,6 +483,10 @@ void CollectionOptions::appendBSON(BSONObjBuilder* builder, if (timeseries && shouldAppend(CreateCommand::kTimeseriesFieldName)) { builder->append(CreateCommand::kTimeseriesFieldName, timeseries->toBSON()); } + + if (encryptedFieldConfig && shouldAppend(CreateCommand::kEncryptedFieldsFieldName)) { + builder->append(CreateCommand::kEncryptedFieldsFieldName, encryptedFieldConfig->toBSON()); + } } bool CollectionOptions::matchesStorageOptions(const CollectionOptions& other, @@ -532,6 +571,12 @@ bool CollectionOptions::matchesStorageOptions(const CollectionOptions& other, return false; } + if ((encryptedFieldConfig && other.encryptedFieldConfig && + encryptedFieldConfig->toBSON().woCompare(other.encryptedFieldConfig->toBSON()) != 0) || + (encryptedFieldConfig == boost::none) != (other.encryptedFieldConfig == boost::none)) { + return false; + } + if (expireAfterSeconds != other.expireAfterSeconds) { return false; } diff --git a/src/mongo/db/catalog/collection_options.h b/src/mongo/db/catalog/collection_options.h index 52e0506bc43..641a0510fa5 100644 --- a/src/mongo/db/catalog/collection_options.h +++ b/src/mongo/db/catalog/collection_options.h @@ -34,6 +34,7 @@ #include <boost/optional.hpp> #include "mongo/base/status.h" +#include "mongo/crypto/encryption_fields_gen.h" #include "mongo/db/catalog/clustered_collection_options_gen.h" #include "mongo/db/catalog/collection_options_gen.h" #include "mongo/db/jsobj.h" @@ -79,7 +80,8 @@ struct CollectionOptions { /** * Converts a client "create" command invocation. */ - static CollectionOptions fromCreateCommand(const CreateCommand& cmd); + static CollectionOptions fromCreateCommand(const NamespaceString& nss, + const CreateCommand& cmd); /** * Serialize to BSON. The 'includeUUID' parameter is used for the listCollections command to do @@ -161,5 +163,8 @@ struct CollectionOptions { // The options that define the time-series collection, or boost::none if not a time-series // collection. boost::optional<TimeseriesOptions> timeseries; + + // The options for collections with encrypted fields + boost::optional<EncryptedFieldConfig> encryptedFieldConfig; }; } // namespace mongo diff --git a/src/mongo/db/catalog/collection_options_test.cpp b/src/mongo/db/catalog/collection_options_test.cpp index 385310f4f87..d6632c3456f 100644 --- a/src/mongo/db/catalog/collection_options_test.cpp +++ b/src/mongo/db/catalog/collection_options_test.cpp @@ -34,6 +34,7 @@ #include <limits> #include "mongo/db/json.h" +#include "mongo/idl/server_parameter_test_util.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -353,4 +354,222 @@ TEST(CollectionOptions, NExtentsNoError) { // Check that $nExtents does not cause an error for backwards compatability assertGet(CollectionOptions::parse(fromjson("{$nExtents: 'a'}"))); } + +#define ASSERT_STATUS_CODE(CODE, EXPRESSION) ASSERT_EQUALS(CODE, (EXPRESSION).getStatus().code()) + +// Duplicate fields is not allowed +TEST(FLECollectionOptions, MultipleFields) { + RAIIServerParameterControllerForTest featureFlagController("featureFlagFLE2", true); + + ASSERT_STATUS_CODE(6338402, CollectionOptions::parse(fromjson(R"({ + encryptedFields: { + "fields": [ + { + "path": "name.first", + "keyId": { '$uuid': '11d58b8a-0c6c-4d69-a0bd-70c6d9befae9' }, + "bsonType": "string", + "queries": {"queryType": "equality"} + }, + { + "path": "name.first", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": "string", + "queries": [{"queryType": "equality"}] + } + ] + }})"))); +} + +// Duplicate key ids are bad, it breaks the design +TEST(FLECollectionOptions, DuplicateKeyIds) { + RAIIServerParameterControllerForTest featureFlagController("featureFlagFLE2", true); + + ASSERT_STATUS_CODE(6338401, CollectionOptions::parse(fromjson(R"({ + encryptedFields: { + "fields": [ + { + "path": "name.first", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": "string", + "queries": {"queryType": "equality"} + }, + { + "path": "name.last", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": "string", + "queries": [{"queryType": "equality"}] + } + ] + }})"))); +} + +TEST(FLECollectionOptions, ConflictingPrefixes) { + RAIIServerParameterControllerForTest featureFlagController("featureFlagFLE2", true); + + ASSERT_STATUS_CODE(6338403, CollectionOptions::parse(fromjson(R"({ + encryptedFields: { + "fields": [ + { + "path": "name", + "keyId": { '$uuid': '11d58b8a-0c6c-4d69-a0bd-70c6d9befae9' }, + "bsonType": "string", + "queries": {"queryType": "equality"} + }, + { + "path": "name.first", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": "string", + "queries": [{"queryType": "equality"}] + } + ] + }})"))); + + ASSERT_STATUS_CODE(6338403, CollectionOptions::parse(fromjson(R"({ + encryptedFields: { + "fields": [ + { + "path": "a.b.c", + "keyId": { '$uuid': '11d58b8a-0c6c-4d69-a0bd-70c6d9befae9' }, + "bsonType": "string", + "queries": {"queryType": "equality"} + }, + { + "path": "a.b.c.d.e", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": "string", + "queries": [{"queryType": "equality"}] + } + ] + }})"))); + + ASSERT_STATUS_CODE(6338403, CollectionOptions::parse(fromjson(R"({ + encryptedFields: { + "fields": [ + { + "path": "a.b.c.d.e.f", + "keyId": { '$uuid': '11d58b8a-0c6c-4d69-a0bd-70c6d9befae9' }, + "bsonType": "string", + "queries": {"queryType": "equality"} + }, + { + "path": "a.b.c.d", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": "string", + "queries": [{"queryType": "equality"}] + } + ] + }})"))); +} + +TEST(FLECollectionOptions, DuplicateQueryTypes) { + + + RAIIServerParameterControllerForTest featureFlagController("featureFlagFLE2", true); + + ASSERT_STATUS_CODE(6338404, CollectionOptions::parse(fromjson(R"({ + encryptedFields: { + "fields": [ + { + "path": "name.first", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": "string", + "queries": [{"queryType": "equality"}, {"queryType": "equality"}] + } + ] + }})"))); +} + +TEST(FLECollectionOptions, AllowedTypes) { + RAIIServerParameterControllerForTest featureFlagController("featureFlagFLE2", true); + + std::vector<std::string> types({ + "string", + "binData", + "objectId", + "bool", + "date", + "regex", + "javascript", + "int", + "timestamp", + "long", + }); + + for (const auto& type : types) { + ASSERT_OK(CollectionOptions::parse(fromjson(str::stream() << R"({ + encryptedFields: { + "fields": [ + { + "path": "name.first", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": ")" << type << R"(" + } + ] + }})")) + .getStatus()); + + ASSERT_OK(CollectionOptions::parse(fromjson(str::stream() << R"({ + encryptedFields: { + "fields": [ + { + "path": "firstName", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": ")" << type << R"(", + "queries": {"queryType": "equality"} + } + ] + } + }})")) + .getStatus()); + } +} + + +TEST(FLECollectionOptions, DisAllowedTypes) { + RAIIServerParameterControllerForTest featureFlagController("featureFlagFLE2", true); + + std::vector<std::string> types({ + "minKey", + "missing", + "double", + "object", + "array", + "null", + "undefined", + "dbPointer", + "symbol", + "javascriptWithScope", + "decimal", + "maxKey", + }); + + for (const auto& type : types) { + ASSERT_NOT_OK(CollectionOptions::parse(fromjson(str::stream() << R"({ + encryptedFields: { + "fields": [ + { + "path": "name.first", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": ")" << type << R"(" + } + ] + }})")) + .getStatus()); + + ASSERT_NOT_OK(CollectionOptions::parse(fromjson(str::stream() << R"({ + encryptedFields: { + "fields": [ + { + "path": "firstName", + "keyId": { '$uuid': '5f34e99a-b214-451f-b6f6-d3d28e933d15' }, + "bsonType": ")" << type << R"(", + "queries": {"queryType": "equality"} + } + ] + } + }})")) + .getStatus()); + } +} + } // namespace mongo diff --git a/src/mongo/db/catalog/collection_options_validation.cpp b/src/mongo/db/catalog/collection_options_validation.cpp index fd01b1e876c..116bb86d261 100644 --- a/src/mongo/db/catalog/collection_options_validation.cpp +++ b/src/mongo/db/catalog/collection_options_validation.cpp @@ -28,6 +28,7 @@ */ #include "mongo/db/catalog/collection_options_validation.h" +#include "mongo/crypto/encryption_fields_util.h" namespace mongo::collection_options_validation { Status validateStorageEngineOptions(const BSONObj& storageEngine) { @@ -54,4 +55,62 @@ Status validateStorageEngineOptions(const BSONObj& storageEngine) { } return Status::OK(); } + +EncryptedFieldConfig processAndValidateEncryptedFields(EncryptedFieldConfig config) { + + if (!gFeatureFlagFLE2.isEnabledAndIgnoreFCV()) { + uasserted(6338408, "Feature flag FLE2 is not enabled"); + } + + stdx::unordered_set<UUID, UUID::Hash> keys(config.getFields().size()); + std::vector<std::string> fieldPaths; + fieldPaths.reserve(config.getFields().size()); + + for (const auto& field : config.getFields()) { + UUID keyId = field.getKeyId(); + + // Duplicate key ids are bad, it breaks the design + uassert(6338401, "Duplicate key ids are not allowed", keys.count(keyId) == 0); + keys.insert(keyId); + + BSONType type = typeFromName(field.getBsonType()); + + for (const auto& path : fieldPaths) { + uassert(6338402, "Duplicate paths are not allowed", field.getPath() != path); + // Cannot have indexes on "a" and "a.b" + uassert(6338403, + str::stream() << "Conflicting index paths found as one is a prefix of another '" + << field.getPath() << "' and '" << path << "'", + !field.getPath().startsWith(path) && + !StringData(path).startsWith(field.getPath())); + } + fieldPaths.push_back(field.getPath().toString()); + + if (field.getQueries().has_value()) { + auto queriesVariant = field.getQueries().get(); + + auto queries = stdx::get_if<std::vector<mongo::QueryTypeConfig>>(&queriesVariant); + if (queries) { + // If the user specified multiple queries, verify they are unique + // TODO - once other index types are added we will need to enhance this check + uassert(6338404, + "Only 1 equality queryType can be specified per field", + queries->size() == 1); + } + + uassert(6338405, + str::stream() << "Type '" << typeName(type) + << "' is not a supported equality indexed type", + isFLE2EqualityIndexedSupportedType(type)); + } else { + uassert(6338406, + str::stream() << "Type '" << typeName(type) + << "' is not a supported unindexed type", + isFLE2UnindexedSupportedType(type)); + } + } + + return config; +} + } // namespace mongo::collection_options_validation diff --git a/src/mongo/db/catalog/collection_options_validation.h b/src/mongo/db/catalog/collection_options_validation.h index db453589f88..09f8e67b742 100644 --- a/src/mongo/db/catalog/collection_options_validation.h +++ b/src/mongo/db/catalog/collection_options_validation.h @@ -31,7 +31,11 @@ #include "mongo/base/status.h" #include "mongo/bson/bsonobj.h" +#include "mongo/crypto/encryption_fields_gen.h" namespace mongo::collection_options_validation { Status validateStorageEngineOptions(const BSONObj& storageEngine); + +EncryptedFieldConfig processAndValidateEncryptedFields(EncryptedFieldConfig config); + } // namespace mongo::collection_options_validation diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp index d5c4caef4cf..89357d9280b 100644 --- a/src/mongo/db/catalog/create_collection.cpp +++ b/src/mongo/db/catalog/create_collection.cpp @@ -667,7 +667,6 @@ Status createCollection(OperationContext* opCtx, return createCollection(opCtx, nss, collectionOptions, idIndex); } - } // namespace Status createCollection(OperationContext* opCtx, @@ -684,7 +683,7 @@ Status createCollection(OperationContext* opCtx, Status createCollection(OperationContext* opCtx, const NamespaceString& ns, const CreateCommand& cmd) { - auto options = CollectionOptions::fromCreateCommand(cmd); + auto options = CollectionOptions::fromCreateCommand(ns, cmd); auto idIndex = std::exchange(options.idIndex, {}); bool hasExplicitlyDisabledClustering = cmd.getClusteredIndex() && stdx::holds_alternative<bool>(*cmd.getClusteredIndex()) && diff --git a/src/mongo/db/commands/create.idl b/src/mongo/db/commands/create.idl index 9ba1e6a82a3..2e156b4f1b5 100644 --- a/src/mongo/db/commands/create.idl +++ b/src/mongo/db/commands/create.idl @@ -32,6 +32,7 @@ global: - "mongo/db/commands/create_command_validation.h" imports: + - "mongo/crypto/encryption_fields.idl" - "mongo/db/auth/access_checks.idl" - "mongo/db/auth/action_type.idl" - "mongo/db/catalog/collection_options.idl" @@ -196,6 +197,11 @@ commands: type: safeInt64 optional: true unstable: false + encryptedFields: + description: "The number of seconds after which old data should be deleted." + type: EncryptedFieldConfig + optional: true + unstable: false temp: description: "DEPRECATED" type: safeBool diff --git a/src/mongo/s/commands/cluster_create_cmd.cpp b/src/mongo/s/commands/cluster_create_cmd.cpp index a82a85ad02b..b7c6d5ea88b 100644 --- a/src/mongo/s/commands/cluster_create_cmd.cpp +++ b/src/mongo/s/commands/cluster_create_cmd.cpp @@ -144,7 +144,8 @@ public: !opCtx->inMultiDocumentTransaction()) { // NamespaceExists will cause multi-document transactions to implicitly abort, so // mongos should surface this error to the client. - auto options = CollectionOptions::fromCreateCommand(cmd); + auto options = CollectionOptions::fromCreateCommand(cmd.getNamespace(), cmd); + checkCollectionOptions(opCtx, cmd.getNamespace(), options); } else { uassertStatusOK(createStatus); |