summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2020-08-11 16:45:06 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-09-02 00:20:03 +0000
commit2973992735143c9f6b6ff2a8bc15e5adf19d9ac6 (patch)
tree898de0308d139b2c65bd82b45a1cf4581ab282f9
parent8cdfbc1bed025b640b98196cc1e2d2494b9dde27 (diff)
downloadmongo-2973992735143c9f6b6ff2a8bc15e5adf19d9ac6.tar.gz
SERVER-45938 Create override for createUser to allow possible cluster members
-rw-r--r--jstests/ssl/x509_client.js122
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp19
-rw-r--r--src/mongo/db/commands/user_management_commands.idl8
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"