mongo/jstests/ssl/cluster_member.js

115 lines
4.3 KiB
JavaScript

// Test configuration parameter tlsClusterAuthX509ExtensionValue
// aka: net.tls.clusterAuthX509.extensionValue
// @tags: [ requires_fcv_70 ]
import {determineSSLProvider} from "jstests/ssl/libs/ssl_helpers.js";
if (determineSSLProvider() !== "openssl") {
jsTest.log("Test requires openssl based TLS support");
quit();
}
// Fails when used without clusterAuthMode == 'X509'
{
const opts = {auth: "", tlsClusterAuthX509ExtensionValue: "foo"};
const errmsg = "net.tls.clusterAuthX509.extensionValue requires a clusterAuthMode which allows for usage of X509";
jsTest.log("No clusterAuthMode set");
clearRawMongoProgramOutput();
assert.throws(() => MongoRunner.runMongod(opts));
assert(rawMongoProgramOutput(".*").includes(errmsg));
jsTest.log("clusterAuthMode == keyFile");
clearRawMongoProgramOutput();
opts.clusterAuthMode = "keyFile";
assert.throws(() => MongoRunner.runMongod(opts));
assert(rawMongoProgramOutput(".*").includes(errmsg));
}
function authAndDo(port, cert, cmd = ";") {
jsTest.log("Connecting to localhost using cert: " + cert);
function x509auth(db) {
const ext = db.getSiblingDB("$external");
assert.commandWorked(ext.runCommand({authenticate: 1, mechanism: "MONGODB-X509"}));
return ext.adminCommand({connectionStatus: 1});
}
clearRawMongoProgramOutput();
const shell = runMongoProgram(
"mongo",
"--host",
"localhost",
"--port",
port,
"--tls",
"--tlsCAFile",
"jstests/libs/ca.pem",
"--tlsCertificateKeyFile",
cert,
"--eval",
x509auth + " x509auth(db); " + cmd,
);
assert.eq(shell, 0);
}
function runTest(conn) {
const SERVER_RDN = "CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US";
const SERVER = "jstests/libs/server.pem";
const FOO_MEMBER = "jstests/ssl/libs/cluster-member-foo.pem";
const BAR_MEMBER = "jstests/ssl/libs/cluster-member-bar.pem";
const FOO_MEMBER_ALT = "jstests/ssl/libs/cluster-member-foo-alt-rdn.pem";
const FOO_MEMBER_ALT_RDN = "CN=Doer,OU=Business,O=Company,L=Fakesville,ST=Example,C=ZZ";
const admin = conn.getDB("admin");
const ext = conn.getDB("$external");
// Ensure no localhost auth bypass available.
assert.commandWorked(admin.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]}));
assert(admin.auth("admin", "admin"));
// Connect using server.pem which has the same RDN, but no custom extension.
// This will result in an unknown user condition because we are
// not recognized as a cluster member.
assert.throws(() => authAndDo(conn.port, SERVER));
const insertCmd = 'assert.writeOK(db.getSiblingDB("test").mycoll.insert({x:1}));';
// Connect using same RDN WITH custom extension.
authAndDo(conn.port, FOO_MEMBER, insertCmd);
// Connect using cert with membership extension, but wrong value.
assert.throws(() => authAndDo(conn.port, BAR_MEMBER));
// Connect using cert with right membership, but different RDN (allowed).
authAndDo(conn.port, FOO_MEMBER_ALT, insertCmd);
// Create a user who would have been a cluster member under name based rules.
// We should have basic privs, testing with read but not write.
const readCmd = 'db.getSiblingDB("test").mycoll.find({});';
const readRoles = [{db: "admin", role: "readAnyDatabase"}];
assert.commandWorked(ext.runCommand({createUser: SERVER_RDN, roles: readRoles}));
authAndDo(conn.port, SERVER, readCmd);
assert.throws(() => authAndDo(conn.port, SERVER, insertCmd));
// Create a user with FOO_MEMBER_ALT's RDN to validate enforceUserClusterSeparation.
authAndDo(conn.port, FOO_MEMBER_ALT);
assert.commandWorked(ext.runCommand({createUser: FOO_MEMBER_ALT_RDN, roles: readRoles}));
assert.throws(() => authAndDo(conn.port, FOO_MEMBER_ALT));
}
{
const opts = {
auth: "",
tlsMode: "requireTLS",
tlsCertificateKeyFile: "jstests/ssl/libs/cluster-member-foo.pem",
tlsCAFile: "jstests/libs/ca.pem",
clusterAuthMode: "x509",
tlsClusterAuthX509ExtensionValue: "foo",
setParameter: {
enforceUserClusterSeparation: "true",
},
};
const mongod = MongoRunner.runMongod(opts);
runTest(mongod);
MongoRunner.stopMongod(mongod);
}