summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorGabriel Marks <gabriel.marks@mongodb.com>2022-03-09 19:30:16 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-09 21:57:26 +0000
commit44ad2b3406535b927e0f968a1a4a0a022a6dbcb1 (patch)
treeb08a5f2ac6ba8a06483d81b9858018e189c7c220 /jstests
parent04010a3b4313f61031327298b07f490c6742dd9a (diff)
downloadmongo-44ad2b3406535b927e0f968a1a4a0a022a6dbcb1.tar.gz
SERVER-63458 Update JSTest to test WriteBlockBypass
Diffstat (limited to 'jstests')
-rw-r--r--jstests/noPassthrough/set_user_write_block_mode.js115
1 files changed, 91 insertions, 24 deletions
diff --git a/jstests/noPassthrough/set_user_write_block_mode.js b/jstests/noPassthrough/set_user_write_block_mode.js
index 717caa8fb7f..48e7ef8cee9 100644
--- a/jstests/noPassthrough/set_user_write_block_mode.js
+++ b/jstests/noPassthrough/set_user_write_block_mode.js
@@ -1,6 +1,8 @@
// Test setUserWriteBlockMode command.
//
// @tags: [
+// creates_and_authenticates_user,
+// requires_auth,
// requires_fcv_53,
// requires_non_retryable_commands,
// requires_replication,
@@ -9,40 +11,105 @@
(function() {
'use strict';
-const runTest = (frontend, backend) => {
+// For this test to work, we expect the state of the collection passed to be a single {a: 2}
+// document. This test is expected to maintain that state.
+function testCUD(coll, shouldSucceed, expectedFailure) {
+ // Ensure we successfully maintained state from last run.
+ assert.eq(0, coll.find({a: 1}).count());
+ assert.eq(1, coll.find({a: 2}).count());
+
+ if (shouldSucceed) {
+ assert.commandWorked(coll.insert({a: 1}));
+ assert.eq(1, coll.find({a: 1}).count());
+ assert.commandWorked(coll.update({a: 1}, {a: 1, b: 2}));
+ assert.eq(1, coll.find({a: 1, b: 2}).count());
+ assert.commandWorked(coll.remove({a: 1}));
+ } else {
+ assert.commandFailedWithCode(coll.insert({a: 1}), expectedFailure);
+ assert.commandFailedWithCode(coll.update({a: 2}, {a: 2, b: 2}), expectedFailure);
+ assert.eq(0, coll.find({a: 2, b: 2}).count());
+ assert.commandFailedWithCode(coll.remove({a: 2}), expectedFailure);
+ }
+
+ // Ensure we successfully maintained state on this run.
+ assert.eq(0, coll.find({a: 1}).count());
+ assert.eq(1, coll.find({a: 2}).count());
+}
+
+const bypassUser = "adminUser";
+const noBypassUser = "user";
+const password = "password";
+
+function runTest(frontend, backend) {
const db = frontend.getDB(jsTestName());
const coll = db.test;
- const admin = backend.getDB("admin");
+ const admin = backend.getDB('admin');
- assert.commandWorked(coll.insert({a: 2}));
+ function asUser(user, fun) {
+ assert(admin.auth(user, password));
+ try {
+ return fun();
+ } finally {
+ admin.logout();
+ }
+ }
- // With setUserWriteBlockMode enabled, ensure that inserts, updates, and removes fail and don't
- // modify data
- assert.commandWorked(admin.runCommand({setUserWriteBlockMode: 1, global: true}));
- assert.commandFailedWithCode(coll.insert({a: 1}), ErrorCodes.OperationFailed);
- assert.commandFailedWithCode(coll.update({a: 2}, {a: 2, b: 2}), ErrorCodes.OperationFailed);
- assert.commandFailedWithCode(coll.remove({a: 2}), ErrorCodes.OperationFailed);
- assert.eq(1, coll.find({a: 2}).count());
- assert.eq(0, coll.find({a: 1}).count());
- assert.eq(0, coll.find({b: 2}).count());
-
- // Disable userWriteBlockMode and ensure that the above operations now succeed and modify data
- assert.commandWorked(admin.runCommand({setUserWriteBlockMode: 1, global: false}));
- assert.commandWorked(coll.insert({a: 1}));
- assert.commandWorked(coll.update({a: 2}, {a: 2, b: 2}));
- assert.eq(1, coll.find({a: 2, b: 2}).count());
- assert.commandWorked(coll.remove({a: 2}));
- assert.eq(0, coll.find({a: 2}).count());
- assert.eq(1, coll.find({a: 1}).count());
-};
+ // User with "__system" role has restore role and thus can bypass user write blocking. Can also
+ // run setUserWriteBlockMode.
+ admin.createUser({user: bypassUser, pwd: password, roles: [{role: "__system", db: "admin"}]});
+
+ asUser(bypassUser, () => {
+ // User with "dbAdminAnyDatabase" does not and thus can't bypass. Cannot run
+ // setUserWriteBlockMode.
+ admin.createUser({
+ user: noBypassUser,
+ pwd: password,
+ roles: [{role: "readWriteAnyDatabase", db: "admin"}]
+ });
+
+ // Set up CUD test
+ assert.commandWorked(coll.insert({a: 2}));
+ // Ensure that without setUserWriteBlockMode, both users are privileged for CUD ops
+ testCUD(coll, true);
+ });
+ asUser(noBypassUser, () => {
+ testCUD(coll, true);
+ // Ensure that the non-privileged user cannot run setUserWriteBlockMode
+ assert.commandFailedWithCode(admin.runCommand({setUserWriteBlockMode: 1, global: true}),
+ ErrorCodes.Unauthorized);
+ });
+
+ asUser(bypassUser, () => {
+ // Ensure that privileged user can run setUserWriteBlockMode
+ assert.commandWorked(admin.runCommand({setUserWriteBlockMode: 1, global: true}));
+ // Now with setUserWriteBlockMode enabled, ensure that only the bypassUser can CUD
+ testCUD(coll, true);
+ });
+
+ asUser(noBypassUser, () => {
+ testCUD(coll, false, ErrorCodes.OperationFailed);
+ });
+
+ // Now disable userWriteBlockMode and ensure both users can CUD again
+ asUser(bypassUser, () => {
+ assert.commandWorked(admin.runCommand({setUserWriteBlockMode: 1, global: false}));
+ testCUD(coll, true);
+ });
+
+ asUser(noBypassUser, () => {
+ testCUD(coll, true);
+ });
+}
// Test on standalone
-const conn = MongoRunner.runMongod();
+const conn = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"});
runTest(conn, conn);
MongoRunner.stopMongod(conn);
+const keyfile = "jstests/libs/key1";
+
// Test on replset primary
-const rst = new ReplSetTest({nodes: 3});
+const rst = new ReplSetTest({nodes: 3, nodeOptions: {auth: "", bind_ip_all: ""}, keyFile: keyfile});
rst.startSet();
rst.initiate();
const primary = rst.getPrimary();