summaryrefslogtreecommitdiff
path: root/jstests/ssl
diff options
context:
space:
mode:
authorKyle Erf <erf@mongodb.com>2013-12-12 15:16:14 -0500
committerMatt Kangas <matt.kangas@mongodb.com>2013-12-13 15:42:28 -0500
commit2c54682ce88e2c4e7fe8c99baeadfece0831dbd2 (patch)
tree9523bca472d92773cb6ef84593e3f62aa0649285 /jstests/ssl
parent779be6eeb263c9dab4072650602366e46d331b1b (diff)
downloadmongo-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.js172
-rw-r--r--jstests/ssl/mixed_mode_repl.js23
-rw-r--r--jstests/ssl/mixed_mode_sharded.js23
-rw-r--r--jstests/ssl/replset1.js32
-rw-r--r--jstests/ssl/upgrade_to_ssl.js43
-rw-r--r--jstests/ssl/upgrade_to_x509_ssl.js51
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");