summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2018-11-30 13:57:15 -0500
committerMathias Stearn <mathias@10gen.com>2019-03-07 17:27:08 -0500
commit05299e4077bebdaaad0622f2fe3c611ba181b134 (patch)
tree3c5192bd4b149cd7f1f6274d9ea5408f56394467
parent470c14ed7543d62a2a76476e6522823316ec36d3 (diff)
downloadmongo-05299e4077bebdaaad0622f2fe3c611ba181b134.tar.gz
SERVER-38319 Propagate URI options from DBClientRS through all codepaths
(cherry picked from commit 3691388900021034e338786116d60fd4d480a6e7)
-rw-r--r--jstests/ssl/mongo_uri_secondaries.js83
-rw-r--r--src/mongo/client/dbclient_connection.cpp21
-rw-r--r--src/mongo/client/dbclient_rs.cpp8
-rw-r--r--src/mongo/client/mongo_uri.cpp94
-rw-r--r--src/mongo/client/mongo_uri.h25
-rw-r--r--src/mongo/client/mongo_uri_test.cpp182
-rw-r--r--src/mongo/client/replica_set_monitor.cpp13
-rw-r--r--src/mongo/client/replica_set_monitor.h7
-rw-r--r--src/mongo/client/replica_set_monitor_internal.h4
-rw-r--r--src/mongo/client/replica_set_monitor_manager.cpp8
10 files changed, 296 insertions, 149 deletions
diff --git a/jstests/ssl/mongo_uri_secondaries.js b/jstests/ssl/mongo_uri_secondaries.js
new file mode 100644
index 00000000000..9512a3c23c3
--- /dev/null
+++ b/jstests/ssl/mongo_uri_secondaries.js
@@ -0,0 +1,83 @@
+// On OSX this test assumes that jstests/libs/trusted-ca.pem has been added as a trusted
+// certificate to the login keychain of the evergreen user. See,
+// https://github.com/10gen/buildslave-cookbooks/commit/af7cabe5b6e0885902ebd4902f7f974b64cc8961
+// for details.
+// To install trusted-ca.pem for local testing on OSX, invoke the following at a console:
+// security add-trusted-cert -d jstests/libs/trusted-ca.pem
+(function() {
+ 'use strict';
+
+ const HOST_TYPE = getBuildInfo().buildEnvironment.target_os;
+ if (HOST_TYPE == "windows") {
+ // OpenSSL backed imports Root CA and intermediate CA
+ runProgram(
+ "certutil.exe", "-addstore", "-user", "-f", "CA", "jstests\\libs\\trusted-ca.pem");
+
+ // SChannel backed follows Windows rules and only trusts the Root store in Local Machine and
+ // Current User.
+ runProgram("certutil.exe", "-addstore", "-f", "Root", "jstests\\libs\\trusted-ca.pem");
+ }
+
+ const x509Options = {
+ sslMode: 'requireSSL',
+ sslPEMKeyFile: 'jstests/libs/trusted-server.pem',
+ sslCAFile: 'jstests/libs/trusted-ca.pem',
+ sslAllowInvalidCertificates: '',
+ sslWeakCertificateValidation: '',
+ };
+
+ const rst = new ReplSetTest({
+ nodes: 2,
+ name: "sslSet",
+ useHostName: false,
+ nodeOptions: x509Options,
+ waitForKeys: false
+ });
+ rst.startSet();
+ rst.initiate();
+
+ const subShellCommand = function(hosts) {
+ var Ms = [];
+ for (var i = 0; i < 10; i++) {
+ Ms.push(new Mongo("mongodb://" + hosts[0] + "," + hosts[1] +
+ "/?ssl=true&replicaSet=sslSet"));
+ }
+
+ for (var i = 0; i < 10; i++) {
+ var db = Ms[i].getDB("test");
+ db.setSlaveOk(true);
+ db.col.find().readPref("secondary").toArray();
+ }
+ };
+
+ const subShellCommandFormatter = function(replSet) {
+ var hosts = [];
+ replSet.nodes.forEach((node) => {
+ hosts.push("localhost:" + node.port);
+ });
+
+ let command = `
+ (function () {
+ 'use strict';
+ let command = ${subShellCommand.toString()};
+ let hosts = ${tojson(hosts)};
+ command(hosts);
+ }());`;
+
+ return command;
+ };
+
+ const subShellArgs = [
+ "env",
+ "SSL_CERT_FILE=jstests/libs/trusted-ca.pem",
+ './mongo',
+ '--nodb',
+ '--eval',
+ subShellCommandFormatter(rst)
+ ];
+
+ const retVal = _runMongoProgram(...subShellArgs);
+ assert.eq(retVal, 0, 'mongo shell did not succeed with exit code 0');
+
+ rst.stopSet();
+}());
diff --git a/src/mongo/client/dbclient_connection.cpp b/src/mongo/client/dbclient_connection.cpp
index 6bc038447d0..67137931f39 100644
--- a/src/mongo/client/dbclient_connection.cpp
+++ b/src/mongo/client/dbclient_connection.cpp
@@ -303,25 +303,8 @@ Status DBClientConnection::connectSocketOnly(const HostAndPort& serverAddress) {
<< ", address resolved to 0.0.0.0");
}
- transport::ConnectSSLMode sslMode = transport::kGlobalSSLMode;
-#ifdef MONGO_CONFIG_SSL
- // Prefer to get SSL mode directly from our URI, but if it is not set, fall back to
- // checking global SSL params. DBClientConnections create through the shell will have a
- // meaningful URI set, but DBClientConnections created from within the server may not.
- auto options = _uri.getOptions();
- auto iter = options.find("ssl");
- if (iter != options.end()) {
- if (iter->second == "true") {
- sslMode = transport::kEnableSSL;
- } else {
- sslMode = transport::kDisableSSL;
- }
- }
-
-#endif
-
- auto tl = getGlobalServiceContext()->getTransportLayer();
- auto sws = tl->connect(serverAddress, sslMode, _socketTimeout.value_or(Milliseconds{5000}));
+ auto sws = getGlobalServiceContext()->getTransportLayer()->connect(
+ serverAddress, _uri.getSSLMode(), _socketTimeout.value_or(Milliseconds{5000}));
if (!sws.isOK()) {
return Status(ErrorCodes::HostUnreachable,
str::stream() << "couldn't connect to server " << _serverAddress.toString()
diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp
index 1360c705832..69a4ac6c1f5 100644
--- a/src/mongo/client/dbclient_rs.cpp
+++ b/src/mongo/client/dbclient_rs.cpp
@@ -297,11 +297,7 @@ DBClientConnection* DBClientReplicaSet::checkMaster() {
_masterHost = h;
- MongoURI masterUri;
- if (!_uri.isValid())
- masterUri = MongoURI(ConnectionString(_masterHost));
- else
- masterUri = _uri.cloneURIForServer(_masterHost);
+ MongoURI masterUri = _uri.cloneURIForServer(_masterHost);
string errmsg;
DBClientConnection* newConn = NULL;
@@ -710,7 +706,7 @@ DBClientConnection* DBClientReplicaSet::selectNodeUsingTags(
// callback. We should eventually not need this after we remove the
// callback.
DBClientConnection* newConn = dynamic_cast<DBClientConnection*>(
- globalConnPool.get(_lastSlaveOkHost.toString(), _so_timeout));
+ globalConnPool.get(_uri.cloneURIForServer(_lastSlaveOkHost), _so_timeout));
// Assert here instead of returning NULL since the contract of this method is such
// that returning NULL means none of the nodes were good, which is not the case here.
diff --git a/src/mongo/client/mongo_uri.cpp b/src/mongo/client/mongo_uri.cpp
index ca61bc328ca..934d5f7540e 100644
--- a/src/mongo/client/mongo_uri.cpp
+++ b/src/mongo/client/mongo_uri.cpp
@@ -96,7 +96,7 @@ mongo::StatusWith<std::string> mongo::uriDecode(StringData toDecode) {
if (swHex.isOK()) {
out << swHex.getValue();
} else {
- return Status(ErrorCodes::FailedToParse,
+ return Status(ErrorCodes::Error(51040),
"The characters after the % do not form a hex value. Please escape "
"the % or pass a valid hex value. ");
}
@@ -183,14 +183,11 @@ std::map<std::string, std::string> parseOptions(StringData options, StringData u
<< "Missing a key for key/value pair in the options for mongodb:// URL: "
<< url);
}
- const auto key = uriDecode(keyRaw);
- if (!key.isOK()) {
- uasserted(
- ErrorCodes::FailedToParse,
- str::stream() << "Key '" << keyRaw
- << "' in options cannot properly be URL decoded for mongodb:// URL: "
- << url);
- }
+ const auto key = uassertStatusOKWithContext(
+ uriDecode(keyRaw),
+ str::stream() << "Key '" << keyRaw
+ << "' in options cannot properly be URL decoded for mongodb:// URL: "
+ << url);
const auto valRaw = kvPair.second;
if (valRaw.empty()) {
uasserted(ErrorCodes::FailedToParse,
@@ -198,16 +195,13 @@ std::map<std::string, std::string> parseOptions(StringData options, StringData u
<< "' in the options for mongodb:// URL: "
<< url);
}
- const auto val = uriDecode(valRaw);
- if (!val.isOK()) {
- uasserted(
- ErrorCodes::FailedToParse,
- str::stream() << "Value '" << valRaw << "' for key '" << keyRaw
- << "' in options cannot properly be URL decoded for mongodb:// URL: "
- << url);
- }
+ const auto val = uassertStatusOKWithContext(
+ uriDecode(valRaw),
+ str::stream() << "Value '" << valRaw << "' for key '" << keyRaw
+ << "' in options cannot properly be URL decoded for mongodb:// URL: "
+ << url);
- ret[key.getValue()] = val.getValue();
+ ret[key] = val;
}
return ret;
@@ -360,21 +354,14 @@ MongoURI MongoURI::parseImpl(const std::string& url) {
}
// Get the username and make sure it did not fail to decode
- const auto usernameWithStatus = uriDecode(usernameSD);
- if (!usernameWithStatus.isOK()) {
- uasserted(ErrorCodes::FailedToParse,
- str::stream() << "Username cannot properly be URL decoded for mongodb:// URL: "
- << url);
- }
- const auto username = usernameWithStatus.getValue();
+ const auto username = uassertStatusOKWithContext(
+ uriDecode(usernameSD),
+ str::stream() << "Username cannot properly be URL decoded for mongodb:// URL: " << url);
// Get the password and make sure it did not fail to decode
- const auto passwordWithStatus = uriDecode(passwordSD);
- if (!passwordWithStatus.isOK())
- uasserted(ErrorCodes::FailedToParse,
- str::stream() << "Password cannot properly be URL decoded for mongodb:// URL: "
- << url);
- const auto password = passwordWithStatus.getValue();
+ const auto password = uassertStatusOKWithContext(
+ uriDecode(passwordSD),
+ str::stream() << "Password cannot properly be URL decoded for mongodb:// URL: " << url);
// 4. Validate, split, and URL decode the host identifiers.
const auto hostIdentifiersStr = hostIdentifiers.toString();
@@ -383,14 +370,10 @@ MongoURI MongoURI::parseImpl(const std::string& url) {
boost::first_finder(",", boost::is_iequal()));
i != std::remove_reference<decltype((i))>::type{};
++i) {
- const auto hostWithStatus = uriDecode(boost::copy_range<std::string>(*i));
- if (!hostWithStatus.isOK()) {
- uasserted(ErrorCodes::FailedToParse,
- str::stream() << "Host cannot properly be URL decoded for mongodb:// URL: "
- << url);
- }
+ const auto host = uassertStatusOKWithContext(
+ uriDecode(boost::copy_range<std::string>(*i)),
+ str::stream() << "Host cannot properly be URL decoded for mongodb:// URL: " << url);
- const auto host = hostWithStatus.getValue();
if (host.empty()) {
continue;
}
@@ -453,14 +436,11 @@ MongoURI MongoURI::parseImpl(const std::string& url) {
}
// 5. Decode the database name
- const auto databaseWithStatus = uriDecode(databaseSD);
- if (!databaseWithStatus.isOK()) {
- uasserted(ErrorCodes::FailedToParse,
- str::stream() << "Database name cannot properly be URL "
- "decoded for mongodb:// URL: "
- << url);
- }
- const auto database = databaseWithStatus.getValue();
+ const auto database =
+ uassertStatusOKWithContext(uriDecode(databaseSD),
+ str::stream() << "Database name cannot properly be URL "
+ "decoded for mongodb:// URL: "
+ << url);
// 6. Validate the database contains no prohibited characters
// Prohibited characters:
@@ -507,10 +487,28 @@ MongoURI MongoURI::parseImpl(const std::string& url) {
}
}
+ transport::ConnectSSLMode sslMode = transport::kGlobalSSLMode;
+ auto sslModeIter = options.find("ssl");
+ if (sslModeIter != options.end()) {
+ const auto& val = sslModeIter->second;
+ if (val == "true") {
+ sslMode = transport::kEnableSSL;
+ } else if (val == "false") {
+ sslMode = transport::kDisableSSL;
+ } else {
+ uasserted(51041, str::stream() << "ssl must be either 'true' or 'false', not" << val);
+ }
+ }
+
ConnectionString cs(
setName.empty() ? ConnectionString::MASTER : ConnectionString::SET, servers, setName);
- return MongoURI(
- std::move(cs), username, password, database, std::move(retryWrites), std::move(options));
+ return MongoURI(std::move(cs),
+ username,
+ password,
+ database,
+ std::move(retryWrites),
+ sslMode,
+ std::move(options));
}
StatusWith<MongoURI> MongoURI::parse(const std::string& url) try {
diff --git a/src/mongo/client/mongo_uri.h b/src/mongo/client/mongo_uri.h
index d05b8b1ab3a..e600522b463 100644
--- a/src/mongo/client/mongo_uri.h
+++ b/src/mongo/client/mongo_uri.h
@@ -41,6 +41,7 @@
#include "mongo/bson/util/builder.h"
#include "mongo/client/connection_string.h"
#include "mongo/stdx/mutex.h"
+#include "mongo/transport/transport_layer.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/net/hostandport.h"
@@ -146,14 +147,10 @@ public:
return _options;
}
- void addOption(std::string newKey, std::string newValue) {
- _options[std::move(newKey)] = std::move(newValue);
- }
-
void setOptionIfNecessary(std::string uriParamKey, std::string value) {
const auto key = _options.find(uriParamKey);
if (key == end(_options) && !value.empty()) {
- addOption(uriParamKey, value);
+ _options[std::move(uriParamKey)] = std::move(value);
}
}
@@ -210,24 +207,25 @@ public:
return _retryWrites;
}
+ transport::ConnectSSLMode getSSLMode() const {
+ return _sslMode;
+ }
+
// If you are trying to clone a URI (including its options/auth information) for a single
// server (say a member of a replica-set), you can pass in its HostAndPort information to
// get a new URI with the same info, except type() will be MASTER and getServers() will
// be the single host you pass in.
MongoURI cloneURIForServer(HostAndPort hostAndPort) const {
- return MongoURI(ConnectionString(std::move(hostAndPort)),
- _user,
- _password,
- _database,
- _retryWrites,
- _options);
+ auto out = *this;
+ out._connectString = ConnectionString(std::move(hostAndPort));
+ return out;
}
ConnectionString::ConnectionType type() const {
return _connectString.type();
}
- explicit MongoURI(const ConnectionString& connectString) : _connectString(connectString){};
+ explicit MongoURI(const ConnectionString& connectString) : _connectString(connectString) {}
MongoURI() = default;
@@ -241,12 +239,14 @@ private:
const std::string& password,
const std::string& database,
boost::optional<bool> retryWrites,
+ transport::ConnectSSLMode sslMode,
OptionsMap options)
: _connectString(std::move(connectString)),
_user(user),
_password(password),
_database(database),
_retryWrites(std::move(retryWrites)),
+ _sslMode(sslMode),
_options(std::move(options)) {}
boost::optional<BSONObj> _makeAuthObjFromOptions(int maxWireVersion) const;
@@ -258,6 +258,7 @@ private:
std::string _password;
std::string _database;
boost::optional<bool> _retryWrites;
+ transport::ConnectSSLMode _sslMode = transport::kGlobalSSLMode;
OptionsMap _options;
};
diff --git a/src/mongo/client/mongo_uri_test.cpp b/src/mongo/client/mongo_uri_test.cpp
index e044c817190..c06ea3f57a7 100644
--- a/src/mongo/client/mongo_uri_test.cpp
+++ b/src/mongo/client/mongo_uri_test.cpp
@@ -46,6 +46,11 @@
namespace mongo {
namespace {
+using transport::ConnectSSLMode;
+using transport::ConnectSSLMode::kEnableSSL;
+using transport::ConnectSSLMode::kDisableSSL;
+using transport::ConnectSSLMode::kGlobalSSLMode;
+
struct URITestCase {
std::string URI;
std::string uname;
@@ -55,14 +60,15 @@ struct URITestCase {
size_t numservers;
size_t numOptions;
std::string database;
+ ConnectSSLMode sslMode;
};
struct InvalidURITestCase {
std::string URI;
- boost::optional<Status> status;
- InvalidURITestCase(std::string aURI, boost::optional<Status> aStatus = boost::none) {
+ boost::optional<ErrorCodes::Error> code;
+ InvalidURITestCase(std::string aURI, boost::optional<ErrorCodes::Error> aCode = boost::none) {
URI = std::move(aURI);
- status = std::move(aStatus);
+ code = std::move(aCode);
}
};
@@ -71,23 +77,39 @@ const ConnectionString::ConnectionType kSet = ConnectionString::SET;
const URITestCase validCases[] = {
- {"mongodb://user:pwd@127.0.0.1", "user", "pwd", kMaster, "", 1, 0, ""},
+ {"mongodb://user:pwd@127.0.0.1", "user", "pwd", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://user@127.0.0.1", "user", "", kMaster, "", 1, 0, ""},
+ {"mongodb://user@127.0.0.1", "user", "", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://localhost/?foo=bar", "", "", kMaster, "", 1, 1, ""},
+ {"mongodb://localhost/?foo=bar", "", "", kMaster, "", 1, 1, "", kGlobalSSLMode},
- {"mongodb://localhost,/?foo=bar", "", "", kMaster, "", 1, 1, ""},
+ {"mongodb://localhost,/?foo=bar", "", "", kMaster, "", 1, 1, "", kGlobalSSLMode},
- {"mongodb://user:pwd@127.0.0.1:1234", "user", "pwd", kMaster, "", 1, 0, ""},
+ {"mongodb://user:pwd@127.0.0.1:1234", "user", "pwd", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://user@127.0.0.1:1234", "user", "", kMaster, "", 1, 0, ""},
+ {"mongodb://user@127.0.0.1:1234", "user", "", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://127.0.0.1:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"},
+ {"mongodb://127.0.0.1:1234/dbName?foo=a&c=b",
+ "",
+ "",
+ kMaster,
+ "",
+ 1,
+ 2,
+ "dbName",
+ kGlobalSSLMode},
- {"mongodb://127.0.0.1/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"},
+ {"mongodb://127.0.0.1/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName", kGlobalSSLMode},
- {"mongodb://user:pwd@127.0.0.1,/dbName?foo=a&c=b", "user", "pwd", kMaster, "", 1, 2, "dbName"},
+ {"mongodb://user:pwd@127.0.0.1,/dbName?foo=a&c=b",
+ "user",
+ "pwd",
+ kMaster,
+ "",
+ 1,
+ 2,
+ "dbName",
+ kGlobalSSLMode},
{"mongodb://user:pwd@127.0.0.1,127.0.0.2/dbname?a=b&replicaSet=replName",
"user",
@@ -96,7 +118,8 @@ const URITestCase validCases[] = {
"replName",
2,
2,
- "dbname"},
+ "dbname",
+ kGlobalSSLMode},
{"mongodb://needs%20encoding%25%23!%3C%3E:pwd@127.0.0.1,127.0.0.2/"
"dbname?a=b&replicaSet=replName",
@@ -106,7 +129,8 @@ const URITestCase validCases[] = {
"replName",
2,
2,
- "dbname"},
+ "dbname",
+ kGlobalSSLMode},
{"mongodb://needs%20encoding%25%23!%3C%3E:pwd@127.0.0.1,127.0.0.2/"
"db@name?a=b&replicaSet=replName",
@@ -116,7 +140,8 @@ const URITestCase validCases[] = {
"replName",
2,
2,
- "db@name"},
+ "db@name",
+ kGlobalSSLMode},
{"mongodb://user:needs%20encoding%25%23!%3C%3E@127.0.0.1,127.0.0.2/"
"dbname?a=b&replicaSet=replName",
@@ -126,7 +151,8 @@ const URITestCase validCases[] = {
"replName",
2,
2,
- "dbname"},
+ "dbname",
+ kGlobalSSLMode},
{"mongodb://user:pwd@127.0.0.1,127.0.0.2/dbname?a=b&replicaSet=needs%20encoding%25%23!%3C%3E",
"user",
@@ -135,7 +161,8 @@ const URITestCase validCases[] = {
"needs encoding%#!<>",
2,
2,
- "dbname"},
+ "dbname",
+ kGlobalSSLMode},
{"mongodb://user:pwd@127.0.0.1,127.0.0.2/needsencoding%40hello?a=b&replicaSet=replName",
"user",
@@ -144,7 +171,8 @@ const URITestCase validCases[] = {
"replName",
2,
2,
- "needsencoding@hello"},
+ "needsencoding@hello",
+ kGlobalSSLMode},
{"mongodb://user:pwd@127.0.0.1,127.0.0.2/?replicaSet=replName",
"user",
@@ -153,7 +181,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://user@127.0.0.1,127.0.0.2/?replicaSet=replName",
"user",
@@ -162,7 +191,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://127.0.0.1,127.0.0.2/dbName?foo=a&c=b&replicaSet=replName",
"",
@@ -171,7 +201,8 @@ const URITestCase validCases[] = {
"replName",
2,
3,
- "dbName"},
+ "dbName",
+ kGlobalSSLMode},
{"mongodb://user:pwd@127.0.0.1:1234,127.0.0.2:1234/?replicaSet=replName",
"user",
@@ -180,7 +211,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://user@127.0.0.1:1234,127.0.0.2:1234/?replicaSet=replName",
"user",
@@ -189,7 +221,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://127.0.0.1:1234,127.0.0.1:1234/dbName?foo=a&c=b&replicaSet=replName",
"",
@@ -198,19 +231,20 @@ const URITestCase validCases[] = {
"replName",
2,
3,
- "dbName"},
+ "dbName",
+ kGlobalSSLMode},
- {"mongodb://user:pwd@[::1]", "user", "pwd", kMaster, "", 1, 0, ""},
+ {"mongodb://user:pwd@[::1]", "user", "pwd", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://user@[::1]", "user", "", kMaster, "", 1, 0, ""},
+ {"mongodb://user@[::1]", "user", "", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://[::1]/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"},
+ {"mongodb://[::1]/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName", kGlobalSSLMode},
- {"mongodb://user:pwd@[::1]:1234", "user", "pwd", kMaster, "", 1, 0, ""},
+ {"mongodb://user:pwd@[::1]:1234", "user", "pwd", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://user@[::1]:1234", "user", "", kMaster, "", 1, 0, ""},
+ {"mongodb://user@[::1]:1234", "user", "", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://[::1]:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"},
+ {"mongodb://[::1]:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName", kGlobalSSLMode},
{"mongodb://user:pwd@[::1],127.0.0.2/?replicaSet=replName",
"user",
@@ -219,9 +253,18 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
- {"mongodb://user@[::1],127.0.0.2/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""},
+ {"mongodb://user@[::1],127.0.0.2/?replicaSet=replName",
+ "user",
+ "",
+ kSet,
+ "replName",
+ 2,
+ 1,
+ "",
+ kGlobalSSLMode},
{"mongodb://[::1],127.0.0.2/dbName?foo=a&c=b&replicaSet=replName",
"",
@@ -230,7 +273,8 @@ const URITestCase validCases[] = {
"replName",
2,
3,
- "dbName"},
+ "dbName",
+ kGlobalSSLMode},
{"mongodb://user:pwd@[::1]:1234,127.0.0.2:1234/?replicaSet=replName",
"user",
@@ -239,7 +283,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://user@[::1]:1234,127.0.0.2:1234/?replicaSet=replName",
"user",
@@ -248,7 +293,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://[::1]:1234,[::1]:1234/dbName?foo=a&c=b&replicaSet=replName",
"",
@@ -257,19 +303,20 @@ const URITestCase validCases[] = {
"replName",
2,
3,
- "dbName"},
+ "dbName",
+ kGlobalSSLMode},
- {"mongodb://user:pwd@[::1]", "user", "pwd", kMaster, "", 1, 0, ""},
+ {"mongodb://user:pwd@[::1]", "user", "pwd", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://user@[::1]", "user", "", kMaster, "", 1, 0, ""},
+ {"mongodb://user@[::1]", "user", "", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://[::1]/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"},
+ {"mongodb://[::1]/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName", kGlobalSSLMode},
- {"mongodb://user:pwd@[::1]:1234", "user", "pwd", kMaster, "", 1, 0, ""},
+ {"mongodb://user:pwd@[::1]:1234", "user", "pwd", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://user@[::1]:1234", "user", "", kMaster, "", 1, 0, ""},
+ {"mongodb://user@[::1]:1234", "user", "", kMaster, "", 1, 0, "", kGlobalSSLMode},
- {"mongodb://[::1]:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"},
+ {"mongodb://[::1]:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName", kGlobalSSLMode},
{"mongodb://user:pwd@[::1],127.0.0.2/?replicaSet=replName",
"user",
@@ -278,9 +325,18 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
- {"mongodb://user@[::1],127.0.0.2/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""},
+ {"mongodb://user@[::1],127.0.0.2/?replicaSet=replName",
+ "user",
+ "",
+ kSet,
+ "replName",
+ 2,
+ 1,
+ "",
+ kGlobalSSLMode},
{"mongodb://[::1],127.0.0.2/dbName?foo=a&c=b&replicaSet=replName",
"",
@@ -289,7 +345,8 @@ const URITestCase validCases[] = {
"replName",
2,
3,
- "dbName"},
+ "dbName",
+ kGlobalSSLMode},
{"mongodb://user:pwd@[::1]:1234,127.0.0.2:1234/?replicaSet=replName",
"user",
@@ -298,7 +355,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://user@[::1]:1234,127.0.0.2:1234/?replicaSet=replName",
"user",
@@ -307,7 +365,8 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://[::1]:1234,[::1]:1234/dbName?foo=a&c=b&replicaSet=replName",
"",
@@ -316,7 +375,8 @@ const URITestCase validCases[] = {
"replName",
2,
3,
- "dbName"},
+ "dbName",
+ kGlobalSSLMode},
{"mongodb://user:pwd@[::1]/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:foobar",
"user",
@@ -325,7 +385,8 @@ const URITestCase validCases[] = {
"",
1,
2,
- ""},
+ "",
+ kGlobalSSLMode},
{"mongodb://user:pwd@[::1]/?authMechanism=GSSAPI&gssapiServiceName=foobar",
"user",
@@ -334,9 +395,10 @@ const URITestCase validCases[] = {
"",
1,
2,
- ""},
+ "",
+ kGlobalSSLMode},
- {"mongodb://%2Ftmp%2Fmongodb-27017.sock", "", "", kMaster, "", 1, 0, ""},
+ {"mongodb://%2Ftmp%2Fmongodb-27017.sock", "", "", kMaster, "", 1, 0, "", kGlobalSSLMode},
{"mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/?replicaSet=replName",
"",
@@ -345,7 +407,11 @@ const URITestCase validCases[] = {
"replName",
2,
1,
- ""},
+ "",
+ kGlobalSSLMode},
+
+ {"mongodb://localhost/?ssl=true", "", "", kMaster, "", 1, 1, "", kEnableSSL},
+ {"mongodb://localhost/?ssl=false", "", "", kMaster, "", 1, 1, "", kDisableSSL},
};
const InvalidURITestCase invalidCases[] = {
@@ -364,10 +430,7 @@ const InvalidURITestCase invalidCases[] = {
{"mongodb://localhost:27017localhost:27018"},
// % symbol in password must be escaped.
- {"mongodb://localhost:pass%word@127.0.0.1:27017",
- Status(ErrorCodes::FailedToParse,
- "The characters after the % do not form a hex value. Please escape the % or pass a "
- "valid hex value. ")},
+ {"mongodb://localhost:pass%word@127.0.0.1:27017", ErrorCodes::duplicateCodeForTest(51040)},
// Domain sockets have to end in ".sock".
{"mongodb://%2Fnotareal%2Fdomainsock"},
@@ -419,6 +482,9 @@ const InvalidURITestCase invalidCases[] = {
// Missing an entire key-value pair
{"mongodb://127.0.0.1:1234/dbName?foo=a&&c=b"},
+
+ // Illegal value for ssl.
+ {"mongodb://127.0.0.1:1234/dbName?ssl=blah", ErrorCodes::duplicateCodeForTest(51041)},
};
// Helper Method to take a filename for a json file and return the array of tests inside of it
@@ -480,8 +546,8 @@ TEST(MongoURI, InvalidURIs) {
unittest::log() << "Testing URI: " << testCase.URI << '\n';
auto cs_status = MongoURI::parse(testCase.URI);
ASSERT_NOT_OK(cs_status);
- if (testCase.status) {
- ASSERT_EQUALS(testCase.status, cs_status.getStatus());
+ if (testCase.code) {
+ ASSERT_EQUALS(*testCase.code, cs_status.getStatus());
}
}
}
diff --git a/src/mongo/client/replica_set_monitor.cpp b/src/mongo/client/replica_set_monitor.cpp
index 187b0c70462..306ce15e3ab 100644
--- a/src/mongo/client/replica_set_monitor.cpp
+++ b/src/mongo/client/replica_set_monitor.cpp
@@ -369,6 +369,11 @@ std::string ReplicaSetMonitor::getServerAddress() const {
return _state->getConfirmedServerAddress();
}
+const MongoURI& ReplicaSetMonitor::getOriginalUri() const {
+ // setUri is const so no need to lock.
+ return _state->setUri;
+}
+
bool ReplicaSetMonitor::contains(const HostAndPort& host) const {
stdx::lock_guard<stdx::mutex> lk(_state->mutex);
return _state->seedNodes.count(host);
@@ -996,13 +1001,14 @@ void Node::update(const IsMasterReply& reply) {
lastWriteDateUpdateTime = Date_t::now();
}
-SetState::SetState(StringData name, const std::set<HostAndPort>& seedNodes)
+SetState::SetState(StringData name, const std::set<HostAndPort>& seedNodes, MongoURI uri)
: name(name.toString()),
consecutiveFailedScans(0),
seedNodes(seedNodes),
latencyThresholdMicros(serverGlobalParams.defaultLocalThresholdMillis * 1000),
rand(int64_t(time(0))),
roundRobin(0),
+ setUri(std::move(uri)),
refreshPeriod(getDefaultRefreshPeriod()) {
uassert(13642, "Replica set seed list can't be empty", !seedNodes.empty());
@@ -1024,9 +1030,8 @@ SetState::SetState(StringData name, const std::set<HostAndPort>& seedNodes)
SetState::SetState(const MongoURI& uri)
: SetState(uri.getSetName(),
- std::set<HostAndPort>(uri.getServers().begin(), uri.getServers().end())) {
- setUri = uri;
-}
+ std::set<HostAndPort>(uri.getServers().begin(), uri.getServers().end()),
+ uri) {}
HostAndPort SetState::getMatchingHost(const ReadPreferenceSetting& criteria) const {
switch (criteria.pref) {
diff --git a/src/mongo/client/replica_set_monitor.h b/src/mongo/client/replica_set_monitor.h
index b394425810c..387b34eceb6 100644
--- a/src/mongo/client/replica_set_monitor.h
+++ b/src/mongo/client/replica_set_monitor.h
@@ -152,10 +152,17 @@ public:
/**
* Returns a std::string with the format name/server1,server2.
* If name is empty, returns just comma-separated list of servers.
+ * It IS updated to reflect the current members of the set.
*/
std::string getServerAddress() const;
/**
+ * Returns the URI that was used to construct this monitor.
+ * It IS NOT updated to reflect the current members of the set.
+ */
+ const MongoURI& getOriginalUri() const;
+
+ /**
* Is server part of this set? Uses only cached information.
*/
bool contains(const HostAndPort& server) const;
diff --git a/src/mongo/client/replica_set_monitor_internal.h b/src/mongo/client/replica_set_monitor_internal.h
index ab3b3d02380..385d3f845d9 100644
--- a/src/mongo/client/replica_set_monitor_internal.h
+++ b/src/mongo/client/replica_set_monitor_internal.h
@@ -143,7 +143,7 @@ public:
/**
* seedNodes must not be empty
*/
- SetState(StringData name, const std::set<HostAndPort>& seedNodes);
+ SetState(StringData name, const std::set<HostAndPort>& seedNodes, MongoURI uri = {});
SetState(const MongoURI& uri);
@@ -208,7 +208,7 @@ public:
int64_t latencyThresholdMicros;
mutable PseudoRandom rand; // only used for host selection to balance load
mutable int roundRobin; // used when useDeterministicHostSelection is true
- MongoURI setUri; // URI that may have constructed this
+ const MongoURI setUri; // URI that may have constructed this
Seconds refreshPeriod;
};
diff --git a/src/mongo/client/replica_set_monitor_manager.cpp b/src/mongo/client/replica_set_monitor_manager.cpp
index 1204c33f656..be61056daf6 100644
--- a/src/mongo/client/replica_set_monitor_manager.cpp
+++ b/src/mongo/client/replica_set_monitor_manager.cpp
@@ -97,6 +97,12 @@ void ReplicaSetMonitorManager::_setupTaskExecutorInLock(const std::string& name)
}
}
+namespace {
+void uassertNotMixingSSL(transport::ConnectSSLMode a, transport::ConnectSSLMode b) {
+ uassert(51042, "Mixing ssl modes with a single replica set is disallowed", a == b);
+}
+}
+
shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(
const ConnectionString& connStr) {
invariant(connStr.type() == ConnectionString::SET);
@@ -106,6 +112,7 @@ shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(
auto setName = connStr.getSetName();
auto monitor = _monitors[setName].lock();
if (monitor) {
+ uassertNotMixingSSL(monitor->getOriginalUri().getSSLMode(), transport::kGlobalSSLMode);
return monitor;
}
@@ -127,6 +134,7 @@ shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(const
const auto& setName = uri.getSetName();
auto monitor = _monitors[setName].lock();
if (monitor) {
+ uassertNotMixingSSL(monitor->getOriginalUri().getSSLMode(), uri.getSSLMode());
return monitor;
}