summaryrefslogtreecommitdiff
path: root/jstests/ssl/x509_enforce_user_cluster_separation.js
diff options
context:
space:
mode:
authorBen Caimano <ben.caimano@10gen.com>2021-02-17 17:42:20 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-02-18 17:01:33 +0000
commit5a76da986da7166226cc3da2eed081bc5263bfe6 (patch)
treef0b99b3a5055f9d6d5484d9a0493ec41fc7e3ccf /jstests/ssl/x509_enforce_user_cluster_separation.js
parentf35a8a1cf31e5589f27012cf6df05c0adfe0b978 (diff)
downloadmongo-5a76da986da7166226cc3da2eed081bc5263bfe6.tar.gz
SERVER-54136 Make the authenticate command respect enforceUserClusterSeparation
Diffstat (limited to 'jstests/ssl/x509_enforce_user_cluster_separation.js')
-rw-r--r--jstests/ssl/x509_enforce_user_cluster_separation.js206
1 files changed, 206 insertions, 0 deletions
diff --git a/jstests/ssl/x509_enforce_user_cluster_separation.js b/jstests/ssl/x509_enforce_user_cluster_separation.js
new file mode 100644
index 00000000000..a27ca670be3
--- /dev/null
+++ b/jstests/ssl/x509_enforce_user_cluster_separation.js
@@ -0,0 +1,206 @@
+// Check if this build supports the authenticationMechanisms startup parameter.
+load("jstests/libs/logv2_helpers.js");
+
+const SERVER_CERT = "jstests/libs/server.pem";
+const SERVER_SAN_CERT = "jstests/libs/server_SAN.pem";
+const CLIENT_CERT = "jstests/libs/client.pem";
+const CA_CERT = "jstests/libs/ca.pem";
+
+const SERVER_USER = "CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US";
+const SERVER_SAN_USER =
+ "CN=Kernel Client Peer Role,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US";
+const CLIENT_USER = "CN=client,OU=KernelUser,O=MongoDB,L=New York City,ST=New York,C=US";
+
+function authAndTest(cert, user) {
+ const INVALID_USER = "C=US,ST=New York,L=New York City,O=MongoDB,OU=KernelUser,CN=invalid";
+
+ let external = db.getSiblingDB("$external");
+ let test = db.getSiblingDB("test");
+
+ assert(!external.auth({user: INVALID_USER, mechanism: 'MONGODB-X509'}),
+ "authentication with invalid user should fail");
+ assert(external.auth({user: user, mechanism: 'MONGODB-X509'}),
+ "authentication with valid user failed");
+ assert(external.auth({mechanism: 'MONGODB-X509'}),
+ "authentication with valid cert and no user field failed");
+ assert(external.runCommand({authenticate: 1, mechanism: 'MONGODB-X509', user: user}).ok,
+ "runCommand authentication with valid cert and user field failed");
+ assert(external.runCommand({authenticate: 1, mechanism: 'MONGODB-X509'}).ok,
+ "runCommand authentication with valid cert and no user field failed");
+ // Smoke our current user with a find.
+ test.foo.findOne();
+
+ // Check that we can add a user and read data.
+ test.createUser(
+ {user: "test", pwd: "test", roles: [{'role': 'readWriteAnyDatabase', 'db': 'admin'}]});
+ test.foo.findOne();
+
+ // Reads are not allowed after logout.
+ external.logout();
+ assert.throws(function() {
+ test.foo.findOne();
+ }, [], "read after logout");
+}
+
+function runSubShell(conn, cert, user, func) {
+ const args = [
+ 'mongo',
+ '--tls',
+ `--tlsCAFile=${CA_CERT}`,
+ `--tlsCertificateKeyFile=${cert}`,
+ '--tlsAllowInvalidHostnames',
+ '--authenticationDatabase=$external',
+ '--authenticationMechanism=MONGODB-X509',
+ `mongodb://${conn.host}`,
+ '--eval',
+ `(${func.toString()})('${cert}', '${user}');`
+ ];
+ const ret = _runMongoProgram(...args);
+ assert(ret == ErrorCodes.OK, 'subshell did not succeed');
+}
+
+function initUser(conn, user) {
+ const external = conn.getDB("$external");
+ external.createUser({
+ user: user,
+ roles: [
+ {'role': 'userAdminAnyDatabase', 'db': 'admin'},
+ {'role': 'readWriteAnyDatabase', 'db': 'admin'},
+ {'role': 'clusterMonitor', 'db': 'admin'},
+ ]
+ });
+
+ // Localhost exception should not be in place anymore
+ const test = conn.getDB("test");
+ assert.throws(function() {
+ test.foo.findOne();
+ }, [], "read without login");
+}
+
+const x509_options = {
+ sslMode: "requireSSL",
+ sslPEMKeyFile: SERVER_CERT,
+ sslCAFile: CA_CERT
+};
+
+const mongodOptions =
+ Object.merge(x509_options, {auth: "", setParameter: {enforceUserClusterSeparation: false}});
+
+const mongosOptions =
+ Object.merge(x509_options, {setParameter: {enforceUserClusterSeparation: false}});
+
+function runMongodTest(desc, func) {
+ print(desc);
+ const mongo = MongoRunner.runMongod(mongodOptions);
+ func(mongo);
+
+ MongoRunner.stopMongod(mongo);
+}
+
+function runMongodFailTest(desc, options) {
+ print(desc);
+ const mongo = MongoRunner.runMongod(Object.merge(mongodOptions, options));
+ assert(!mongo, "MongoD started successfully with bad options");
+}
+
+function runMongosTest(desc, func) {
+ print(desc);
+ const st = new ShardingTest({
+ shards: 1,
+ mongos: 1,
+ other: {
+ keyFile: 'jstests/libs/key1',
+ configOptions: mongodOptions,
+ mongosOptions: mongosOptions,
+ shardOptions: x509_options,
+ useHostname: false
+ }
+ });
+
+ const mongo = new Mongo(`localhost:${st.s0.port}`);
+ func(mongo);
+ st.stop();
+}
+
+function runMongosFailTest(desc, options) {
+ print(desc);
+ // We start the ShardingTest cleanly first because it throws and fails to clean up after itself.
+ const st = new ShardingTest({
+ config: 1,
+ shards: 1,
+ mongos: 1,
+ other: {
+ keyFile: 'jstests/libs/key1',
+ configOptions: mongodOptions,
+ mongosOptions: mongosOptions,
+ shardOptions: x509_options,
+ useHostname: false
+ }
+ });
+
+ const failOptions = Object.merge(mongosOptions, options);
+ print(`Fail options: ${tojson(failOptions)}`);
+
+ assert.throws(function() {
+ // Start a new mongos with bad options.
+ st.restartMongos(0, failOptions);
+ }, [], "MongoS restarted successfully with bad options");
+
+ // Avoid st.stop() because it will throw when it attempts to stop the second mongos.
+ st.stopAllShards();
+ st.stopAllConfigServers();
+}
+
+runMongodTest("1a. Testing x.509 auth to mongod with a client user/cert", function(conn) {
+ initUser(conn, CLIENT_USER);
+
+ runSubShell(conn, CLIENT_CERT, CLIENT_USER, authAndTest);
+});
+
+runMongodTest("1b. Testing x.509 auth to mongod with the server user/cert", function(conn) {
+ initUser(conn, SERVER_USER);
+
+ runSubShell(conn, SERVER_CERT, SERVER_USER, authAndTest);
+});
+
+runMongodTest("1c. Testing x.509 auth to mongod with a cluster user/cert", function(conn) {
+ initUser(conn, SERVER_SAN_USER);
+
+ runSubShell(conn, SERVER_SAN_CERT, SERVER_SAN_USER, authAndTest);
+});
+
+runMongodFailTest('1d. Testing x.509 cluster auth on mongod with "x509" option',
+ {clusterAuthMode: "x509"});
+
+runMongodFailTest('1e. Testing x.509 cluster auth on mongod with "sendX509" option',
+ {clusterAuthMode: "sendX509"});
+
+runMongodFailTest('1e. Testing x.509 cluster auth on mongod with "sendKeyFile" option',
+ {clusterAuthMode: "sendKeyFile"});
+
+runMongosTest("2a. Testing x.509 auth to mongos with a client user/cert", function(conn) {
+ initUser(conn, CLIENT_USER);
+
+ runSubShell(conn, CLIENT_CERT, CLIENT_USER, authAndTest);
+});
+
+runMongosTest("2b. Testing x.509 auth to mongos with the server user/cert", function(conn) {
+ initUser(conn, SERVER_USER);
+
+ runSubShell(conn, SERVER_CERT, SERVER_USER, authAndTest);
+});
+
+runMongosTest("2c. Testing x.509 auth to mongos with a cluster user/cert", function(conn) {
+ initUser(conn, SERVER_SAN_USER);
+
+ runSubShell(conn, SERVER_SAN_CERT, SERVER_SAN_USER, authAndTest);
+});
+
+runMongosFailTest('2d. Testing x.509 cluster auth on mongos with "x509" option',
+ {restart: true, clusterAuthMode: "x509"});
+
+runMongosFailTest('2e. Testing x.509 cluster auth on mongos with "sendX509" option',
+ {clusterAuthMode: "sendX509"});
+
+runMongosFailTest('2f. Testing x.509 cluster auth on mongos with "sendKeyFile" option',
+ {clusterAuthMode: "sendKeyFile"});