mongo/jstests/ssl/x509_client.js

136 lines
4.6 KiB
JavaScript

// Check if this build supports the authenticationMechanisms startup parameter.
import {ShardingTest} from "jstests/libs/shardingtest.js";
const SERVER_CERT = "jstests/libs/server.pem";
const CA_CERT = "jstests/libs/ca.pem";
const INTERNAL_USER = "CN=internal,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US";
const SERVER_USER = "CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US";
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) {
let external = mongo.getDB("$external");
let test = mongo.getDB("test");
// Add user using localhost exception
external.createUser({
user: CLIENT_USER,
roles: [
{"role": "userAdminAnyDatabase", "db": "admin"},
{"role": "readWriteAnyDatabase", "db": "admin"},
{"role": "clusterMonitor", "db": "admin"},
],
});
// Localhost exception should not be in place anymore
assert.throws(
function () {
test.foo.findOne();
},
[],
"read without login",
);
assert(
!external.auth({user: INVALID_CLIENT_USER, mechanism: "MONGODB-X509"}),
"authentication with invalid user should fail",
);
assert(external.auth({user: CLIENT_USER, mechanism: "MONGODB-X509"}), "authentication with valid user failed");
assert(
external.auth({mechanism: "MONGODB-X509"}),
"authentication with valid client cert and no user field failed",
);
const withUserReply = assert.commandWorked(
external.runCommand({authenticate: 1, mechanism: "MONGODB-X509", user: CLIENT_USER}),
"runCommand authentication with valid client cert and user field failed",
);
assert.eq(withUserReply.user, CLIENT_USER);
assert.eq(withUserReply.dbname, "$external");
const noUserReply = assert.commandWorked(
external.runCommand({authenticate: 1, mechanism: "MONGODB-X509"}),
"runCommand authentication with valid client cert and no user field failed",
);
assert.eq(noUserReply.user, CLIENT_USER);
assert.eq(noUserReply.dbname, "$external");
// Check that there's a "Successfully authenticated" message that includes the client IP
const log = assert.commandWorked(external.getSiblingDB("admin").runCommand({getLog: "global"})).log;
function checkAuthSuccess(element /*, index, array*/) {
const logJson = JSON.parse(element);
return (
logJson.id === 5286306 &&
logJson.attr.user === CLIENT_USER &&
logJson.attr.db === "$external" &&
/(?:\d{1,3}\.){3}\d{1,3}:\d+/.test(logJson.attr.client)
);
}
assert(log.some(checkAuthSuccess));
// It should be impossible to create users with the same name as the server's subject,
// unless guardrails are explicitly overridden
assert.commandFailedWithCode(
external.runCommand({createUser: SERVER_USER, roles: [{"role": "userAdminAnyDatabase", "db": "admin"}]}),
ErrorCodes.BadValue,
"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
assert.commandFailedWithCode(
external.runCommand({createUser: INTERNAL_USER, roles: [{"role": "userAdminAnyDatabase", "db": "admin"}]}),
ErrorCodes.BadValue,
"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"}]});
test.foo.findOne();
external.logout();
assert.throws(
function () {
test.foo.findOne();
},
[],
"read after logout",
);
}
const x509_options = {
tlsMode: "requireTLS",
tlsCertificateKeyFile: SERVER_CERT,
tlsCAFile: CA_CERT,
};
{
print("1. Testing x.509 auth to mongod");
const mongo = MongoRunner.runMongod(Object.merge(x509_options, {auth: ""}));
authAndTest(mongo);
MongoRunner.stopMongod(mongo);
}
{
print("2. Testing x.509 auth to mongos");
let st = new ShardingTest({
shards: 1,
mongos: 1,
other: {
keyFile: "jstests/libs/key1",
configOptions: x509_options,
mongosOptions: x509_options,
rsOptions: x509_options,
useHostname: false,
},
});
authAndTest(new Mongo("localhost:" + st.s0.port));
st.stop();
}