mirror of https://github.com/mongodb/mongo
292 lines
11 KiB
JavaScript
292 lines
11 KiB
JavaScript
/**
|
|
* This test checks that authentication restrictions can be set and respected.
|
|
* @tags: [requires_sharding, requires_replication]
|
|
*/
|
|
import {get_ipaddr, getIpv6addr} from "jstests/libs/host_ipaddr.js";
|
|
import {ReplSetTest} from "jstests/libs/replsettest.js";
|
|
import {ShardingTest} from "jstests/libs/shardingtest.js";
|
|
|
|
// Multiple users cannot be authenticated on one connection within a session.
|
|
TestData.disableImplicitSessions = true;
|
|
|
|
function testConnection(conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) {
|
|
// Create a session which observes an eventually consistent view of user data
|
|
const eventualDb = eventuallyConsistentConn.getDB("admin");
|
|
|
|
// Create a session for modifying user data during the life of the test
|
|
const adminSession = new Mongo("localhost:" + conn.port);
|
|
const admin = adminSession.getDB("admin");
|
|
assert.commandWorked(admin.runCommand({createUser: "admin", pwd: "admin", roles: [{role: "root", db: "admin"}]}));
|
|
assert(admin.auth("admin", "admin"));
|
|
admin.logout();
|
|
|
|
// Create a strongly consistent session for consuming user data
|
|
const db = conn.getDB("admin");
|
|
let ipv6addr = getIpv6addr(true, false);
|
|
|
|
// Create a strongly consistent session for consuming user data, with a non-localhost
|
|
// source IP.
|
|
const externalMongo = new Mongo(get_ipaddr() + ":" + conn.port);
|
|
const externalDb = externalMongo.getDB("admin");
|
|
|
|
// Create a connection which remains authenticated as 'admin'
|
|
// so that we can create/mutate users/roles while we do
|
|
// multiple authentications.
|
|
const adminMongo = new Mongo(conn.host);
|
|
const adminDB = adminMongo.getDB("admin");
|
|
assert(adminDB.auth("admin", "admin"));
|
|
|
|
assert.commandWorked(
|
|
adminDB.runCommand({
|
|
createUser: "user2",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{clientSource: ["127.0.0.1"]}],
|
|
}),
|
|
);
|
|
assert.commandWorked(adminDB.runCommand({createUser: "user3", pwd: "user", roles: []}));
|
|
assert.commandWorked(
|
|
adminDB.runCommand({updateUser: "user3", authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}]}),
|
|
);
|
|
|
|
print("=== User creation tests");
|
|
print(
|
|
"When a client creates users with empty authenticationRestrictions, the operation succeeds, though it has no effect",
|
|
);
|
|
assert.commandWorked(
|
|
adminDB.runCommand({createUser: "user4", pwd: "user", roles: [], authenticationRestrictions: []}),
|
|
);
|
|
assert(!Object.keys(adminDB.system.users.findOne({user: "user4"})).includes("authenticationRestrictions"));
|
|
|
|
print(
|
|
"When a client updates a user's authenticationRestrictions to be empty, the operation succeeds, and removes the authenticationRestrictions field",
|
|
);
|
|
assert.commandWorked(adminDB.runCommand({createUser: "user5", pwd: "user", roles: []}));
|
|
assert.commandWorked(adminDB.runCommand({updateUser: "user5", authenticationRestrictions: []}));
|
|
assert(!Object.keys(adminDB.system.users.findOne({user: "user5"})).includes("authenticationRestrictions"));
|
|
assert.commandWorked(
|
|
adminDB.runCommand({updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]}),
|
|
);
|
|
assert(Object.keys(adminDB.system.users.findOne({user: "user5"})).includes("authenticationRestrictions"));
|
|
assert.commandWorked(adminDB.runCommand({updateUser: "user5", authenticationRestrictions: []}));
|
|
assert(!Object.keys(adminDB.system.users.findOne({user: "user5"})).includes("authenticationRestrictions"));
|
|
|
|
print("When a client updates a user's authenticationRestrictions to be null or undefined, the operation fails");
|
|
assert.commandWorked(
|
|
adminDB.runCommand({updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]}),
|
|
);
|
|
assert(Object.keys(adminDB.system.users.findOne({user: "user5"})).includes("authenticationRestrictions"));
|
|
assert.commandFailed(adminDB.runCommand({updateUser: "user5", authenticationRestrictions: null}));
|
|
assert(Object.keys(adminDB.system.users.findOne({user: "user5"})).includes("authenticationRestrictions"));
|
|
assert.commandFailed(adminDB.runCommand({updateUser: "user5", authenticationRestrictions: undefined}));
|
|
assert(Object.keys(adminDB.system.users.findOne({user: "user5"})).includes("authenticationRestrictions"));
|
|
|
|
print("When a client creates users, it may use clientSource and serverAddress authenticationRestrictions");
|
|
assert.commandWorked(
|
|
adminDB.runCommand({
|
|
createUser: "user6",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{clientSource: ["127.0.0.1"]}],
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
adminDB.runCommand({
|
|
createUser: "user7",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}],
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
adminDB.runCommand({
|
|
createUser: "user8",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}],
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
adminDB.runCommand({
|
|
createUser: "user9",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{clientSource: ["127.0.0.1"]}, {serverAddress: ["127.0.0.1"]}],
|
|
}),
|
|
);
|
|
assert.commandFailed(
|
|
adminDB.runCommand({
|
|
createUser: "user10",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{invalidRestriction: ["127.0.0.1"]}],
|
|
}),
|
|
);
|
|
if (ipv6addr != "" && ipv6addr != null) {
|
|
assert.commandWorked(
|
|
adminDB.runCommand({
|
|
createUser: "ipv6user1",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{clientSource: [ipv6addr]}],
|
|
}),
|
|
);
|
|
print(
|
|
'When a client on a link-local IPv6 address authenticates to a user with {clientSource: "' +
|
|
ipv6addr +
|
|
'"}, it will succeed',
|
|
);
|
|
|
|
clearRawMongoProgramOutput();
|
|
const ipv6Command = [
|
|
"mongo",
|
|
"--ipv6",
|
|
"--host",
|
|
"[" + ipv6addr + "]",
|
|
"--port",
|
|
conn.port,
|
|
"-u",
|
|
"ipv6user1",
|
|
"-p",
|
|
"user",
|
|
"--authenticationDatabase",
|
|
"admin",
|
|
];
|
|
let clientPID = _startMongoProgram({args: ipv6Command});
|
|
assert.soon(() => {
|
|
const output = rawMongoProgramOutput(".*");
|
|
if (output.includes("Successfully authenticated")) {
|
|
stopMongoProgramByPid(clientPID);
|
|
return true;
|
|
}
|
|
if (output.includes("Error:")) {
|
|
print("ipv6 auth attempt failed with output: " + output);
|
|
return false;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
print("=== Localhost access tests");
|
|
|
|
print('When a client on the loopback authenticates to a user with {clientSource: "127.0.0.1"}, it will succeed');
|
|
assert(db.auth("user6", "user"));
|
|
db.logout();
|
|
|
|
print('When a client on the loopback authenticates to a user with {serverAddress: "127.0.0.1"}, it will succeed');
|
|
assert(db.auth("user7", "user"));
|
|
db.logout();
|
|
|
|
print(
|
|
'When a client on the loopback authenticates to a user with {clientSource: "127.0.0.1", serverAddress: "127.0.0.1"}, it will succeed',
|
|
);
|
|
assert(db.auth("user8", "user"));
|
|
db.logout();
|
|
|
|
print("=== Remote access tests");
|
|
print(
|
|
'When a client on the external interface authenticates to a user with {clientSource: "127.0.0.1"}, it will fail',
|
|
);
|
|
assert(!externalDb.auth("user6", "user"));
|
|
|
|
print(
|
|
'When a client on the external interface authenticates to a user with {serverAddress: "127.0.0.1"}, it will fail',
|
|
);
|
|
assert(!externalDb.auth("user7", "user"));
|
|
|
|
print(
|
|
'When a client on the external interface authenticates to a user with {clientSource: "127.0.0.1", serverAddress: "127.0.0.1"}, it will fail',
|
|
);
|
|
assert(!externalDb.auth("user8", "user"));
|
|
|
|
print("=== Invalidation tests");
|
|
print("When a client removes all authenticationRestrictions from a user, authentication will succeed");
|
|
assert.commandWorked(
|
|
adminDB.runCommand({
|
|
createUser: "user11",
|
|
pwd: "user",
|
|
roles: [],
|
|
authenticationRestrictions: [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}],
|
|
}),
|
|
);
|
|
assert(!externalDb.auth("user11", "user"));
|
|
assert.commandWorked(adminDB.runCommand({updateUser: "user11", authenticationRestrictions: []}));
|
|
assert(externalDb.auth("user11", "user"));
|
|
externalDb.logout();
|
|
|
|
print("When a client sets authenticationRestrictions on a user, authorization privileges are revoked");
|
|
assert.commandWorked(
|
|
adminDB.runCommand({createUser: "user12", pwd: "user", roles: [{role: "readWrite", db: "test"}]}),
|
|
);
|
|
|
|
assert(db.auth("user12", "user"));
|
|
assert.commandWorked(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0}));
|
|
db.logout();
|
|
|
|
sleepUntilUserDataPropagated();
|
|
assert(eventualDb.auth("user12", "user"));
|
|
assert.commandWorked(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0}));
|
|
|
|
assert.commandWorked(
|
|
adminDB.runCommand({updateUser: "user12", authenticationRestrictions: [{clientSource: ["192.0.2.0"]}]}),
|
|
);
|
|
|
|
assert(!db.auth("user12", "user"));
|
|
|
|
sleepUntilUserDataRefreshed();
|
|
assert.commandFailed(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0}));
|
|
}
|
|
|
|
print("Testing standalone");
|
|
const conn = MongoRunner.runMongod({bind_ip_all: "", ipv6: "", auth: ""});
|
|
testConnection(
|
|
conn,
|
|
conn,
|
|
function () {},
|
|
function () {},
|
|
);
|
|
MongoRunner.stopMongod(conn);
|
|
|
|
const keyfile = "jstests/libs/key1";
|
|
|
|
print("Testing replicaset");
|
|
const rst = new ReplSetTest({
|
|
name: "testset",
|
|
nodes: 2,
|
|
nodeOptions: {bind_ip_all: "", ipv6: "", auth: ""},
|
|
keyFile: keyfile,
|
|
});
|
|
const nodes = rst.startSet();
|
|
rst.initiate();
|
|
rst.awaitSecondaryNodes();
|
|
const awaitReplication = function () {
|
|
authutil.asCluster(nodes, "jstests/libs/key1", function () {
|
|
rst.awaitReplication();
|
|
});
|
|
};
|
|
|
|
testConnection(rst.getPrimary(), rst.getSecondary(), awaitReplication, awaitReplication);
|
|
rst.stopSet();
|
|
|
|
print("Testing sharded cluster");
|
|
const st = new ShardingTest({
|
|
mongos: 2,
|
|
config: 3,
|
|
shard: 1,
|
|
keyFile: keyfile,
|
|
other: {
|
|
mongosOptions: {bind_ip_all: "", auth: null},
|
|
configOptions: {auth: null},
|
|
rsOptions: {auth: null},
|
|
},
|
|
});
|
|
testConnection(
|
|
st.s0,
|
|
st.s1,
|
|
function () {},
|
|
function () {
|
|
sleep(40 * 1000); // Wait for mongos user cache invalidation
|
|
},
|
|
);
|
|
st.stop();
|