1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// Check if this build supports the authenticationMechanisms startup parameter.
load("jstests/libs/logv2_helpers.js");
const SERVER_CERT = "jstests/libs/server.pem";
const CA_CERT = "jstests/libs/ca.pem";
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) {
external = mongo.getDB("$external");
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;
if (isJsonLog(mongo)) {
function checkAuthSuccess(element, index, array) {
const logJson = JSON.parse(element);
return logJson.id === 20429 && 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));
} else {
const successRegex =
new RegExp(`Successfully authenticated as principal ${CLIENT_USER} on ` +
`\\$external from client (?:\\d{1,3}\\.){3}\\d{1,3}:\\d+`);
assert(log.some((line) => successRegex.test(line)));
}
let createServerUser = function() {
// It should be impossible to create users with the same name as the server's subject,
// unless guardrails are explicitly overridden
external.createUser(
{user: SERVER_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]});
};
assert.throws(
createServerUser, [], "Created user with same name as the server's x.509 subject");
let createInternalUser = function() {
// It should be impossible to create users with names recognized as cluster members,
// unless guardrails are explicitly overridden
external.createUser(
{user: INTERNAL_USER, roles: [{'role': 'userAdminAnyDatabase', 'db': 'admin'}]});
};
assert.throws(
createInternalUser, [], "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 = {
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: ""}));
authAndTest(mongo);
MongoRunner.stopMongod(mongo);
}
{
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
}
});
authAndTest(new Mongo("localhost:" + st.s0.port));
st.stop();
}
|