summaryrefslogtreecommitdiff
path: root/jstests/serverless/native_tenant_data_isolation_initial_sync.js
blob: 678618facb4e3336b9625d26c5149bfe4b0fa79a (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
/**
 * Tests that initial sync works correctly when multitenancySupport is enabled.
 */

(function() {
"use strict";

load('jstests/aggregation/extras/utils.js');  // For arrayEq()
load("jstests/libs/feature_flag_util.js");    // for isEnabled

const rst = new ReplSetTest({
    nodes: 1,
    nodeOptions: {
        auth: '',
        setParameter: {
            multitenancySupport: true,
            featureFlagSecurityToken: true,
        }
    }
});
rst.startSet({keyFile: 'jstests/libs/key1'});
rst.initiate();

const primary = rst.getPrimary();

const kTenant1 = ObjectId();
const kTenant2 = ObjectId();
const kDbName = "test";
const kCollName = "foo";

const primaryConn = new Mongo(primary.host);
const primaryDB = primaryConn.getDB(kDbName);

// Create users for two different tenants.
const adminDb = primary.getDB('admin');
assert.commandWorked(adminDb.runCommand({createUser: 'admin', pwd: 'pwd', roles: ['root']}));
assert(adminDb.auth('admin', 'pwd'));

const featureFlagRequireTenantId = FeatureFlagUtil.isEnabled(adminDb, "RequireTenantID");

const securityToken1 =
    _createSecurityToken({user: "userTenant1", db: '$external', tenant: kTenant1});
assert.commandWorked(primary.getDB('$external').runCommand({
    createUser: "userTenant1",
    '$tenant': kTenant1,
    roles: [{role: 'dbAdminAnyDatabase', db: 'admin'}, {role: 'readWriteAnyDatabase', db: 'admin'}]
}));

const securityToken2 =
    _createSecurityToken({user: "userTenant2", db: '$external', tenant: kTenant2});
assert.commandWorked(primary.getDB('$external').runCommand({
    createUser: "userTenant2",
    '$tenant': kTenant2,
    roles: [{role: 'dbAdminAnyDatabase', db: 'admin'}, {role: 'readWriteAnyDatabase', db: 'admin'}]
}));

// Logout the root user to avoid multiple authentication.
primaryConn.getDB("admin").logout();

// Create a collection, insert some data, and create indexes on the collection for tenant1.
primaryConn._setSecurityToken(securityToken1);

const tenant1Docs = [{_id: 0, a: 1, b: 1}, {_id: 1, a: 2, b: 3}];
assert.commandWorked(primaryDB.runCommand({insert: kCollName, documents: tenant1Docs}));

const tenant1Idxs = [{key: {a: 1}, name: "indexA"}, {key: {b: 1}, name: "indexB"}];
let res =
    assert.commandWorked(primaryDB.runCommand({createIndexes: kCollName, indexes: tenant1Idxs}));
assert.eq(3, res.numIndexesAfter);

// Create a collections, insert some data, and create indexes on the collection for tenant2.
primaryConn._setSecurityToken(securityToken2);

const tenant2Docs = [{_id: 10, a: 10, b: 10}, {_id: 11, a: 20, b: 30}];
assert.commandWorked(primaryDB.runCommand({insert: kCollName, documents: tenant2Docs}));

const tenant2Idxs = [{key: {a: -1}, name: "indexA"}, {key: {b: -1}, name: "indexB"}];
res = assert.commandWorked(primaryDB.runCommand({createIndexes: kCollName, indexes: tenant2Idxs}));
assert.eq(3, res.numIndexesAfter);

// Add a new secondary to the replica set and wait for initial sync to finish.
const secondary = rst.add({
    setParameter: {
        multitenancySupport: true,
        featureFlagSecurityToken: true,
    }
});
rst.reInitiate();
rst.awaitReplication();
rst.awaitSecondaryNodes();

// Check that we find the data for each tenant on the newly synced secondary.
const secondaryConn = new Mongo(secondary.host);
const secondaryDB = secondaryConn.getDB(kDbName);
secondaryConn.setSecondaryOk();

// Look for tenant1's data and indexes.
secondaryConn._setSecurityToken(securityToken1);

const findTenant1Res = assert.commandWorked(secondaryDB.runCommand({find: kCollName, filter: {}}));
assert(arrayEq(tenant1Docs, findTenant1Res.cursor.firstBatch), tojson(findTenant1Res));

res = assert.commandWorked(secondaryDB.runCommand({listIndexes: kCollName}));
assert.eq(3, res.cursor.firstBatch.length);
assert(arrayEq(tenant1Idxs.concat([
    {key: {"_id": 1}, name: "_id_"},
]),
               res.cursor.firstBatch.map(function(index) {
                   return {key: index.key, name: index.name};
               })));

// Look for tenant2's data and indexes.
secondaryConn._setSecurityToken(securityToken2);
const findTenant2Res = assert.commandWorked(secondaryDB.runCommand({find: kCollName, filter: {}}));
assert(arrayEq(tenant2Docs, findTenant2Res.cursor.firstBatch), tojson(findTenant2Res));

res = assert.commandWorked(secondaryDB.runCommand({listIndexes: kCollName}));
assert.eq(3, res.cursor.firstBatch.length);
assert(arrayEq(tenant2Idxs.concat([
    {key: {"_id": 1}, name: "_id_"},
]),
               res.cursor.firstBatch.map(function(index) {
                   return {key: index.key, name: index.name};
               })));

rst.stopSet();
})();