mirror of https://github.com/mongodb/mongo
800 lines
27 KiB
JavaScript
800 lines
27 KiB
JavaScript
import {Thread} from "jstests/libs/parallelTester.js";
|
|
|
|
/**
|
|
* Implements a kill session test helper
|
|
*/
|
|
export var _kill_sessions_api_module = (function () {
|
|
let KillSessionsTestHelper = {};
|
|
|
|
function isdbgrid(client) {
|
|
let result = assert.commandWorked(client.getDB("admin").runCommand({ismaster: 1}));
|
|
|
|
return result.msg === "isdbgrid";
|
|
}
|
|
|
|
function Fixture(clientToExecuteVia, clientToKillVia, clientsToVerifyVia) {
|
|
this._clientToExecuteVia = clientToExecuteVia;
|
|
this._clientToExecuteViaIsdbgrid = isdbgrid(clientToExecuteVia);
|
|
this._clientToKillVia = clientToKillVia;
|
|
this._clientToKillViaIsdbgrid = isdbgrid(clientToKillVia);
|
|
this._clientsToVerifyVia = clientsToVerifyVia;
|
|
this._hangingOpId = 10000000;
|
|
}
|
|
|
|
Fixture.prototype.loginForExecute = function (cred) {
|
|
this._clientToExecuteVia.getDB("admin").auth(cred, "password");
|
|
this._clientToExecuteViaCredentials = cred;
|
|
};
|
|
|
|
Fixture.prototype.loginForKill = function (cred) {
|
|
this._clientToKillVia.getDB("admin").auth(cred, "password");
|
|
this._clientToKillViaCredentials = cred;
|
|
};
|
|
|
|
Fixture.prototype.logout = function (db) {
|
|
this._clientToExecuteVia.logout("admin");
|
|
this._clientToKillVia.logout("admin");
|
|
};
|
|
|
|
Fixture.prototype.kill = function (db, command) {
|
|
let result = this._clientToKillVia.getDB(db).runCommand(command);
|
|
if (!result.ok) {
|
|
jsTest.log.info({result});
|
|
}
|
|
assert(result.ok);
|
|
};
|
|
|
|
Fixture.prototype.assertKillFailed = function (db, command) {
|
|
let result = this._clientToKillVia.getDB(db).runCommand(command);
|
|
if (result.ok) {
|
|
jsTest.log.info({result, command});
|
|
}
|
|
assert(!result.ok);
|
|
};
|
|
|
|
Fixture.prototype.visit = function (cb) {
|
|
for (let i = 0; i < this._clientsToVerifyVia.length; ++i) {
|
|
cb(this._clientsToVerifyVia[i], i);
|
|
}
|
|
};
|
|
|
|
function HangingOpHandle(thread, lsid) {
|
|
this._thread = thread;
|
|
this._lsid = lsid;
|
|
}
|
|
|
|
HangingOpHandle.prototype.join = function () {
|
|
return this._thread.join();
|
|
};
|
|
|
|
HangingOpHandle.prototype.getLsid = function () {
|
|
return this._lsid;
|
|
};
|
|
|
|
/**
|
|
* We start hanging ops by running the test command sleep with a special number of secs that's
|
|
* meant to be universal per test run. In mongos, we multicast it out (to guarantee it's on all
|
|
* of the random accessory nodes).
|
|
*/
|
|
Fixture.prototype.startHangingOp = function () {
|
|
let id = this._hangingOpId++;
|
|
// When creating a hanging op, we have to use a background thread (because the command will
|
|
// hang).
|
|
let thread = new Thread(
|
|
function (connstring, credentials, tag, isdbgrid) {
|
|
let client = new Mongo(connstring);
|
|
if (credentials) {
|
|
client.getDB("admin").auth(credentials, "password");
|
|
}
|
|
let session = client.startSession();
|
|
let db = session.getDatabase("admin");
|
|
try {
|
|
let cmd = {
|
|
sleep: 1,
|
|
lock: "none",
|
|
secs: tag,
|
|
};
|
|
if (isdbgrid) {
|
|
db.runCommand({
|
|
multicast: cmd,
|
|
});
|
|
} else {
|
|
db.runCommand(cmd);
|
|
}
|
|
} catch (e) {}
|
|
session.endSession();
|
|
client.close();
|
|
},
|
|
this._clientToExecuteVia.host,
|
|
this._clientToExecuteViaCredentials,
|
|
id,
|
|
this._clientToExecuteViaIsdbgrid,
|
|
);
|
|
thread.start();
|
|
|
|
let lsid;
|
|
// We verify that our hanging op is up by looking for it in current op on the required
|
|
// hosts. We identify particular ops by secs sleeping.
|
|
this.visit(function (client) {
|
|
let admin = client.getDB("admin");
|
|
admin.getMongo().setSecondaryOk();
|
|
|
|
assert.soon(
|
|
function () {
|
|
let inProgressOps = admin.aggregate([{$currentOp: {"allUsers": true}}]);
|
|
while (inProgressOps.hasNext()) {
|
|
let op = inProgressOps.next();
|
|
if (op.command && op.command.sleep && op.command.secs == id && op.lsid) {
|
|
lsid = op.lsid;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
},
|
|
"never started sleep with 'secs' " + id,
|
|
30000,
|
|
1,
|
|
);
|
|
});
|
|
|
|
return new HangingOpHandle(thread, lsid);
|
|
};
|
|
|
|
/**
|
|
* passes the lsid of each running op into our callback. Makes it easy to ensure that a session
|
|
* is well and truly dead
|
|
*/
|
|
Fixture.prototype.assertNoSessionsInCurrentOp = function (cb) {
|
|
this.visit(function (client) {
|
|
let inprog = client.getDB("admin").currentOp().inprog;
|
|
inprog.forEach(function (op) {
|
|
assert(op.killPending || !op.lsid);
|
|
});
|
|
});
|
|
};
|
|
|
|
Fixture.prototype.assertSessionsInCurrentOp = function (checkExist, checkNotExist) {
|
|
this.visit(function (client) {
|
|
let needToFind = checkExist.map(function (handle) {
|
|
return handle.getLsid();
|
|
});
|
|
let inprog = client.getDB("admin").currentOp().inprog;
|
|
inprog.forEach(function (op) {
|
|
if (op.lsid && !op.killPending) {
|
|
checkNotExist.forEach(function (handle) {
|
|
assert.neq(bsonWoCompare(handle.getLsid(), op.lsid), 0);
|
|
});
|
|
|
|
for (let i = 0; i < needToFind.length; ++i) {
|
|
if (bsonWoCompare(needToFind[i], op.lsid) == 0) {
|
|
needToFind.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
assert.eq(needToFind.length, 0);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Asserts that there are no sessions in any live cursors.
|
|
*/
|
|
Fixture.prototype.assertNoSessionsInCursors = function () {
|
|
this.visit(function (client) {
|
|
let db = client.getDB("admin");
|
|
db.setSecondaryOk();
|
|
assert.soon(() => {
|
|
let cursors = db.aggregate([{"$currentOp": {"idleCursors": true, "allUsers": true}}]).toArray();
|
|
return cursors.every((cursor) => !cursor.lsid);
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Asserts that one subset of sessions is alive in active cursors and that another set is not.
|
|
*/
|
|
Fixture.prototype.assertSessionsInCursors = function (checkExist, checkNotExist) {
|
|
this.visit(function (client) {
|
|
let needToFind = checkExist.map(function (handle) {
|
|
return {
|
|
lsid: handle.getLsid(),
|
|
};
|
|
});
|
|
|
|
let db = client.getDB("admin");
|
|
db.setSecondaryOk();
|
|
let cursors = db
|
|
.aggregate([{"$currentOp": {"idleCursors": true, "allUsers": true}}, {"$match": {type: "idleCursor"}}])
|
|
.toArray();
|
|
cursors.forEach(function (cursor) {
|
|
if (cursor.lsid) {
|
|
checkNotExist.forEach(function (handle) {
|
|
assert.neq(bsonWoCompare({x: handle.getLsid().id}, {x: cursor.lsid.id}), 0);
|
|
});
|
|
|
|
for (let i = 0; i < needToFind.length; ++i) {
|
|
if (bsonWoCompare({x: needToFind[i].lsid.id}, {x: cursor.lsid.id}) == 0) {
|
|
needToFind.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
assert.eq(needToFind.length, 0, cursors);
|
|
});
|
|
};
|
|
|
|
Fixture.prototype.assertCursorKillLogMessages = function (cursorHandles) {
|
|
cursorHandles.forEach((cursorHandle) => cursorHandle.assertCursorKillLogMessages(this._clientsToVerifyVia));
|
|
};
|
|
|
|
function CursorHandle(session, cursors) {
|
|
this._session = session;
|
|
this._cursors = cursors;
|
|
}
|
|
|
|
CursorHandle.prototype.getLsid = function () {
|
|
return this._session._serverSession.handle.getId();
|
|
};
|
|
|
|
CursorHandle.prototype.join = function () {
|
|
this._session.endSession();
|
|
};
|
|
|
|
CursorHandle.prototype.assertCursorKillLogMessages = function (hostsToCheck) {
|
|
for (let hostToCheck of hostsToCheck) {
|
|
if (hostToCheck.host in this._cursors) {
|
|
assert(
|
|
checkLog.checkContainsOnceJsonStringMatch(
|
|
hostToCheck,
|
|
20528,
|
|
"cursorId",
|
|
this._cursors[hostToCheck.host].exactValueString,
|
|
),
|
|
"cursor kill was not logged by " + hostToCheck.host,
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* We start cursors on all nodes in a very artificial way. In particular, we run currentOp
|
|
* (because it's a data source that's always there) and use an agg pipeline to get enough
|
|
* records that we can't return it in one batch. In sharding, we use multicast to force open
|
|
* cursors on all nodes at once.
|
|
*/
|
|
Fixture.prototype.startCursor = function () {
|
|
let session = this._clientToExecuteVia.startSession();
|
|
let db = session.getDatabase("admin");
|
|
|
|
let cmd = {
|
|
aggregate: 1,
|
|
pipeline: [
|
|
{"$currentOp": {"allUsers": false}},
|
|
{"$addFields": {magic: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}},
|
|
{"$project": {magic: 1}},
|
|
{"$unwind": "$magic"},
|
|
],
|
|
cursor: {batchSize: 1},
|
|
"$readPreference": {
|
|
mode: "primaryPreferred",
|
|
},
|
|
readConcern: {},
|
|
writeConcern: {w: 1},
|
|
};
|
|
|
|
let cursors = {};
|
|
let result;
|
|
if (this._clientToExecuteViaIsdbgrid) {
|
|
result = db.runCommand({multicast: cmd});
|
|
for (let host of Object.keys(result.hosts)) {
|
|
cursors[host] = result.hosts[host].data.cursor.id;
|
|
}
|
|
} else {
|
|
result = db.runCommand(cmd);
|
|
cursors[db.getMongo().host] = result.cursor.id;
|
|
}
|
|
if (!result.ok) {
|
|
jsTest.log.info({result});
|
|
}
|
|
assert(result.ok);
|
|
|
|
return new CursorHandle(session, cursors);
|
|
};
|
|
|
|
/**
|
|
* A suite of tests verifying that various forms of no argument kill work. Outside of auth
|
|
*/
|
|
function makeNoAuthNoArgKill(cmd) {
|
|
let obj = {};
|
|
obj[cmd] = [];
|
|
return [
|
|
// Verify that we can invoke cmd
|
|
function (fixture) {
|
|
fixture.kill("admin", obj);
|
|
},
|
|
|
|
// Verify that we can start a session and kill it with cmd
|
|
function (fixture) {
|
|
let handle = fixture.startHangingOp();
|
|
fixture.kill("admin", obj);
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle.join();
|
|
},
|
|
|
|
// Verify that we can kill two sessions
|
|
function (fixture) {
|
|
let handle1 = fixture.startHangingOp();
|
|
let handle2 = fixture.startHangingOp();
|
|
fixture.kill("admin", obj);
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle1.join();
|
|
handle2.join();
|
|
},
|
|
|
|
// Verify that we can start a session with a cursor and kill it with cmd
|
|
function (fixture) {
|
|
let handle = fixture.startCursor();
|
|
fixture.assertSessionsInCursors([handle], []);
|
|
fixture.kill("admin", obj);
|
|
fixture.assertNoSessionsInCursors();
|
|
fixture.assertCursorKillLogMessages([handle]);
|
|
handle.join();
|
|
},
|
|
|
|
// Verify that we can kill two sessions with cursors
|
|
function (fixture) {
|
|
let handle1 = fixture.startCursor();
|
|
let handle2 = fixture.startCursor();
|
|
fixture.assertSessionsInCursors([handle1, handle2], []);
|
|
fixture.kill("admin", obj);
|
|
fixture.assertNoSessionsInCursors();
|
|
fixture.assertCursorKillLogMessages([handle1, handle2]);
|
|
handle1.join();
|
|
handle2.join();
|
|
},
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Verifies that various argument taking kills work. Outside of auth
|
|
*/
|
|
function makeNoAuthArgKill(cmd, genArg) {
|
|
return [
|
|
// Verify that we can kill two of three sessions, and that the other stays alive
|
|
function (fixture) {
|
|
let handle1 = fixture.startHangingOp();
|
|
let handle2 = fixture.startHangingOp();
|
|
let handle3 = fixture.startHangingOp();
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle1.getLsid(), handle2.getLsid()].map(genArg);
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertSessionsInCurrentOp([handle3], [handle1, handle2]);
|
|
handle1.join();
|
|
handle2.join();
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle3.getLsid()].map(genArg);
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle3.join();
|
|
},
|
|
|
|
// Verify that we can kill two of three sessions, and that the other stays (with
|
|
// cursors)
|
|
function (fixture) {
|
|
let handle1 = fixture.startCursor();
|
|
let handle2 = fixture.startCursor();
|
|
let handle3 = fixture.startCursor();
|
|
fixture.assertSessionsInCursors([handle1, handle2, handle3], []);
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle1.getLsid(), handle2.getLsid()].map(genArg);
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertSessionsInCursors([handle3], [handle1, handle2]);
|
|
fixture.assertCursorKillLogMessages([handle1, handle2]);
|
|
handle1.join();
|
|
handle2.join();
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle3.getLsid()].map(genArg);
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertNoSessionsInCursors();
|
|
fixture.assertCursorKillLogMessages([handle3]);
|
|
handle3.join();
|
|
},
|
|
];
|
|
}
|
|
|
|
let noAuth = [
|
|
// Verify that we can kill two sessions with the kill all args from killAllSessionsByPattern
|
|
function (fixture) {
|
|
let handle1 = fixture.startHangingOp();
|
|
let handle2 = fixture.startHangingOp();
|
|
fixture.kill("admin", {killAllSessionsByPattern: [{}]});
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle1.join();
|
|
handle2.join();
|
|
},
|
|
];
|
|
|
|
// Runs our noarg suite for all commands
|
|
["killSessions", "killAllSessions", "killAllSessionsByPattern"].forEach(function (cmd) {
|
|
noAuth = noAuth.concat(makeNoAuthNoArgKill(cmd));
|
|
});
|
|
|
|
[
|
|
[
|
|
// Verifies that we can killSessions by lsid
|
|
"killSessions",
|
|
function (x) {
|
|
if (!x.uid) {
|
|
return {
|
|
id: x.id,
|
|
uid: computeSHA256Block(""),
|
|
};
|
|
} else {
|
|
return x;
|
|
}
|
|
},
|
|
],
|
|
[
|
|
// Verifies that we can kill by pattern by lsid
|
|
"killAllSessionsByPattern",
|
|
function (x) {
|
|
if (!x.uid) {
|
|
return {
|
|
lsid: {
|
|
id: x.id,
|
|
uid: computeSHA256Block(""),
|
|
},
|
|
};
|
|
} else {
|
|
return {lsid: x};
|
|
}
|
|
},
|
|
],
|
|
].forEach(function (cmd) {
|
|
noAuth = noAuth.concat(makeNoAuthArgKill.apply({}, cmd));
|
|
});
|
|
|
|
KillSessionsTestHelper.runNoAuth = function (clientToExecuteVia, clientToKillVia, clientsToVerifyVia) {
|
|
let fixture = new Fixture(clientToExecuteVia, clientToKillVia, clientsToVerifyVia);
|
|
|
|
for (let i = 0; i < noAuth.length; ++i) {
|
|
noAuth[i](fixture);
|
|
}
|
|
};
|
|
|
|
// Run tests for a command that takes no args in auth
|
|
function makeAuthNoArgKill(cmd, execUserCred, killUserCred) {
|
|
let obj = {};
|
|
obj[cmd] = [];
|
|
return [
|
|
// Verify that we can invoke cmd
|
|
function (fixture) {
|
|
fixture.loginForExecute(execUserCred);
|
|
fixture.loginForKill(killUserCred);
|
|
fixture.kill("admin", obj);
|
|
},
|
|
|
|
// Verify that we can start a session and kill it with cmd
|
|
function (fixture) {
|
|
fixture.loginForExecute(execUserCred);
|
|
fixture.loginForKill(killUserCred);
|
|
let handle = fixture.startHangingOp();
|
|
fixture.kill("admin", obj);
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle.join();
|
|
},
|
|
];
|
|
}
|
|
|
|
// Run tests for a command that takes args in auth.
|
|
//
|
|
// The genArg argument is a function which returns another function given a username. It's
|
|
// meant to adapt various lsid's from ops/cursors to various commands.
|
|
function makeAuthArgKill(cmd, execUserCred1, execUserCred2, killUserCred, genArg) {
|
|
return [
|
|
// Run 3 ops, 2 under 1 user, 1 under another. Then kill, making sure that the 3rd op
|
|
// stays up
|
|
function (fixture) {
|
|
fixture.loginForExecute(execUserCred1);
|
|
let handle1 = fixture.startHangingOp();
|
|
let handle2 = fixture.startHangingOp();
|
|
|
|
fixture.logout();
|
|
fixture.loginForExecute(execUserCred2);
|
|
let handle3 = fixture.startHangingOp();
|
|
|
|
fixture.loginForKill(killUserCred);
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle1.getLsid(), handle2.getLsid()].map(genArg(execUserCred1));
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertSessionsInCurrentOp([handle3], [handle1, handle2]);
|
|
handle1.join();
|
|
handle2.join();
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle3.getLsid()].map(genArg(execUserCred2));
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle3.join();
|
|
},
|
|
|
|
// Repeat for cursors
|
|
function (fixture) {
|
|
fixture.loginForExecute(execUserCred1);
|
|
|
|
let handle1 = fixture.startCursor();
|
|
let handle2 = fixture.startCursor();
|
|
|
|
fixture.logout();
|
|
fixture.loginForExecute(execUserCred2);
|
|
|
|
let handle3 = fixture.startCursor();
|
|
fixture.assertSessionsInCursors([handle1, handle2, handle3], []);
|
|
|
|
fixture.loginForKill(killUserCred);
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle1.getLsid(), handle2.getLsid()].map(genArg(execUserCred1));
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertSessionsInCursors([handle3], [handle1, handle2]);
|
|
fixture.assertCursorKillLogMessages([handle1, handle2]);
|
|
handle1.join();
|
|
handle2.join();
|
|
|
|
{
|
|
var obj = {};
|
|
obj[cmd] = [handle3.getLsid()].map(genArg(execUserCred2));
|
|
fixture.kill("admin", obj);
|
|
}
|
|
fixture.assertNoSessionsInCursors();
|
|
fixture.assertCursorKillLogMessages([handle3]);
|
|
handle3.join();
|
|
},
|
|
];
|
|
}
|
|
|
|
let auth = [
|
|
// Verify that we can start a session and kill it with the universal pattern
|
|
function (fixture) {
|
|
fixture.loginForExecute("simple");
|
|
fixture.loginForKill("killAny");
|
|
let handle = fixture.startHangingOp();
|
|
fixture.kill("admin", {killAllSessionsByPattern: [{}]});
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle.join();
|
|
},
|
|
// Verify that we can impersonate, with that permission
|
|
function (fixture) {
|
|
fixture.loginForExecute("simple");
|
|
fixture.loginForKill("impersonate");
|
|
let handle = fixture.startHangingOp();
|
|
fixture.kill("admin", {killAllSessionsByPattern: [{users: [], roles: []}]});
|
|
fixture.assertNoSessionsInCurrentOp();
|
|
handle.join();
|
|
},
|
|
];
|
|
|
|
// Tests for makeAuthNoArgKill
|
|
[
|
|
[
|
|
// We can kill our own sessions
|
|
"killSessions",
|
|
"simple",
|
|
"simple",
|
|
],
|
|
[
|
|
// We can kill all sessions
|
|
"killAllSessions",
|
|
"simple",
|
|
"killAny",
|
|
],
|
|
[
|
|
// We can kill all sessions by pattern
|
|
"killAllSessionsByPattern",
|
|
"simple",
|
|
"killAny",
|
|
],
|
|
].forEach(function (cmd) {
|
|
auth = auth.concat(makeAuthNoArgKill.apply({}, cmd));
|
|
});
|
|
|
|
// Tests for makeAuthArgKill
|
|
[
|
|
[
|
|
// We can kill our own sessions by id (spoofing our own id)
|
|
"killSessions",
|
|
"simple",
|
|
"simple",
|
|
"killAny",
|
|
function () {
|
|
return function (x) {
|
|
if (!x.uid) {
|
|
return {
|
|
id: x.id,
|
|
uid: computeSHA256Block("simple@admin"),
|
|
};
|
|
} else {
|
|
return x;
|
|
}
|
|
};
|
|
},
|
|
],
|
|
[
|
|
// We can kill our own sessions without spoofing
|
|
"killSessions",
|
|
"simple",
|
|
"simple",
|
|
"simple",
|
|
function () {
|
|
return function (x) {
|
|
return x;
|
|
};
|
|
},
|
|
],
|
|
[
|
|
// We can kill by pattern by id
|
|
"killAllSessionsByPattern",
|
|
"simple",
|
|
"simple",
|
|
"killAny",
|
|
function () {
|
|
return function (x) {
|
|
if (!x.uid) {
|
|
return {
|
|
lsid: {
|
|
id: x.id,
|
|
uid: computeSHA256Block("simple@admin"),
|
|
},
|
|
};
|
|
} else {
|
|
return {lsid: x};
|
|
}
|
|
};
|
|
},
|
|
],
|
|
[
|
|
// We can kill any by user
|
|
"killAllSessions",
|
|
"simple",
|
|
"simple2",
|
|
"killAny",
|
|
function (user) {
|
|
return function (x) {
|
|
return {db: "admin", user: user};
|
|
};
|
|
},
|
|
],
|
|
[
|
|
// We can kill any by pattern by user
|
|
"killAllSessionsByPattern",
|
|
"simple",
|
|
"simple2",
|
|
"killAny",
|
|
function (user) {
|
|
return function (x) {
|
|
return {uid: computeSHA256Block(user + "@admin")};
|
|
};
|
|
},
|
|
],
|
|
].forEach(function (cmd) {
|
|
auth = auth.concat(makeAuthArgKill.apply({}, cmd));
|
|
});
|
|
|
|
// Ensures that illegal things fail
|
|
function makeAuthArgKillFailure(cmd, execUserCred, killUserCred, genArg) {
|
|
return [
|
|
function (fixture) {
|
|
fixture.loginForExecute(execUserCred);
|
|
fixture.loginForKill(killUserCred);
|
|
|
|
let session = fixture._clientToExecuteVia.startSession();
|
|
|
|
let obj = {};
|
|
obj[cmd] = [session._serverSession.handle.getId()].map(genArg(execUserCred));
|
|
fixture.assertKillFailed("admin", obj);
|
|
session.endSession();
|
|
},
|
|
];
|
|
}
|
|
|
|
// Tests for makeAuthArgKillFailure
|
|
[
|
|
[
|
|
// We can't kill another users sessions
|
|
"killSessions",
|
|
"simple",
|
|
"simple2",
|
|
function (user) {
|
|
return function (x) {
|
|
return {
|
|
id: x.id,
|
|
uid: computeSHA256Block(user + "@admin"),
|
|
};
|
|
};
|
|
},
|
|
],
|
|
[
|
|
// We can't impersonate without impersonate
|
|
"killAllSessionsByPattern",
|
|
"simple",
|
|
"killAny",
|
|
function (user) {
|
|
return function (x) {
|
|
return {
|
|
users: {},
|
|
roles: {},
|
|
};
|
|
};
|
|
},
|
|
],
|
|
].forEach(function (cmd) {
|
|
auth = auth.concat(makeAuthArgKillFailure.apply({}, cmd));
|
|
});
|
|
|
|
KillSessionsTestHelper.runAuth = function (clientToExecuteVia, clientToKillVia, clientsToVerifyVia) {
|
|
let fixture = new Fixture(clientToExecuteVia, clientToKillVia, clientsToVerifyVia);
|
|
|
|
for (let i = 0; i < auth.length; ++i) {
|
|
fixture.logout();
|
|
auth[i](fixture);
|
|
}
|
|
};
|
|
|
|
KillSessionsTestHelper.initializeAuth = function (client) {
|
|
let admin = client.getDB("admin");
|
|
admin.createUser({user: "super", pwd: "password", roles: jsTest.adminUserRoles});
|
|
admin.auth("super", "password");
|
|
admin.createRole({
|
|
role: "killAnySession",
|
|
roles: [],
|
|
privileges: [{resource: {cluster: true}, actions: ["killAnySession"]}],
|
|
});
|
|
admin.createRole({
|
|
role: "forSimpleTest",
|
|
roles: [],
|
|
privileges: [{resource: {cluster: true}, actions: ["inprog"]}],
|
|
});
|
|
admin.createRole({
|
|
role: "forImpersonate",
|
|
roles: [],
|
|
privileges: [{resource: {cluster: true}, actions: ["impersonate"]}],
|
|
});
|
|
|
|
admin.createUser({user: "simple", pwd: "password", roles: ["forSimpleTest"]});
|
|
admin.createUser({user: "simple2", pwd: "password", roles: ["forSimpleTest"]});
|
|
admin.createUser({user: "killAny", pwd: "password", roles: ["killAnySession"]});
|
|
admin.createUser({user: "impersonate", pwd: "password", roles: ["forImpersonate", "killAnySession"]});
|
|
};
|
|
|
|
let module = {};
|
|
module.KillSessionsTestHelper = KillSessionsTestHelper;
|
|
|
|
return module;
|
|
})();
|
|
|
|
// Globals
|
|
export var KillSessionsTestHelper = _kill_sessions_api_module.KillSessionsTestHelper;
|