summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/auth/auth_pass_prompt.js2
-rw-r--r--jstests/auth/speculative-sasl-start.js16
-rw-r--r--src/mongo/db/audit.cpp300
-rw-r--r--src/mongo/db/audit.h57
-rw-r--r--src/mongo/db/auth/authentication_session.cpp32
-rw-r--r--src/mongo/db/auth/sasl_commands.cpp44
-rw-r--r--src/mongo/db/auth/sasl_mechanism_registry.h7
7 files changed, 261 insertions, 197 deletions
diff --git a/jstests/auth/auth_pass_prompt.js b/jstests/auth/auth_pass_prompt.js
index 13f38b3a989..11dccae04d1 100644
--- a/jstests/auth/auth_pass_prompt.js
+++ b/jstests/auth/auth_pass_prompt.js
@@ -22,7 +22,7 @@ if (!_isWindows()) {
assert.soon(() => {
const output = rawMongoProgramOutput();
- return output.includes("Enter password:") && output.includes("Successful authentication");
+ return output.includes("Enter password:") && output.includes("Authentication succeeded");
});
MongoRunner.stopMongod(conn);
diff --git a/jstests/auth/speculative-sasl-start.js b/jstests/auth/speculative-sasl-start.js
index d0206fd099e..eadb501f09a 100644
--- a/jstests/auth/speculative-sasl-start.js
+++ b/jstests/auth/speculative-sasl-start.js
@@ -83,35 +83,35 @@ const speculativeSHA1AuthFailedAttrs = {
"speculative": true,
"principalName": "admin",
"authenticationDatabase": "admin",
- "result": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
+ "error": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
};
const sha1AuthFailedAttrs = {
"mechanism": "SCRAM-SHA-1",
"speculative": false,
"principalName": "admin",
"authenticationDatabase": "admin",
- "result": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
+ "error": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
};
const speculativeSHA256AuthFailedAttrs = {
"mechanism": "SCRAM-SHA-256",
"speculative": true,
"principalName": "admin",
"authenticationDatabase": "admin",
- "result": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
+ "error": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
};
const sha256AuthFailedAttrs = {
"mechanism": "SCRAM-SHA-256",
"speculative": false,
"principalName": "admin",
"authenticationDatabase": "admin",
- "result": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
+ "error": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
};
const speculativeSHA256MechUnavailableAttrs = {
"mechanism": "SCRAM-SHA-256",
"speculative": true,
"principalName": "admin",
"authenticationDatabase": "admin",
- "result":
+ "error":
"MechanismUnavailable: Unable to use SCRAM-SHA-256 based authentication for user without any SCRAM-SHA-256 credentials registered"
};
const sha256MechUnavailableAttrs = {
@@ -119,7 +119,7 @@ const sha256MechUnavailableAttrs = {
"speculative": false,
"principalName": "admin",
"authenticationDatabase": "admin",
- "result":
+ "error":
"MechanismUnavailable: Unable to use SCRAM-SHA-256 based authentication for user without any SCRAM-SHA-256 credentials registered"
};
const speculativeClusterAuthFailedAttrs = {
@@ -127,14 +127,14 @@ const speculativeClusterAuthFailedAttrs = {
"speculative": true,
"principalName": "__system",
"authenticationDatabase": "local",
- "result": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
+ "error": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
};
const clusterAuthFailedAttrs = {
"mechanism": "SCRAM-SHA-256",
"speculative": false,
"principalName": "__system",
"authenticationDatabase": "local",
- "result": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
+ "error": "AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"
};
admin.setLogLevel(5);
// Invalid password should never connect regardless of speculative auth.
diff --git a/src/mongo/db/audit.cpp b/src/mongo/db/audit.cpp
index ab5aed971ab..60e826e91fb 100644
--- a/src/mongo/db/audit.cpp
+++ b/src/mongo/db/audit.cpp
@@ -29,190 +29,174 @@
#include "mongo/db/audit.h"
-#if !MONGO_ENTERPRISE_AUDIT
+namespace mongo {
+namespace audit {
-mongo::audit::ImpersonatedClientAttrs::ImpersonatedClientAttrs(Client* client) {}
-
-void mongo::audit::logAuthentication(Client* client,
- StringData mechanism,
- const UserName& user,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logCommandAuthzCheck(Client* client,
- const OpMsgRequest& cmdObj,
- const CommandInterface& command,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logDeleteAuthzCheck(Client* client,
- const NamespaceString& ns,
- const BSONObj& pattern,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logGetMoreAuthzCheck(Client* client,
- const NamespaceString& ns,
- long long cursorId,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logInsertAuthzCheck(Client* client,
- const NamespaceString& ns,
- const BSONObj& insertedObj,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logKillCursorsAuthzCheck(Client* client,
- const NamespaceString& ns,
- long long cursorId,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logQueryAuthzCheck(Client* client,
- const NamespaceString& ns,
- const BSONObj& query,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logUpdateAuthzCheck(Client* client,
- const NamespaceString& ns,
- const BSONObj& query,
- const write_ops::UpdateModification& update,
- bool isUpsert,
- bool isMulti,
- ErrorCodes::Error result) {}
-
-void mongo::audit::logCreateUser(Client* client,
- const UserName& username,
- bool password,
- const BSONObj* customData,
- const std::vector<RoleName>& roles,
- const boost::optional<BSONArray>& restrictions) {}
-
-void mongo::audit::logDropUser(Client* client, const UserName& username) {}
-
-void mongo::audit::logDropAllUsersFromDatabase(Client* client, StringData dbname) {}
-
-void mongo::audit::logUpdateUser(Client* client,
- const UserName& username,
- bool password,
- const BSONObj* customData,
- const std::vector<RoleName>* roles,
- const boost::optional<BSONArray>& restrictions) {}
-
-void mongo::audit::logGrantRolesToUser(Client* client,
- const UserName& username,
- const std::vector<RoleName>& roles) {}
-
-void mongo::audit::logRevokeRolesFromUser(Client* client,
- const UserName& username,
- const std::vector<RoleName>& roles) {}
-
-void mongo::audit::logCreateRole(Client* client,
- const RoleName& role,
- const std::vector<RoleName>& roles,
- const PrivilegeVector& privileges,
- const boost::optional<BSONArray>& restrictions) {}
+#if !MONGO_ENTERPRISE_AUDIT
-void mongo::audit::logUpdateRole(Client* client,
+ImpersonatedClientAttrs::ImpersonatedClientAttrs(Client* client) {}
+
+void logAuthentication(Client*, const AuthenticateEvent&) {}
+
+void logCommandAuthzCheck(Client* client,
+ const OpMsgRequest& cmdObj,
+ const CommandInterface& command,
+ ErrorCodes::Error result) {}
+
+void logDeleteAuthzCheck(Client* client,
+ const NamespaceString& ns,
+ const BSONObj& pattern,
+ ErrorCodes::Error result) {}
+
+void logGetMoreAuthzCheck(Client* client,
+ const NamespaceString& ns,
+ long long cursorId,
+ ErrorCodes::Error result) {}
+
+void logInsertAuthzCheck(Client* client,
+ const NamespaceString& ns,
+ const BSONObj& insertedObj,
+ ErrorCodes::Error result) {}
+
+void logKillCursorsAuthzCheck(Client* client,
+ const NamespaceString& ns,
+ long long cursorId,
+ ErrorCodes::Error result) {}
+
+void logQueryAuthzCheck(Client* client,
+ const NamespaceString& ns,
+ const BSONObj& query,
+ ErrorCodes::Error result) {}
+
+void logUpdateAuthzCheck(Client* client,
+ const NamespaceString& ns,
+ const BSONObj& query,
+ const write_ops::UpdateModification& update,
+ bool isUpsert,
+ bool isMulti,
+ ErrorCodes::Error result) {}
+
+void logCreateUser(Client* client,
+ const UserName& username,
+ bool password,
+ const BSONObj* customData,
+ const std::vector<RoleName>& roles,
+ const boost::optional<BSONArray>& restrictions) {}
+
+void logDropUser(Client* client, const UserName& username) {}
+
+void logDropAllUsersFromDatabase(Client* client, StringData dbname) {}
+
+void logUpdateUser(Client* client,
+ const UserName& username,
+ bool password,
+ const BSONObj* customData,
+ const std::vector<RoleName>* roles,
+ const boost::optional<BSONArray>& restrictions) {}
+
+void logGrantRolesToUser(Client* client,
+ const UserName& username,
+ const std::vector<RoleName>& roles) {}
+
+void logRevokeRolesFromUser(Client* client,
+ const UserName& username,
+ const std::vector<RoleName>& roles) {}
+
+void logCreateRole(Client* client,
+ const RoleName& role,
+ const std::vector<RoleName>& roles,
+ const PrivilegeVector& privileges,
+ const boost::optional<BSONArray>& restrictions) {}
+
+void logUpdateRole(Client* client,
+ const RoleName& role,
+ const std::vector<RoleName>* roles,
+ const PrivilegeVector* privileges,
+ const boost::optional<BSONArray>& restrictions) {}
+
+void logDropRole(Client* client, const RoleName& role) {}
+
+void logDropAllRolesFromDatabase(Client* client, StringData dbname) {}
+
+void logGrantRolesToRole(Client* client, const RoleName& role, const std::vector<RoleName>& roles) {
+}
+
+void logRevokeRolesFromRole(Client* client,
+ const RoleName& role,
+ const std::vector<RoleName>& roles) {}
+
+void logGrantPrivilegesToRole(Client* client,
+ const RoleName& role,
+ const PrivilegeVector& privileges) {}
+
+void logRevokePrivilegesFromRole(Client* client,
const RoleName& role,
- const std::vector<RoleName>* roles,
- const PrivilegeVector* privileges,
- const boost::optional<BSONArray>& restrictions) {}
-
-void mongo::audit::logDropRole(Client* client, const RoleName& role) {}
-
-void mongo::audit::logDropAllRolesFromDatabase(Client* client, StringData dbname) {}
+ const PrivilegeVector& privileges) {}
-void mongo::audit::logGrantRolesToRole(Client* client,
- const RoleName& role,
- const std::vector<RoleName>& roles) {}
+void logReplSetReconfig(Client* client, const BSONObj* oldConfig, const BSONObj* newConfig) {}
-void mongo::audit::logRevokeRolesFromRole(Client* client,
- const RoleName& role,
- const std::vector<RoleName>& roles) {}
+void logApplicationMessage(Client* client, StringData msg) {}
-void mongo::audit::logGrantPrivilegesToRole(Client* client,
- const RoleName& role,
- const PrivilegeVector& privileges) {}
+void logStartupOptions(Client* client, const BSONObj& startupOptions) {}
-void mongo::audit::logRevokePrivilegesFromRole(Client* client,
- const RoleName& role,
- const PrivilegeVector& privileges) {}
+void logShutdown(Client* client) {}
-void mongo::audit::logReplSetReconfig(Client* client,
- const BSONObj* oldConfig,
- const BSONObj* newConfig) {}
+void logLogout(Client* client,
+ StringData reason,
+ const BSONArray& initialUsers,
+ const BSONArray& updatedUsers) {}
-void mongo::audit::logApplicationMessage(Client* client, StringData msg) {}
+void logCreateIndex(Client* client,
+ const BSONObj* indexSpec,
+ StringData indexname,
+ const NamespaceString& nsname) {}
-void mongo::audit::logStartupOptions(Client* client, const BSONObj& startupOptions) {}
+void logCreateCollection(Client* client, const NamespaceString& nsname) {}
-void mongo::audit::logShutdown(Client* client) {}
+void logCreateView(Client* client,
+ const NamespaceString& nsname,
+ StringData viewOn,
+ BSONArray pipeline,
+ ErrorCodes::Error code) {}
-void mongo::audit::logLogout(Client* client,
- StringData reason,
- const BSONArray& initialUsers,
- const BSONArray& updatedUsers) {}
+void logImportCollection(Client* client, const NamespaceString& nsname) {}
-void mongo::audit::logCreateIndex(Client* client,
- const BSONObj* indexSpec,
- StringData indexname,
- const NamespaceString& nsname) {}
+void logCreateDatabase(Client* client, StringData dbname) {}
-void mongo::audit::logCreateCollection(Client* client, const NamespaceString& nsname) {}
-void mongo::audit::logCreateView(Client* client,
- const NamespaceString& nsname,
- StringData viewOn,
- BSONArray pipeline,
- ErrorCodes::Error code) {}
+void logDropIndex(Client* client, StringData indexname, const NamespaceString& nsname) {}
-void mongo::audit::logImportCollection(Client* client, const NamespaceString& nsname) {}
+void logDropCollection(Client* client, const NamespaceString& nsname) {}
-void mongo::audit::logCreateDatabase(Client* client, StringData dbname) {}
+void logDropView(Client* client,
+ const NamespaceString& nsname,
+ StringData viewOn,
+ const std::vector<BSONObj>& pipeline,
+ ErrorCodes::Error code) {}
+void logDropDatabase(Client* client, StringData dbname) {}
-void mongo::audit::logDropIndex(Client* client,
- StringData indexname,
- const NamespaceString& nsname) {}
+void logRenameCollection(Client* client,
+ const NamespaceString& source,
+ const NamespaceString& target) {}
-void mongo::audit::logDropCollection(Client* client, const NamespaceString& nsname) {}
+void logEnableSharding(Client* client, StringData dbname) {}
-void mongo::audit::logDropView(Client* client,
- const NamespaceString& nsname,
- StringData viewOn,
- const std::vector<BSONObj>& pipeline,
- ErrorCodes::Error code) {}
+void logAddShard(Client* client, StringData name, const std::string& servers, long long maxSize) {}
-void mongo::audit::logDropDatabase(Client* client, StringData dbname) {}
+void logRemoveShard(Client* client, StringData shardname) {}
-void mongo::audit::logRenameCollection(Client* client,
- const NamespaceString& source,
- const NamespaceString& target) {}
+void logShardCollection(Client* client, StringData ns, const BSONObj& keyPattern, bool unique) {}
-void mongo::audit::logEnableSharding(Client* client, StringData dbname) {}
+void logRefineCollectionShardKey(Client* client, StringData ns, const BSONObj& keyPattern) {}
-void mongo::audit::logAddShard(Client* client,
- StringData name,
- const std::string& servers,
- long long maxSize) {}
+void logInsertOperation(Client* client, const NamespaceString& nss, const BSONObj& doc) {}
-void mongo::audit::logRemoveShard(Client* client, StringData shardname) {}
+void logUpdateOperation(Client* client, const NamespaceString& nss, const BSONObj& doc) {}
-void mongo::audit::logShardCollection(Client* client,
- StringData ns,
- const BSONObj& keyPattern,
- bool unique) {}
-
-void mongo::audit::logRefineCollectionShardKey(Client* client,
- StringData ns,
- const BSONObj& keyPattern) {}
-
-void mongo::audit::logInsertOperation(Client* client,
- const NamespaceString& nss,
- const BSONObj& doc) {}
-
-void mongo::audit::logUpdateOperation(Client* client,
- const NamespaceString& nss,
- const BSONObj& doc) {}
-
-void mongo::audit::logRemoveOperation(Client* client,
- const NamespaceString& nss,
- const BSONObj& doc) {}
+void logRemoveOperation(Client* client, const NamespaceString& nss, const BSONObj& doc) {}
#endif
+
+} // namespace audit
+} // namespace mongo
diff --git a/src/mongo/db/audit.h b/src/mongo/db/audit.h
index 1fb5a06f254..5f0c3e329db 100644
--- a/src/mongo/db/audit.h
+++ b/src/mongo/db/audit.h
@@ -39,11 +39,13 @@
#include "mongo/db/auth/user.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/rpc/op_msg.h"
+#include "mongo/util/functional.h"
namespace mongo {
class AuthorizationSession;
class BSONObj;
+class BSONObjBuilder;
class Client;
class NamespaceString;
class OperationContext;
@@ -86,12 +88,59 @@ public:
};
/**
+ * AuthenticateEvent is a opaque view into a finished authentication handshake.
+ *
+ * This object is only valid within its initial stack context.
+ */
+class AuthenticateEvent {
+public:
+ using Appender = unique_function<void(BSONObjBuilder*)>;
+
+ AuthenticateEvent(StringData mechanism,
+ StringData db,
+ StringData user,
+ Appender appender,
+ ErrorCodes::Error result)
+ : _mechanism(mechanism),
+ _db(db),
+ _user(user),
+ _appender(std::move(appender)),
+ _result(result) {}
+
+ StringData getMechanism() const {
+ return _mechanism;
+ }
+
+ StringData getDatabase() const {
+ return _db;
+ }
+
+ StringData getUser() const {
+ return _user;
+ }
+
+ ErrorCodes::Error getResult() const {
+ return _result;
+ }
+
+ void appendExtraInfo(BSONObjBuilder* bob) const {
+ _appender(bob);
+ }
+
+private:
+ StringData _mechanism;
+ StringData _db;
+ StringData _user;
+
+ Appender _appender;
+
+ ErrorCodes::Error _result;
+};
+
+/**
* Logs the result of an authentication attempt.
*/
-void logAuthentication(Client* client,
- StringData mechanism,
- const UserName& user,
- ErrorCodes::Error result);
+void logAuthentication(Client* client, const AuthenticateEvent& event);
//
// Authorization (authz) logging functions.
diff --git a/src/mongo/db/auth/authentication_session.cpp b/src/mongo/db/auth/authentication_session.cpp
index 45b70cacd68..c0fa8a8b898 100644
--- a/src/mongo/db/auth/authentication_session.cpp
+++ b/src/mongo/db/auth/authentication_session.cpp
@@ -91,6 +91,14 @@ auto registerer = ServiceContext::ConstructorActionRegisterer{
"AuthenticationClientObserver", [](ServiceContext* service) {
service->registerClientObserver(std::make_unique<AuthenticationClientObserver>());
}};
+
+auto makeAppender(ServerMechanismBase* mech) {
+ return [mech](BSONObjBuilder* bob) {
+ if (mech) {
+ mech->appendExtraInfo(bob);
+ }
+ };
+}
} // namespace
AuthenticationSession::StepGuard::StepGuard(OperationContext* opCtx, StepType currentStep)
@@ -197,10 +205,12 @@ void AuthenticationSession::_verifyUserNameFromSaslSupportedMechanisms(const Use
// Reset _ssmUserName since we have found a conflict.
auto ssmUserName = std::exchange(_ssmUserName, {});
- audit::logAuthentication(_client,
- auth::kSaslSupportedMechanisms,
- std::move(ssmUserName),
- ErrorCodes::AuthenticationAbandoned);
+ auto event = audit::AuthenticateEvent(auth::kSaslSupportedMechanisms,
+ ssmUserName.getDB(),
+ ssmUserName.getUser(),
+ makeAppender(_mech.get()),
+ ErrorCodes::AuthenticationAbandoned);
+ audit::logAuthentication(_client, event);
}
}
@@ -264,7 +274,12 @@ void AuthenticationSession::markSuccessful() {
_mechCounter->incSpeculativeAuthenticateSuccessful();
}
- audit::logAuthentication(_client, _mechName, _userName, ErrorCodes::OK);
+ auto event = audit::AuthenticateEvent(_mechName,
+ _userName.getDB(),
+ _userName.getUser(),
+ makeAppender(_mech.get()),
+ ErrorCodes::OK);
+ audit::logAuthentication(_client, event);
LOGV2_DEBUG(5286306,
kDiagnosticLogLevel,
@@ -280,7 +295,12 @@ void AuthenticationSession::markSuccessful() {
void AuthenticationSession::markFailed(const Status& status) {
_finish();
- audit::logAuthentication(_client, _mechName, _userName, status.code());
+ auto event = audit::AuthenticateEvent(_mechName,
+ _userName.getDB(),
+ _userName.getUser(),
+ makeAppender(_mech.get()),
+ status.code());
+ audit::logAuthentication(_client, event);
LOGV2_DEBUG(5286307,
kDiagnosticLogLevel,
diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp
index 2c997e12c85..519f512ae90 100644
--- a/src/mongo/db/auth/sasl_commands.cpp
+++ b/src/mongo/db/auth/sasl_commands.cpp
@@ -50,6 +50,7 @@
#include "mongo/db/commands.h"
#include "mongo/db/commands/authentication_commands.h"
#include "mongo/db/server_options.h"
+#include "mongo/logv2/attribute_storage.h"
#include "mongo/logv2/log.h"
#include "mongo/util/base64.h"
#include "mongo/util/sequence_util.h"
@@ -143,24 +144,33 @@ SaslReply doSaslStep(OperationContext* opCtx,
// Passing in a payload and extracting a responsePayload
StatusWith<std::string> swResponse = mechanism.step(opCtx, payload.get());
+ auto makeLogAttributes = [&]() {
+ logv2::DynamicAttributes attrs;
+ attrs.add("mechanism", mechanism.mechanismName());
+ attrs.add("speculative", session->isSpeculative());
+ attrs.add("principalName", mechanism.getPrincipalName());
+ attrs.add("authenticationDatabase", mechanism.getAuthenticationDatabase());
+ attrs.addDeepCopy("remote", opCtx->getClient()->getRemote().toString());
+ {
+ auto bob = BSONObjBuilder();
+ mechanism.appendExtraInfo(&bob);
+ attrs.add("extraInfo", bob.obj());
+ }
+
+ return attrs;
+ };
+
if (!swResponse.isOK()) {
int64_t dLevel = 0;
if (session->isSpeculative() &&
(swResponse.getStatus() == ErrorCodes::MechanismUnavailable)) {
dLevel = 5;
}
- LOGV2_DEBUG(20249,
- dLevel,
- "SASL {mechanism} authentication failed for "
- "{principalName} on {authenticationDatabase} from client "
- "{client} ; {result}",
- "Authentication failed",
- "mechanism"_attr = mechanism.mechanismName(),
- "speculative"_attr = session->isSpeculative(),
- "principalName"_attr = mechanism.getPrincipalName(),
- "authenticationDatabase"_attr = mechanism.getAuthenticationDatabase(),
- "remote"_attr = opCtx->getClient()->getRemote(),
- "result"_attr = redact(swResponse.getStatus()));
+
+ auto attrs = makeLogAttributes();
+ auto errorString = redact(swResponse.getStatus());
+ attrs.add("error", errorString);
+ LOGV2_DEBUG(20249, dLevel, "Authentication failed", attrs);
sleepmillis(saslGlobalParams.authFailedDelay.load());
// All the client needs to know is that authentication has failed.
@@ -173,14 +183,8 @@ SaslReply doSaslStep(OperationContext* opCtx,
AuthorizationSession::get(opCtx->getClient())->addAndAuthorizeUser(opCtx, userName));
if (!serverGlobalParams.quiet.load()) {
- LOGV2(20250,
- "Successfully authenticated as principal {principalName} on "
- "{authenticationDatabase} from client {client} with mechanism {mechanism}",
- "Successful authentication",
- "mechanism"_attr = mechanism.mechanismName(),
- "principalName"_attr = mechanism.getPrincipalName(),
- "authenticationDatabase"_attr = mechanism.getAuthenticationDatabase(),
- "remote"_attr = opCtx->getClient()->session()->remote());
+ auto attrs = makeLogAttributes();
+ LOGV2(20250, "Authentication succeeded", attrs);
}
session->markSuccessful();
diff --git a/src/mongo/db/auth/sasl_mechanism_registry.h b/src/mongo/db/auth/sasl_mechanism_registry.h
index f23b0c5ac83..cceff146750 100644
--- a/src/mongo/db/auth/sasl_mechanism_registry.h
+++ b/src/mongo/db/auth/sasl_mechanism_registry.h
@@ -43,6 +43,7 @@
namespace mongo {
class User;
+class BSONObjBuilder;
/**
* The set of attributes SASL mechanisms may possess.
@@ -145,6 +146,12 @@ public:
}
/**
+ * Appends mechanism specific info in BSON form. The schema of this BSON will vary by mechanism
+ * implementation, thus this info is entirely diagnostic/for records.
+ */
+ virtual void appendExtraInfo(BSONObjBuilder*) const {}
+
+ /**
* Standard method in mongodb for determining if "authenticatedUser" may act as "requestedUser."
*
* The standard rule in MongoDB is simple. The authenticated user name must be the same as the