Files
mongo/jstests/sharding/auth.js
Kaloian Manassiev 6745d91683 SERVER-21050 Introduce ReplSetTest.State enumeration everywhere
Makes all JS tests access the replica set member state from the class
itself instead of the object instance. Also removes some unused code.
2015-12-11 13:32:56 -05:00

339 lines
11 KiB
JavaScript

// Tests administrative sharding operations and map-reduce work or fail as expected, when key-based
// authentication is used
(function() {
'use strict';
var adminUser = {
db : "admin",
username : "foo",
password : "bar"
};
var testUser = {
db : "test",
username : "bar",
password : "baz"
};
var testUserReadOnly = {
db : "test",
username : "sad",
password : "bat"
};
function login(userObj, thingToUse) {
if (!thingToUse) {
thingToUse = s;
}
thingToUse.getDB(userObj.db).auth(userObj.username, userObj.password);
}
function logout(userObj, thingToUse) {
if (!thingToUse)
thingToUse = s;
s.getDB(userObj.db).runCommand({logout:1});
}
function getShardName(rsTest) {
var master = rsTest.getPrimary();
var config = master.getDB("local").system.replset.findOne();
var members = config.members.map(function(elem) { return elem.host; });
return config._id+"/"+members.join(",");
}
var s = new ShardingTest({ name: "auth",
mongos: 1,
shards: 0,
other: {
extraOptions: { "keyFile": "jstests/libs/key1" },
noChunkSize: true, }
});
if (s.getDB('admin').runCommand('buildInfo').bits < 64) {
print('Skipping test on 32-bit platforms');
return;
}
print("Configuration: Add user " + tojson(adminUser));
s.getDB(adminUser.db).createUser({user: adminUser.username,
pwd: adminUser.password,
roles: jsTest.adminUserRoles});
login(adminUser);
// Set the chunk size, disable the secondary throttle (so the test doesn't run so slow)
assert.writeOK(s.getDB( "config" ).settings.update({ _id: "chunksize" },
{ $set: { value : 1 } },
{ upsert: true }));
assert.writeOK(s.getDB( "config" ).settings.update(
{ _id: "balancer" },
{ $set: { "_secondaryThrottle" : false,
"_waitForDelete" : true } },
{ upsert: true }));
printjson(s.getDB("config").settings.find().toArray());
print("Restart mongos with different auth options");
s.restartMongos(0, { v: 2,
configdb: s._configDB,
keyFile: "jstests/libs/key1",
chunkSize: 1 });
login(adminUser);
var d1 = new ReplSetTest({ name : "d1", nodes : 3, useHostName : true });
d1.startSet({keyFile : "jstests/libs/key2" });
d1.initiate();
print("d1 initiated");
var shardName = authutil.asCluster(d1.nodes,
"jstests/libs/key2",
function() { return getShardName(d1); });
print("adding shard w/out auth "+shardName);
logout(adminUser);
var result = s.getDB("admin").runCommand({addShard : shardName});
printjson(result);
assert.eq(result.code, 13);
login(adminUser);
print("adding shard w/wrong key "+shardName);
var thrown = false;
try {
result = s.adminCommand({addShard : shardName});
}
catch(e) {
thrown = true;
printjson(e);
}
assert(thrown);
print("start rs w/correct key");
d1.stopSet();
d1.startSet({keyFile : "jstests/libs/key1" });
d1.initiate();
var master = d1.getPrimary();
print("adding shard w/auth " + shardName);
result = s.getDB("admin").runCommand({addShard : shardName});
assert.eq(result.ok, 1, tojson(result));
s.getDB("admin").runCommand({enableSharding : "test"});
s.getDB("admin").runCommand({shardCollection : "test.foo", key : {x : 1}});
d1.waitForState( d1.getSecondaries(), ReplSetTest.State.SECONDARY, 5 * 60 * 1000 )
s.getDB(testUser.db).createUser({user: testUser.username,
pwd: testUser.password,
roles: jsTest.basicUserRoles})
s.getDB(testUserReadOnly.db).createUser({user: testUserReadOnly.username,
pwd: testUserReadOnly.password,
roles: jsTest.readOnlyUserRoles});
logout(adminUser);
print("query try");
var e = assert.throws(function() {
s.s.getDB("foo").bar.findOne();
});
printjson(e);
print("cmd try");
assert.eq(0, s.s.getDB("foo").runCommand({listDatabases:1}).ok);
print("insert try 1");
s.getDB("test").foo.insert({x:1});
login(testUser);
assert.eq(s.getDB("test").foo.findOne(), null);
print("insert try 2");
assert.writeOK(s.getDB("test").foo.insert({ x: 1 }));
assert.eq( 1 , s.getDB( "test" ).foo.find().itcount() , tojson(result) );
logout(testUser);
var d2 = new ReplSetTest({name : "d2", nodes : 3, useHostName : true });
d2.startSet({keyFile : "jstests/libs/key1" });
d2.initiate();
d2.awaitSecondaryNodes();
shardName = authutil.asCluster(d2.nodes, "jstests/libs/key1",
function() { return getShardName(d2); });
print("adding shard "+shardName);
login(adminUser);
print("logged in");
result = s.getDB("admin").runCommand({addShard : shardName})
ReplSetTest.awaitRSClientHosts(s.s, d1.nodes, {ok: true });
ReplSetTest.awaitRSClientHosts(s.s, d2.nodes, {ok: true });
s.getDB("test").foo.remove({})
var num = 10000;
var bulk = s.getDB("test").foo.initializeUnorderedBulkOp();
for (i=0; i<num; i++) {
bulk.insert({ _id: i, x: i, abc: "defg", date: new Date(), str: "all the talk on the market" });
}
assert.writeOK(bulk.execute());
s.startBalancer(60000);
assert.soon(function() {
var d1Chunks = s.getDB("config").chunks.count({shard : "d1"});
var d2Chunks = s.getDB("config").chunks.count({shard : "d2"});
var totalChunks = s.getDB("config").chunks.count({ns : "test.foo"});
print("chunks: " + d1Chunks+" "+d2Chunks+" "+totalChunks);
return d1Chunks > 0 && d2Chunks > 0 && (d1Chunks + d2Chunks == totalChunks);
},
"Chunks failed to balance",
60000,
5000);
//SERVER-3645
//assert.eq(s.getDB("test").foo.count(), num+1);
var numDocs = s.getDB("test").foo.find().itcount()
if (numDocs != num) {
// Missing documents. At this point we're already in a failure mode, the code in this statement
// is to get a better idea how/why it's failing.
var numDocsSeen = 0;
var lastDocNumber = -1;
var missingDocNumbers = [];
var docs = s.getDB("test").foo.find().sort({x:1}).toArray();
for (var i = 0; i < docs.length; i++) {
if (docs[i].x != lastDocNumber + 1) {
for (var missing = lastDocNumber + 1; missing < docs[i].x; missing++) {
missingDocNumbers.push(missing);
}
}
lastDocNumber = docs[i].x;
numDocsSeen++;
}
assert.eq(numDocs, numDocsSeen, "More docs discovered on second find()")
assert.eq(num - numDocs, missingDocNumbers.length);
load('jstests/libs/trace_missing_docs.js');
for ( var i = 0; i < missingDocNumbers.length; i++ ) {
jsTest.log( "Tracing doc: " + missingDocNumbers[i] );
traceMissingDoc( s.getDB( "test" ).foo, { _id : missingDocNumbers[i],
x : missingDocNumbers[i] } );
}
assert(false, "Number of docs found does not equal the number inserted. Missing docs: " + missingDocNumbers);
}
// We're only sure we aren't duplicating documents iff there's no balancing going on here
// This call also waits for any ongoing balancing to stop
s.stopBalancer(60000);
var cursor = s.getDB("test").foo.find({x:{$lt : 500}});
var count = 0;
while (cursor.hasNext()) {
cursor.next();
count++;
}
assert.eq(count, 500);
logout(adminUser);
d1.waitForState( d1.getSecondaries(), ReplSetTest.State.SECONDARY, 5 * 60 * 1000 );
d2.waitForState( d2.getSecondaries(), ReplSetTest.State.SECONDARY, 5 * 60 * 1000 );
authutil.asCluster(d1.nodes, "jstests/libs/key1", function() { d1.awaitReplication(120000); });
authutil.asCluster(d2.nodes, "jstests/libs/key1", function() { d2.awaitReplication(120000); });
// add admin on shard itself, hack to prevent localhost auth bypass
d1.getPrimary().getDB(adminUser.db).createUser({user: adminUser.username,
pwd: adminUser.password,
roles: jsTest.adminUserRoles},
{w: 3, wtimeout: 60000});
d2.getPrimary().getDB(adminUser.db).createUser({user: adminUser.username,
pwd: adminUser.password,
roles: jsTest.adminUserRoles},
{w: 3, wtimeout: 60000});
login(testUser);
print( "testing map reduce" );
// Sharded map reduce can be tricky since all components talk to each other. For example
// SERVER-4114 is triggered when 1 mongod connects to another for final reduce it's not
// properly tested here since addresses are localhost, which is more permissive.
var res = s.getDB("test").runCommand(
{mapreduce : "foo",
map : function() { emit(this.x, 1); },
reduce : function(key, values) { return values.length; },
out:"mrout"
});
printjson(res);
assert.commandWorked(res);
// Check that dump doesn't get stuck with auth
var x = runMongoProgram("mongodump",
"--host", s.s.host,
"-d", testUser.db,
"-u", testUser.username,
"-p", testUser.password,
"--authenticationMechanism", "SCRAM-SHA-1");
print("result: " + x);
// Test read only users
print( "starting read only tests" );
var readOnlyS = new Mongo( s.getDB( "test" ).getMongo().host )
var readOnlyDB = readOnlyS.getDB( "test" );
print( " testing find that should fail" );
assert.throws( function(){ readOnlyDB.foo.findOne(); } )
print( " logging in" );
login( testUserReadOnly , readOnlyS );
print( " testing find that should work" );
readOnlyDB.foo.findOne();
print( " testing write that should fail" );
assert.writeError(readOnlyDB.foo.insert({ eliot: 1 }));
print( " testing read command (should succeed)" );
assert.commandWorked(readOnlyDB.runCommand({count : "foo"}));
print("make sure currentOp/killOp fail");
assert.commandFailed(readOnlyDB.currentOp());
assert.commandFailed(readOnlyDB.killOp(123));
// fsyncUnlock doesn't work in mongos anyway, so no need check authorization for it
/*
broken because of SERVER-4156
print( " testing write command (should fail)" );
assert.commandFailed(readOnlyDB.runCommand(
{mapreduce : "foo",
map : function() { emit(this.y, 1); },
reduce : function(key, values) { return values.length; },
out:"blarg"
}));
*/
print( " testing logout (should succeed)" );
assert.commandWorked(readOnlyDB.runCommand({logout : 1}));
print("make sure currentOp/killOp fail again");
assert.commandFailed(readOnlyDB.currentOp());
assert.commandFailed(readOnlyDB.killOp(123));
s.stop();
})();