summaryrefslogtreecommitdiff
path: root/jstests/sharding/mongod_returns_no_cluster_time_without_keys.js
blob: 82bdaeed018addf63e96a57caed22a136ed85935 (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
/**
 * Tests that mongod does not gossip cluster time metadata and operation time until at least one key
 * is created on the
 * config server.
 *
 * This test restarts shard replica sets, so it requires a persistent storage engine.
 * @tags: [requires_persistence]
 */
(function() {
"use strict";

// This test uses authentication and runs commands without authenticating, which is not
// compatible with implicit sessions.
TestData.disableImplicitSessions = true;

load("jstests/multiVersion/libs/multi_rs.js");

// TODO SERVER-32672: remove this flag.
TestData.skipGossipingClusterTime = true;
const keyFile = 'jstests/libs/key1';
const adminUser = {
    db: "admin",
    username: "foo",
    password: "bar"
};
const rUser = {
    db: "test",
    username: "r",
    password: "bar"
};
const timeoutValidLogicalTimeMs = 20 * 1000;

function assertContainsValidLogicalTime(adminConn) {
    try {
        const res = adminConn.runCommand({isMaster: 1});
        assert.hasFields(res, ["$clusterTime"]);
        assert.hasFields(res.$clusterTime, ["signature", "clusterTime"]);
        // clusterTime must be greater than the uninitialzed value.
        assert.hasFields(res.$clusterTime.signature, ["hash", "keyId"]);
        // The signature must have been signed by a key with a valid generation.
        assert(res.$clusterTime.signature.keyId > NumberLong(0));

        assert.hasFields(res, ["operationTime"]);
        assert(Object.prototype.toString.call(res.operationTime) === "[object Timestamp]",
               "operationTime must be a timestamp");
        return true;
    } catch (error) {
        return false;
    }
}

let st = new ShardingTest({shards: {rs0: {nodes: 2}}, other: {keyFile: keyFile}});

jsTestLog("Started ShardingTest");

var adminDB = st.s.getDB("admin");
adminDB.createUser({user: adminUser.username, pwd: adminUser.password, roles: ["__system"]});

adminDB.auth(adminUser.username, adminUser.password);
assert(st.s.getDB("admin").system.keys.count() >= 2);

let priRSConn = st.rs0.getPrimary().getDB("admin");
priRSConn.createUser({user: rUser.username, pwd: rUser.password, roles: ["root"]});
priRSConn.auth(rUser.username, rUser.password);

// use assert.soon since it's possible the shard primary may not have refreshed
// and loaded the keys into its KeyManager cache.
assert.soon(function() {
    return assertContainsValidLogicalTime(priRSConn);
}, "Failed to assert valid logical time", timeoutValidLogicalTimeMs);

priRSConn.logout();

// Enable the failpoint, remove all keys, and restart the config servers with the failpoint
// still enabled to guarantee there are no keys.
for (let i = 0; i < st.configRS.nodes.length; i++) {
    assert.commandWorked(st.configRS.nodes[i].adminCommand(
        {"configureFailPoint": "disableKeyGeneration", "mode": "alwaysOn"}));
}

var priCSConn = st.configRS.getPrimary();
authutil.asCluster(priCSConn, keyFile, function() {
    priCSConn.getDB("admin").system.keys.remove({purpose: "HMAC"});
});

assert(adminDB.system.keys.count() == 0, "expected there to be no keys on the config server");
adminDB.logout();

st.configRS.stopSet(null /* signal */, true /* forRestart */);
st.configRS.startSet(
    {restart: true, setParameter: {"failpoint.disableKeyGeneration": "{'mode':'alwaysOn'}"}});

// bounce rs0 to clean the key cache
st.rs0.stopSet(null /* signal */, true /* forRestart */);
st.rs0.startSet({restart: true});

priRSConn = st.rs0.getPrimary().getDB("admin");
priRSConn.auth(rUser.username, rUser.password);
const resNoKeys = assert.commandWorked(priRSConn.runCommand({isMaster: 1}));
priRSConn.logout();

assert.eq(resNoKeys.hasOwnProperty("$clusterTime"), false);
assert.eq(resNoKeys.hasOwnProperty("operationTime"), false);

st.stop();
})();