summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShreyas Kalyan <shreyas.kalyan@10gen.com>2022-03-24 15:15:05 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-04-02 01:20:51 +0000
commit26ea3d0d44d791ada367b2c2525ba6ac592ecdcf (patch)
tree38889eceea8bf895f5737ab5a6d04aaa230ed8c6
parentce3e917bfb81b54c3ded7b3f64692f666ddb2162 (diff)
downloadmongo-26ea3d0d44d791ada367b2c2525ba6ac592ecdcf.tar.gz
SERVER-64294 Enhance redact to always redact BinData 6
-rw-r--r--src/mongo/bson/bsonobj.cpp36
-rw-r--r--src/mongo/bson/bsonobj.h2
-rw-r--r--src/mongo/logv2/SConscript12
-rw-r--r--src/mongo/logv2/log_util.cpp10
-rw-r--r--src/mongo/logv2/log_util.h11
-rw-r--r--src/mongo/logv2/logv2_options.cpp71
-rw-r--r--src/mongo/logv2/logv2_options.idl41
-rw-r--r--src/mongo/logv2/redaction.cpp8
-rw-r--r--src/mongo/logv2/redaction_test.cpp27
9 files changed, 206 insertions, 12 deletions
diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp
index 73f824735ed..7b5fa7dae04 100644
--- a/src/mongo/bson/bsonobj.cpp
+++ b/src/mongo/bson/bsonobj.cpp
@@ -27,6 +27,7 @@
* it in the license file.
*/
+#include "mongo/bson/bsonelement.h"
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault
#include "mongo/db/jsobj.h"
@@ -137,25 +138,42 @@ BSONObj BSONObj::getOwned(const BSONObj& obj) {
return obj.getOwned();
}
-BSONObj BSONObj::redact() const {
+BSONObj BSONObj::redact(bool onlyEncryptedFields) const {
_validateUnownedSize(objsize());
// Helper to get an "internal function" to be able to do recursion
struct redactor {
- void operator()(BSONObjBuilder& builder, const BSONObj& obj, bool appendMask) {
+ void appendRedactedElem(BSONObjBuilder& builder, const BSONElement& e, bool appendMask) {
+ if (appendMask) {
+ builder.append(e.fieldNameStringData(), "###"_sd);
+ } else {
+ builder.appendNull(e.fieldNameStringData());
+ }
+ }
+
+ void operator()(BSONObjBuilder& builder,
+ const BSONObj& obj,
+ bool appendMask,
+ bool onlyEncryptedFields) {
for (BSONElement e : obj) {
if (e.type() == Object) {
BSONObjBuilder subBuilder = builder.subobjStart(e.fieldNameStringData());
- operator()(subBuilder, e.Obj(), appendMask);
+ operator()(subBuilder, e.Obj(), appendMask, onlyEncryptedFields);
subBuilder.done();
} else if (e.type() == Array) {
BSONObjBuilder subBuilder = builder.subarrayStart(e.fieldNameStringData());
- operator()(subBuilder, e.Obj(), appendMask);
+ operator()(subBuilder, e.Obj(), appendMask, onlyEncryptedFields);
subBuilder.done();
- } else if (appendMask) {
- builder.append(e.fieldNameStringData(), "###"_sd);
} else {
- builder.appendNull(e.fieldNameStringData());
+ if (onlyEncryptedFields) {
+ if (e.type() == BinData && e.binDataType() == BinDataType::Encrypt) {
+ appendRedactedElem(builder, e, appendMask);
+ } else {
+ builder.append(e);
+ }
+ } else {
+ appendRedactedElem(builder, e, appendMask);
+ }
}
}
}
@@ -163,7 +181,7 @@ BSONObj BSONObj::redact() const {
try {
BSONObjBuilder builder;
- redactor()(builder, *this, /*appendMask=*/true);
+ redactor()(builder, *this, /*appendMask=*/true, onlyEncryptedFields);
return builder.obj();
} catch (const ExceptionFor<ErrorCodes::BSONObjectTooLarge>&) {
}
@@ -173,7 +191,7 @@ BSONObj BSONObj::redact() const {
// we use BSONType::jstNull, which ensures the redacted object will not be larger than the
// original.
BSONObjBuilder builder;
- redactor()(builder, *this, /*appendMask=*/false);
+ redactor()(builder, *this, /*appendMask=*/false, onlyEncryptedFields);
return builder.obj();
}
diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h
index 2f1e511704d..a5270adfd25 100644
--- a/src/mongo/bson/bsonobj.h
+++ b/src/mongo/bson/bsonobj.h
@@ -267,7 +267,7 @@ public:
/**
* @return a new full (and owned) redacted copy of the object.
*/
- BSONObj redact() const;
+ BSONObj redact(bool onlyEncryptedFields = false) const;
/**
* Readable representation of a BSON object in an extended JSON-style notation.
diff --git a/src/mongo/logv2/SConscript b/src/mongo/logv2/SConscript
index 2ceefd5b03c..05351e1a2fe 100644
--- a/src/mongo/logv2/SConscript
+++ b/src/mongo/logv2/SConscript
@@ -27,3 +27,15 @@ env.Benchmark(
'$BUILD_DIR/mongo/base',
],
)
+
+env.Library(
+ target='logv2_options',
+ source=[
+ 'logv2_options.cpp',
+ 'logv2_options.idl',
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/idl/server_parameter',
+ ],
+)
diff --git a/src/mongo/logv2/log_util.cpp b/src/mongo/logv2/log_util.cpp
index c44ff5988af..8013d8a328e 100644
--- a/src/mongo/logv2/log_util.cpp
+++ b/src/mongo/logv2/log_util.cpp
@@ -42,6 +42,7 @@ namespace mongo::logv2 {
namespace {
AtomicWord<bool> redactionEnabled{false};
+AtomicWord<bool> redactBinDataEncrypt{true};
std::map<StringData, LogRotateCallback> logRotateCallbacks;
} // namespace
@@ -101,4 +102,13 @@ bool shouldRedactLogs() {
void setShouldRedactLogs(bool enabled) {
redactionEnabled.store(enabled);
}
+
+bool shouldRedactBinDataEncrypt() {
+ return redactBinDataEncrypt.loadRelaxed();
+}
+
+void setShouldRedactBinDataEncrypt(bool enabled) {
+ redactBinDataEncrypt.store(enabled);
+}
+
} // namespace mongo::logv2
diff --git a/src/mongo/logv2/log_util.h b/src/mongo/logv2/log_util.h
index e1b6c2c34e0..09505e02d94 100644
--- a/src/mongo/logv2/log_util.h
+++ b/src/mongo/logv2/log_util.h
@@ -90,4 +90,15 @@ bool shouldRedactLogs();
* Set the 'redact' mode of the server.
*/
void setShouldRedactLogs(bool enabled);
+
+/**
+ * Returns true if the BinData Encrypt should be redacted. Default true.
+ */
+bool shouldRedactBinDataEncrypt();
+
+/**
+ * Sets the redact mode of the bin data encrypt field.
+ */
+void setShouldRedactBinDataEncrypt(bool enabled);
+
} // namespace mongo::logv2
diff --git a/src/mongo/logv2/logv2_options.cpp b/src/mongo/logv2/logv2_options.cpp
new file mode 100644
index 00000000000..05b786e8878
--- /dev/null
+++ b/src/mongo/logv2/logv2_options.cpp
@@ -0,0 +1,71 @@
+/**
+ * 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.
+ */
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/base/status.h"
+#include "mongo/logv2/log_util.h"
+#include "mongo/logv2/logv2_options_gen.h"
+#include "mongo/util/options_parser/option_section.h"
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+void RedactEncryptedFields::append(OperationContext* opCtx,
+ BSONObjBuilder& b,
+ const std::string& name) {
+ b << name << logv2::shouldRedactBinDataEncrypt();
+}
+
+Status RedactEncryptedFields::set(const BSONElement& newValueElement) {
+ bool newVal;
+ if (!newValueElement.coerce(&newVal)) {
+ return {ErrorCodes::BadValue,
+ str::stream() << "Invalid value for redactEncryptedFields: " << newValueElement};
+ }
+
+ logv2::setShouldRedactBinDataEncrypt(newVal);
+ return Status::OK();
+}
+
+Status RedactEncryptedFields::setFromString(const std::string& str) {
+ if (str == "true" || str == "1") {
+ logv2::setShouldRedactBinDataEncrypt(true);
+ } else if (str == "false" || str == "0") {
+ logv2::setShouldRedactBinDataEncrypt(false);
+ } else {
+ return {ErrorCodes::BadValue,
+ str::stream() << "Invalid value for redactEncryptedFields: " << str};
+ }
+ return Status::OK();
+}
+
+} // namespace mongo
diff --git a/src/mongo/logv2/logv2_options.idl b/src/mongo/logv2/logv2_options.idl
new file mode 100644
index 00000000000..f385e0c5f07
--- /dev/null
+++ b/src/mongo/logv2/logv2_options.idl
@@ -0,0 +1,41 @@
+# 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.
+#
+
+global:
+ cpp_namespace: "mongo"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+server_parameters:
+ redactEncryptedFields:
+ description: "Enables redaction of encrypted fields in BSON Objects, defaults to on"
+ set_at: [ startup, runtime ]
+ cpp_class:
+ name: RedactEncryptedFields
+ override_set: true
diff --git a/src/mongo/logv2/redaction.cpp b/src/mongo/logv2/redaction.cpp
index 239e091aead..0b143ba39ae 100644
--- a/src/mongo/logv2/redaction.cpp
+++ b/src/mongo/logv2/redaction.cpp
@@ -36,6 +36,7 @@
#include "mongo/base/status.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/logv2/log_util.h"
+#include "mongo/logv2/logv2_options_gen.h"
#include "mongo/util/assert_util.h"
namespace mongo {
@@ -48,10 +49,13 @@ constexpr auto kRedactionDefaultMask = "###"_sd;
BSONObj redact(const BSONObj& objectToRedact) {
if (!logv2::shouldRedactLogs()) {
- return objectToRedact;
+ if (!logv2::shouldRedactBinDataEncrypt()) {
+ return objectToRedact;
+ }
+ return objectToRedact.redact(true /* onlyEncryptedFields */);
}
- return objectToRedact.redact();
+ return objectToRedact.redact(false /* onlyEncryptedFields */);
}
StringData redact(StringData stringToRedact) {
diff --git a/src/mongo/logv2/redaction_test.cpp b/src/mongo/logv2/redaction_test.cpp
index bc22f60b4ae..dda840a4681 100644
--- a/src/mongo/logv2/redaction_test.cpp
+++ b/src/mongo/logv2/redaction_test.cpp
@@ -31,6 +31,9 @@
#include "mongo/logv2/redaction.h"
+#include "mongo/base/error_extra_info.h"
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/bson/bsontypes.h"
#include "mongo/db/jsobj.h"
#include "mongo/logv2/log_util.h"
#include "mongo/unittest/unittest.h"
@@ -122,6 +125,30 @@ TEST(RedactBSONTest, BasicBSON) {
"{ a: \"###\", a: \"###\" }")});
}
+unsigned char zero[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+TEST(RedactEncryptedStringTest, BasicStrings) {
+ logv2::setShouldRedactBinDataEncrypt(true);
+ logv2::setShouldRedactLogs(false);
+
+ BSONObjBuilder builder{};
+ builder.appendBinData("type6", sizeof(zero), BinDataType::Encrypt, zero);
+ builder.append("string", "string");
+ {
+ BSONObjBuilder sub(builder.subobjStart("nestedobj"));
+ sub.appendBinData("subobj", sizeof(zero), BinDataType::Encrypt, zero);
+ }
+ BSONObj obj = builder.done();
+
+ std::cout << "This is obj: " << obj.toString() << std::endl;
+
+ auto redactedStr = R"({ type6: "###", string: "string", nestedobj: { subobj: "###" } })";
+ ASSERT_EQ(redact(obj).toString(), redactedStr);
+
+ logv2::setShouldRedactBinDataEncrypt(false);
+ ASSERT_EQ(redact(obj).toString(), obj.toString());
+}
+
void testBSONCases(std::vector<BSONStringPair>& testCases) {
for (auto m : testCases) {
ASSERT_EQ(redact(m.first).toString(), m.second);