mirror of https://github.com/mongodb/mongo
221 lines
7.5 KiB
JavaScript
221 lines
7.5 KiB
JavaScript
// Test restricting role authorization via X509 extensions.
|
|
import {requireSSLProvider} from "jstests/ssl/libs/ssl_helpers.js";
|
|
|
|
requireSSLProvider("openssl", function () {
|
|
const SERVER_CERT = "jstests/libs/server.pem";
|
|
const COMBINED_CA_CERT = "jstests/ssl/x509/root-and-trusted-ca.pem";
|
|
const CA_HASH = cat("jstests/libs/ca.pem.digest.sha256");
|
|
const TRUSTED_CA_HASH = cat("jstests/libs/trusted-ca.pem.digest.sha256");
|
|
|
|
// Common suffix, keep the lines short.
|
|
const RDN_SUFFIX = ",O=MongoDB,L=New York City,ST=New York,C=US";
|
|
const USERS = [];
|
|
|
|
const CLIENT = {
|
|
cert: "jstests/libs/client.pem",
|
|
roles: [],
|
|
};
|
|
USERS.push("CN=client,OU=KernelUser");
|
|
|
|
const CLIENT_ROLES = {
|
|
cert: "jstests/libs/client_roles.pem",
|
|
roles: [
|
|
{role: "backup", db: "admin"},
|
|
{role: "readAnyDatabase", db: "admin"},
|
|
],
|
|
};
|
|
USERS.push("CN=Kernel Client Peer Role,OU=Kernel Users");
|
|
|
|
const TRUSTED_CLIENT_TESTDB_ROLES = {
|
|
cert: "jstests/ssl/x509/trusted-client-testdb-roles.pem",
|
|
roles: [
|
|
{role: "role1", db: "testDB"},
|
|
{role: "role2", db: "testDB"},
|
|
],
|
|
};
|
|
USERS.push("CN=Trusted Kernel Test Client With Roles,OU=Kernel Users");
|
|
|
|
function test(tlsCATrusts, success, failure) {
|
|
const options = {
|
|
auth: "",
|
|
tlsMode: "requireTLS",
|
|
tlsCertificateKeyFile: SERVER_CERT,
|
|
tlsCAFile: COMBINED_CA_CERT,
|
|
};
|
|
|
|
if (tlsCATrusts !== null) {
|
|
options.setParameter = {
|
|
tlsCATrusts: tojson(tlsCATrusts),
|
|
};
|
|
}
|
|
|
|
const mongod = MongoRunner.runMongod(options);
|
|
|
|
const admin = mongod.getDB("admin");
|
|
admin.createUser({user: "admin", pwd: "pwd", roles: ["root"]});
|
|
admin.auth({user: "admin", pwd: "pwd"});
|
|
|
|
const external = mongod.getDB("$external");
|
|
USERS.forEach((u) => external.createUser({user: u + RDN_SUFFIX, roles: []}));
|
|
|
|
const testDB = mongod.getDB("test");
|
|
testDB.createRole({role: "role1", privileges: [], roles: []});
|
|
testDB.createRole({role: "role2", privileges: [], roles: []});
|
|
|
|
// Sorting JS arrays of objects with arbitrary order is... complex.
|
|
const serverTrusts = assert.commandWorked(admin.runCommand({getParameter: 1, tlsCATrusts: 1})).tlsCATrusts;
|
|
function sortAndNormalizeRoles(roles) {
|
|
return roles
|
|
.map((r) => r.role + "." + r.db)
|
|
.sort()
|
|
.join("/");
|
|
}
|
|
function sortAndNormalizeTrusts(trusts) {
|
|
if (trusts === null) {
|
|
return "(unconfigured)";
|
|
}
|
|
return trusts.map((t) => t.sha256 + "/" + sortAndNormalizeRoles(t.roles)).sort();
|
|
}
|
|
assert.eq(sortAndNormalizeTrusts(tlsCATrusts), sortAndNormalizeTrusts(serverTrusts));
|
|
|
|
function impl(user, expect) {
|
|
const snRoles = tojson(sortAndNormalizeRoles(user.roles));
|
|
const uri = "mongodb://localhost:" + mongod.port + "/admin";
|
|
const script =
|
|
tojson(sortAndNormalizeRoles) +
|
|
'assert(db.getSiblingDB("$external").auth({mechanism: "MONGODB-X509"}));' +
|
|
"const status = assert.commandWorked(db.runCommand({connectionStatus: 1}));" +
|
|
"const roles = status.authInfo.authenticatedUserRoles;" +
|
|
"assert.eq(" +
|
|
snRoles +
|
|
", sortAndNormalizeRoles(roles));";
|
|
const mongo = runMongoProgram(
|
|
"mongo",
|
|
"--tls",
|
|
"--tlsCertificateKeyFile",
|
|
user.cert,
|
|
"--tlsCAFile",
|
|
COMBINED_CA_CERT,
|
|
uri,
|
|
"--eval",
|
|
script,
|
|
);
|
|
expect(mongo, 0);
|
|
}
|
|
|
|
success.forEach((u) => impl(u, assert.eq));
|
|
failure.forEach((u) => impl(u, assert.neq));
|
|
|
|
MongoRunner.stopMongod(mongod);
|
|
}
|
|
|
|
// Positive tests.
|
|
const unconfigured = null;
|
|
test(unconfigured, [CLIENT, CLIENT_ROLES, TRUSTED_CLIENT_TESTDB_ROLES], []);
|
|
|
|
const allRoles = [
|
|
{sha256: CA_HASH, roles: [{role: "", db: ""}]},
|
|
{sha256: TRUSTED_CA_HASH, roles: [{role: "", db: ""}]},
|
|
];
|
|
test(allRoles, [CLIENT, CLIENT_ROLES, TRUSTED_CLIENT_TESTDB_ROLES], []);
|
|
|
|
const allRolesOnAdmin = [{sha256: CA_HASH, roles: [{role: "", db: "admin"}]}];
|
|
test(allRolesOnAdmin, [CLIENT, CLIENT_ROLES], [TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const specificRolesOnAnyDB = [
|
|
{
|
|
sha256: CA_HASH,
|
|
roles: [
|
|
{role: "backup", db: ""},
|
|
{role: "readAnyDatabase", db: ""},
|
|
],
|
|
},
|
|
];
|
|
test(specificRolesOnAnyDB, [CLIENT, CLIENT_ROLES], [TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const exactRoles = [
|
|
{
|
|
sha256: CA_HASH,
|
|
roles: [
|
|
{role: "backup", db: "admin"},
|
|
{role: "readAnyDatabase", db: "admin"},
|
|
],
|
|
},
|
|
];
|
|
test(exactRoles, [CLIENT, CLIENT_ROLES], [TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const extraRoles = [
|
|
{
|
|
sha256: CA_HASH,
|
|
roles: [
|
|
{role: "backup", db: "admin"},
|
|
{role: "readAnyDatabase", db: "admin"},
|
|
{role: "readWrite", db: "admin"},
|
|
],
|
|
},
|
|
];
|
|
test(extraRoles, [CLIENT, CLIENT_ROLES], [TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const similarRoles = [
|
|
{
|
|
sha256: CA_HASH,
|
|
roles: [
|
|
{role: "backup", db: "test"},
|
|
{role: "readAnyDatabase", db: ""},
|
|
{role: "backup", db: "admin"},
|
|
],
|
|
},
|
|
{
|
|
sha256: TRUSTED_CA_HASH,
|
|
roles: [
|
|
{role: "role1", db: "admin"},
|
|
{role: "role2", db: "testDB"},
|
|
{role: "role1", db: "testDB"},
|
|
],
|
|
},
|
|
];
|
|
test(similarRoles, [CLIENT, CLIENT_ROLES, TRUSTED_CLIENT_TESTDB_ROLES], []);
|
|
|
|
const withUntrusted = [
|
|
{sha256: CA_HASH, roles: [{role: "", db: ""}]},
|
|
{sha256: TRUSTED_CA_HASH, roles: []},
|
|
];
|
|
test(withUntrusted, [CLIENT, CLIENT_ROLES], [TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const customRoles = [
|
|
{
|
|
sha256: TRUSTED_CA_HASH,
|
|
roles: [
|
|
{role: "role1", db: "testDB"},
|
|
{role: "role2", db: "testDB"},
|
|
],
|
|
},
|
|
];
|
|
test(customRoles, [CLIENT, TRUSTED_CLIENT_TESTDB_ROLES], [CLIENT_ROLES]);
|
|
|
|
// Negative tests. CLIENT_CERT is okay because it doesn't ask for roles.
|
|
const noTrustedCAs = [];
|
|
test(noTrustedCAs, [CLIENT], [CLIENT_ROLES, TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const noRoles = [{sha256: CA_HASH, roles: []}];
|
|
test(noRoles, [CLIENT], [CLIENT_ROLES, TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const insufficientRoles1 = [
|
|
{sha256: CA_HASH, roles: [{role: "backup", db: ""}]},
|
|
{sha256: TRUSTED_CA_HASH, roles: [{role: "role1", db: "testDB"}]},
|
|
];
|
|
test(insufficientRoles1, [CLIENT], [CLIENT_ROLES, TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const insufficientRoles2 = [
|
|
{sha256: CA_HASH, roles: [{role: "readWriteAnyDatabase", db: ""}]},
|
|
{sha256: TRUSTED_CA_HASH, roles: [{role: "role2", db: "testDB"}]},
|
|
];
|
|
test(insufficientRoles2, [CLIENT], [CLIENT_ROLES, TRUSTED_CLIENT_TESTDB_ROLES]);
|
|
|
|
const withTrusted = [
|
|
{sha256: CA_HASH, roles: []},
|
|
{sha256: TRUSTED_CA_HASH, roles: [{role: "", db: ""}]},
|
|
];
|
|
test(withTrusted, [CLIENT, TRUSTED_CLIENT_TESTDB_ROLES], [CLIENT_ROLES]);
|
|
});
|