summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2018-08-22 15:25:52 -0400
committerSpencer Jackson <spencer.jackson@mongodb.com>2018-09-17 17:21:40 -0400
commite78dc4e8cf32da88062090410ab8617f604633c9 (patch)
treedf238a81200a01b354ebad2ad9ecd2dc7c9bedb3
parentf99914d14b76718f1fef879cfaabe23c0c8f0857 (diff)
downloadmongo-e78dc4e8cf32da88062090410ab8617f604633c9.tar.gz
SERVER-36606: Allow commands to expose names of sensitive fields
-rw-r--r--src/mongo/db/audit.h4
-rw-r--r--src/mongo/db/auth/sasl_commands.cpp15
-rw-r--r--src/mongo/db/commands.cpp36
-rw-r--r--src/mongo/db/commands.h14
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp9
-rw-r--r--src/mongo/db/commands/user_management_commands.h7
-rw-r--r--src/mongo/db/commands/user_management_commands_common.cpp9
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp6
-rw-r--r--src/mongo/db/curop.cpp2
-rw-r--r--src/mongo/db/service_entry_point_common.cpp2
-rw-r--r--src/mongo/s/commands/cluster_user_management_commands.cpp8
11 files changed, 68 insertions, 44 deletions
diff --git a/src/mongo/db/audit.h b/src/mongo/db/audit.h
index 6e2c3fae986..aa44fc8e539 100644
--- a/src/mongo/db/audit.h
+++ b/src/mongo/db/audit.h
@@ -60,7 +60,9 @@ namespace audit {
class CommandInterface {
public:
virtual ~CommandInterface() = default;
- virtual void redactForLogging(mutablebson::Document* cmdObj) const = 0;
+ virtual StringData sensitiveFieldName() const = 0;
+ virtual void snipForLogging(mutablebson::Document* cmdObj) const = 0;
+ virtual StringData getName() const = 0;
virtual NamespaceString ns() const = 0;
virtual bool redactArgs() const = 0;
};
diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp
index aa6a19b840c..5937069e05c 100644
--- a/src/mongo/db/auth/sasl_commands.cpp
+++ b/src/mongo/db/auth/sasl_commands.cpp
@@ -72,7 +72,9 @@ public:
const BSONObj&,
std::vector<Privilege>*) const {}
- void redactForLogging(mutablebson::Document* cmdObj) const override;
+ StringData sensitiveFieldName() const final {
+ return "payload"_sd;
+ }
virtual bool run(OperationContext* opCtx,
const std::string& db,
@@ -100,6 +102,10 @@ public:
const BSONObj&,
std::vector<Privilege>*) const {}
+ StringData sensitiveFieldName() const final {
+ return "payload"_sd;
+ }
+
virtual bool run(OperationContext* opCtx,
const std::string& db,
const BSONObj& cmdObj,
@@ -262,13 +268,6 @@ std::string CmdSaslStart::help() const {
return "First step in a SASL authentication conversation.";
}
-void CmdSaslStart::redactForLogging(mutablebson::Document* cmdObj) const {
- mutablebson::Element element = mutablebson::findFirstChildNamed(cmdObj->root(), "payload");
- if (element.ok()) {
- element.setValueString("xxx").transitional_ignore();
- }
-}
-
bool CmdSaslStart::run(OperationContext* opCtx,
const std::string& db,
const BSONObj& cmdObj,
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 63500fe2af4..a30ad90600c 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -35,6 +35,7 @@
#include <string>
#include <vector>
+#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/bson/timestamp.h"
#include "mongo/db/audit.h"
@@ -142,12 +143,26 @@ void CommandHelpers::auditLogAuthEvent(OperationContext* opCtx,
explicit Hook(const CommandInvocation* invocation, const NamespaceString* nss)
: _invocation(invocation), _nss(nss) {}
- void redactForLogging(mutablebson::Document* cmdObj) const override {
+ void snipForLogging(mutablebson::Document* cmdObj) const override {
if (_invocation) {
- _invocation->definition()->redactForLogging(cmdObj);
+ _invocation->definition()->snipForLogging(cmdObj);
}
}
+ StringData sensitiveFieldName() const override {
+ if (_invocation) {
+ return _invocation->definition()->sensitiveFieldName();
+ }
+ return StringData{};
+ }
+
+ StringData getName() const override {
+ if (!_invocation) {
+ return "Error"_sd;
+ }
+ return _invocation->definition()->getName();
+ }
+
NamespaceString ns() const override {
return *_nss;
}
@@ -404,7 +419,7 @@ void CommandInvocation::checkAuthorization(OperationContext* opCtx,
} catch (const ExceptionFor<ErrorCodes::Unauthorized>&) {
namespace mmb = mutablebson;
mmb::Document cmdToLog(request.body, mmb::Document::kInPlaceDisabled);
- c->redactForLogging(&cmdToLog);
+ c->snipForLogging(&cmdToLog);
auto dbname = request.getDatabase();
uasserted(ErrorCodes::Unauthorized,
str::stream() << "not authorized on " << dbname << " to execute command "
@@ -476,6 +491,21 @@ private:
Command::~Command() = default;
+void Command::snipForLogging(mutablebson::Document* cmdObj) const {
+ StringData sensitiveField = sensitiveFieldName();
+ if (!sensitiveField.empty()) {
+
+ for (mutablebson::Element pwdElement =
+ mutablebson::findFirstChildNamed(cmdObj->root(), sensitiveField);
+ pwdElement.ok();
+ pwdElement =
+ mutablebson::findElementNamed(pwdElement.rightSibling(), sensitiveField)) {
+ uassertStatusOK(pwdElement.setValueString("xxx"));
+ }
+ }
+}
+
+
std::unique_ptr<CommandInvocation> BasicCommand::parse(OperationContext* opCtx,
const OpMsgRequest& request) {
CommandHelpers::uassertNoDocumentSequences(getName(), request);
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index 3dfe96e5cd8..f49c9e3792e 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -341,13 +341,23 @@ public:
/**
* Redacts "cmdObj" in-place to a form suitable for writing to logs.
*
- * The default implementation does nothing.
+ * The default implementation removes the field returned by sensitiveFieldName.
*
* This is NOT used to implement user-configurable redaction of PII. Instead, that is
* implemented via the set of redact() free functions, which are no-ops when log redaction is
* disabled. All PII must pass through one of the redact() overloads before being logged.
*/
- virtual void redactForLogging(mutablebson::Document* cmdObj) const {}
+ virtual void snipForLogging(mutablebson::Document* cmdObj) const;
+
+ /**
+ * Marks a field name in a cmdObj as sensitive.
+ *
+ * The default snipForLogging shall remove these field names. Auditing shall not
+ * include these fields in audit outputs.
+ */
+ virtual StringData sensitiveFieldName() const {
+ return StringData{};
+ }
/**
* Return true if a replica set secondary should go into "recovering"
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index 603e5519b1d..84fff5c50a8 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -850,8 +850,8 @@ public:
return true;
}
- void redactForLogging(mutablebson::Document* cmdObj) const override {
- auth::redactPasswordData(cmdObj->root());
+ StringData sensitiveFieldName() const final {
+ return "pwd"_sd;
}
} cmdCreateUser;
@@ -980,10 +980,9 @@ public:
return true;
}
- void redactForLogging(mutablebson::Document* cmdObj) const override {
- auth::redactPasswordData(cmdObj->root());
+ StringData sensitiveFieldName() const final {
+ return "pwd"_sd;
}
-
} cmdUpdateUser;
class CmdDropUser : public BasicCommand {
diff --git a/src/mongo/db/commands/user_management_commands.h b/src/mongo/db/commands/user_management_commands.h
index 3db786df4ac..cb1b2cec805 100644
--- a/src/mongo/db/commands/user_management_commands.h
+++ b/src/mongo/db/commands/user_management_commands.h
@@ -47,13 +47,6 @@ class OperationContext;
namespace auth {
-/**
- * Looks for a field name "pwd" in the given BSONObj and if found replaces its contents with the
- * string "xxx" so that password data on the command object used in executing a user management
- * command isn't exposed in the logs.
- */
-void redactPasswordData(mutablebson::Element parent);
-
//
// checkAuthorizedTo* methods
//
diff --git a/src/mongo/db/commands/user_management_commands_common.cpp b/src/mongo/db/commands/user_management_commands_common.cpp
index 106bfe8c860..069e7df9b86 100644
--- a/src/mongo/db/commands/user_management_commands_common.cpp
+++ b/src/mongo/db/commands/user_management_commands_common.cpp
@@ -52,15 +52,6 @@
namespace mongo {
namespace auth {
-void redactPasswordData(mutablebson::Element parent) {
- namespace mmb = mutablebson;
- const auto pwdFieldName = "pwd"_sd;
- for (mmb::Element pwdElement = mmb::findFirstChildNamed(parent, pwdFieldName); pwdElement.ok();
- pwdElement = mmb::findElementNamed(pwdElement.rightSibling(), pwdFieldName)) {
- pwdElement.setValueString("xxx").transitional_ignore();
- }
-}
-
Status checkAuthorizedToGrantRoles(AuthorizationSession* authzSession,
const std::vector<RoleName>& roles) {
for (size_t i = 0; i < roles.size(); ++i) {
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index 65f0ec7c963..e6f2882825b 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -310,7 +310,7 @@ private:
return stdx::make_unique<Invocation>(this, request);
}
- void redactForLogging(mutablebson::Document* cmdObj) const final {
+ void snipForLogging(mutablebson::Document* cmdObj) const final {
redactTooLongLog(cmdObj, "documents");
}
@@ -387,7 +387,7 @@ private:
return stdx::make_unique<Invocation>(this, request);
}
- void redactForLogging(mutablebson::Document* cmdObj) const final {
+ void snipForLogging(mutablebson::Document* cmdObj) const final {
redactTooLongLog(cmdObj, "updates");
}
@@ -461,7 +461,7 @@ private:
return stdx::make_unique<Invocation>(this, request);
}
- void redactForLogging(mutablebson::Document* cmdObj) const final {
+ void snipForLogging(mutablebson::Document* cmdObj) const final {
redactTooLongLog(cmdObj, "deletes");
}
diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp
index a8576d29120..7fbc23630b7 100644
--- a/src/mongo/db/curop.cpp
+++ b/src/mongo/db/curop.cpp
@@ -555,7 +555,7 @@ string OpDebug::report(Client* client,
const Command* curCommand = curop.getCommand();
if (curCommand) {
mutablebson::Document cmdToLog(query, mutablebson::Document::kInPlaceDisabled);
- curCommand->redactForLogging(&cmdToLog);
+ curCommand->snipForLogging(&cmdToLog);
s << curCommand->getName() << " ";
s << redact(cmdToLog.getObject());
} else {
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index 956d4d5865b..75d7f8b3071 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -1255,7 +1255,7 @@ DbResponse receivedGetMore(OperationContext* opCtx,
BSONObj ServiceEntryPointCommon::getRedactedCopyForLogging(const Command* command,
const BSONObj& cmdObj) {
mutablebson::Document cmdToLog(cmdObj, mutablebson::Document::kInPlaceDisabled);
- command->redactForLogging(&cmdToLog);
+ command->snipForLogging(&cmdToLog);
BSONObjBuilder bob;
cmdToLog.writeTo(&bob);
return bob.obj();
diff --git a/src/mongo/s/commands/cluster_user_management_commands.cpp b/src/mongo/s/commands/cluster_user_management_commands.cpp
index 76c34c7d63c..1d4d836fc09 100644
--- a/src/mongo/s/commands/cluster_user_management_commands.cpp
+++ b/src/mongo/s/commands/cluster_user_management_commands.cpp
@@ -94,8 +94,8 @@ public:
&result);
}
- void redactForLogging(mutablebson::Document* cmdObj) const override {
- auth::redactPasswordData(cmdObj->root());
+ StringData sensitiveFieldName() const final {
+ return "pwd"_sd;
}
} cmdCreateUser;
@@ -144,8 +144,8 @@ public:
return ok;
}
- void redactForLogging(mutablebson::Document* cmdObj) const override {
- auth::redactPasswordData(cmdObj->root());
+ StringData sensitiveFieldName() const final {
+ return "pwd"_sd;
}
} cmdUpdateUser;