diff options
author | Katherine Wu <katherine.wu@mongodb.com> | 2020-05-14 13:47:20 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-09-30 15:19:29 +0000 |
commit | e8b6b2815cdce52f980ccaf03d9753b377c1dd61 (patch) | |
tree | a7f93f0245d926be007dc62c323239714b9b6602 | |
parent | 9e252edecf6d934bbce6ae39638fc066f37120e6 (diff) | |
download | mongo-e8b6b2815cdce52f980ccaf03d9753b377c1dd61.tar.gz |
SERVER-46625 Improve diagnostics when mongocryptd requests are sent to non-mongocryptd daemon
(cherry picked from commit becc8e5ecca4260e844725fa71f4ed1164647e4a)
(cherry picked from commit 77154fe6e600510d06d2e44015668aedfd8d2c97)
-rw-r--r-- | jstests/core/command_json_schema_field.js | 49 | ||||
-rw-r--r-- | src/mongo/db/command_generic_argument.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/command_generic_argument.h | 6 | ||||
-rw-r--r-- | src/mongo/db/commands/explain_cmd.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/pipeline/aggregation_request.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/query/find_and_modify_request.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/query/query_request.cpp | 6 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.cpp | 8 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_explain_cmd.cpp | 3 |
9 files changed, 87 insertions, 0 deletions
diff --git a/jstests/core/command_json_schema_field.js b/jstests/core/command_json_schema_field.js new file mode 100644 index 00000000000..4e7cbd4eeaf --- /dev/null +++ b/jstests/core/command_json_schema_field.js @@ -0,0 +1,49 @@ +/* + * FLE-supported commands that contain an invalid 'jsonSchema' field should return to the user a + * more specific error message for diagnostic purposes. + * + * @tags: [requires_non_retryable_writes] + */ +(function() { +'use strict'; + +const coll = db.command_json_schema_field; +coll.drop(); +assert.commandWorked(coll.insert({a: 1})); +assert.commandWorked(coll.insert({a: 2})); + +function assertCommandFailsWithCorrectError(command, code) { + let res = db.runCommand(command); + assert.commandFailedWithCode(res, code); + assert(res.errmsg.includes("This command may be meant for a mongocryptd process")); +} + +// Aggregate +assertCommandFailsWithCorrectError( + {aggregate: coll.getName(), pipeline: [], cursor: {}, jsonSchema: {}}, + ErrorCodes.FailedToParse); + +// Find +assertCommandFailsWithCorrectError({find: coll.getName(), jsonSchema: {}}, + ErrorCodes.FailedToParse); + +// FindAndModify +assertCommandFailsWithCorrectError( + {findAndModify: coll.getName(), query: {_id: 0}, remove: true, jsonSchema: {}}, + ErrorCodes.FailedToParse); + +// Distinct +assertCommandFailsWithCorrectError({distinct: coll.getName(), key: "a", jsonSchema: {}}, 4662500); + +// Write Commands +assertCommandFailsWithCorrectError({insert: coll.getName(), documents: [{}], jsonSchema: {}}, + 4662500); +assertCommandFailsWithCorrectError( + {update: coll.getName(), updates: [{q: {}, u: {$inc: {a: 1}}}], jsonSchema: {}}, 4662500); +assertCommandFailsWithCorrectError( + {delete: coll.getName(), deletes: [{q: {}, limit: 0}], jsonSchema: {}}, 4662500); + +// Explain +assertCommandFailsWithCorrectError({explain: {find: coll.getName(), filter: {}}, jsonSchema: {}}, + ErrorCodes.FailedToParse); +}()); diff --git a/src/mongo/db/command_generic_argument.cpp b/src/mongo/db/command_generic_argument.cpp index 4044bbf62a0..e1b92141587 100644 --- a/src/mongo/db/command_generic_argument.cpp +++ b/src/mongo/db/command_generic_argument.cpp @@ -107,4 +107,8 @@ bool isReplyStripArgument(StringData arg) { return p && p->stripFromReply; } +bool isMongocryptdArgument(StringData arg) { + return arg == "jsonSchema"_sd; +} + } // namespace mongo diff --git a/src/mongo/db/command_generic_argument.h b/src/mongo/db/command_generic_argument.h index 5d4026e9177..69d695250ec 100644 --- a/src/mongo/db/command_generic_argument.h +++ b/src/mongo/db/command_generic_argument.h @@ -53,4 +53,10 @@ bool isRequestStripArgument(StringData arg); */ bool isReplyStripArgument(StringData arg); +/** + * Returns true if the provided argument is one that should be handled by a mongocryptd process. + */ +bool isMongocryptdArgument(StringData arg); + + } // namespace mongo diff --git a/src/mongo/db/commands/explain_cmd.cpp b/src/mongo/db/commands/explain_cmd.cpp index a29d01cf985..3877a59c110 100644 --- a/src/mongo/db/commands/explain_cmd.cpp +++ b/src/mongo/db/commands/explain_cmd.cpp @@ -145,6 +145,9 @@ std::unique_ptr<CommandInvocation> CmdExplain::parse(OperationContext* opCtx, CommandHelpers::uassertNoDocumentSequences(getName(), request); std::string dbname = request.getDatabase().toString(); const BSONObj& cmdObj = request.body; + uassert(ErrorCodes::FailedToParse, + "Unrecognized field 'jsonSchema'. This command may be meant for a mongocryptd process.", + !cmdObj.hasField("jsonSchema"_sd)); ExplainOptions::Verbosity verbosity = uassertStatusOK(ExplainOptions::parseCmdBSON(cmdObj)); uassert(ErrorCodes::BadValue, "explain command requires a nested object", diff --git a/src/mongo/db/pipeline/aggregation_request.cpp b/src/mongo/db/pipeline/aggregation_request.cpp index 81c4567e48f..9733168fb51 100644 --- a/src/mongo/db/pipeline/aggregation_request.cpp +++ b/src/mongo/db/pipeline/aggregation_request.cpp @@ -234,6 +234,10 @@ StatusWith<AggregationRequest> AggregationRequest::parseFromBSON( } catch (const DBException& ex) { return ex.toStatus(); } + } else if (isMongocryptdArgument(fieldName)) { + return {ErrorCodes::FailedToParse, + str::stream() << "unrecognized field '" << elem.fieldName() + << "'. This command may be meant for a mongocryptd process."}; } else if (!isGenericArgument(fieldName)) { return {ErrorCodes::FailedToParse, str::stream() << "unrecognized field '" << elem.fieldName() << "'"}; diff --git a/src/mongo/db/query/find_and_modify_request.cpp b/src/mongo/db/query/find_and_modify_request.cpp index 9bf40a1f456..70c41058170 100644 --- a/src/mongo/db/query/find_and_modify_request.cpp +++ b/src/mongo/db/query/find_and_modify_request.cpp @@ -249,6 +249,10 @@ StatusWith<FindAndModifyRequest> FindAndModifyRequest::parseFromBSON(NamespaceSt } else { writeConcernOptionsSet = true; } + } else if (isMongocryptdArgument(field)) { + return {ErrorCodes::FailedToParse, + str::stream() << "unrecognized field '" << field + << "'. This command may be meant for a mongocryptd process."}; } else if (!isGenericArgument(field) && !std::count(_knownFields.begin(), _knownFields.end(), field)) { return {ErrorCodes::Error(51177), diff --git a/src/mongo/db/query/query_request.cpp b/src/mongo/db/query/query_request.cpp index e0082a90d80..3662ad109f1 100644 --- a/src/mongo/db/query/query_request.cpp +++ b/src/mongo/db/query/query_request.cpp @@ -396,6 +396,12 @@ StatusWith<unique_ptr<QueryRequest>> QueryRequest::parseFromFindCommand(unique_p return status; } qr->_internalReadAtClusterTime = el.timestamp(); + } else if (isMongocryptdArgument(fieldName)) { + return Status(ErrorCodes::FailedToParse, + str::stream() + << "Failed to parse: " << cmdObj.toString() + << ". Unrecognized field '" << fieldName + << "'. This command may be meant for a mongocryptd process."); } else if (!isGenericArgument(fieldName)) { return Status(ErrorCodes::FailedToParse, str::stream() << "Failed to parse: " << cmdObj.toString() << ". " diff --git a/src/mongo/idl/idl_parser.cpp b/src/mongo/idl/idl_parser.cpp index 0adb3fa62c2..aa162b79afb 100644 --- a/src/mongo/idl/idl_parser.cpp +++ b/src/mongo/idl/idl_parser.cpp @@ -183,6 +183,14 @@ void IDLParserErrorContext::throwMissingField(StringData fieldName) const { void IDLParserErrorContext::throwUnknownField(StringData fieldName) const { std::string path = getElementPath(fieldName); + if (isMongocryptdArgument(fieldName)) { + uasserted( + 4662500, + str::stream() + << "BSON field '" << path + << "' is an unknown field. This command may be meant for a mongocryptd process."); + } + uasserted(40415, str::stream() << "BSON field '" << path << "' is an unknown field."); } diff --git a/src/mongo/s/commands/cluster_explain_cmd.cpp b/src/mongo/s/commands/cluster_explain_cmd.cpp index c188fe19b65..6c7b05a527c 100644 --- a/src/mongo/s/commands/cluster_explain_cmd.cpp +++ b/src/mongo/s/commands/cluster_explain_cmd.cpp @@ -170,6 +170,9 @@ std::unique_ptr<CommandInvocation> ClusterExplainCmd::parse(OperationContext* op CommandHelpers::uassertNoDocumentSequences(getName(), request); std::string dbName = request.getDatabase().toString(); const BSONObj& cmdObj = request.body; + uassert(ErrorCodes::FailedToParse, + "Unrecognized field 'jsonSchema'. This command may be meant for a mongocryptd process.", + !cmdObj.hasField("jsonSchema"_sd)); ExplainOptions::Verbosity verbosity = uassertStatusOK(ExplainOptions::parseCmdBSON(cmdObj)); // This is the nested command which we are explaining. We need to propagate generic |