diff options
author | Adam Cooper <adam.cooper@mongodb.com> | 2020-08-14 13:46:35 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-08-14 21:01:59 +0000 |
commit | 24dd72daae9e4cf59ad51910058bc111f20edbff (patch) | |
tree | f019be38662bc5a86c68ac1f4a006f479a408647 /src | |
parent | 6b1a0403f17b688940eb9d86f41d95bdd943d3f4 (diff) | |
download | mongo-24dd72daae9e4cf59ad51910058bc111f20edbff.tar.gz |
SERVER-48693 Add network counter for cluster authentication
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/client/authenticate.h | 1 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_commands.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_mechanism_registry.h | 9 | ||||
-rw-r--r-- | src/mongo/db/commands/authentication_commands.cpp | 65 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.h | 7 |
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>; |