diff options
author | Tad Marshall <tad@10gen.com> | 2013-03-10 13:34:11 -0400 |
---|---|---|
committer | Tad Marshall <tad@10gen.com> | 2013-07-29 13:48:33 -0400 |
commit | 031daa05328127af84a0625ab9165a531678fe5d (patch) | |
tree | 9dfdc68d3e0851c2fc8d7a1325ad4edb0ef55118 | |
parent | ad46ea3318bd584ac27cca7b90fe6f68948c2530 (diff) | |
download | mongo-031daa05328127af84a0625ab9165a531678fe5d.tar.gz |
SERVER-8030 Validate connection string in JavaScript connect() function
Validate that the "URL" passed to the connect() function matches one of the
accepted formats (host:port/database, host/database or database) before trying
to use it to connect to a server. Change a uassert in HostAndPort::init() to
an massert to match the massert four lines above it. Add jstest for connect()
validation.
-rw-r--r-- | jstests/connection_string_validation.js | 99 | ||||
-rw-r--r-- | src/mongo/shell/mongo.js | 64 | ||||
-rw-r--r-- | src/mongo/util/net/hostandport.h | 2 |
3 files changed, 148 insertions, 17 deletions
diff --git a/jstests/connection_string_validation.js b/jstests/connection_string_validation.js new file mode 100644 index 00000000000..fe15ea6808c --- /dev/null +++ b/jstests/connection_string_validation.js @@ -0,0 +1,99 @@ +// Test validation of connection strings passed to the JavaScript "connect()" function. +// Related to SERVER-8030. + +var goodStrings = [ + "localhost:27999/test", + "127.0.0.1:27999/test" + ]; + +var badStrings = [ + { s: undefined, r: /^Missing connection string$/ }, + { s: 7, r: /^Incorrect type/ }, + { s: null, r: /^Incorrect type/ }, + { s: "", r: /^Empty connection string$/ }, + { s: " ", r: /^Empty connection string$/ }, + { s: ":", r: /^Missing host name/ }, + { s: "/", r: /^Missing host name/ }, + { s: ":/", r: /^Missing host name/ }, + { s: ":/test", r: /^Missing host name/ }, + { s: ":27999/", r: /^Missing host name/ }, + { s: ":27999/test", r: /^Missing host name/ }, + { s: "/test", r: /^Missing host name/ }, + { s: "localhost:/test", r: /^Missing port number/ }, + { s: "127.0.0.1:/test", r: /^Missing port number/ }, + { s: "127.0.0.1:cat/test", r: /^Invalid port number/ }, + { s: "127.0.0.1:1cat/test", r: /^Invalid port number/ }, + { s: "127.0.0.1:123456/test", r: /^Invalid port number/ }, + { s: "127.0.0.1:65536/test", r: /^Invalid port number/ }, + { s: "::1:65536/test", r: /^Invalid port number/ }, + { s: "127.0.0.1:27999/", r: /^Missing database name/ }, + { s: "::1:27999/", r: /^Missing database name/ } + ]; + +function testGood(i, connectionString) { + print("\nTesting good connection string " + i + " (\"" + connectionString + "\") ..."); + var gotException = false; + var exception; + try { + var connectDB = connect(connectionString); + connectDB = null; + } + catch (e) { + gotException = true; + exception = e; + } + if (!gotException) { + print("Good connection string " + i + + " (\"" + connectionString + "\") correctly validated"); + return; + } + var message = "FAILED to correctly validate goodString " + i + + " (\"" + connectionString + "\"): exception was \"" + tojson(exception) + "\""; + doassert(message); +} + +function testBad(i, connectionString, errorRegex) { + print("\nTesting bad connection string " + i + " (\"" + connectionString + "\") ..."); + var gotException = false; + var gotCorrectErrorText = false; + var exception; + try { + var connectDB = connect(connectionString); + connectDB = null; + } + catch (e) { + gotException = true; + exception = e; + if (errorRegex.test(e.message)) { + gotCorrectErrorText = true; + } + } + if (gotCorrectErrorText) { + print("Bad connection string " + i + " (\"" + connectionString + + "\") correctly rejected:\n" + tojson(exception)); + return; + } + var message = "FAILED to generate correct exception for badString " + i + + " (\"" + connectionString + "\"): "; + if (gotException) { + message += "exception was \"" + tojson(exception) + + "\", it should have matched \"" + errorRegex.toString() + "\""; + } + else { + message += "no exception was thrown"; + } + doassert(message); +} + +var i; +jsTest.log("TESTING " + goodStrings.length + " good connection strings"); +for (i = 0; i < goodStrings.length; ++i) { + testGood(i, goodStrings[i]); +} + +jsTest.log("TESTING " + badStrings.length + " bad connection strings"); +for (i = 0; i < badStrings.length; ++i) { + testBad(i, badStrings[i].s, badStrings[i].r); +} + +jsTest.log("SUCCESSFUL test completion"); diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js index e4786a7cc17..2f3667f53f3 100644 --- a/src/mongo/shell/mongo.js +++ b/src/mongo/shell/mongo.js @@ -98,26 +98,58 @@ Mongo.prototype.getReadPrefTagSet = function () { return this._readPrefTagSet; }; -connect = function( url , user , pass ){ - chatty( "connecting to: " + url ) - - if ( user && ! pass ) - throw "you specified a user and not a password. either you need a password, or you're using the old connect api"; +connect = function(url, user, pass) { + if (user && !pass) + throw Error("you specified a user and not a password. " + + "either you need a password, or you're using the old connect api"); + + // Validate connection string "url" as "hostName:portNumber/databaseName" + // or "hostName/databaseName" + // or "databaseName" + // hostName may be an IPv6 address (with colons), in which case ":portNumber" is required + // + var urlType = typeof url; + if (urlType == "undefined") { + throw Error("Missing connection string"); + } + if (urlType != "string") { + throw Error("Incorrect type \"" + urlType + + "\" for connection string \"" + tojson(url) + "\""); + } + url = url.trim(); + if (0 == url.length) { + throw Error("Empty connection string"); + } + var colon = url.lastIndexOf(":"); + var slash = url.lastIndexOf("/"); + if (0 == colon || 0 == slash) { + throw Error("Missing host name in connection string \"" + url + "\""); + } + if (colon == slash - 1 || colon == url.length - 1) { + throw Error("Missing port number in connection string \"" + url + "\""); + } + if (colon != -1 && colon < slash) { + var portNumber = url.substring(colon + 1, slash); + if (portNumber.length > 5 || !/^\d*$/.test(portNumber) || parseInt(portNumber) > 65535) { + throw Error("Invalid port number \"" + portNumber + + "\" in connection string \"" + url + "\""); + } + } + if (slash == url.length - 1) { + throw Error("Missing database name in connection string \"" + url + "\""); + } - var idx = url.lastIndexOf( "/" ); - + chatty("connecting to: " + url) var db; - - if ( idx < 0 ) - db = new Mongo().getDB( url ); + if (slash == -1) + db = new Mongo().getDB(url); else - db = new Mongo( url.substring( 0 , idx ) ).getDB( url.substring( idx + 1 ) ); - - if ( user && pass ){ - if ( ! db.auth( user , pass ) ){ - throw "couldn't login"; + db = new Mongo(url.substring(0, slash)).getDB(url.substring(slash + 1)); + + if (user && pass) { + if (!db.auth(user, pass)) { + throw Error("couldn't login"); } } - return db; } diff --git a/src/mongo/util/net/hostandport.h b/src/mongo/util/net/hostandport.h index 2d8e435293c..ff47d7f9ef4 100644 --- a/src/mongo/util/net/hostandport.h +++ b/src/mongo/util/net/hostandport.h @@ -170,7 +170,7 @@ namespace mongo { const char *colon = strrchr(p, ':'); if( colon ) { int port = atoi(colon+1); - uassert(13095, "HostAndPort: bad port #", port > 0); + massert(13095, "HostAndPort: bad port #", port > 0); _host = string(p,colon-p); _port = port; } |