summaryrefslogtreecommitdiff
path: root/jstests/auth/auth-counters.js
blob: b74fa531725c1ee911970afc5e09e8f75139c8fe (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 for auth counters in serverStatus.
// @tags: [requires_replication]

(function() {
'use strict';

const keyfile = 'jstests/libs/key1';
const badKeyfile = 'jstests/libs/key2';
let replTest = new ReplSetTest({nodes: 1, keyFile: keyfile, nodeOptions: {auth: ""}});
replTest.startSet();
replTest.initiate();
let primary = replTest.getPrimary();

const admin = primary.getDB('admin');
const test = primary.getDB('test');

admin.createUser({user: 'admin', pwd: 'pwd', roles: ['root'], mechanisms: ['SCRAM-SHA-256']});
admin.auth('admin', 'pwd');

test.createUser({user: 'user1', pwd: 'pwd', roles: [], mechanisms: ['SCRAM-SHA-1']});
test.createUser({user: 'user256', pwd: 'pwd', roles: [], mechanisms: ['SCRAM-SHA-256']});
test.createUser(
    {user: 'user', pwd: 'pwd', roles: [], mechanisms: ['SCRAM-SHA-1', 'SCRAM-SHA-256']});

// Count the number of authentications performed during setup
const expected =
    assert.commandWorked(admin.runCommand({serverStatus: 1})).security.authentication.mechanisms;

function assertStats() {
    const mechStats = assert.commandWorked(admin.runCommand({serverStatus: 1}))
                          .security.authentication.mechanisms;
    Object.keys(expected).forEach(function(mech) {
        try {
            assert.eq(mechStats[mech].authenticate.received, expected[mech].authenticate.received);
            assert.eq(mechStats[mech].authenticate.successful,
                      expected[mech].authenticate.successful);
            assert.eq(mechStats[mech].clusterAuthenticate.received,
                      expected[mech].clusterAuthenticate.received);
            assert.eq(mechStats[mech].clusterAuthenticate.successful,
                      expected[mech].clusterAuthenticate.successful);
        } catch (e) {
            print("Mechanism: " + mech);
            print("mechStats: " + tojson(mechStats));
            print("expected: " + tojson(expected));
            throw e;
        }
    });
}

function assertSuccess(creds, mech, db = test) {
    assert.eq(db.auth(creds), true);
    if (db !== admin) {
        db.logout();
    }
    ++expected[mech].authenticate.received;
    ++expected[mech].authenticate.successful;
    assertStats();
}

function assertFailure(creds, mech, db = test) {
    assert.eq(db.auth(creds), false);
    ++expected[mech].authenticate.received;
    assertStats();
}

function assertSuccessInternal() {
    const mech = "SCRAM-SHA-256";
    // asCluster exiting cleanly indicates successful auth
    assert.eq(authutil.asCluster(replTest.nodes, keyfile, () => true), true);
    ++expected[mech].authenticate.received;
    ++expected[mech].authenticate.successful;
    ++expected[mech].clusterAuthenticate.received;
    ++expected[mech].clusterAuthenticate.successful;
    // we have to re-auth as admin to get stats, which are validated at the end of assertSuccess
    assertSuccess({user: 'admin', pwd: 'pwd'}, 'SCRAM-SHA-256', admin);
}

// Because authutil.asCluster utilizes SCRAM-SHA-256 as a default keyfile mechanism, we will attempt
// to record this authentication with an invalid keyfile, and then verify that the # of
// successful attempts made using the fallback (SCRAM-SHA-256) has NOT been incremented
function assertFailureInternal() {
    const mech = "SCRAM-SHA-256";
    // If asCluster fails, it explodes.
    assert.throws(authutil.asCluster, [replTest.nodes, badKeyfile, () => true]);
    ++expected[mech].authenticate.received;
    ++expected[mech].clusterAuthenticate.received;
    // we have to re-auth as admin to get stats, which are validated at the end of assertSuccess
    assertSuccess({user: 'admin', pwd: 'pwd'}, 'SCRAM-SHA-256', admin);
    assertStats();
}

// Initial condition, one auth by admin during user setups above.
// Using negotiated SCRAM-SHA-256 only.
assertStats();

// user1 should negotiate and succeed at SHA1
assertSuccess({user: 'user1', pwd: 'pwd'}, 'SCRAM-SHA-1');

// user and user256 should both negotiate and success at SHA256
assertSuccess({user: 'user256', pwd: 'pwd'}, 'SCRAM-SHA-256');
assertSuccess({user: 'user', pwd: 'pwd'}, 'SCRAM-SHA-256');

// user, user1, and user256 as above, but explicitly asking for mechanisms.
assertSuccess({user: 'user1', pwd: 'pwd', mechanism: 'SCRAM-SHA-1'}, 'SCRAM-SHA-1');
assertSuccess({user: 'user256', pwd: 'pwd', mechanism: 'SCRAM-SHA-256'}, 'SCRAM-SHA-256');
assertSuccess({user: 'user', pwd: 'pwd', mechanism: 'SCRAM-SHA-1'}, 'SCRAM-SHA-1');
assertSuccess({user: 'user', pwd: 'pwd', mechanism: 'SCRAM-SHA-256'}, 'SCRAM-SHA-256');

// Incorrect password.
assertFailure({user: 'user1', pwd: 'haxx'}, 'SCRAM-SHA-1');
assertFailure({user: 'user256', pwd: 'haxx'}, 'SCRAM-SHA-256');
assertFailure({user: 'user', pwd: 'haxx'}, 'SCRAM-SHA-256');
assertFailure({user: 'user', pwd: 'haxx', mechanism: 'SCRAM-SHA-1'}, 'SCRAM-SHA-1');

// Incorrect mechanism.
assertFailure({user: 'user1', pwd: 'pwd', mechanism: 'SCRAM-SHA-256'}, 'SCRAM-SHA-256');
assertFailure({user: 'user256', pwd: 'pwd', mechanism: 'SCRAM-SHA-1'}, 'SCRAM-SHA-1');

// Cluster auth counter checks.
assertSuccessInternal();
assertFailureInternal();

// Need to auth as admin one more time to get final stats.
admin.auth('admin', 'pwd');

const finalStats =
    assert.commandWorked(admin.runCommand({serverStatus: 1})).security.authentication.mechanisms;
replTest.stopSet();

printjson(finalStats);
})();