summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorAdam Cooper <adam.cooper@mongodb.com>2020-08-14 13:46:35 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-08-14 21:01:59 +0000
commit24dd72daae9e4cf59ad51910058bc111f20edbff (patch)
treef019be38662bc5a86c68ac1f4a006f479a408647 /src/mongo
parent6b1a0403f17b688940eb9d86f41d95bdd943d3f4 (diff)
downloadmongo-24dd72daae9e4cf59ad51910058bc111f20edbff.tar.gz
SERVER-48693 Add network counter for cluster authentication
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/client/authenticate.h1
-rw-r--r--src/mongo/db/auth/sasl_commands.cpp32
-rw-r--r--src/mongo/db/auth/sasl_mechanism_registry.h9
-rw-r--r--src/mongo/db/commands/authentication_commands.cpp65
-rw-r--r--src/mongo/db/stats/counters.cpp28
-rw-r--r--src/mongo/db/stats/counters.h7
6 files changed, 100 insertions, 42 deletions
diff --git a/src/mongo/client/authenticate.h b/src/mongo/client/authenticate.h
index ee50f8c8ade..44d90eae612 100644
--- a/src/mongo/client/authenticate.h
+++ b/src/mongo/client/authenticate.h
@@ -72,6 +72,7 @@ constexpr auto kMechanismMongoAWS = "MONGODB-AWS"_sd;
constexpr auto kInternalAuthFallbackMechanism = kMechanismScramSha1;
constexpr auto kSpeculativeAuthenticate = "speculativeAuthenticate"_sd;
+constexpr auto kClusterAuthenticate = "clusterAuthenticate"_sd;
constexpr auto kAuthenticateCommand = "authenticate"_sd;
/**
diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp
index 7f4b1010462..81d784e64a3 100644
--- a/src/mongo/db/auth/sasl_commands.cpp
+++ b/src/mongo/db/auth/sasl_commands.cpp
@@ -335,18 +335,26 @@ bool runSaslStart(OperationContext* opCtx,
}
std::string principalName;
- auto swSession = doSaslStart(opCtx, db, cmdObj, &result, &principalName, speculative);
-
- if (!swSession.isOK() || swSession.getValue()->getMechanism().isSuccess()) {
- audit::logAuthentication(
- client, mechanismName, UserName(principalName, db), swSession.getStatus().code());
- uassertStatusOK(swSession.getStatus());
- if (swSession.getValue()->getMechanism().isSuccess()) {
+ try {
+ auto session =
+ uassertStatusOK(doSaslStart(opCtx, db, cmdObj, &result, &principalName, speculative));
+ const bool isClusterMember = session->getMechanism().isClusterMember();
+ if (isClusterMember) {
+ uassertStatusOK(authCounter.incClusterAuthenticateReceived(mechanismName));
+ }
+ if (session->getMechanism().isSuccess()) {
uassertStatusOK(authCounter.incAuthenticateSuccessful(mechanismName));
+ if (isClusterMember) {
+ uassertStatusOK(authCounter.incClusterAuthenticateSuccessful(mechanismName));
+ }
+ audit::logAuthentication(
+ client, mechanismName, UserName(principalName, db), Status::OK().code());
+ } else {
+ AuthenticationSession::swap(client, session);
}
- } else {
- auto session = std::move(swSession.getValue());
- AuthenticationSession::swap(client, session);
+ } catch (const AssertionException& ex) {
+ audit::logAuthentication(client, mechanismName, UserName(principalName, db), ex.code());
+ throw;
}
return true;
@@ -408,6 +416,10 @@ bool CmdSaslContinue::run(OperationContext* opCtx,
if (mechanism.isSuccess()) {
uassertStatusOK(
authCounter.incAuthenticateSuccessful(mechanism.mechanismName().toString()));
+ if (mechanism.isClusterMember()) {
+ uassertStatusOK(authCounter.incClusterAuthenticateSuccessful(
+ mechanism.mechanismName().toString()));
+ }
}
} else {
AuthenticationSession::swap(client, sessionGuard);
diff --git a/src/mongo/db/auth/sasl_mechanism_registry.h b/src/mongo/db/auth/sasl_mechanism_registry.h
index 98f2d8ddae9..0215328d9cb 100644
--- a/src/mongo/db/auth/sasl_mechanism_registry.h
+++ b/src/mongo/db/auth/sasl_mechanism_registry.h
@@ -155,6 +155,15 @@ public:
}
/**
+ * Provides logic for determining if a user is a cluster member or an actual client for SASL
+ * authentication mechanisms
+ */
+ bool isClusterMember() const {
+ return _principalName == internalSecurity.user->getName().getUser().toString() &&
+ getAuthenticationDatabase() == internalSecurity.user->getName().getDB();
+ };
+
+ /**
* Performs a single step of a SASL exchange. Takes an input provided by a client,
* and either returns an error, or a response to be sent back.
*/
diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp
index 77f014207fb..c3ba51aef15 100644
--- a/src/mongo/db/commands/authentication_commands.cpp
+++ b/src/mongo/db/commands/authentication_commands.cpp
@@ -44,6 +44,7 @@
#include "mongo/client/sasl_client_authenticate.h"
#include "mongo/config.h"
#include "mongo/db/audit.h"
+#include "mongo/db/auth/authentication_session.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/sasl_options.h"
@@ -292,48 +293,48 @@ bool CmdAuthenticate::run(OperationContext* opCtx,
user = internalSecurity.user->getName();
}
- Status status = authCounter.incAuthenticateReceived(mechanism);
- if (status.isOK()) {
- status = _authenticate(opCtx, mechanism, user, cmdObj);
- }
- audit::logAuthentication(Client::getCurrent(), mechanism, user, status.code());
+ try {
+ uassertStatusOK(authCounter.incAuthenticateReceived(mechanism));
+ const bool isClusterMember =
+ opCtx->getClient()->session()->getSSLConfiguration()->isClusterMember(user.getUser());
+ if (isClusterMember) {
+ uassertStatusOK(authCounter.incClusterAuthenticateReceived(mechanism));
+ }
+
+ uassertStatusOK(_authenticate(opCtx, mechanism, user, cmdObj));
+ audit::logAuthentication(opCtx->getClient(), mechanism, user, Status::OK().code());
- if (!status.isOK()) {
if (!serverGlobalParams.quiet.load()) {
- auto const client = opCtx->getClient();
+ LOGV2(20429,
+ "Successfully authenticated as principal {user} on {db} from client {client}",
+ "Successfully authenticated",
+ "user"_attr = user.getUser(),
+ "db"_attr = user.getDB(),
+ "client"_attr = opCtx->getClient()->session()->remote());
+ }
+
+ uassertStatusOK(authCounter.incAuthenticateSuccessful(mechanism));
+ if (isClusterMember) {
+ uassertStatusOK(authCounter.incClusterAuthenticateSuccessful(mechanism));
+ }
+
+ result.append("dbname", user.getDB());
+ result.append("user", user.getUser());
+ return true;
+ } catch (const AssertionException& ex) {
+ auto status = ex.toStatus();
+ auto const client = opCtx->getClient();
+ audit::logAuthentication(Client::getCurrent(), mechanism, user, status.code());
+ if (!serverGlobalParams.quiet.load()) {
LOGV2(20428,
- "Failed to authenticate {user} from client {client} with mechanism "
- "{mechanism}: {error}",
"Failed to authenticate",
"user"_attr = user,
"client"_attr = client->getRemote(),
"mechanism"_attr = mechanism,
"error"_attr = status);
}
- sleepmillis(saslGlobalParams.authFailedDelay.load());
- if (status.code() == ErrorCodes::AuthenticationFailed) {
- // Statuses with code AuthenticationFailed may contain messages we do not wish to
- // reveal to the user, so we return a status with the message "auth failed".
- uasserted(ErrorCodes::AuthenticationFailed, "auth failed");
- } else {
- uassertStatusOK(status);
- }
- return false;
+ throw;
}
-
- if (!serverGlobalParams.quiet.load()) {
- LOGV2(20429,
- "Successfully authenticated as principal {user} on {db} from client {client}",
- "Successfully authenticated",
- "user"_attr = user.getUser(),
- "db"_attr = user.getDB(),
- "client"_attr = opCtx->getClient()->session()->remote());
- }
-
- uassertStatusOK(authCounter.incAuthenticateSuccessful(mechanism));
- result.append("dbname", user.getDB());
- result.append("user", user.getUser());
- return true;
}
Status CmdAuthenticate::_authenticate(OperationContext* opCtx,
diff --git a/src/mongo/db/stats/counters.cpp b/src/mongo/db/stats/counters.cpp
index 63a0b6eb66d..4180275393b 100644
--- a/src/mongo/db/stats/counters.cpp
+++ b/src/mongo/db/stats/counters.cpp
@@ -244,6 +244,24 @@ Status AuthCounter::incAuthenticateSuccessful(const std::string& mechanism) try
<< " which is not enabled"};
}
+Status AuthCounter::incClusterAuthenticateReceived(const std::string& mechanism) try {
+ _mechanisms.at(mechanism).clusterAuthenticate.received.fetchAndAddRelaxed(1);
+ return Status::OK();
+} catch (const std::out_of_range&) {
+ return {ErrorCodes::BadValue,
+ str::stream() << "Received authentication for mechanism " << mechanism
+ << " which is unknown or not enabled"};
+}
+
+Status AuthCounter::incClusterAuthenticateSuccessful(const std::string& mechanism) try {
+ _mechanisms.at(mechanism).clusterAuthenticate.successful.fetchAndAddRelaxed(1);
+ return Status::OK();
+} catch (const std::out_of_range&) {
+ return {ErrorCodes::BadValue,
+ str::stream() << "Received authentication for mechanism " << mechanism
+ << " which is not enabled"};
+}
+
/**
* authentication: {
* "mechanisms": {
@@ -275,6 +293,16 @@ void AuthCounter::append(BSONObjBuilder* b) {
}
{
+ const auto received = it.second.clusterAuthenticate.received.load();
+ const auto successful = it.second.clusterAuthenticate.successful.load();
+
+ BSONObjBuilder clusterAuthBuilder(mechBuilder.subobjStart(auth::kClusterAuthenticate));
+ clusterAuthBuilder.append("received", received);
+ clusterAuthBuilder.append("successful", successful);
+ clusterAuthBuilder.done();
+ }
+
+ {
const auto received = it.second.authenticate.received.load();
const auto successful = it.second.authenticate.successful.load();
diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h
index 9b10cb2a049..a202746be03 100644
--- a/src/mongo/db/stats/counters.h
+++ b/src/mongo/db/stats/counters.h
@@ -226,6 +226,9 @@ public:
Status incAuthenticateReceived(const std::string& mechanism);
Status incAuthenticateSuccessful(const std::string& mechanism);
+ Status incClusterAuthenticateReceived(const std::string& mechanism);
+ Status incClusterAuthenticateSuccessful(const std::string& mechanism);
+
void append(BSONObjBuilder*);
void initializeMechanismMap(const std::vector<std::string>&);
@@ -240,6 +243,10 @@ private:
AtomicWord<long long> received;
AtomicWord<long long> successful;
} authenticate;
+ struct {
+ AtomicWord<long long> received;
+ AtomicWord<long long> successful;
+ } clusterAuthenticate;
};
using MechanismMap = std::map<std::string, MechanismData>;