summaryrefslogtreecommitdiff
path: root/jstests
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
parentf35a8a1cf31e5589f27012cf6df05c0adfe0b978 (diff)
downloadmongo-5a76da986da7166226cc3da2eed081bc5263bfe6.tar.gz
SERVER-54136 Make the authenticate command respect enforceUserClusterSeparation
Diffstat (limited to 'jstests')
-rw-r--r--jstests/ssl/x509_client.js52
-rw-r--r--jstests/ssl/x509_enforce_user_cluster_separation.js206
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"});