diff options
-rw-r--r-- | jstests/ssl/x509_client.js | 122 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.idl | 8 |
3 files changed, 91 insertions, 58 deletions
diff --git a/jstests/ssl/x509_client.js b/jstests/ssl/x509_client.js index 7fe351f25d6..00624c63a33 100644 --- a/jstests/ssl/x509_client.js +++ b/jstests/ssl/x509_client.js @@ -1,20 +1,5 @@ // Check if this build supports the authenticationMechanisms startup parameter. load("jstests/libs/logv2_helpers.js"); -var conn = MongoRunner.runMongod({ - auth: "", - sslMode: "requireSSL", - sslPEMKeyFile: "jstests/libs/server.pem", - sslCAFile: "jstests/libs/ca.pem" -}); -conn.getDB('admin').createUser({user: "root", pwd: "pass", roles: ["root"]}); -conn.getDB('admin').auth("root", "pass"); -var cmdOut = conn.getDB('admin').runCommand({getParameter: 1, authenticationMechanisms: 1}); -if (cmdOut.ok) { - TestData.authMechanism = "MONGODB-X509,SCRAM-SHA-1"; // SERVER-10353 -} -conn.getDB('admin').dropAllUsers(); -conn.getDB('admin').logout(); -MongoRunner.stopMongod(conn); const SERVER_CERT = "jstests/libs/server.pem"; const CA_CERT = "jstests/libs/ca.pem"; @@ -24,22 +9,10 @@ const INTERNAL_USER = "C=US,ST=New York,L=New York City,O=MongoDB,OU=Kernel,CN=i const CLIENT_USER = "CN=client,OU=KernelUser,O=MongoDB,L=New York City,ST=New York,C=US"; const INVALID_CLIENT_USER = "C=US,ST=New York,L=New York City,O=MongoDB,OU=KernelUser,CN=invalid"; -function authAndTest(mongo) { +function authAndTest(mongo, {clusterUserSeparationOveride = false} = {}) { external = mongo.getDB("$external"); test = mongo.getDB("test"); - // It should be impossible to create users with the same name as the server's subject - assert.throws(function() { - external.createUser( - {user: SERVER_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]}); - }, [], "Created user with same name as the server's x.509 subject"); - - // It should be impossible to create users with names recognized as cluster members - assert.throws(function() { - external.createUser( - {user: INTERNAL_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]}); - }, [], "Created user which would be recognized as a cluster member"); - // Add user using localhost exception external.createUser({ user: CLIENT_USER, @@ -50,12 +23,6 @@ function authAndTest(mongo) { ] }); - // It should be impossible to create users with an internal name - assert.throws(function() { - external.createUser( - {user: SERVER_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]}); - }); - // Localhost exception should not be in place anymore assert.throws(function() { test.foo.findOne(); @@ -93,6 +60,22 @@ function authAndTest(mongo) { assert(log.some((line) => successRegex.test(line))); } + const overrideDependentTester = + clusterUserSeparationOveride ? assert.doesNotThrow : assert.throws; + // It should be impossible to create users with the same name as the server's subject, + // unless guardrails are explicitly overridden + overrideDependentTester(function() { + external.createUser( + {user: SERVER_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]}); + }, [], "Created user with same name as the server's x.509 subject"); + + // It should be impossible to create users with names recognized as cluster members, + // unless guardrails are explicitly overridden + overrideDependentTester(function() { + external.createUser( + {user: INTERNAL_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]}); + }, [], "Created user which would be recognized as a cluster member"); + // Check that we can add a user and read data test.createUser( {user: "test", pwd: "test", roles: [{'role': 'readWriteAnyDatabase', 'db': 'admin'}]}); @@ -104,27 +87,60 @@ function authAndTest(mongo) { }, [], "read after logout"); } -print("1. Testing x.509 auth to mongod"); -var x509_options = {sslMode: "requireSSL", sslPEMKeyFile: SERVER_CERT, sslCAFile: CA_CERT}; +const x509_options = { + sslMode: "requireSSL", + sslPEMKeyFile: SERVER_CERT, + sslCAFile: CA_CERT +}; + +{ + print("1. Testing x.509 auth to mongod"); + const mongo = MongoRunner.runMongod(Object.merge(x509_options, {auth: ""})); -var mongo = MongoRunner.runMongod(Object.merge(x509_options, {auth: ""})); + authAndTest(mongo); + MongoRunner.stopMongod(mongo); +} +{ + print("1.5. Testing x.509 auth to mongod with cluster/user separation disabled"); + const mongo = MongoRunner.runMongod(Object.merge( + x509_options, {auth: "", setParameter: {enforceUserClusterSeparation: false}})); -authAndTest(mongo); -MongoRunner.stopMongod(mongo); + authAndTest(mongo, {clusterUserSeparationOveride: true}); + MongoRunner.stopMongod(mongo); +} -print("2. Testing x.509 auth to mongos"); +{ + print("2. Testing x.509 auth to mongos"); + var st = new ShardingTest({ + shards: 1, + mongos: 1, + other: { + keyFile: 'jstests/libs/key1', + configOptions: x509_options, + mongosOptions: x509_options, + shardOptions: x509_options, + useHostname: false + } + }); -var st = new ShardingTest({ - shards: 1, - mongos: 1, - other: { - keyFile: 'jstests/libs/key1', - configOptions: x509_options, - mongosOptions: x509_options, - shardOptions: x509_options, - useHostname: false - } -}); + authAndTest(new Mongo("localhost:" + st.s0.port)); + st.stop(); +} +{ + print("2.5 Testing x.509 auth to mongos with cluster/user separation disabled"); + var st = new ShardingTest({ + shards: 1, + mongos: 1, + other: { + keyFile: 'jstests/libs/key1', + configOptions: + Object.merge(x509_options, {setParameter: {enforceUserClusterSeparation: false}}), + mongosOptions: x509_options, + shardOptions: x509_options, + useHostname: false + } + }); -authAndTest(new Mongo("localhost:" + st.s0.port)); -st.stop(); + authAndTest(new Mongo("localhost:" + st.s0.port), {clusterUserSeparationOveride: true}); + st.stop(); +} diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index 5694a2368cb..33c64a07122 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -812,11 +812,20 @@ void CmdUMCTyped<CreateUserCommand, void>::Invocation::typedRun(OperationContext #ifdef MONGO_CONFIG_SSL auto configuration = opCtx->getClient()->session()->getSSLConfiguration(); - uassert(ErrorCodes::BadValue, - "Cannot create an x.509 user with a subjectname that would be " - "recognized as an internal cluster member", - (dbname != "$external") || !configuration || - !configuration->isClusterMember(userName.getUser())); + + if ((dbname == "$external") && configuration && + configuration->isClusterMember(userName.getUser())) { + if (gEnforceUserClusterSeparation) { + uasserted(ErrorCodes::BadValue, + "Cannot create an x.509 user with a subjectname that would be " + "recognized as an internal cluster member"); + } else { + LOGV2(4593800, + "Creating user which would be considered a cluster member if clusterAuthMode " + "enabled X509 authentication", + "user"_attr = userName); + } + } #endif // Synthesize a user document diff --git a/src/mongo/db/commands/user_management_commands.idl b/src/mongo/db/commands/user_management_commands.idl index 53437d600c0..ca1c510a872 100644 --- a/src/mongo/db/commands/user_management_commands.idl +++ b/src/mongo/db/commands/user_management_commands.idl @@ -33,6 +33,14 @@ imports: - "mongo/db/auth/auth_types.idl" - "mongo/db/auth/address_restriction.idl" +server_parameters: + enforceUserClusterSeparation: + description: "Prevents creation of users whose names would be interpreted as cluster members" + set_at: startup + cpp_varname: "gEnforceUserClusterSeparation" + cpp_vartype: bool + default: true + structs: dropAllUsersFromDatabaseReply: description: "Response for dropAllUsersFromDatabase command" |