diff options
-rw-r--r-- | jstests/auth/role_management_commands_lib.js (renamed from jstests/auth/role_management_commands.js) | 126 | ||||
-rw-r--r-- | jstests/auth/role_management_commands_sharded_wc_1.js | 10 | ||||
-rw-r--r-- | jstests/auth/role_management_commands_sharded_wc_majority.js | 10 | ||||
-rw-r--r-- | jstests/auth/role_management_commands_standalone.js | 9 | ||||
-rw-r--r-- | jstests/auth/user_management_commands_lib.js (renamed from jstests/auth/user_management_commands.js) | 87 | ||||
-rw-r--r-- | jstests/auth/user_management_commands_sharded_wc_1.js | 9 | ||||
-rw-r--r-- | jstests/auth/user_management_commands_sharded_wc_majority.js | 9 | ||||
-rw-r--r-- | jstests/auth/user_management_commands_standalone.js | 9 | ||||
-rw-r--r-- | src/mongo/db/write_concern_options.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/write_concern_options.h | 1 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/sharding_catalog_client_impl.cpp | 49 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/sharding_catalog_test.cpp | 78 |
12 files changed, 253 insertions, 148 deletions
diff --git a/jstests/auth/role_management_commands.js b/jstests/auth/role_management_commands_lib.js index af2f7709bf1..e1ff7860950 100644 --- a/jstests/auth/role_management_commands.js +++ b/jstests/auth/role_management_commands_lib.js @@ -2,20 +2,21 @@ * This tests that all the different commands for role manipulation all work properly for all valid * forms of input. */ +function runAllRoleManagementCommandsTests(conn, writeConcern) { + 'use strict'; -function runTest(conn) { - var authzErrorCode = 13; var hasAuthzError = function(result) { assert(result.hasWriteError()); - assert.eq(authzErrorCode, result.getWriteError().code); + assert.eq(ErrorCodes.Unauthorized, result.getWriteError().code); }; var userAdminConn = new Mongo(conn.host); var testUserAdmin = userAdminConn.getDB('test'); var adminUserAdmin = userAdminConn.getDB('admin'); - adminUserAdmin.createUser({user: 'userAdmin', pwd: 'pwd', roles: ['userAdminAnyDatabase']}); + adminUserAdmin.createUser({user: 'userAdmin', pwd: 'pwd', roles: ['userAdminAnyDatabase']}, + writeConcern); adminUserAdmin.auth('userAdmin', 'pwd'); - testUserAdmin.createUser({user: 'testUser', pwd: 'pwd', roles: []}); + testUserAdmin.createUser({user: 'testUser', pwd: 'pwd', roles: []}, writeConcern); var db = conn.getDB('test'); assert(db.auth('testUser', 'pwd')); @@ -30,25 +31,30 @@ function runTest(conn) { (function testCreateRole() { jsTestLog("Testing createRole"); - testUserAdmin.createRole({role: "testRole1", roles: ['read'], privileges: []}); + testUserAdmin.createRole({role: "testRole1", roles: ['read'], privileges: []}, + writeConcern); testUserAdmin.createRole({ role: "testRole2", roles: [], privileges: [{resource: {db: 'test', collection: 'foo'}, actions: ['insert']}] - }); + }, + writeConcern); testUserAdmin.createRole({ role: "testRole3", roles: ['testRole1', {role: 'testRole2', db: 'test'}], privileges: [] - }); - testUserAdmin.createRole({role: "testRole4", roles: [], privileges: []}); + }, + writeConcern); + testUserAdmin.createRole({role: "testRole4", roles: [], privileges: []}, writeConcern); adminUserAdmin.createRole({ role: "adminRole", roles: [], privileges: [{resource: {cluster: true}, actions: ['connPoolSync']}] - }); + }, + writeConcern); - testUserAdmin.updateUser('testUser', {roles: [{role: 'adminRole', db: 'admin'}]}); + testUserAdmin.updateUser( + 'testUser', {roles: [{role: 'adminRole', db: 'admin'}]}, writeConcern); assert.throws(function() { db.foo.findOne(); }); @@ -56,24 +62,24 @@ function runTest(conn) { hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); assert.commandWorked(db.adminCommand('connPoolSync')); - testUserAdmin.updateUser('testUser', {roles: ['testRole1']}); + testUserAdmin.updateUser('testUser', {roles: ['testRole1']}, writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); assert.eq(0, db.foo.count()); hasAuthzError(db.foo.insert({a: 1})); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); - testUserAdmin.updateUser('testUser', {roles: ['testRole2']}); + testUserAdmin.updateUser('testUser', {roles: ['testRole2']}, writeConcern); assert.throws(function() { db.foo.findOne(); }); assert.writeOK(db.foo.insert({a: 1})); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); - testUserAdmin.updateUser('testUser', {roles: ['testRole3']}); + testUserAdmin.updateUser('testUser', {roles: ['testRole3']}, writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -82,32 +88,34 @@ function runTest(conn) { assert.eq(2, db.foo.count()); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); assert.eq(1, db.foo.findOne().a); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); - testUserAdmin.updateUser('testUser', {roles: [{role: 'testRole4', db: 'test'}]}); + testUserAdmin.updateUser( + 'testUser', {roles: [{role: 'testRole4', db: 'test'}]}, writeConcern); assert.throws(function() { db.foo.findOne(); }); hasAuthzError(db.foo.insert({a: 1})); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); })(); (function testUpdateRole() { jsTestLog("Testing updateRole"); - testUserAdmin.updateRole('testRole4', - {roles: [{role: 'testRole2', db: 'test'}, "testRole2"]}); + testUserAdmin.updateRole( + 'testRole4', {roles: [{role: 'testRole2', db: 'test'}, "testRole2"]}, writeConcern); assert.throws(function() { db.foo.findOne(); }); assert.writeOK(db.foo.insert({a: 1})); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); testUserAdmin.updateRole( 'testRole4', - {privileges: [{resource: {db: 'test', collection: ''}, actions: ['find']}]}); + {privileges: [{resource: {db: 'test', collection: ''}, actions: ['find']}]}, + writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -116,9 +124,9 @@ function runTest(conn) { assert.eq(4, db.foo.count()); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); assert.eq(1, db.foo.findOne().a); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); - testUserAdmin.updateRole('testRole4', {roles: []}); + testUserAdmin.updateRole('testRole4', {roles: []}, writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -127,10 +135,11 @@ function runTest(conn) { assert.eq(4, db.foo.count()); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); assert.eq(1, db.foo.findOne().a); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); - testUserAdmin.updateUser('testUser', {roles: [{role: 'adminRole', db: 'admin'}]}); - adminUserAdmin.updateRole('adminRole', {roles: [{role: 'read', db: 'test'}]}); + testUserAdmin.updateUser( + 'testUser', {roles: [{role: 'adminRole', db: 'admin'}]}, writeConcern); + adminUserAdmin.updateRole('adminRole', {roles: [{role: 'read', db: 'test'}]}, writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -145,11 +154,12 @@ function runTest(conn) { (function testGrantRolesToRole() { jsTestLog("Testing grantRolesToRole"); - assert.commandFailedWithCode(db.adminCommand('serverStatus'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('serverStatus'), ErrorCodes.Unauthorized); adminUserAdmin.grantRolesToRole( "adminRole", - ['clusterMonitor', {role: 'read', db: 'test'}, {role: 'testRole2', db: 'test'}]); + ['clusterMonitor', {role: 'read', db: 'test'}, {role: 'testRole2', db: 'test'}], + writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -167,23 +177,27 @@ function runTest(conn) { adminUserAdmin.revokeRolesFromRole( "adminRole", - ['clusterMonitor', {role: 'read', db: 'test'}, {role: 'testRole2', db: 'test'}]); + ['clusterMonitor', {role: 'read', db: 'test'}, {role: 'testRole2', db: 'test'}], + writeConcern); assert.throws(function() { db.foo.findOne(); }); hasAuthzError(db.foo.insert({a: 1})); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); assert.commandWorked(db.adminCommand('connPoolSync')); - assert.commandFailedWithCode(db.adminCommand('serverStatus'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('serverStatus'), ErrorCodes.Unauthorized); })(); (function testGrantPrivilegesToRole() { jsTestLog("Testing grantPrivilegesToRole"); - adminUserAdmin.grantPrivilegesToRole('adminRole', [ - {resource: {cluster: true}, actions: ['serverStatus']}, - {resource: {db: "", collection: ""}, actions: ['find']} - ]); + adminUserAdmin.grantPrivilegesToRole( + 'adminRole', + [ + {resource: {cluster: true}, actions: ['serverStatus']}, + {resource: {db: "", collection: ""}, actions: ['find']} + ], + writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -194,11 +208,14 @@ function runTest(conn) { assert.commandWorked(db.adminCommand('connPoolSync')); assert.commandWorked(db.adminCommand('serverStatus')); - testUserAdmin.updateUser('testUser', {roles: ['testRole2']}); - testUserAdmin.grantPrivilegesToRole('testRole2', [ - {resource: {db: 'test', collection: ''}, actions: ['insert', 'update']}, - {resource: {db: 'test', collection: 'foo'}, actions: ['find']} - ]); + testUserAdmin.updateUser('testUser', {roles: ['testRole2']}, writeConcern); + testUserAdmin.grantPrivilegesToRole( + 'testRole2', + [ + {resource: {db: 'test', collection: ''}, actions: ['insert', 'update']}, + {resource: {db: 'test', collection: 'foo'}, actions: ['find']} + ], + writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -206,8 +223,8 @@ function runTest(conn) { assert.eq(6, db.foo.count()); assert.writeOK(db.foo.update({}, {$inc: {a: 1}}, false, true)); assert.eq(2, db.foo.findOne().a); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); - assert.commandFailedWithCode(db.adminCommand('serverStatus'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); + assert.commandFailedWithCode(db.adminCommand('serverStatus'), ErrorCodes.Unauthorized); })(); (function testRevokePrivilegesFromRole() { @@ -215,7 +232,8 @@ function runTest(conn) { testUserAdmin.revokePrivilegesFromRole( 'testRole2', - [{resource: {db: 'test', collection: ''}, actions: ['insert', 'update', 'find']}]); + [{resource: {db: 'test', collection: ''}, actions: ['insert', 'update', 'find']}], + writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); }); @@ -223,8 +241,8 @@ function runTest(conn) { assert.eq(7, db.foo.count()); hasAuthzError(db.foo.update({}, {$inc: {a: 1}}, false, true)); assert.eq(2, db.foo.findOne().a); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); - assert.commandFailedWithCode(db.adminCommand('serverStatus'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); + assert.commandFailedWithCode(db.adminCommand('serverStatus'), ErrorCodes.Unauthorized); })(); (function testRolesInfo() { @@ -265,7 +283,7 @@ function runTest(conn) { (function testDropRole() { jsTestLog("Testing dropRole"); - testUserAdmin.grantRolesToUser('testUser', ['testRole4']); + testUserAdmin.grantRolesToUser('testUser', ['testRole4'], writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); @@ -273,7 +291,7 @@ function runTest(conn) { assert.writeOK(db.foo.insert({a: 1})); assert.eq(8, db.foo.count()); - assert.commandWorked(testUserAdmin.runCommand({dropRole: 'testRole2'})); + testUserAdmin.dropRole('testRole2', writeConcern); assert.doesNotThrow(function() { db.foo.findOne(); @@ -292,7 +310,7 @@ function runTest(conn) { }); assert.eq(3, testUserAdmin.getRoles().length); - assert.commandWorked(testUserAdmin.runCommand({dropAllRolesFromDatabase: 1})); + testUserAdmin.dropAllRoles(writeConcern); assert.throws(function() { db.foo.findOne(); @@ -300,13 +318,3 @@ function runTest(conn) { assert.eq(0, testUserAdmin.getRoles().length); })(); } - -jsTest.log('Test standalone'); -var conn = MongoRunner.runMongod({auth: '', useHostname: false}); -runTest(conn); -MongoRunner.stopMongod(conn.port); - -jsTest.log('Test sharding'); -var st = new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1', useHostname: false}); -runTest(st.s); -st.stop(); diff --git a/jstests/auth/role_management_commands_sharded_wc_1.js b/jstests/auth/role_management_commands_sharded_wc_1.js new file mode 100644 index 00000000000..78ce948802b --- /dev/null +++ b/jstests/auth/role_management_commands_sharded_wc_1.js @@ -0,0 +1,10 @@ +(function() { + 'use strict'; + + load('jstests/auth/role_management_commands_lib.js'); + + var st = + new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1', useHostname: false}); + runAllRoleManagementCommandsTests(st.s, {w: 1}); + st.stop(); +})(); diff --git a/jstests/auth/role_management_commands_sharded_wc_majority.js b/jstests/auth/role_management_commands_sharded_wc_majority.js new file mode 100644 index 00000000000..19aa8e2c37e --- /dev/null +++ b/jstests/auth/role_management_commands_sharded_wc_majority.js @@ -0,0 +1,10 @@ +(function() { + 'use strict'; + + load('jstests/auth/role_management_commands_lib.js'); + + var st = + new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1', useHostname: false}); + runAllRoleManagementCommandsTests(st.s, {w: 'majority', wtimeout: 60 * 1000}); + st.stop(); +})(); diff --git a/jstests/auth/role_management_commands_standalone.js b/jstests/auth/role_management_commands_standalone.js new file mode 100644 index 00000000000..38f848f9936 --- /dev/null +++ b/jstests/auth/role_management_commands_standalone.js @@ -0,0 +1,9 @@ +(function() { + 'use strict'; + + load('jstests/auth/role_management_commands_lib.js'); + + var conn = MongoRunner.runMongod({auth: '', useHostname: false}); + runAllRoleManagementCommandsTests(conn); + MongoRunner.stopMongod(conn.port); +})(); diff --git a/jstests/auth/user_management_commands.js b/jstests/auth/user_management_commands_lib.js index a5cca448576..424fe5ef4ee 100644 --- a/jstests/auth/user_management_commands.js +++ b/jstests/auth/user_management_commands_lib.js @@ -2,22 +2,23 @@ * This tests that all the different commands for user manipulation all work properly for all valid * forms of input. */ +function runAllUserManagementCommandsTests(conn, writeConcern) { + 'use strict'; -function runTest(conn) { - var authzErrorCode = 13; var hasAuthzError = function(result) { assert(result.hasWriteError()); - assert.eq(authzErrorCode, result.getWriteError().code); + assert.eq(ErrorCodes.Unauthorized, result.getWriteError().code); }; - conn.getDB('admin').createUser({user: 'admin', pwd: 'pwd', roles: ['root']}); + conn.getDB('admin').createUser({user: 'admin', pwd: 'pwd', roles: ['root']}, writeConcern); conn.getDB('admin').auth('admin', 'pwd'); conn.getDB('admin').createUser({ user: 'userAdmin', pwd: 'pwd', roles: ['userAdminAnyDatabase'], customData: {userAdmin: true} - }); + }, + writeConcern); conn.getDB('admin').logout(); var userAdminConn = new Mongo(conn.host); @@ -27,12 +28,14 @@ function runTest(conn) { role: 'testRole', roles: [], privileges: [{resource: {db: 'test', collection: ''}, actions: ['viewRole']}], - }); + }, + writeConcern); userAdminConn.getDB('admin').createRole({ role: 'adminRole', roles: [], privileges: [{resource: {cluster: true}, actions: ['connPoolSync']}] - }); + }, + writeConcern); var db = conn.getDB('test'); @@ -51,8 +54,9 @@ function runTest(conn) { pwd: "pwd", customData: {zipCode: 10028}, roles: ['readWrite', 'testRole', {role: 'adminRole', db: 'admin'}] - }); - testUserAdmin.createUser({user: "andy", pwd: "pwd", roles: []}); + }, + writeConcern); + testUserAdmin.createUser({user: "andy", pwd: "pwd", roles: []}, writeConcern); var user = testUserAdmin.getUser('spencer'); assert.eq(10028, user.customData.zipCode); @@ -78,14 +82,14 @@ function runTest(conn) { (function testUpdateUser() { jsTestLog("Testing updateUser"); - testUserAdmin.updateUser('spencer', {pwd: 'password', customData: {}}); + testUserAdmin.updateUser('spencer', {pwd: 'password', customData: {}}, writeConcern); var user = testUserAdmin.getUser('spencer'); assert.eq(null, user.customData.zipCode); assert(!db.auth('spencer', 'pwd')); assert(db.auth('spencer', 'password')); - testUserAdmin.updateUser('spencer', - {customData: {zipCode: 10036}, roles: ["read", "testRole"]}); + testUserAdmin.updateUser( + 'spencer', {customData: {zipCode: 10036}, roles: ["read", "testRole"]}, writeConcern); var user = testUserAdmin.getUser('spencer'); assert.eq(10036, user.customData.zipCode); hasAuthzError(db.foo.insert({a: 1})); @@ -94,10 +98,10 @@ function runTest(conn) { assert.doesNotThrow(function() { db.getRole('testRole'); }); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); - testUserAdmin.updateUser('spencer', - {roles: ["readWrite", {role: 'adminRole', db: 'admin'}]}); + testUserAdmin.updateUser( + 'spencer', {roles: ["readWrite", {role: 'adminRole', db: 'admin'}]}, writeConcern); assert.writeOK(db.foo.update({}, {$inc: {a: 1}})); assert.eq(2, db.foo.findOne().a); assert.eq(1, db.foo.count()); @@ -111,15 +115,17 @@ function runTest(conn) { jsTestLog("Testing grantRolesToUser"); assert.commandFailedWithCode(db.runCommand({collMod: 'foo', usePowerOf2Sizes: true}), - authzErrorCode); - - testUserAdmin.grantRolesToUser('spencer', [ - 'readWrite', - 'dbAdmin', - {role: 'readWrite', db: 'test'}, - {role: 'testRole', db: 'test'}, - 'readWrite' - ]); + ErrorCodes.Unauthorized); + + testUserAdmin.grantRolesToUser('spencer', + [ + 'readWrite', + 'dbAdmin', + {role: 'readWrite', db: 'test'}, + {role: 'testRole', db: 'test'}, + 'readWrite' + ], + writeConcern); assert.commandWorked(db.runCommand({collMod: 'foo', usePowerOf2Sizes: true})); assert.writeOK(db.foo.update({}, {$inc: {a: 1}})); @@ -134,11 +140,14 @@ function runTest(conn) { (function testRevokeRolesFromUser() { jsTestLog("Testing revokeRolesFromUser"); - testUserAdmin.revokeRolesFromUser('spencer', [ - 'readWrite', - {role: 'dbAdmin', db: 'test2'}, // role user doesnt have - "testRole" - ]); + testUserAdmin.revokeRolesFromUser( + 'spencer', + [ + 'readWrite', + {role: 'dbAdmin', db: 'test2'}, // role user doesnt have + "testRole" + ], + writeConcern); assert.commandWorked(db.runCommand({collMod: 'foo', usePowerOf2Sizes: true})); hasAuthzError(db.foo.update({}, {$inc: {a: 1}})); @@ -150,7 +159,8 @@ function runTest(conn) { }); assert.commandWorked(db.adminCommand('connPoolSync')); - testUserAdmin.revokeRolesFromUser('spencer', [{role: 'adminRole', db: 'admin'}]); + testUserAdmin.revokeRolesFromUser( + 'spencer', [{role: 'adminRole', db: 'admin'}], writeConcern); hasAuthzError(db.foo.update({}, {$inc: {a: 1}})); assert.throws(function() { @@ -159,7 +169,7 @@ function runTest(conn) { assert.throws(function() { db.getRole('testRole'); }); - assert.commandFailedWithCode(db.adminCommand('connPoolSync'), authzErrorCode); + assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); })(); @@ -214,7 +224,7 @@ function runTest(conn) { assert(db.auth('spencer', 'password')); assert(db.auth('andy', 'pwd')); - assert.commandWorked(testUserAdmin.runCommand({dropUser: 'spencer'})); + testUserAdmin.dropUser('spencer', writeConcern); assert(!db.auth('spencer', 'password')); assert(db.auth('andy', 'pwd')); @@ -228,20 +238,9 @@ function runTest(conn) { assert.eq(1, testUserAdmin.getUsers().length); assert(db.auth('andy', 'pwd')); - assert.commandWorked(testUserAdmin.runCommand({dropAllUsersFromDatabase: 1})); + testUserAdmin.dropAllUsers(writeConcern); assert(!db.auth('andy', 'pwd')); assert.eq(0, testUserAdmin.getUsers().length); })(); } - -jsTest.log('Test standalone'); -var conn = MongoRunner.runMongod({auth: ''}); -conn.getDB('admin').runCommand({setParameter: 1, newCollectionsUsePowerOf2Sizes: false}); -runTest(conn); -MongoRunner.stopMongod(conn.port); - -jsTest.log('Test sharding'); -var st = new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1'}); -runTest(st.s); -st.stop(); diff --git a/jstests/auth/user_management_commands_sharded_wc_1.js b/jstests/auth/user_management_commands_sharded_wc_1.js new file mode 100644 index 00000000000..ff5bc0cfc43 --- /dev/null +++ b/jstests/auth/user_management_commands_sharded_wc_1.js @@ -0,0 +1,9 @@ +(function() { + 'use strict'; + + load('jstests/auth/user_management_commands_lib.js'); + + var st = new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1'}); + runAllUserManagementCommandsTests(st.s, {w: 1}); + st.stop(); +})(); diff --git a/jstests/auth/user_management_commands_sharded_wc_majority.js b/jstests/auth/user_management_commands_sharded_wc_majority.js new file mode 100644 index 00000000000..a18bc70e96a --- /dev/null +++ b/jstests/auth/user_management_commands_sharded_wc_majority.js @@ -0,0 +1,9 @@ +(function() { + 'use strict'; + + load('jstests/auth/user_management_commands_lib.js'); + + var st = new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1'}); + runAllUserManagementCommandsTests(st.s, {w: 'majority', wtimeout: 60 * 1000}); + st.stop(); +})(); diff --git a/jstests/auth/user_management_commands_standalone.js b/jstests/auth/user_management_commands_standalone.js new file mode 100644 index 00000000000..951ee1e9801 --- /dev/null +++ b/jstests/auth/user_management_commands_standalone.js @@ -0,0 +1,9 @@ +(function() { + 'use strict'; + + load('jstests/auth/user_management_commands_lib.js'); + + var conn = MongoRunner.runMongod({auth: '', useHostname: false}); + runAllUserManagementCommandsTests(conn); + MongoRunner.stopMongod(conn.port); +})(); diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp index 028d03d4635..dd9694dcc61 100644 --- a/src/mongo/db/write_concern_options.cpp +++ b/src/mongo/db/write_concern_options.cpp @@ -62,6 +62,7 @@ constexpr StringData kWElectionIdFieldName = "wElectionId"_sd; const int WriteConcernOptions::kNoTimeout(0); const int WriteConcernOptions::kNoWaiting(-1); +const StringData WriteConcernOptions::kWriteConcernField = "writeConcern"_sd; const char WriteConcernOptions::kMajority[] = "majority"; const BSONObj WriteConcernOptions::Default = BSONObj(); @@ -159,7 +160,8 @@ StatusWith<WriteConcernOptions> WriteConcernOptions::extractWCFromCommand( } BSONElement writeConcernElement; - Status wcStatus = bsonExtractTypedField(cmdObj, "writeConcern", Object, &writeConcernElement); + Status wcStatus = + bsonExtractTypedField(cmdObj, kWriteConcernField, Object, &writeConcernElement); if (!wcStatus.isOK()) { if (wcStatus == ErrorCodes::NoSuchKey) { // Return default write concern if no write concern is given. diff --git a/src/mongo/db/write_concern_options.h b/src/mongo/db/write_concern_options.h index 06ddfbc56a0..85f9e0e0390 100644 --- a/src/mongo/db/write_concern_options.h +++ b/src/mongo/db/write_concern_options.h @@ -47,6 +47,7 @@ public: static const BSONObj Unacknowledged; static const BSONObj Majority; + static const StringData kWriteConcernField; static const char kMajority[]; // = "majority" WriteConcernOptions() { diff --git a/src/mongo/s/catalog/replset/sharding_catalog_client_impl.cpp b/src/mongo/s/catalog/replset/sharding_catalog_client_impl.cpp index 0c9e47d976e..57d701a82a6 100644 --- a/src/mongo/s/catalog/replset/sharding_catalog_client_impl.cpp +++ b/src/mongo/s/catalog/replset/sharding_catalog_client_impl.cpp @@ -96,8 +96,6 @@ using str::stream; namespace { -const char kWriteConcernField[] = "writeConcern"; - const ReadPreferenceSetting kConfigReadSelector(ReadPreference::Nearest, TagSet{}); const ReadPreferenceSetting kConfigPrimaryPreferredSelector(ReadPreference::PrimaryPreferred, TagSet{}); @@ -767,12 +765,13 @@ Status ShardingCatalogClientImpl::dropCollection(OperationContext* txn, const Na return {ErrorCodes::ShardNotFound, str::stream() << "shard " << shardEntry.getName() << " not found"}; } - auto dropResult = shard->runCommand( - txn, - ReadPreferenceSetting{ReadPreference::PrimaryOnly}, - ns.db().toString(), - BSON("drop" << ns.coll() << "writeConcern" << txn->getWriteConcern().toBSON()), - Shard::RetryPolicy::kIdempotent); + auto dropResult = + shard->runCommand(txn, + ReadPreferenceSetting{ReadPreference::PrimaryOnly}, + ns.db().toString(), + BSON("drop" << ns.coll() << WriteConcernOptions::kWriteConcernField + << txn->getWriteConcern().toBSON()), + Shard::RetryPolicy::kIdempotent); if (!dropResult.isOK()) { return Status(dropResult.getStatus().code(), @@ -1134,24 +1133,26 @@ bool ShardingCatalogClientImpl::runUserManagementWriteCommand(OperationContext* // convert w:1 or no write concern to w:majority before sending. WriteConcernOptions writeConcern; writeConcern.reset(); - const char* writeConcernFieldName = "writeConcern"; - BSONElement writeConcernElement = cmdObj[writeConcernFieldName]; + + BSONElement writeConcernElement = cmdObj[WriteConcernOptions::kWriteConcernField]; bool initialCmdHadWriteConcern = !writeConcernElement.eoo(); if (initialCmdHadWriteConcern) { Status status = writeConcern.parse(writeConcernElement.Obj()); if (!status.isOK()) { return Command::appendCommandStatus(*result, status); } - if (!writeConcern.validForConfigServers()) { + + if (!(writeConcern.wNumNodes == 1 || + writeConcern.wMode == WriteConcernOptions::kMajority)) { return Command::appendCommandStatus( *result, - Status(ErrorCodes::InvalidOptions, - str::stream() - << "Invalid replication write concern. Writes to config server " - "replica sets must use w:'majority', got: " - << writeConcern.toBSON())); + {ErrorCodes::InvalidOptions, + str::stream() << "Invalid replication write concern. User management write " + "commands may only use w:1 or w:'majority', got: " + << writeConcern.toBSON()}); } } + writeConcern.wMode = WriteConcernOptions::kMajority; writeConcern.wNumNodes = 0; @@ -1162,13 +1163,13 @@ bool ShardingCatalogClientImpl::runUserManagementWriteCommand(OperationContext* BSONObjIterator cmdObjIter(cmdObj); while (cmdObjIter.more()) { BSONElement e = cmdObjIter.next(); - if (str::equals(e.fieldName(), writeConcernFieldName)) { + if (WriteConcernOptions::kWriteConcernField == e.fieldName()) { continue; } modifiedCmd.append(e); } } - modifiedCmd.append(writeConcernFieldName, writeConcern.toBSON()); + modifiedCmd.append(WriteConcernOptions::kWriteConcernField, writeConcern.toBSON()); cmdToRun = modifiedCmd.obj(); } @@ -1230,9 +1231,9 @@ Status ShardingCatalogClientImpl::applyChunkOpsDeprecated(OperationContext* txn, const BSONArray& preCondition, const std::string& nss, const ChunkVersion& lastChunkVersion) { - BSONObj cmd = - BSON("applyOps" << updateOps << "preCondition" << preCondition << kWriteConcernField - << ShardingCatalogClient::kMajorityWriteConcern.toBSON()); + BSONObj cmd = BSON("applyOps" << updateOps << "preCondition" << preCondition + << WriteConcernOptions::kWriteConcernField + << ShardingCatalogClient::kMajorityWriteConcern.toBSON()); auto response = Grid::get(txn)->shardRegistry()->getConfigShard()->runCommand( txn, @@ -1511,9 +1512,9 @@ Status ShardingCatalogClientImpl::_checkDbDoesNotExist(OperationContext* txn, Status ShardingCatalogClientImpl::_createCappedConfigCollection(OperationContext* txn, StringData collName, int cappedSize) { - BSONObj createCmd = - BSON("create" << collName << "capped" << true << "size" << cappedSize << "writeConcern" - << ShardingCatalogClient::kMajorityWriteConcern.toBSON()); + BSONObj createCmd = BSON("create" << collName << "capped" << true << "size" << cappedSize + << WriteConcernOptions::kWriteConcernField + << ShardingCatalogClient::kMajorityWriteConcern.toBSON()); auto result = Grid::get(txn)->shardRegistry()->getConfigShard()->runCommand( txn, diff --git a/src/mongo/s/catalog/replset/sharding_catalog_test.cpp b/src/mongo/s/catalog/replset/sharding_catalog_test.cpp index 5ecf1899c60..e4d06494d1b 100644 --- a/src/mongo/s/catalog/replset/sharding_catalog_test.cpp +++ b/src/mongo/s/catalog/replset/sharding_catalog_test.cpp @@ -679,27 +679,9 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandSuccess) { future.timed_get(kFutureTimeout); } -TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandWithInvalidWriteConcernSingleNode) { - // Tests that if you send a non-majority write concern it will not be accepted - BSONObjBuilder responseBuilder; - bool ok = - catalogClient()->runUserManagementWriteCommand(operationContext(), - "dropUser", - "test", - BSON("dropUser" - << "test" - << "writeConcern" - << BSON("w" << 1 << "wtimeout" << 30)), - &responseBuilder); - ASSERT_FALSE(ok); - - Status commandStatus = getStatusFromCommandResult(responseBuilder.obj()); - ASSERT_EQUALS(ErrorCodes::InvalidOptions, commandStatus); - ASSERT_STRING_CONTAINS(commandStatus.reason(), "Invalid replication write concern"); -} +TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandInvalidWriteConcern) { + configTargeter()->setFindHostReturnValue(HostAndPort("TestHost1")); -TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandInvalidWriteConcernTwoNodes) { - // Tests that if you send a non-majority write concern it will not be accepted BSONObjBuilder responseBuilder; bool ok = catalogClient()->runUserManagementWriteCommand(operationContext(), "dropUser", @@ -716,6 +698,62 @@ TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandInvalidWriteConce ASSERT_STRING_CONTAINS(commandStatus.reason(), "Invalid replication write concern"); } +TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandRewriteWriteConcern) { + // Tests that if you send a w:1 write concern it gets replaced with w:majority + configTargeter()->setFindHostReturnValue(HostAndPort("TestHost1")); + + distLock()->expectLock( + [](StringData name, + StringData whyMessage, + Milliseconds waitFor, + Milliseconds lockTryInterval) { + ASSERT_EQUALS("authorizationData", name); + ASSERT_EQUALS("dropUser", whyMessage); + }, + Status::OK()); + + auto future = launchAsync([this] { + BSONObjBuilder responseBuilder; + bool ok = catalogClient()->runUserManagementWriteCommand(operationContext(), + "dropUser", + "test", + BSON("dropUser" + << "test" + << "writeConcern" + << BSON("w" << 1 << "wtimeout" + << 30)), + &responseBuilder); + ASSERT_FALSE(ok); + + Status commandStatus = getStatusFromCommandResult(responseBuilder.obj()); + ASSERT_EQUALS(ErrorCodes::UserNotFound, commandStatus); + }); + + onCommand([](const RemoteCommandRequest& request) { + ASSERT_EQUALS("test", request.dbname); + ASSERT_EQUALS(BSON("dropUser" + << "test" + << "writeConcern" + << BSON("w" + << "majority" + << "wtimeout" + << 30) + << "maxTimeMS" + << 30000), + request.cmdObj); + + ASSERT_EQUALS(BSON(rpc::kReplSetMetadataFieldName << 1), request.metadata); + + BSONObjBuilder responseBuilder; + Command::appendCommandStatus(responseBuilder, + Status(ErrorCodes::UserNotFound, "User test@test not found")); + return responseBuilder.obj(); + }); + + // Now wait for the runUserManagementWriteCommand call to return + future.timed_get(kFutureTimeout); +} + TEST_F(ShardingCatalogClientTest, RunUserManagementWriteCommandNotMaster) { configTargeter()->setFindHostReturnValue(HostAndPort("TestHost1")); |