summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/client/SConscript1
-rw-r--r--src/mongo/client/cyrus_sasl_client_session.cpp2
-rw-r--r--src/mongo/client/native_sasl_client_session.cpp11
-rw-r--r--src/mongo/client/sasl_scram_client_conversation.cpp16
-rw-r--r--src/mongo/client/sasl_scram_client_conversation.h21
-rw-r--r--src/mongo/db/auth/SConscript1
-rw-r--r--src/mongo/db/auth/native_sasl_authentication_session.cpp7
-rw-r--r--src/mongo/db/auth/sasl_authentication_session.cpp1
-rw-r--r--src/mongo/db/auth/sasl_authentication_session.h1
-rw-r--r--src/mongo/db/auth/sasl_authentication_session_test.cpp15
-rw-r--r--src/mongo/db/auth/sasl_options.cpp1
-rw-r--r--src/mongo/db/auth/sasl_scram_server_conversation.cpp6
-rw-r--r--src/mongo/db/auth/sasl_scram_server_conversation.h15
-rw-r--r--src/mongo/db/commands/authentication_commands.h1
14 files changed, 79 insertions, 20 deletions
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index 6b54c9c7e70..3a48533419e 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -110,6 +110,7 @@ saslClientEnv.Library(
'$BUILD_DIR/mongo/executor/remote_command',
'$BUILD_DIR/mongo/rpc/command_status',
'$BUILD_DIR/mongo/rpc/metadata',
+ '$BUILD_DIR/mongo/util/icu',
'$BUILD_DIR/mongo/util/md5',
'$BUILD_DIR/mongo/util/net/network',
],
diff --git a/src/mongo/client/cyrus_sasl_client_session.cpp b/src/mongo/client/cyrus_sasl_client_session.cpp
index 503a41303ac..e4d55c0bf42 100644
--- a/src/mongo/client/cyrus_sasl_client_session.cpp
+++ b/src/mongo/client/cyrus_sasl_client_session.cpp
@@ -41,7 +41,7 @@ namespace mongo {
namespace {
SaslClientSession* createCyrusSaslClientSession(const std::string& mech) {
- if (mech == "SCRAM-SHA-1") {
+ if ((mech == "SCRAM-SHA-1") || (mech == "SCRAM-SHA-256")) {
return new NativeSaslClientSession();
}
return new CyrusSaslClientSession();
diff --git a/src/mongo/client/native_sasl_client_session.cpp b/src/mongo/client/native_sasl_client_session.cpp
index bce0e220bc8..afa5073069b 100644
--- a/src/mongo/client/native_sasl_client_session.cpp
+++ b/src/mongo/client/native_sasl_client_session.cpp
@@ -48,8 +48,9 @@ MONGO_INITIALIZER(NativeSaslClientContext)(InitializerContext* context) {
return Status::OK();
}
-// Global cache for SCRAM-SHA-1 credentials
-SCRAMSHA1ClientCache* scramsha1ClientCache = new SCRAMSHA1ClientCache;
+// Global cache for SCRAM-SHA-1/256 credentials
+auto* scramsha1ClientCache = new SCRAMClientCache<SHA1Block>;
+auto* scramsha256ClientCache = new SCRAMClientCache<SHA256Block>;
} // namespace
@@ -67,7 +68,11 @@ Status NativeSaslClientSession::initialize() {
if (mechanism == "PLAIN") {
_saslConversation.reset(new SaslPLAINClientConversation(this));
} else if (mechanism == "SCRAM-SHA-1") {
- _saslConversation.reset(new SaslSCRAMSHA1ClientConversation(this, scramsha1ClientCache));
+ _saslConversation.reset(
+ new SaslSCRAMClientConversationImpl<SHA1Block>(this, scramsha1ClientCache));
+ } else if (mechanism == "SCRAM-SHA-256") {
+ _saslConversation.reset(
+ new SaslSCRAMClientConversationImpl<SHA256Block>(this, scramsha256ClientCache));
} else {
return Status(ErrorCodes::BadValue,
mongoutils::str::stream() << "SASL mechanism " << mechanism
diff --git a/src/mongo/client/sasl_scram_client_conversation.cpp b/src/mongo/client/sasl_scram_client_conversation.cpp
index 0a95f5f9cf8..5cca962271f 100644
--- a/src/mongo/client/sasl_scram_client_conversation.cpp
+++ b/src/mongo/client/sasl_scram_client_conversation.cpp
@@ -94,8 +94,13 @@ StatusWith<bool> SaslSCRAMClientConversation::_firstStep(std::string* outputData
binaryNonce[1] = sr->nextInt64();
binaryNonce[2] = sr->nextInt64();
- std::string user =
- _saslClientSession->getParameter(SaslClientSession::parameterUser).toString();
+ auto swUser =
+ saslPrep(_saslClientSession->getParameter(SaslClientSession::parameterUser).toString());
+ if (!swUser.isOK()) {
+ return swUser.getStatus();
+ }
+ auto user = swUser.getValue();
+
encodeSCRAMUsername(user);
_clientNonce = base64::encode(reinterpret_cast<char*>(binaryNonce), sizeof(binaryNonce));
@@ -160,16 +165,15 @@ StatusWith<bool> SaslSCRAMClientConversation::_secondStep(const std::vector<stri
// Append client-final-message-without-proof to _authMessage
_authMessage += "c=biws,r=" + nonce;
- std::string decodedSalt;
+ std::string decodedSalt, clientProof;
try {
decodedSalt = base64::decode(salt);
+ clientProof = generateClientProof(
+ std::vector<std::uint8_t>(decodedSalt.begin(), decodedSalt.end()), iterationCount);
} catch (const DBException& ex) {
return StatusWith<bool>(ex.toStatus());
}
- auto clientProof = generateClientProof(
- std::vector<std::uint8_t>(decodedSalt.begin(), decodedSalt.end()), iterationCount);
-
StringBuilder sb;
sb << "c=biws,r=" << nonce << ",p=" << clientProof;
*outputData = sb.str();
diff --git a/src/mongo/client/sasl_scram_client_conversation.h b/src/mongo/client/sasl_scram_client_conversation.h
index f714e3145d7..63ffca61db6 100644
--- a/src/mongo/client/sasl_scram_client_conversation.h
+++ b/src/mongo/client/sasl_scram_client_conversation.h
@@ -38,6 +38,7 @@
#include "mongo/client/sasl_client_session.h"
#include "mongo/client/scram_client_cache.h"
#include "mongo/crypto/mechanism_scram.h"
+#include "mongo/util/icu.h"
namespace mongo {
@@ -70,6 +71,11 @@ public:
*/
virtual bool verifyServerSignature(StringData sig) const = 0;
+ /**
+ * Runs saslPrep except on SHA-1.
+ */
+ virtual StatusWith<std::string> saslPrep(StringData val) const = 0;
+
private:
/**
* Generates client-first-message.
@@ -103,10 +109,9 @@ public:
std::string generateClientProof(const std::vector<std::uint8_t>& salt,
size_t iterationCount) final {
- scram::Presecrets<HashBlock> presecrets(
- _saslClientSession->getParameter(SaslClientSession::parameterPassword).toString(),
- salt,
- iterationCount);
+ auto password = uassertStatusOK(saslPrep(
+ _saslClientSession->getParameter(SaslClientSession::parameterPassword).toString()));
+ scram::Presecrets<HashBlock> presecrets(password, salt, iterationCount);
auto targetHost = HostAndPort::parse(
_saslClientSession->getParameter(SaslClientSession::parameterServiceHostAndPort));
@@ -129,6 +134,14 @@ public:
return _credentials.verifyServerSignature(_authMessage, sig);
}
+ StatusWith<std::string> saslPrep(StringData val) const final {
+ if (std::is_same<SHA1Block, HashBlock>::value) {
+ return val.toString();
+ } else {
+ return mongo::saslPrep(val);
+ }
+ }
+
private:
// Secrets and secrets cache
scram::Secrets<HashBlock> _credentials;
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index 9be76b3c20d..8752e0cec57 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -181,6 +181,7 @@ env.Library('saslauth',
'sasl_options',
'$BUILD_DIR/mongo/base/secure_allocator',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
+ '$BUILD_DIR/mongo/util/icu',
'$BUILD_DIR/mongo/util/net/network',
],
)
diff --git a/src/mongo/db/auth/native_sasl_authentication_session.cpp b/src/mongo/db/auth/native_sasl_authentication_session.cpp
index bfddca7fc5f..74b7688f265 100644
--- a/src/mongo/db/auth/native_sasl_authentication_session.cpp
+++ b/src/mongo/db/auth/native_sasl_authentication_session.cpp
@@ -80,7 +80,8 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(PostSaslCommands, ("NativeSaslServerCore"))
for (size_t i = 0; i < saslGlobalParams.authenticationMechanisms.size(); ++i) {
const std::string& mechanism = saslGlobalParams.authenticationMechanisms[i];
- if (mechanism == "MONGODB-CR" || mechanism == "MONGODB-X509") {
+ if (mechanism == "SCRAM-SHA-1" || mechanism == "SCRAM-SHA-256" ||
+ mechanism == "MONGODB-X509") {
// Not a SASL mechanism; no need to smoke test built-in mechanisms.
continue;
}
@@ -124,7 +125,9 @@ Status NativeSaslAuthenticationSession::start(StringData authenticationDatabase,
if (mechanism == "PLAIN") {
_saslConversation.reset(new SaslPLAINServerConversation(this));
} else if (mechanism == "SCRAM-SHA-1") {
- _saslConversation.reset(new SaslSCRAMSHA1ServerConversation(this));
+ _saslConversation.reset(new SaslSCRAMServerConversationImpl<SHA1Block>(this));
+ } else if (mechanism == "SCRAM-SHA-256") {
+ _saslConversation.reset(new SaslSCRAMServerConversationImpl<SHA256Block>(this));
} else {
return Status(ErrorCodes::BadValue,
mongoutils::str::stream() << "SASL mechanism " << mechanism
diff --git a/src/mongo/db/auth/sasl_authentication_session.cpp b/src/mongo/db/auth/sasl_authentication_session.cpp
index b2679702da7..5195a6aa193 100644
--- a/src/mongo/db/auth/sasl_authentication_session.cpp
+++ b/src/mongo/db/auth/sasl_authentication_session.cpp
@@ -49,6 +49,7 @@ namespace mongo {
SaslAuthenticationSession::SaslAuthenticationSessionFactoryFn SaslAuthenticationSession::create;
// Mechanism name constants.
+const char SaslAuthenticationSession::mechanismSCRAMSHA256[] = "SCRAM-SHA-256";
const char SaslAuthenticationSession::mechanismSCRAMSHA1[] = "SCRAM-SHA-1";
const char SaslAuthenticationSession::mechanismGSSAPI[] = "GSSAPI";
const char SaslAuthenticationSession::mechanismPLAIN[] = "PLAIN";
diff --git a/src/mongo/db/auth/sasl_authentication_session.h b/src/mongo/db/auth/sasl_authentication_session.h
index 621ccd1fd3c..c28e60919e8 100644
--- a/src/mongo/db/auth/sasl_authentication_session.h
+++ b/src/mongo/db/auth/sasl_authentication_session.h
@@ -57,6 +57,7 @@ public:
static SaslAuthenticationSessionFactoryFn create;
// Mechanism name constants.
+ static const char mechanismSCRAMSHA256[];
static const char mechanismSCRAMSHA1[];
static const char mechanismGSSAPI[];
static const char mechanismPLAIN[];
diff --git a/src/mongo/db/auth/sasl_authentication_session_test.cpp b/src/mongo/db/auth/sasl_authentication_session_test.cpp
index 2906d9f04c7..ebabda5bfe3 100644
--- a/src/mongo/db/auth/sasl_authentication_session_test.cpp
+++ b/src/mongo/db/auth/sasl_authentication_session_test.cpp
@@ -77,9 +77,17 @@ SaslConversation::SaslConversation(std::string mech)
true,
BSONObj()));
- const auto authHash = (mech == "SCRAM-SHA-1") ? "frim" : createPasswordDigest("andy", "frim");
- const auto creds = BSON("SCRAM-SHA-1" << scram::SHA1Secrets::generateCredentials(
- authHash, saslGlobalParams.scramSHA1IterationCount.load()));
+ // PLAIN mechanism uses the same hashed password as SCRAM-SHA-1,
+ // but SCRAM-SHA-1's implementation makes the assumption the hashing has already
+ // happened at both ends.
+ // SCRAM-SHA-256 doesn't have this problem and always uses a pure password as input.
+ const auto pwHash = (mech == "PLAIN") ? createPasswordDigest("andy", "frim") : "frim";
+ const auto creds =
+ BSON("SCRAM-SHA-1" << scram::Secrets<SHA1Block>::generateCredentials(
+ pwHash, saslGlobalParams.scramSHA1IterationCount.load())
+ << "SCRAM-SHA-256"
+ << scram::Secrets<SHA256Block>::generateCredentials(
+ "frim", saslGlobalParams.scramSHA256IterationCount.load()));
ASSERT_OK(authManagerExternalState->insert(&opCtx,
NamespaceString("admin.system.users"),
@@ -213,6 +221,7 @@ void SaslConversation::testWrongServerMechanism() {
DEFINE_ALL_MECHANISM_TESTS(SaslConversation##CLASS_SUFFIX)
TEST_MECHANISM(SCRAMSHA1, "SCRAM-SHA-1")
+TEST_MECHANISM(SCRAMSHA256, "SCRAM-SHA-256")
TEST_MECHANISM(PLAIN, "PLAIN")
TEST_F(SaslIllegalConversation, IllegalClientMechanism) {
diff --git a/src/mongo/db/auth/sasl_options.cpp b/src/mongo/db/auth/sasl_options.cpp
index 5e48aaaf1e8..f35825c6d14 100644
--- a/src/mongo/db/auth/sasl_options.cpp
+++ b/src/mongo/db/auth/sasl_options.cpp
@@ -56,6 +56,7 @@ SASLGlobalParams::SASLGlobalParams() {
// Authentication mechanisms supported by default.
authenticationMechanisms.push_back("MONGODB-X509");
authenticationMechanisms.push_back("SCRAM-SHA-1");
+ authenticationMechanisms.push_back("SCRAM-SHA-256");
// Default iteration count for SCRAM authentication.
scramSHA1IterationCount.store(defaultScramSHA1IterationCount);
diff --git a/src/mongo/db/auth/sasl_scram_server_conversation.cpp b/src/mongo/db/auth/sasl_scram_server_conversation.cpp
index 2ac64aedb34..7ae3373e614 100644
--- a/src/mongo/db/auth/sasl_scram_server_conversation.cpp
+++ b/src/mongo/db/auth/sasl_scram_server_conversation.cpp
@@ -144,6 +144,12 @@ StatusWith<bool> SaslSCRAMServerConversation::_firstStep(std::vector<string>& in
decodeSCRAMUsername(_user);
+ auto swUser = saslPrep(_user);
+ if (!swUser.isOK()) {
+ return swUser.getStatus();
+ }
+ _user = std::move(swUser.getValue());
+
// SERVER-16534, SCRAM-SHA-1 must be enabled for authenticating the internal user, so that
// cluster members may communicate with each other. Hence ignore disabled auth mechanism
// for the internal user.
diff --git a/src/mongo/db/auth/sasl_scram_server_conversation.h b/src/mongo/db/auth/sasl_scram_server_conversation.h
index 4c08140ef41..d2166bb4377 100644
--- a/src/mongo/db/auth/sasl_scram_server_conversation.h
+++ b/src/mongo/db/auth/sasl_scram_server_conversation.h
@@ -33,9 +33,11 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
+#include "mongo/base/status_with.h"
#include "mongo/base/string_data.h"
#include "mongo/crypto/mechanism_scram.h"
#include "mongo/db/auth/sasl_server_conversation.h"
+#include "mongo/util/icu.h"
namespace mongo {
/**
@@ -83,6 +85,11 @@ public:
*/
virtual std::string generateServerSignature() const = 0;
+ /**
+ * Runs saslPrep except on SHA-1.
+ */
+ virtual StatusWith<std::string> saslPrep(StringData str) const = 0;
+
private:
/**
* Parse client-first-message and generate server-first-message
@@ -138,6 +145,14 @@ public:
return _credentials.generateServerSignature(_authMessage);
}
+ StatusWith<std::string> saslPrep(StringData str) const final {
+ if (std::is_same<SHA1Block, HashBlock>::value) {
+ return str.toString();
+ } else {
+ return mongo::saslPrep(str);
+ }
+ }
+
private:
scram::Secrets<HashBlock> _credentials;
};
diff --git a/src/mongo/db/commands/authentication_commands.h b/src/mongo/db/commands/authentication_commands.h
index c79dc4a6979..e04237ea91d 100644
--- a/src/mongo/db/commands/authentication_commands.h
+++ b/src/mongo/db/commands/authentication_commands.h
@@ -76,7 +76,6 @@ private:
const std::string& mechanism,
const UserName& user,
const BSONObj& cmdObj);
- Status _authenticateCR(OperationContext* opCtx, const UserName& user, const BSONObj& cmdObj);
Status _authenticateX509(OperationContext* opCtx, const UserName& user, const BSONObj& cmdObj);
};