mongodb 3.5.11 → 3.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +42 -21
- package/lib/admin.js +1 -0
- package/lib/bulk/common.js +48 -4
- package/lib/change_stream.js +0 -1
- package/lib/cmap/connection.js +9 -6
- package/lib/cmap/connection_pool.js +4 -10
- package/lib/collection.js +59 -81
- package/lib/core/auth/auth_provider.js +29 -132
- package/lib/core/auth/defaultAuthProviders.js +2 -2
- package/lib/core/auth/gssapi.js +124 -214
- package/lib/core/auth/mongo_credentials.js +29 -3
- package/lib/core/auth/mongocr.js +6 -12
- package/lib/core/auth/mongodb_aws.js +256 -0
- package/lib/core/auth/plain.js +5 -12
- package/lib/core/auth/scram.js +229 -212
- package/lib/core/auth/x509.js +25 -16
- package/lib/core/connection/connect.js +97 -161
- package/lib/core/connection/connection.js +71 -3
- package/lib/core/connection/pool.js +2 -2
- package/lib/core/cursor.js +18 -11
- package/lib/core/error.js +82 -8
- package/lib/core/sdam/common.js +8 -0
- package/lib/core/sdam/monitor.js +240 -78
- package/lib/core/sdam/server.js +81 -15
- package/lib/core/sdam/server_description.js +37 -2
- package/lib/core/sdam/topology.js +41 -8
- package/lib/core/sdam/topology_description.js +21 -3
- package/lib/core/sessions.js +38 -51
- package/lib/core/topologies/mongos.js +18 -6
- package/lib/core/topologies/read_preference.js +15 -3
- package/lib/core/topologies/replset.js +4 -4
- package/lib/core/topologies/server.js +1 -1
- package/lib/core/topologies/shared.js +39 -16
- package/lib/core/uri_parser.js +41 -6
- package/lib/core/utils.js +30 -0
- package/lib/core/wireprotocol/command.js +1 -4
- package/lib/core/wireprotocol/constants.js +2 -2
- package/lib/core/wireprotocol/query.js +4 -0
- package/lib/cursor.js +0 -1
- package/lib/db.js +6 -5
- package/lib/error.js +6 -1
- package/lib/gridfs-stream/download.js +13 -2
- package/lib/mongo_client.js +6 -4
- package/lib/operations/collection_ops.js +0 -20
- package/lib/operations/command_v2.js +1 -1
- package/lib/operations/common_functions.js +3 -0
- package/lib/operations/connect.js +11 -14
- package/lib/operations/create_collection.js +37 -52
- package/lib/operations/create_indexes.js +111 -35
- package/lib/operations/find.js +7 -1
- package/lib/operations/find_and_modify.js +17 -0
- package/lib/operations/find_one_and_delete.js +5 -0
- package/lib/operations/find_one_and_replace.js +13 -0
- package/lib/operations/find_one_and_update.js +13 -0
- package/lib/operations/map_reduce.js +1 -1
- package/lib/operations/re_index.js +22 -17
- package/lib/operations/replace_one.js +11 -4
- package/lib/operations/update_many.js +5 -0
- package/lib/operations/update_one.js +5 -0
- package/lib/operations/validate_collection.js +1 -2
- package/lib/topologies/mongos.js +1 -1
- package/lib/topologies/replset.js +1 -1
- package/lib/topologies/server.js +1 -1
- package/lib/utils.js +18 -1
- package/lib/write_concern.js +10 -0
- package/package.json +1 -1
- package/lib/core/auth/sspi.js +0 -131
- package/lib/operations/create_index.js +0 -92
package/lib/core/auth/gssapi.js
CHANGED
|
@@ -1,241 +1,151 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const dns = require('dns');
|
|
2
3
|
|
|
3
4
|
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
4
5
|
const retrieveKerberos = require('../utils').retrieveKerberos;
|
|
6
|
+
const MongoError = require('../error').MongoError;
|
|
7
|
+
|
|
8
|
+
const kGssapiClient = Symbol('GSSAPI_CLIENT');
|
|
5
9
|
let kerberos;
|
|
6
10
|
|
|
7
|
-
/**
|
|
8
|
-
* Creates a new GSSAPI authentication mechanism
|
|
9
|
-
* @class
|
|
10
|
-
* @extends AuthProvider
|
|
11
|
-
*/
|
|
12
11
|
class GSSAPI extends AuthProvider {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
prepare(handshakeDoc, authContext, callback) {
|
|
13
|
+
const host = authContext.options.host;
|
|
14
|
+
const port = authContext.options.port;
|
|
15
|
+
const credentials = authContext.credentials;
|
|
16
|
+
if (!host || !port || !credentials) {
|
|
17
|
+
return callback(
|
|
18
|
+
new MongoError(
|
|
19
|
+
`Connection must specify: ${host ? 'host' : ''}, ${port ? 'port' : ''}, ${
|
|
20
|
+
credentials ? 'host' : 'credentials'
|
|
21
|
+
}.`
|
|
22
|
+
)
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
if (kerberos == null) {
|
|
26
|
+
try {
|
|
27
|
+
kerberos = retrieveKerberos();
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return callback(e);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
19
32
|
const username = credentials.username;
|
|
20
33
|
const password = credentials.password;
|
|
21
34
|
const mechanismProperties = credentials.mechanismProperties;
|
|
22
|
-
const
|
|
35
|
+
const serviceName =
|
|
23
36
|
mechanismProperties['gssapiservicename'] ||
|
|
24
37
|
mechanismProperties['gssapiServiceName'] ||
|
|
25
38
|
'mongodb';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
username,
|
|
32
|
-
password,
|
|
33
|
-
source,
|
|
34
|
-
gssapiServiceName,
|
|
35
|
-
sendAuthCommand,
|
|
36
|
-
connection,
|
|
37
|
-
mechanismProperties,
|
|
38
|
-
callback
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Authenticate
|
|
44
|
-
* @override
|
|
45
|
-
* @method
|
|
46
|
-
*/
|
|
47
|
-
auth(sendAuthCommand, connections, credentials, callback) {
|
|
48
|
-
if (kerberos == null) {
|
|
49
|
-
try {
|
|
50
|
-
kerberos = retrieveKerberos();
|
|
51
|
-
} catch (e) {
|
|
52
|
-
return callback(e, null);
|
|
39
|
+
performGssapiCanonicalizeHostName(host, mechanismProperties, (err, host) => {
|
|
40
|
+
if (err) return callback(err);
|
|
41
|
+
const initOptions = {};
|
|
42
|
+
if (password != null) {
|
|
43
|
+
Object.assign(initOptions, { user: username, password: password });
|
|
53
44
|
}
|
|
45
|
+
kerberos.initializeClient(
|
|
46
|
+
`${serviceName}${process.platform === 'win32' ? '/' : '@'}${host}`,
|
|
47
|
+
initOptions,
|
|
48
|
+
(err, client) => {
|
|
49
|
+
if (err) return callback(new MongoError(err));
|
|
50
|
+
if (client == null) return callback();
|
|
51
|
+
this[kGssapiClient] = client;
|
|
52
|
+
callback(undefined, handshakeDoc);
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
auth(authContext, callback) {
|
|
58
|
+
const connection = authContext.connection;
|
|
59
|
+
const credentials = authContext.credentials;
|
|
60
|
+
if (credentials == null) return callback(new MongoError('credentials required'));
|
|
61
|
+
const username = credentials.username;
|
|
62
|
+
const client = this[kGssapiClient];
|
|
63
|
+
if (client == null) return callback(new MongoError('gssapi client missing'));
|
|
64
|
+
function externalCommand(command, cb) {
|
|
65
|
+
return connection.command('$external.$cmd', command, cb);
|
|
54
66
|
}
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
client.step('', (err, payload) => {
|
|
68
|
+
if (err) return callback(err);
|
|
69
|
+
externalCommand(saslStart(payload), (err, response) => {
|
|
70
|
+
const result = response.result;
|
|
71
|
+
if (err) return callback(err);
|
|
72
|
+
negotiate(client, 10, result.payload, (err, payload) => {
|
|
73
|
+
if (err) return callback(err);
|
|
74
|
+
externalCommand(saslContinue(payload, result.conversationId), (err, response) => {
|
|
75
|
+
const result = response.result;
|
|
76
|
+
if (err) return callback(err);
|
|
77
|
+
finalize(client, username, result.payload, (err, payload) => {
|
|
78
|
+
if (err) return callback(err);
|
|
79
|
+
externalCommand(
|
|
80
|
+
{
|
|
81
|
+
saslContinue: 1,
|
|
82
|
+
conversationId: result.conversationId,
|
|
83
|
+
payload
|
|
84
|
+
},
|
|
85
|
+
(err, result) => {
|
|
86
|
+
if (err) return callback(err);
|
|
87
|
+
callback(undefined, result);
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
57
95
|
}
|
|
58
96
|
}
|
|
97
|
+
module.exports = GSSAPI;
|
|
59
98
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
var GSSAPIInitialize = function(
|
|
63
|
-
self,
|
|
64
|
-
MongoAuthProcess,
|
|
65
|
-
db,
|
|
66
|
-
username,
|
|
67
|
-
password,
|
|
68
|
-
authdb,
|
|
69
|
-
gssapiServiceName,
|
|
70
|
-
sendAuthCommand,
|
|
71
|
-
connection,
|
|
72
|
-
options,
|
|
73
|
-
callback
|
|
74
|
-
) {
|
|
75
|
-
// Create authenticator
|
|
76
|
-
var mongo_auth_process = new MongoAuthProcess(
|
|
77
|
-
connection.host,
|
|
78
|
-
connection.port,
|
|
79
|
-
gssapiServiceName,
|
|
80
|
-
options
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
// Perform initialization
|
|
84
|
-
mongo_auth_process.init(username, password, function(err) {
|
|
85
|
-
if (err) return callback(err, false);
|
|
86
|
-
|
|
87
|
-
// Perform the first step
|
|
88
|
-
mongo_auth_process.transition('', function(err, payload) {
|
|
89
|
-
if (err) return callback(err, false);
|
|
90
|
-
|
|
91
|
-
// Call the next db step
|
|
92
|
-
MongoDBGSSAPIFirstStep(
|
|
93
|
-
self,
|
|
94
|
-
mongo_auth_process,
|
|
95
|
-
payload,
|
|
96
|
-
db,
|
|
97
|
-
username,
|
|
98
|
-
password,
|
|
99
|
-
authdb,
|
|
100
|
-
sendAuthCommand,
|
|
101
|
-
connection,
|
|
102
|
-
callback
|
|
103
|
-
);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
// Perform first step against mongodb
|
|
110
|
-
var MongoDBGSSAPIFirstStep = function(
|
|
111
|
-
self,
|
|
112
|
-
mongo_auth_process,
|
|
113
|
-
payload,
|
|
114
|
-
db,
|
|
115
|
-
username,
|
|
116
|
-
password,
|
|
117
|
-
authdb,
|
|
118
|
-
sendAuthCommand,
|
|
119
|
-
connection,
|
|
120
|
-
callback
|
|
121
|
-
) {
|
|
122
|
-
// Build the sasl start command
|
|
123
|
-
var command = {
|
|
99
|
+
function saslStart(payload) {
|
|
100
|
+
return {
|
|
124
101
|
saslStart: 1,
|
|
125
102
|
mechanism: 'GSSAPI',
|
|
126
|
-
payload
|
|
103
|
+
payload,
|
|
127
104
|
autoAuthorize: 1
|
|
128
105
|
};
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (err) return callback(err, false);
|
|
133
|
-
// Execute mongodb transition
|
|
134
|
-
mongo_auth_process.transition(doc.payload, function(err, payload) {
|
|
135
|
-
if (err) return callback(err, false);
|
|
136
|
-
|
|
137
|
-
// MongoDB API Second Step
|
|
138
|
-
MongoDBGSSAPISecondStep(
|
|
139
|
-
self,
|
|
140
|
-
mongo_auth_process,
|
|
141
|
-
payload,
|
|
142
|
-
doc,
|
|
143
|
-
db,
|
|
144
|
-
username,
|
|
145
|
-
password,
|
|
146
|
-
authdb,
|
|
147
|
-
sendAuthCommand,
|
|
148
|
-
connection,
|
|
149
|
-
callback
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
//
|
|
156
|
-
// Perform first step against mongodb
|
|
157
|
-
var MongoDBGSSAPISecondStep = function(
|
|
158
|
-
self,
|
|
159
|
-
mongo_auth_process,
|
|
160
|
-
payload,
|
|
161
|
-
doc,
|
|
162
|
-
db,
|
|
163
|
-
username,
|
|
164
|
-
password,
|
|
165
|
-
authdb,
|
|
166
|
-
sendAuthCommand,
|
|
167
|
-
connection,
|
|
168
|
-
callback
|
|
169
|
-
) {
|
|
170
|
-
// Build Authentication command to send to MongoDB
|
|
171
|
-
var command = {
|
|
106
|
+
}
|
|
107
|
+
function saslContinue(payload, conversationId) {
|
|
108
|
+
return {
|
|
172
109
|
saslContinue: 1,
|
|
173
|
-
conversationId
|
|
174
|
-
payload
|
|
110
|
+
conversationId,
|
|
111
|
+
payload
|
|
175
112
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (err) return callback(err
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// Call the last and third step
|
|
186
|
-
MongoDBGSSAPIThirdStep(
|
|
187
|
-
self,
|
|
188
|
-
mongo_auth_process,
|
|
189
|
-
payload,
|
|
190
|
-
doc,
|
|
191
|
-
db,
|
|
192
|
-
username,
|
|
193
|
-
password,
|
|
194
|
-
authdb,
|
|
195
|
-
sendAuthCommand,
|
|
196
|
-
connection,
|
|
197
|
-
callback
|
|
198
|
-
);
|
|
199
|
-
});
|
|
113
|
+
}
|
|
114
|
+
function negotiate(client, retries, payload, callback) {
|
|
115
|
+
client.step(payload, (err, response) => {
|
|
116
|
+
// Retries exhausted, raise error
|
|
117
|
+
if (err && retries === 0) return callback(err);
|
|
118
|
+
// Adjust number of retries and call step again
|
|
119
|
+
if (err) return negotiate(client, retries - 1, payload, callback);
|
|
120
|
+
// Return the payload
|
|
121
|
+
callback(undefined, response || '');
|
|
200
122
|
});
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
authdb,
|
|
212
|
-
sendAuthCommand,
|
|
213
|
-
connection,
|
|
214
|
-
callback
|
|
215
|
-
) {
|
|
216
|
-
// Build final command
|
|
217
|
-
var command = {
|
|
218
|
-
saslContinue: 1,
|
|
219
|
-
conversationId: doc.conversationId,
|
|
220
|
-
payload: payload
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
// Execute the command
|
|
224
|
-
sendAuthCommand(connection, '$external.$cmd', command, (err, r) => {
|
|
225
|
-
if (err) return callback(err, false);
|
|
226
|
-
mongo_auth_process.transition(null, function(err) {
|
|
227
|
-
if (err) return callback(err, null);
|
|
228
|
-
callback(null, r);
|
|
123
|
+
}
|
|
124
|
+
function finalize(client, user, payload, callback) {
|
|
125
|
+
// GSS Client Unwrap
|
|
126
|
+
client.unwrap(payload, (err, response) => {
|
|
127
|
+
if (err) return callback(err);
|
|
128
|
+
// Wrap the response
|
|
129
|
+
client.wrap(response || '', { user }, (err, wrapped) => {
|
|
130
|
+
if (err) return callback(err);
|
|
131
|
+
// Return the payload
|
|
132
|
+
callback(undefined, wrapped);
|
|
229
133
|
});
|
|
230
134
|
});
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
135
|
+
}
|
|
136
|
+
function performGssapiCanonicalizeHostName(host, mechanismProperties, callback) {
|
|
137
|
+
const canonicalizeHostName =
|
|
138
|
+
typeof mechanismProperties.gssapiCanonicalizeHostName === 'boolean'
|
|
139
|
+
? mechanismProperties.gssapiCanonicalizeHostName
|
|
140
|
+
: false;
|
|
141
|
+
if (!canonicalizeHostName) return callback(undefined, host);
|
|
142
|
+
// Attempt to resolve the host name
|
|
143
|
+
dns.resolveCname(host, (err, r) => {
|
|
144
|
+
if (err) return callback(err);
|
|
145
|
+
// Get the first resolve host id
|
|
146
|
+
if (Array.isArray(r) && r.length > 0) {
|
|
147
|
+
return callback(undefined, r[0]);
|
|
148
|
+
}
|
|
149
|
+
callback(undefined, host);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
@@ -47,7 +47,24 @@ class MongoCredentials {
|
|
|
47
47
|
this.password = options.password;
|
|
48
48
|
this.source = options.source || options.db;
|
|
49
49
|
this.mechanism = options.mechanism || 'default';
|
|
50
|
-
this.mechanismProperties = options.mechanismProperties;
|
|
50
|
+
this.mechanismProperties = options.mechanismProperties || {};
|
|
51
|
+
|
|
52
|
+
if (this.mechanism.match(/MONGODB-AWS/i)) {
|
|
53
|
+
if (this.username == null && process.env.AWS_ACCESS_KEY_ID) {
|
|
54
|
+
this.username = process.env.AWS_ACCESS_KEY_ID;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (this.password == null && process.env.AWS_SECRET_ACCESS_KEY) {
|
|
58
|
+
this.password = process.env.AWS_SECRET_ACCESS_KEY;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (this.mechanismProperties.AWS_SESSION_TOKEN == null && process.env.AWS_SESSION_TOKEN) {
|
|
62
|
+
this.mechanismProperties.AWS_SESSION_TOKEN = process.env.AWS_SESSION_TOKEN;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
Object.freeze(this.mechanismProperties);
|
|
67
|
+
Object.freeze(this);
|
|
51
68
|
}
|
|
52
69
|
|
|
53
70
|
/**
|
|
@@ -69,12 +86,21 @@ class MongoCredentials {
|
|
|
69
86
|
* based on the server version and server supported sasl mechanisms.
|
|
70
87
|
*
|
|
71
88
|
* @param {Object} [ismaster] An ismaster response from the server
|
|
89
|
+
* @returns {MongoCredentials}
|
|
72
90
|
*/
|
|
73
91
|
resolveAuthMechanism(ismaster) {
|
|
74
92
|
// If the mechanism is not "default", then it does not need to be resolved
|
|
75
|
-
if (this.mechanism.
|
|
76
|
-
|
|
93
|
+
if (this.mechanism.match(/DEFAULT/i)) {
|
|
94
|
+
return new MongoCredentials({
|
|
95
|
+
username: this.username,
|
|
96
|
+
password: this.password,
|
|
97
|
+
source: this.source,
|
|
98
|
+
mechanism: getDefaultAuthMechanism(ismaster),
|
|
99
|
+
mechanismProperties: this.mechanismProperties
|
|
100
|
+
});
|
|
77
101
|
}
|
|
102
|
+
|
|
103
|
+
return this;
|
|
78
104
|
}
|
|
79
105
|
}
|
|
80
106
|
|
package/lib/core/auth/mongocr.js
CHANGED
|
@@ -3,27 +3,21 @@
|
|
|
3
3
|
const crypto = require('crypto');
|
|
4
4
|
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Creates a new MongoCR authentication mechanism
|
|
8
|
-
*
|
|
9
|
-
* @extends AuthProvider
|
|
10
|
-
*/
|
|
11
6
|
class MongoCR extends AuthProvider {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*/
|
|
16
|
-
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
|
7
|
+
auth(authContext, callback) {
|
|
8
|
+
const connection = authContext.connection;
|
|
9
|
+
const credentials = authContext.credentials;
|
|
17
10
|
const username = credentials.username;
|
|
18
11
|
const password = credentials.password;
|
|
19
12
|
const source = credentials.source;
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
connection.command(`${source}.$cmd`, { getnonce: 1 }, (err, result) => {
|
|
22
15
|
let nonce = null;
|
|
23
16
|
let key = null;
|
|
24
17
|
|
|
25
18
|
// Get nonce
|
|
26
19
|
if (err == null) {
|
|
20
|
+
const r = result.result;
|
|
27
21
|
nonce = r.nonce;
|
|
28
22
|
// Use node md5 generator
|
|
29
23
|
let md5 = crypto.createHash('md5');
|
|
@@ -43,7 +37,7 @@ class MongoCR extends AuthProvider {
|
|
|
43
37
|
key
|
|
44
38
|
};
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
connection.command(`${source}.$cmd`, authenticateCommand, callback);
|
|
47
41
|
});
|
|
48
42
|
}
|
|
49
43
|
}
|