summaryrefslogtreecommitdiff
path: root/jstests/auth/localhost_authbypass_state.js
blob: c0b09579e42c2ecd445b5edf3a7c4da26357021d (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
/* Make sure auth bypass is correctly detected across restarts and user add/delete
 * @tags: [requires_replication, requires_persistence]
 */

(function() {
'use strict';

const keyfile = 'jstests/libs/key1';
const keyfileContents = cat(keyfile).replace(/[\011-\015\040]/g, '');

function createUserCommand(user, roles, wc) {
    return {createUser: user, pwd: 'pwd', roles: roles, writeConcern: wc};
}

function runTest(name, conns, restartCallback) {
    const CREATE_ADMIN = createUserCommand('admin', ['__system'], conns.wc);
    const CREATE_USER1 = createUserCommand('user1', [], conns.wc);
    const CREATE_USER2 = createUserCommand('user2', [], conns.wc);
    const CREATE_USER3 = createUserCommand('user3', [], conns.wc);

    jsTest.log('Starting: ' + name);
    assert(conns.primary);
    let admin = conns.primary.getDB('admin');

    // Initial localhost auth bypass in effect.
    assert.commandWorked(admin.runCommand(CREATE_ADMIN));

    // Localhost auth bypass is now closed.
    assert.commandFailed(admin.runCommand(CREATE_USER1));
    if (conns.replset) {
        assert.commandFailed(conns.replset.getSecondary().getDB('admin').runCommand(CREATE_USER1));
    }

    // But it's okay if we actually auth.
    assert(admin.auth('admin', 'pwd'));
    assert.commandWorked(admin.runCommand(CREATE_USER1));
    admin.logout();

    // Shut down server and restart.
    jsTest.log('Restarting: ' + name);
    conns = restartCallback();
    assert(conns.primary);
    admin = conns.primary.getDB('admin');

    // Localhost auth bypass is still closed.
    assert.commandFailed(admin.runCommand(CREATE_USER2));
    if (conns.replset) {
        assert.commandFailed(conns.replset.getSecondary().getDB('admin').runCommand(CREATE_USER2));
    }

    // We can happily auth and make another user.
    assert(admin.auth('admin', 'pwd'));
    assert.commandWorked(admin.runCommand(CREATE_USER2));

    // We can even drop the collection and our login session will be invalidated.
    const preDrop =
        assert.commandWorked(admin.runCommand({connectionStatus: 1})).authInfo.authenticatedUsers;
    assert.eq(preDrop.length, 1);
    assert.writeOK(admin.system.users.remove({}, {writeConcern: conns.wc}));
    const postDrop =
        assert.commandWorked(admin.runCommand({connectionStatus: 1})).authInfo.authenticatedUsers;
    assert.eq(postDrop.length, 0);

    // Can't recreate ourselves because localhost auth bypass is still disabled.
    assert.commandFailed(admin.runCommand(CREATE_ADMIN));

    jsTest.log('Finished: ' + name);
}

// Node will be bounced. Confirm write goes all the way to disk.
const standaloneWC = {
    w: 1,
    j: true
};
let standalone = MongoRunner.runMongod({auth: '', useHostName: false});
runTest('Standalone', {primary: standalone, wc: standaloneWC}, function() {
    const dbpath = standalone.dbpath;
    MongoRunner.stopMongod(standalone);
    standalone = MongoRunner.runMongod(
        {auth: '', restart: true, cleanData: false, dbpath: dbpath, useHostName: false});
    return {primary: standalone, wc: standaloneWC};
});
MongoRunner.stopMongod(standalone);

const replsetNodes = 2;
// We're going to b bouncing these nodes, make sure writes propagate.
const replsetWC = {
    w: replsetNodes,
    j: true
};
const replset = new ReplSetTest({
    name: 'rs0',
    nodes: replsetNodes,
    nodeOptions: {auth: ''},
    keyFile: keyfile,
    useHostName: false,
});
replset.startSet();
replset.initiate();
replset.awaitSecondaryNodes();
runTest('ReplSet', {primary: replset.getPrimary(), replset: replset, wc: replsetWC}, function() {
    const kAppliedOpTimeTimeoutMS = 10 * 1000;
    // Need to be authed for restart.
    // Only __system is guaranteed to be available, especially during 2nd restart.
    replset.nodes.forEach((node) => assert(node.getDB('admin').auth('__system', keyfileContents)));
    replset.awaitNodesAgreeOnAppliedOpTime(kAppliedOpTimeTimeoutMS, replset.nodes);
    replset.restart(replset.nodes);
    replset.awaitSecondaryNodes();
    return {primary: replset.getPrimary(), replset: replset, wc: replsetWC};
});
replset.stopSet();
})();