summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/set_user_write_block_mode.js
blob: b8974bc6eb9ed2b19eefa19fa55e5401eecd4cc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Test setUserWriteBlockMode command.
//
// @tags: [
//   creates_and_authenticates_user,
//   requires_auth,
//   requires_fcv_60,
//   requires_non_retryable_commands,
//   requires_replication,
//   featureFlagUserWriteBlocking,
// ]

load("jstests/noPassthrough/libs/user_write_blocking.js");

(function() {
'use strict';

const {
    WriteBlockState,
    ShardingFixture,
    ReplicaFixture,
    bypassUser,
    noBypassUser,
    password,
    keyfile
} = UserWriteBlockHelpers;

function runTest(fixture) {
    // 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());
    }

    // Set up backing collections
    fixture.asUser(({coll}) => assert.commandWorked(coll.insert({a: 2})));

    fixture.assertWriteBlockMode(WriteBlockState.DISABLED);

    // Ensure that without setUserWriteBlockMode, both users are privileged for CUD ops
    fixture.asUser(({coll}) => testCUD(coll, true));
    fixture.asAdmin(({coll}) => testCUD(coll, true));

    fixture.enableWriteBlockMode();

    fixture.assertWriteBlockMode(WriteBlockState.ENABLED);

    // Now with setUserWriteBlockMode enabled, ensure that only the bypassUser can CUD
    fixture.asAdmin(({coll}) => {
        testCUD(coll, true);
    });
    fixture.asUser(({coll}) => {
        testCUD(coll, false, ErrorCodes.OperationFailed);
    });

    // Restarting the cluster has no impact, as write block state is durable
    fixture.restart();

    fixture.assertWriteBlockMode(WriteBlockState.ENABLED);

    fixture.asAdmin(({coll}) => {
        testCUD(coll, true);
    });
    fixture.asUser(({coll}) => {
        testCUD(coll, false, ErrorCodes.OperationFailed);
    });

    // Now disable userWriteBlockMode and ensure both users can CUD again

    fixture.disableWriteBlockMode();

    fixture.assertWriteBlockMode(WriteBlockState.DISABLED);

    fixture.asUser(({coll}) => {
        testCUD(coll, true);
    });
    fixture.asAdmin(({coll}) => {
        testCUD(coll, true);
    });

    if (fixture.takeGlobalLock) {
        let globalLock = fixture.takeGlobalLock();
        try {
            fixture.assertWriteBlockMode(WriteBlockState.UNKNOWN);
        } finally {
            globalLock.unlock();
        }
    }
}

{
    // Validate that setting user write blocking fails on standalones
    const conn = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"});
    const admin = conn.getDB("admin");
    assert.commandWorked(admin.runCommand(
        {createUser: "root", pwd: "root", roles: [{role: "__system", db: "admin"}]}));
    assert(admin.auth("root", "root"));

    assert.commandFailedWithCode(admin.runCommand({setUserWriteBlockMode: 1, global: true}),
                                 ErrorCodes.IllegalOperation);
    MongoRunner.stopMongod(conn);
}

// Test on replset primary
const rst = new ReplicaFixture();
runTest(rst);
rst.stop();

// Test on a sharded cluster
const st = new ShardingFixture();
runTest(st);
st.stop();
})();