diff options
author | Kyle Erf <erf@mongodb.com> | 2013-12-12 15:16:14 -0500 |
---|---|---|
committer | Matt Kangas <matt.kangas@mongodb.com> | 2013-12-13 15:42:28 -0500 |
commit | 2c54682ce88e2c4e7fe8c99baeadfece0831dbd2 (patch) | |
tree | 9523bca472d92773cb6ef84593e3f62aa0649285 /jstests/ssl | |
parent | 779be6eeb263c9dab4072650602366e46d331b1b (diff) | |
download | mongo-2c54682ce88e2c4e7fe8c99baeadfece0831dbd2.tar.gz |
SERVER-11554: Added new tests for mixed mode ssl
Also added ssl testing library functions
Signed-off-by: Matt Kangas <matt.kangas@mongodb.com>
Diffstat (limited to 'jstests/ssl')
-rw-r--r-- | jstests/ssl/libs/ssl_helpers.js | 172 | ||||
-rw-r--r-- | jstests/ssl/mixed_mode_repl.js | 23 | ||||
-rw-r--r-- | jstests/ssl/mixed_mode_sharded.js | 23 | ||||
-rw-r--r-- | jstests/ssl/replset1.js | 32 | ||||
-rw-r--r-- | jstests/ssl/upgrade_to_ssl.js | 43 | ||||
-rw-r--r-- | jstests/ssl/upgrade_to_x509_ssl.js | 51 |
6 files changed, 312 insertions, 32 deletions
diff --git a/jstests/ssl/libs/ssl_helpers.js b/jstests/ssl/libs/ssl_helpers.js new file mode 100644 index 00000000000..0d47e2102c5 --- /dev/null +++ b/jstests/ssl/libs/ssl_helpers.js @@ -0,0 +1,172 @@ +//=== Shared SSL testing library functions and constants === + +var KEYFILE = "jstests/libs/key1" +var SERVER_CERT = "jstests/libs/server.pem" +var CA_CERT = "jstests/libs/ca.pem" +var CLIENT_CERT = "jstests/libs/client.pem" + +// Note: "sslAllowInvalidCertificates" is enabled to avoid +// hostname conflicts with our testing certificates +disabled = {sslMode: "disabled"}; +allowSSL = {sslMode : "allowSSL", + sslAllowInvalidCertificates: "", + sslPEMKeyFile : SERVER_CERT, + sslCAFile: CA_CERT}; +preferSSL = {sslMode : "preferSSL", + sslAllowInvalidCertificates: "", + sslPEMKeyFile : SERVER_CERT, + sslCAFile: CA_CERT}; +requireSSL = {sslMode : "requireSSL", + sslAllowInvalidCertificates: "", + sslPEMKeyFile : SERVER_CERT, + sslCAFile: CA_CERT}; + +// Test if ssl replset configs work +var replShouldSucceed = function(opt1, opt2) { + ssl_options1 = opt1; + ssl_options2 = opt2; + // try running this file using the given config + load("jstests/replsets/replset1.js"); +} + +// Test if ssl replset configs fail +var replShouldFail = function(opt1, opt2) { + ssl_options1 = opt1; + ssl_options2 = opt2; + replTest = null; + assert.throws(load,["jstests/replsets/replset1.js"], + "This setup should have failed"); + // clean up to continue running... + if (replTest) { + replTest.stopSet(15); + } +} + +/** + * Takes in two mongod/mongos configuration options and runs a basic + * sharding test to see if they can work together... + */ +function mixedShardTest(options1, options2, shouldSucceed) { + try { + var st = new ShardingTest({ + mongos : [options1], + config : [options1], + shards : [options1, options2] + }); + + var r = st.adminCommand({enableSharding: "test"}); + assert.eq(r, true, "error enabling sharding for this configuration"); + + db1 = st.getDB("test"); + r = st.adminCommand({ shardCollection : "test.col" , key : { _id : 1 } }); + assert.eq(r, true, "error sharding collection for this configuration"); + + var bigstr = Array(1024*1024).join("#"); + + for(var i = 0; i < 128; i++){ + db1.col.insert({_id:i, string:bigstr}); + } + db1.getLastError(); + assert.eq(128, db1.col.count(), "error retrieving documents from cluster"); + st.config.shards.find().forEach(function(z){printjson(z);}); + var shardDict = {}; + st.config.chunks.find().forEach(function(z){ + printjson(z); + shardDict[z.shard] = 1; + }); + assert.eq(1, shardDict["shard0000"], "shards not properly utilized by cluster"); + assert.eq(1, shardDict["shard0001"], "shards not properly utilized by cluster"); + db1.col.remove(); + + } catch(e) { + if (shouldSucceed) throw e; + //silence error if we should fail... + print("IMPORTANT! => Test failed when it should have failed...continuing..."); + } finally { + // This has to be done in order for failure + // to not prevent future tests from running... + if(st) { + st.stop(); + } + } +} + +// +// Utility functions for upgrading replica sets +// +// Hacked from version upgrading functions in multiVersion folder. +// TODO: merge this with that file and add to utils? +// + +ReplSetTest.prototype.upgradeSet = function( options ){ + options = options || {} + + var nodes = this.nodes + var primary = this.getPrimary() + + // Upgrade secondaries first + var nodesToUpgrade = this.getSecondaries() + + // Then upgrade primaries + nodesToUpgrade.push( primary ) + + // We can upgrade with no primary downtime if we have enough nodes + var noDowntimePossible = nodes.length > 2 + + for( var i = 0; i < nodesToUpgrade.length; i++ ){ + var node = nodesToUpgrade[ i ] + if( node == primary ){ + node = this.stepdown( node ) + primary = this.getPrimary() + } + + var prevPrimaryId = this.getNodeId( primary ); + //merge new options into node settings... + for(var nodeName in this.nodeOptions){ + this.nodeOptions[nodeName] = Object.merge(this.nodeOptions[nodeName], options); + } + printjson(this.nodeOptions); + this.upgradeNode( node, options, true ) + + if( noDowntimePossible ) + assert.eq( this.getNodeId( primary ), prevPrimaryId ) + } +} + +ReplSetTest.prototype.upgradeNode = function( node, opts, waitForState ){ + var node = this.restart( node, opts ) + // By default, wait for primary or secondary state + if( waitForState == undefined ) waitForState = true + if( waitForState == true ) waitForState = [ ReplSetTest.State.PRIMARY, + ReplSetTest.State.SECONDARY, + ReplSetTest.State.ARBITER ] + if( waitForState ) + this.waitForState( node, waitForState ) + + return node +} + +ReplSetTest.prototype.stepdown = function( nodeId ){ + nodeId = this.getNodeId( nodeId ) + assert.eq( this.getNodeId( this.getPrimary() ), nodeId ) + var node = this.nodes[ nodeId ] + try { + node.getDB("admin").runCommand({ replSetStepDown: 50, force : true }) + assert( false ) + } + catch( e ){ + printjson( e ); + } + return this.reconnect( node ) +} + +ReplSetTest.prototype.reconnect = function( node ){ + var nodeId = this.getNodeId( node ) + this.nodes[ nodeId ] = new Mongo( node.host ) + var except = {} + for( var i in node ){ + if( typeof( node[i] ) == "function" ) continue + this.nodes[ nodeId ][ i ] = node[ i ] + } + return this.nodes[ nodeId ] +} diff --git a/jstests/ssl/mixed_mode_repl.js b/jstests/ssl/mixed_mode_repl.js new file mode 100644 index 00000000000..f87f8d4dcd6 --- /dev/null +++ b/jstests/ssl/mixed_mode_repl.js @@ -0,0 +1,23 @@ +// This test is related to mixed_mode_repl_nossl.js in +// the sslSpecial test set. This test must be run with --use-ssl + +// If we are running in use-x509 passthrough mode, turn it off +// since it is not necessary for this test. +TestData.useX509 = false; +load("jstests/ssl/libs/ssl_helpers.js") + +// Verify that requireSSL allows ssl connections +print("=== Testing requireSSL/requireSSL cluster ==="); +replShouldSucceed( requireSSL, requireSSL); + +// Test mixed sslMode allowSSL/preferSSL +print("=== Testing allowSSL/preferSSL cluster ==="); +replShouldSucceed(allowSSL, preferSSL); + +// Test mixed sslMode preferSSL/requireSSL +print("=== Testing preferSSL/requireSSL cluster ===") +replShouldSucceed( preferSSL, requireSSL); + +// Test mixed sslMode disabled/preferSSL - should fail +print("=== Testing allowSSL/requireSSL cluster - SHOULD FAIL ==="); +replShouldFail(allowSSL, requireSSL); diff --git a/jstests/ssl/mixed_mode_sharded.js b/jstests/ssl/mixed_mode_sharded.js new file mode 100644 index 00000000000..08d872939a2 --- /dev/null +++ b/jstests/ssl/mixed_mode_sharded.js @@ -0,0 +1,23 @@ +/** + * This test checks if different mixtures of ssl modes + * in a sharded cluster can or cannot function + */ + +// If we are running in use-x509 passthrough mode, turn it off +// since it is not necessary for this test. +TestData.useX509 = false; +load("jstests/ssl/libs/ssl_helpers.js"); + +print("=== Testing requireSSL/requireSSL cluster ==="); +mixedShardTest(requireSSL, requireSSL, true); + +print("=== Testing preferSSL/requireSSL cluster ===") +mixedShardTest(preferSSL, requireSSL, true); +mixedShardTest(requireSSL, preferSSL, true); + +print("=== Testing allowSSL/preferSSL cluster ==="); +mixedShardTest(preferSSL, allowSSL, true); +mixedShardTest(allowSSL, preferSSL, true); + +print("=== Testing allowSSL/requireSSL cluster - SHOULD FAIL ==="); +mixedShardTest(requireSSL, allowSSL, false); diff --git a/jstests/ssl/replset1.js b/jstests/ssl/replset1.js deleted file mode 100644 index 3b11710b6ab..00000000000 --- a/jstests/ssl/replset1.js +++ /dev/null @@ -1,32 +0,0 @@ -// If we are running in use-x509 passthrough mode, turn it off -// since it is not necessary for this test. -TestData.useX509 = false; - -ssl_options1 = {sslMode : "requireSSL", - sslPEMKeyFile : "jstests/libs/server.pem", - sslCAFile: "jstests/libs/ca.pem", - sslAllowInvalidCertificates: ""}; -ssl_options2 = ssl_options1; -load("jstests/replsets/replset1.js"); - -// Test mixed sslMode allowSSL/preferSSL -ssl_options1 = {sslMode : "allowSSL", - sslPEMKeyFile : "jstests/libs/server.pem", - sslCAFile: "jstests/libs/ca.pem", - sslAllowInvalidCertificates: ""}; -ssl_options2 = {sslMode : "preferSSL", - sslPEMKeyFile : "jstests/libs/server.pem", - sslCAFile: "jstests/libs/ca.pem", - sslAllowInvalidCertificates: ""}; -load("jstests/replsets/replset1.js"); - -// Test mixed sslMode preferSSL/requireSSL -ssl_options1 = {sslMode : "preferSSL", - sslPEMKeyFile : "jstests/libs/server.pem", - sslCAFile: "jstests/libs/ca.pem", - sslAllowInvalidCertificates: ""}; -ssl_options2 = {sslMode : "requireSSL", - sslPEMKeyFile : "jstests/libs/server.pem", - sslCAFile: "jstests/libs/ca.pem", - sslAllowInvalidCertificates: ""}; -load("jstests/replsets/replset1.js"); diff --git a/jstests/ssl/upgrade_to_ssl.js b/jstests/ssl/upgrade_to_ssl.js new file mode 100644 index 00000000000..3b179cec613 --- /dev/null +++ b/jstests/ssl/upgrade_to_ssl.js @@ -0,0 +1,43 @@ +/** + * This test checks the upgrade path for mixed mode ssl + * from allowSSL up to requireSSL + * + * NOTE: This test is similar to upgrade_to_ssl_nossl.js in the + * sslSpecial test suite. This test uses ssl communication + * and therefore cannot test modes that do not allow ssl. + */ + +// If we are running in use-x509 passthrough mode, turn it off +// since it is not necessary for this test. +TestData.useX509 = false; +load("jstests/ssl/libs/ssl_helpers.js"); + +// "sslAllowInvalidCertificates" is enabled to avoid hostname conflicts with our testing certs +opts = {sslMode:"allowSSL", sslPEMKeyFile: SERVER_CERT, sslAllowInvalidCertificates: ""}; +var rst = new ReplSetTest({ name: 'sslSet', nodes: 3, nodeOptions : opts }); +rst.startSet(); +rst.initiate(); + +var rstConn1 = rst.getMaster(); +rstConn1.getDB("test").a.insert({a:1, str:"TESTTESTTEST"}); +assert.eq(1, rstConn1.getDB("test").a.count(), "Error interacting with replSet"); + +print("===== UPGRADE allowSSL -> preferSSL ====="); +rst.upgradeSet({sslMode:"preferSSL", sslPEMKeyFile: SERVER_CERT, sslAllowInvalidCertificates: ""}); +var rstConn2 = rst.getMaster(); +rstConn2.getDB("test").a.insert({a:2, str:"CHECKCHECK"}); +assert.eq(2, rstConn2.getDB("test").a.count(), "Error interacting with replSet"); + +// Check that non-ssl connections can still be made +var canConnectNoSSL = runMongoProgram("mongo", "--port", rst.ports[0], "--eval", ";"); +assert.eq(0, canConnectNoSSL, "non-SSL Connection attempt failed when it should succeed"); + +print("===== UPGRADE preferSSL -> requireSSL ====="); +rst.upgradeSet({sslMode:"requireSSL", sslPEMKeyFile: SERVER_CERT, sslAllowInvalidCertificates: ""}); +var rstConn3 = rst.getMaster(); +rstConn3.getDB("test").a.insert({a:3, str:"GREENEGGSANDHAM"}); +assert.eq(3, rstConn3.getDB("test").a.count(), "Error interacting with replSet"); + +// Check that ssl connections can be made +var canConnectSSL = runMongoProgram("mongo", "--port", rst.ports[0], "--ssl", "--eval", ";"); +assert.eq(0, canConnectSSL, "SSL Connection attempt failed when it should succeed"); diff --git a/jstests/ssl/upgrade_to_x509_ssl.js b/jstests/ssl/upgrade_to_x509_ssl.js new file mode 100644 index 00000000000..89696eb864c --- /dev/null +++ b/jstests/ssl/upgrade_to_x509_ssl.js @@ -0,0 +1,51 @@ +/** + * This test checks the upgrade path for mixed mode ssl + x509 auth + * from disabled/keyfiles up to preferSSL/x509 + * + * NOTE: This test is similar to upgrade_to_x509_ssl_nossl.js in the + * sslSpecial test suite. This test uses ssl communication + * and therefore cannot test modes that do not allow ssl. + */ + +// If we are running in use-x509 passthrough mode, turn it off +// since it is not necessary for this test. +TestData.useX509 = false; +load("jstests/ssl/libs/ssl_helpers.js"); + +opts = {sslMode:"allowSSL", sslPEMKeyFile: SERVER_CERT, + sslAllowInvalidCertificates: "", + clusterAuthMode:"sendKeyFile", keyFile: KEYFILE, + sslCAFile: CA_CERT}; +var rst = new ReplSetTest({ name: 'sslSet', nodes: 3, nodeOptions : opts }); +rst.startSet(); +rst.initiate(); + +// Connect to master and do some basic operations +var rstConn1 = rst.getMaster(); +rstConn1.getDB("test").a.insert({a:1, str:"TESTTESTTEST"}); +rstConn1.getDB("test").a.insert({a:1, str:"WOOPWOOPWOOPWOOPWOOP"}); +assert.eq(2, rstConn1.getDB("test").a.count(), "Error interacting with replSet"); + +print("===== UPGRADE allowSSL,sendKeyfile -> preferSSL,sendX509 ====="); +rst.upgradeSet({sslMode:"preferSSL", sslPEMKeyFile: SERVER_CERT, + sslAllowInvalidCertificates: "", + clusterAuthMode:"sendX509", keyFile: KEYFILE, + sslCAFile: CA_CERT}); +rst.awaitReplication(); +var rstConn3 = rst.getMaster(); +rstConn3.getDB("test").a.insert({a:3, str:"TESTTESTTEST"}); +assert.eq(3, rstConn3.getDB("test").a.count(), "Error interacting with replSet"); + +// Test that a non-ssl connection can still be made +var canConnectNoSSL = runMongoProgram("mongo", "--port", rst.ports[0], "--eval", ";"); +assert.eq(0, canConnectNoSSL, "SSL Connection attempt failed when it should succeed"); + +print("===== UPGRADE preferSSL,sendX509 -> requireSSL,x509 ====="); +rst.upgradeSet({sslMode:"requireSSL", sslPEMKeyFile: SERVER_CERT, + sslAllowInvalidCertificates: "", + clusterAuthMode:"x509", keyFile: KEYFILE, + sslCAFile: CA_CERT}); +rst.awaitReplication(); +var rstConn4 = rst.getMaster(); +rstConn4.getDB("test").a.insert({a:4, str:"TESTTESTTEST"}); +assert.eq(4, rstConn4.getDB("test").a.count(), "Error interacting with replSet"); |