mongo/jstests/replsets/localhostAuthBypass.js

234 lines
6.5 KiB
JavaScript

// SERVER-6591: Localhost authentication exception doesn't work right on sharded cluster
// @tags: [requires_os_access]
// This test is to ensure that localhost authentication works correctly against a replica set
// whether they are hosted with "localhost" or a hostname.
let replSetName = "replsets_server-6591";
let keyfile = "jstests/libs/key1";
let username = "foo";
let password = "bar";
import {get_ipaddr} from "jstests/libs/host_ipaddr.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";
let createUser = function (mongo) {
print("============ adding a user.");
mongo.getDB("admin").createUser({user: username, pwd: password, roles: jsTest.adminUserRoles});
};
let assertCannotRunCommands = function (mongo, isPrimary) {
print("============ ensuring that commands cannot be run.");
let test = mongo.getDB("test");
assert.throws(function () {
test.system.users.findOne();
});
assert.throws(function () {
test.foo.findOne({_id: 0});
});
if (isPrimary) {
assert.writeError(test.foo.save({_id: 0}));
assert.writeError(test.foo.update({_id: 0}, {$set: {x: 20}}));
assert.writeError(test.foo.remove({_id: 0}));
}
assert.throws(function () {
test.foo.mapReduce(
function () {
emit(1, 1);
},
function (id, count) {
return Array.sum(count);
},
{out: "other"},
);
});
// Create collection
let authorizeErrorCode = 13;
assert.commandFailedWithCode(
mongo.getDB("test").createCollection("log", {capped: true, size: 5242880, max: 5000}),
authorizeErrorCode,
"createCollection",
);
// Set/Get system parameters
let params = [
{param: "journalCommitInterval", val: 200},
{param: "logLevel", val: 2},
{param: "logUserIds", val: 1},
{param: "notablescan", val: 1},
{param: "quiet", val: 1},
{param: "replApplyBatchSize", val: 10},
{param: "replIndexPrefetch", val: "none"},
{param: "syncdelay", val: 30},
{param: "traceExceptions", val: true},
{param: "sslMode", val: "preferSSL"},
{param: "clusterAuthMode", val: "sendX509"},
{param: "userCacheInvalidationIntervalSecs", val: 300},
];
params.forEach(function (p) {
let cmd = {setParameter: 1};
cmd[p.param] = p.val;
assert.commandFailedWithCode(
mongo.getDB("admin").runCommand(cmd),
authorizeErrorCode,
"setParameter: " + p.param,
);
});
params.forEach(function (p) {
let cmd = {getParameter: 1};
cmd[p.param] = 1;
assert.commandFailedWithCode(
mongo.getDB("admin").runCommand(cmd),
authorizeErrorCode,
"getParameter: " + p.param,
);
});
};
let assertCanRunCommands = function (mongo) {
print("============ ensuring that commands can be run.");
let test = mongo.getDB("test");
// will throw on failure
test.system.users.findOne();
assert.commandWorked(test.foo.save({_id: 0}));
assert.commandWorked(test.foo.update({_id: 0}, {$set: {x: 20}}));
assert.commandWorked(test.foo.remove({_id: 0}));
test.foo.mapReduce(
function () {
emit(1, 1);
},
function (id, count) {
return Array.sum(count);
},
{out: "other"},
);
assert.commandWorked(mongo.getDB("admin").runCommand({replSetGetStatus: 1}));
};
let authenticate = function (mongo) {
print("============ authenticating user.");
mongo.getDB("admin").auth(username, password);
};
let start = function (useHostName) {
const rs = new ReplSetTest({name: replSetName, nodes: 3, keyFile: keyfile, auth: "", useHostName: useHostName});
rs.startSet();
rs.initiate();
return rs;
};
let shutdown = function (rs) {
print("============ shutting down.");
rs.stopSet(/*signal*/ false, /*forRestart*/ false, {auth: {user: username, pwd: password}});
};
let runTest = function (useHostName) {
print("=====================");
print("starting replica set: useHostName=" + useHostName);
print("=====================");
const rs = start(useHostName);
let port = rs.getPort(rs.getPrimary());
let host = "localhost:" + port;
let secHosts = [];
rs.getSecondaries().forEach(function (sec) {
secHosts.push("localhost:" + rs.getPort(sec));
});
let mongo = new Mongo(host);
assertCannotRunCommands(mongo, true);
// Test localhost access on secondaries
let mongoSecs = [];
secHosts.forEach(function (h) {
mongoSecs.push(new Mongo(h));
});
mongoSecs.forEach(function (m) {
assertCannotRunCommands(m, false);
});
createUser(mongo);
assertCannotRunCommands(mongo, true);
authenticate(mongo);
assertCanRunCommands(mongo, true);
// Test localhost access on secondaries on exsiting connection
mongoSecs.forEach(function (m) {
assertCannotRunCommands(m, false);
authenticate(m);
});
print("===============================");
print("reconnecting with a new client.");
print("===============================");
mongo = new Mongo(host);
assertCannotRunCommands(mongo, true);
authenticate(mongo);
assertCanRunCommands(mongo, true);
// Test localhost access on secondaries on new connection
secHosts.forEach(function (h) {
let m = new Mongo(h);
assertCannotRunCommands(m, false);
authenticate(m);
});
shutdown(rs);
};
let runNonlocalTest = function (ipAddr) {
print("==========================");
print("starting mongod: non-local host access " + ipAddr);
print("==========================");
const rs = start(false);
let port = rs.getPort(rs.getPrimary());
let host = ipAddr + ":" + port;
let secHosts = [];
rs.getSecondaries().forEach(function (sec) {
secHosts.push(ipAddr + ":" + rs.getPort(sec));
});
let mongo = new Mongo(host);
assertCannotRunCommands(mongo, true);
// Test localhost access on secondaries
let mongoSecs = [];
secHosts.forEach(function (h) {
mongoSecs.push(new Mongo(h));
});
mongoSecs.forEach(function (m) {
assertCannotRunCommands(m, false);
});
assert.throws(function () {
mongo.getDB("admin").createUser({user: username, pwd: password, roles: jsTest.adminUserRoles});
});
shutdown(rs);
};
runTest(false);
runTest(true);
runNonlocalTest(get_ipaddr());