summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatherine Wu <katherine.wu@mongodb.com>2020-05-14 13:47:20 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-09-30 15:19:29 +0000
commite8b6b2815cdce52f980ccaf03d9753b377c1dd61 (patch)
treea7f93f0245d926be007dc62c323239714b9b6602
parent9e252edecf6d934bbce6ae39638fc066f37120e6 (diff)
downloadmongo-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.js49
-rw-r--r--src/mongo/db/command_generic_argument.cpp4
-rw-r--r--src/mongo/db/command_generic_argument.h6
-rw-r--r--src/mongo/db/commands/explain_cmd.cpp3
-rw-r--r--src/mongo/db/pipeline/aggregation_request.cpp4
-rw-r--r--src/mongo/db/query/find_and_modify_request.cpp4
-rw-r--r--src/mongo/db/query/query_request.cpp6
-rw-r--r--src/mongo/idl/idl_parser.cpp8
-rw-r--r--src/mongo/s/commands/cluster_explain_cmd.cpp3
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