diff options
author | Ben Caimano <ben.caimano@10gen.com> | 2021-02-17 17:42:20 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-18 17:01:33 +0000 |
commit | 5a76da986da7166226cc3da2eed081bc5263bfe6 (patch) | |
tree | f0b99b3a5055f9d6d5484d9a0493ec41fc7e3ccf /jstests | |
parent | f35a8a1cf31e5589f27012cf6df05c0adfe0b978 (diff) | |
download | mongo-5a76da986da7166226cc3da2eed081bc5263bfe6.tar.gz |
SERVER-54136 Make the authenticate command respect enforceUserClusterSeparation
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/ssl/x509_client.js | 52 | ||||
-rw-r--r-- | jstests/ssl/x509_enforce_user_cluster_separation.js | 206 |
2 files changed, 219 insertions, 39 deletions
diff --git a/jstests/ssl/x509_client.js b/jstests/ssl/x509_client.js index 00624c63a33..26f4ecc4c71 100644 --- a/jstests/ssl/x509_client.js +++ b/jstests/ssl/x509_client.js @@ -4,12 +4,10 @@ load("jstests/libs/logv2_helpers.js"); const SERVER_CERT = "jstests/libs/server.pem"; const CA_CERT = "jstests/libs/ca.pem"; -const SERVER_USER = "C=US,ST=New York,L=New York City,O=MongoDB,OU=Kernel,CN=server"; -const INTERNAL_USER = "C=US,ST=New York,L=New York City,O=MongoDB,OU=Kernel,CN=internal"; const CLIENT_USER = "CN=client,OU=KernelUser,O=MongoDB,L=New York City,ST=New York,C=US"; const INVALID_CLIENT_USER = "C=US,ST=New York,L=New York City,O=MongoDB,OU=KernelUser,CN=invalid"; -function authAndTest(mongo, {clusterUserSeparationOveride = false} = {}) { +function authAndTest(mongo) { external = mongo.getDB("$external"); test = mongo.getDB("test"); @@ -60,21 +58,23 @@ function authAndTest(mongo, {clusterUserSeparationOveride = false} = {}) { assert(log.some((line) => successRegex.test(line))); } - const overrideDependentTester = - clusterUserSeparationOveride ? assert.doesNotThrow : assert.throws; - // It should be impossible to create users with the same name as the server's subject, - // unless guardrails are explicitly overridden - overrideDependentTester(function() { + let createServerUser = function() { + // It should be impossible to create users with the same name as the server's subject, + // unless guardrails are explicitly overridden external.createUser( {user: SERVER_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]}); - }, [], "Created user with same name as the server's x.509 subject"); + }; + assert.throws( + createServerUser, [], "Created user with same name as the server's x.509 subject"); - // It should be impossible to create users with names recognized as cluster members, - // unless guardrails are explicitly overridden - overrideDependentTester(function() { + let createInternalUser = function() { + // It should be impossible to create users with names recognized as cluster members, + // unless guardrails are explicitly overridden external.createUser( {user: INTERNAL_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]}); - }, [], "Created user which would be recognized as a cluster member"); + }; + assert.throws( + createInternalUser, [], "Created user which would be recognized as a cluster member"); // Check that we can add a user and read data test.createUser( @@ -100,14 +100,6 @@ const x509_options = { authAndTest(mongo); MongoRunner.stopMongod(mongo); } -{ - print("1.5. Testing x.509 auth to mongod with cluster/user separation disabled"); - const mongo = MongoRunner.runMongod(Object.merge( - x509_options, {auth: "", setParameter: {enforceUserClusterSeparation: false}})); - - authAndTest(mongo, {clusterUserSeparationOveride: true}); - MongoRunner.stopMongod(mongo); -} { print("2. Testing x.509 auth to mongos"); @@ -126,21 +118,3 @@ const x509_options = { authAndTest(new Mongo("localhost:" + st.s0.port)); st.stop(); } -{ - print("2.5 Testing x.509 auth to mongos with cluster/user separation disabled"); - var st = new ShardingTest({ - shards: 1, - mongos: 1, - other: { - keyFile: 'jstests/libs/key1', - configOptions: - Object.merge(x509_options, {setParameter: {enforceUserClusterSeparation: false}}), - mongosOptions: x509_options, - shardOptions: x509_options, - useHostname: false - } - }); - - authAndTest(new Mongo("localhost:" + st.s0.port), {clusterUserSeparationOveride: true}); - st.stop(); -} 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"}); |