diff options
author | Spencer Jackson <spencer.jackson@mongodb.com> | 2018-08-22 15:25:52 -0400 |
---|---|---|
committer | Spencer Jackson <spencer.jackson@mongodb.com> | 2018-09-17 17:21:40 -0400 |
commit | e78dc4e8cf32da88062090410ab8617f604633c9 (patch) | |
tree | df238a81200a01b354ebad2ad9ecd2dc7c9bedb3 | |
parent | f99914d14b76718f1fef879cfaabe23c0c8f0857 (diff) | |
download | mongo-e78dc4e8cf32da88062090410ab8617f604633c9.tar.gz |
SERVER-36606: Allow commands to expose names of sensitive fields
-rw-r--r-- | src/mongo/db/audit.h | 4 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_commands.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/commands.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/commands.h | 14 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.h | 7 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands_common.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands/write_commands.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/curop.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_common.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_user_management_commands.cpp | 8 |
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; |