summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Reams <jbreams@mongodb.com>2019-06-07 11:07:10 -0400
committerJonathan Reams <jbreams@mongodb.com>2019-07-09 15:38:46 -0400
commitc0f9667715e87634ba3d8d956e8bc9ae752518cf (patch)
treeb54ec2359414be798c7f8e71d66eca7bf921a9e2
parentdb2d8257db38d2f285cabb36407031f0f48e319e (diff)
downloadmongo-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.js130
-rw-r--r--src/mongo/db/auth/SConscript1
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.cpp8
-rw-r--r--src/mongo/db/commands/authentication_commands.cpp6
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()) {