diff options
author | Jonathan Reams <jbreams@mongodb.com> | 2019-06-07 11:07:10 -0400 |
---|---|---|
committer | Jonathan Reams <jbreams@mongodb.com> | 2019-07-09 15:38:46 -0400 |
commit | c0f9667715e87634ba3d8d956e8bc9ae752518cf (patch) | |
tree | b54ec2359414be798c7f8e71d66eca7bf921a9e2 | |
parent | db2d8257db38d2f285cabb36407031f0f48e319e (diff) | |
download | mongo-c0f9667715e87634ba3d8d956e8bc9ae752518cf.tar.gz |
SERVER-41069 Add option to disable embedded roles from X509 certificates
(cherry picked from commit 85ec26ff72f4029c52c40fab796ad53533828e60)
(cherry picked from commit 20c801587e1dab2d9cb2d468a4b10e3549d91e24)
-rw-r--r-- | jstests/ssl/ssl_x509_roles.js | 130 | ||||
-rw-r--r-- | src/mongo/db/auth/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/commands/authentication_commands.cpp | 6 |
4 files changed, 96 insertions, 49 deletions
diff --git a/jstests/ssl/ssl_x509_roles.js b/jstests/ssl/ssl_x509_roles.js index ac355414787..e9bf6493027 100644 --- a/jstests/ssl/ssl_x509_roles.js +++ b/jstests/ssl/ssl_x509_roles.js @@ -12,12 +12,20 @@ load('jstests/ssl/libs/ssl_helpers.js'); const CLIENT_UTF8_CERT = "jstests/libs/client_utf8.pem"; const CLIENT_EMAIL_CERT = "jstests/libs/client_email.pem"; const CLIENT_TITLE_CERT = "jstests/libs/client_title.pem"; + const CLIENT_CERT_NO_ROLES = "jstests/libs/client.pem"; const CLIENT_USER = "C=US,ST=New York,L=New York City,O=MongoDB,OU=Kernel Users,CN=Kernel Client Peer Role"; - function authAndTest(port) { - const mongo = runMongoProgram("mongo", + const CLIENT_USER_NO_ROLES = + "C=US,ST=New York,L=New York City,O=MongoDB,OU=KernelUser,CN=client"; + const smokeScript = + 'assert(db.getSiblingDB(\'$external\').auth({ mechanism: \'MONGODB-X509\' }));'; + + function authAndTest(port, expectSuccess) { + // First we run the shell with the "smoke" user that has no embedded roles to verify + // that X509 auth works overall. + const smoke = runMongoProgram("mongo", "--host", "localhost", "--port", @@ -26,13 +34,13 @@ load('jstests/ssl/libs/ssl_helpers.js'); "--sslCAFile", CA_CERT, "--sslPEMKeyFile", - CLIENT_CERT, - "jstests/ssl/libs/ssl_x509_role_auth.js"); - - // runMongoProgram returns 0 on success - assert.eq(0, mongo, "Connection attempt failed"); + CLIENT_CERT_NO_ROLES, + "--eval", + smokeScript); + assert.eq(smoke, 0, "Could not auth with smoke user"); - const escaped = runMongoProgram("mongo", + const runTest = function(cert, script) { + const res = runMongoProgram("mongo", "--host", "localhost", "--port", @@ -41,55 +49,63 @@ load('jstests/ssl/libs/ssl_helpers.js'); "--sslCAFile", CA_CERT, "--sslPEMKeyFile", - CLIENT_ESCAPE_CERT, - "jstests/ssl/libs/ssl_x509_role_auth_escape.js"); - - // runMongoProgram returns 0 on success - assert.eq(0, escaped, "Connection attempt failed"); - - const utf8 = runMongoProgram("mongo", - "--host", - "localhost", - "--port", - port, - "--ssl", - "--sslCAFile", - CA_CERT, - "--sslPEMKeyFile", - CLIENT_UTF8_CERT, - "jstests/ssl/libs/ssl_x509_role_auth_utf8.js"); - - // runMongoProgram returns 0 on success - assert.eq(0, utf8, "Connection attempt failed"); - - const email = runMongoProgram("mongo", - "--host", - "localhost", - "--port", - port, - "--ssl", - "--sslCAFile", - CA_CERT, - "--sslPEMKeyFile", - CLIENT_EMAIL_CERT, - "jstests/ssl/libs/ssl_x509_role_auth_email.js"); + cert, + script); + + let expectExitCode = 0; + if (!expectSuccess) { + if (_isWindows()) { + expectExitCode = -3; + } else { + expectExitCode = 253; + } + } + + assert.eq(expectExitCode, res, "Connection attempt failed"); + }; - // runMongoProgram returns 0 on success - assert.eq(0, email, "Connection attempt failed"); + // Then we assert success or failure with each of the X509 certs with embedded roles. + runTest(CLIENT_CERT, "jstests/ssl/libs/ssl_x509_role_auth.js"); + runTest(CLIENT_ESCAPE_CERT, "jstests/ssl/libs/ssl_x509_role_auth_escape.js"); + runTest(CLIENT_UTF8_CERT, "jstests/ssl/libs/ssl_x509_role_auth_utf8.js"); + runTest(CLIENT_EMAIL_CERT, "jstests/ssl/libs/ssl_x509_role_auth_email.js"); } + const prepConn = function(conn) { + const admin = conn.getDB('admin'); + admin.createUser({user: "admin", pwd: "admin", roles: ["root"]}); + assert(admin.auth('admin', 'admin')); + + const external = conn.getDB('$external'); + external.createUser( + {user: CLIENT_USER_NO_ROLES, roles: [{'role': 'readWrite', 'db': 'test'}]}); + }; + const x509_options = {sslMode: "requireSSL", sslPEMKeyFile: SERVER_CERT, sslCAFile: CA_CERT}; print("1. Testing x.509 auth to mongod"); { let mongo = MongoRunner.runMongod(Object.merge(x509_options, {auth: ""})); + prepConn(mongo); + + authAndTest(mongo.port, true); + + MongoRunner.stopMongod(mongo); + } - authAndTest(mongo.port); + jsTestLog("2. Testing disabling x.509 auth with roles"); + { + const mongo = MongoRunner.runMongod(Object.merge( + x509_options, {auth: "", setParameter: "allowRolesFromX509Certificates=false"})); + + prepConn(mongo); + + authAndTest(mongo.port, false); MongoRunner.stopMongod(mongo); } - print("2. Testing x.509 auth to mongos"); + print("3. Testing x.509 auth to mongos"); { // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. let st = new ShardingTest({ @@ -105,7 +121,31 @@ load('jstests/ssl/libs/ssl_helpers.js'); } }); - authAndTest(st.s0.port); + prepConn(st.s0); + authAndTest(st.s0.port, true); + st.stop(); + } + + print("4. Testing x.509 auth to mongos with x509 roles disabled"); + { + const localOptions = + Object.merge(x509_options, {setParameter: "allowRolesFromX509Certificates=false"}); + // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. + let st = new ShardingTest({ + shards: 1, + mongos: 1, + other: { + keyFile: 'jstests/libs/key1', + configOptions: localOptions, + mongosOptions: localOptions, + shardOptions: localOptions, + useHostname: false, + shardAsReplicaSet: false + } + }); + + prepConn(st.s0); + authAndTest(st.s0.port, false); st.stop(); } }()); diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index 35c418f448d..5ed6c6f2e77 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -171,6 +171,7 @@ env.Library( '$BUILD_DIR/mongo/db/global_settings', '$BUILD_DIR/mongo/db/namespace_string', '$BUILD_DIR/mongo/db/pipeline/lite_parsed_document_source', + '$BUILD_DIR/mongo/db/server_parameters', '$BUILD_DIR/mongo/db/update/update_driver', '$BUILD_DIR/mongo/util/icu', '$BUILD_DIR/mongo/util/net/ssl_manager', diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp index 8774bf7293b..b4f2391b0cd 100644 --- a/src/mongo/db/auth/authz_manager_external_state.cpp +++ b/src/mongo/db/auth/authz_manager_external_state.cpp @@ -34,9 +34,13 @@ #include "mongo/db/auth/authz_manager_external_state.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/operation_context.h" +#include "mongo/db/server_parameters.h" #include "mongo/util/net/ssl_types.h" namespace mongo { +namespace { +MONGO_EXPORT_STARTUP_SERVER_PARAMETER(allowRolesFromX509Certificates, bool, true); +} MONGO_DEFINE_SHIM(AuthzManagerExternalState::create); @@ -50,6 +54,10 @@ bool AuthzManagerExternalState::shouldUseRolesFromConnection(OperationContext* o return false; } + if (!allowRolesFromX509Certificates) { + return false; + } + auto& sslPeerInfo = SSLPeerInfo::forSession(opCtx->getClient()->session()); return sslPeerInfo.subjectName.toString() == userName.getUser() && userName.getDB() == "$external" && !sslPeerInfo.roles.empty(); diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp index 8a5c9b1cf9f..fbc7ed593d9 100644 --- a/src/mongo/db/commands/authentication_commands.cpp +++ b/src/mongo/db/commands/authentication_commands.cpp @@ -65,9 +65,7 @@ namespace mongo { namespace { static bool _isX509AuthDisabled; -static const char _nonceAuthenticationDisabledMessage[] = - "Challenge-response authentication using getnonce and authenticate commands is disabled."; -static const char _x509AuthenticationDisabledMessage[] = "x.509 authentication is disabled."; +static constexpr auto kX509AuthenticationDisabledMessage = "x.509 authentication is disabled."_sd; #ifdef MONGO_CONFIG_SSL Status _authenticateX509(OperationContext* opCtx, const UserName& user, const BSONObj& cmdObj) { @@ -110,7 +108,7 @@ Status _authenticateX509(OperationContext* opCtx, const UserName& user, const BS // Handle normal client authentication, only applies to client-server connections else { if (_isX509AuthDisabled) { - return Status(ErrorCodes::BadValue, _x509AuthenticationDisabledMessage); + return Status(ErrorCodes::BadValue, kX509AuthenticationDisabledMessage); } Status status = authorizationSession->addAndAuthorizeUser(opCtx, user); if (!status.isOK()) { |