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
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
3
|
+
const MongoCredentials = require('./mongo_credentials').MongoCredentials;
|
|
4
|
+
const MongoError = require('../error').MongoError;
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const http = require('http');
|
|
7
|
+
const maxWireVersion = require('../utils').maxWireVersion;
|
|
8
|
+
const url = require('url');
|
|
9
|
+
|
|
10
|
+
let aws4;
|
|
11
|
+
try {
|
|
12
|
+
aws4 = require('aws4');
|
|
13
|
+
} catch (e) {
|
|
14
|
+
// don't do anything;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ASCII_N = 110;
|
|
18
|
+
const AWS_RELATIVE_URI = 'http://169.254.170.2';
|
|
19
|
+
const AWS_EC2_URI = 'http://169.254.169.254';
|
|
20
|
+
const AWS_EC2_PATH = '/latest/meta-data/iam/security-credentials';
|
|
21
|
+
|
|
22
|
+
class MongoDBAWS extends AuthProvider {
|
|
23
|
+
auth(authContext, callback) {
|
|
24
|
+
const connection = authContext.connection;
|
|
25
|
+
const credentials = authContext.credentials;
|
|
26
|
+
|
|
27
|
+
if (maxWireVersion(connection) < 9) {
|
|
28
|
+
callback(new MongoError('MONGODB-AWS authentication requires MongoDB version 4.4 or later'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (aws4 == null) {
|
|
33
|
+
callback(
|
|
34
|
+
new MongoError(
|
|
35
|
+
'MONGODB-AWS authentication requires the `aws4` module, please install it as a dependency of your project'
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (credentials.username == null) {
|
|
43
|
+
makeTempCredentials(credentials, (err, tempCredentials) => {
|
|
44
|
+
if (err) return callback(err);
|
|
45
|
+
|
|
46
|
+
authContext.credentials = tempCredentials;
|
|
47
|
+
this.auth(authContext, callback);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const username = credentials.username;
|
|
54
|
+
const password = credentials.password;
|
|
55
|
+
const db = credentials.source;
|
|
56
|
+
const token = credentials.mechanismProperties.AWS_SESSION_TOKEN;
|
|
57
|
+
const bson = this.bson;
|
|
58
|
+
|
|
59
|
+
crypto.randomBytes(32, (err, nonce) => {
|
|
60
|
+
if (err) {
|
|
61
|
+
callback(err);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const saslStart = {
|
|
66
|
+
saslStart: 1,
|
|
67
|
+
mechanism: 'MONGODB-AWS',
|
|
68
|
+
payload: bson.serialize({ r: nonce, p: ASCII_N })
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
connection.command(`${db}.$cmd`, saslStart, (err, result) => {
|
|
72
|
+
if (err) return callback(err);
|
|
73
|
+
|
|
74
|
+
const res = result.result;
|
|
75
|
+
const serverResponse = bson.deserialize(res.payload.buffer);
|
|
76
|
+
const host = serverResponse.h;
|
|
77
|
+
const serverNonce = serverResponse.s.buffer;
|
|
78
|
+
if (serverNonce.length !== 64) {
|
|
79
|
+
callback(
|
|
80
|
+
new MongoError(`Invalid server nonce length ${serverNonce.length}, expected 64`)
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (serverNonce.compare(nonce, 0, nonce.length, 0, nonce.length) !== 0) {
|
|
86
|
+
callback(new MongoError('Server nonce does not begin with client nonce'));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (host.length < 1 || host.length > 255 || host.indexOf('..') !== -1) {
|
|
91
|
+
callback(new MongoError(`Server returned an invalid host: "${host}"`));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const body = 'Action=GetCallerIdentity&Version=2011-06-15';
|
|
96
|
+
const options = aws4.sign(
|
|
97
|
+
{
|
|
98
|
+
method: 'POST',
|
|
99
|
+
host,
|
|
100
|
+
region: deriveRegion(serverResponse.h),
|
|
101
|
+
service: 'sts',
|
|
102
|
+
headers: {
|
|
103
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
104
|
+
'Content-Length': body.length,
|
|
105
|
+
'X-MongoDB-Server-Nonce': serverNonce.toString('base64'),
|
|
106
|
+
'X-MongoDB-GS2-CB-Flag': 'n'
|
|
107
|
+
},
|
|
108
|
+
path: '/',
|
|
109
|
+
body
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
accessKeyId: username,
|
|
113
|
+
secretAccessKey: password,
|
|
114
|
+
token
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const authorization = options.headers.Authorization;
|
|
119
|
+
const date = options.headers['X-Amz-Date'];
|
|
120
|
+
const payload = { a: authorization, d: date };
|
|
121
|
+
if (token) {
|
|
122
|
+
payload.t = token;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const saslContinue = {
|
|
126
|
+
saslContinue: 1,
|
|
127
|
+
conversationId: 1,
|
|
128
|
+
payload: bson.serialize(payload)
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
connection.command(`${db}.$cmd`, saslContinue, err => {
|
|
132
|
+
if (err) return callback(err);
|
|
133
|
+
callback();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function makeTempCredentials(credentials, callback) {
|
|
141
|
+
function done(creds) {
|
|
142
|
+
if (creds.AccessKeyId == null || creds.SecretAccessKey == null || creds.Token == null) {
|
|
143
|
+
callback(new MongoError('Could not obtain temporary MONGODB-AWS credentials'));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
callback(
|
|
148
|
+
undefined,
|
|
149
|
+
new MongoCredentials({
|
|
150
|
+
username: creds.AccessKeyId,
|
|
151
|
+
password: creds.SecretAccessKey,
|
|
152
|
+
source: credentials.source,
|
|
153
|
+
mechanism: 'MONGODB-AWS',
|
|
154
|
+
mechanismProperties: {
|
|
155
|
+
AWS_SESSION_TOKEN: creds.Token
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
|
|
162
|
+
// is set then drivers MUST assume that it was set by an AWS ECS agent
|
|
163
|
+
if (process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) {
|
|
164
|
+
request(
|
|
165
|
+
`${AWS_RELATIVE_URI}${process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}`,
|
|
166
|
+
(err, res) => {
|
|
167
|
+
if (err) return callback(err);
|
|
168
|
+
done(res);
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Otherwise assume we are on an EC2 instance
|
|
176
|
+
|
|
177
|
+
// get a token
|
|
178
|
+
|
|
179
|
+
request(
|
|
180
|
+
`${AWS_EC2_URI}/latest/api/token`,
|
|
181
|
+
{ method: 'PUT', json: false, headers: { 'X-aws-ec2-metadata-token-ttl-seconds': 30 } },
|
|
182
|
+
(err, token) => {
|
|
183
|
+
if (err) return callback(err);
|
|
184
|
+
|
|
185
|
+
// get role name
|
|
186
|
+
request(
|
|
187
|
+
`${AWS_EC2_URI}/${AWS_EC2_PATH}`,
|
|
188
|
+
{ json: false, headers: { 'X-aws-ec2-metadata-token': token } },
|
|
189
|
+
(err, roleName) => {
|
|
190
|
+
if (err) return callback(err);
|
|
191
|
+
|
|
192
|
+
// get temp credentials
|
|
193
|
+
request(
|
|
194
|
+
`${AWS_EC2_URI}/${AWS_EC2_PATH}/${roleName}`,
|
|
195
|
+
{ headers: { 'X-aws-ec2-metadata-token': token } },
|
|
196
|
+
(err, creds) => {
|
|
197
|
+
if (err) return callback(err);
|
|
198
|
+
done(creds);
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function deriveRegion(host) {
|
|
208
|
+
const parts = host.split('.');
|
|
209
|
+
if (parts.length === 1 || parts[1] === 'amazonaws') {
|
|
210
|
+
return 'us-east-1';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return parts[1];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function request(uri, options, callback) {
|
|
217
|
+
if (typeof options === 'function') {
|
|
218
|
+
callback = options;
|
|
219
|
+
options = {};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
options = Object.assign(
|
|
223
|
+
{
|
|
224
|
+
method: 'GET',
|
|
225
|
+
timeout: 10000,
|
|
226
|
+
json: true
|
|
227
|
+
},
|
|
228
|
+
url.parse(uri),
|
|
229
|
+
options
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
const req = http.request(options, res => {
|
|
233
|
+
res.setEncoding('utf8');
|
|
234
|
+
|
|
235
|
+
let data = '';
|
|
236
|
+
res.on('data', d => (data += d));
|
|
237
|
+
res.on('end', () => {
|
|
238
|
+
if (options.json === false) {
|
|
239
|
+
callback(undefined, data);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const parsed = JSON.parse(data);
|
|
245
|
+
callback(undefined, parsed);
|
|
246
|
+
} catch (err) {
|
|
247
|
+
callback(new MongoError(`Invalid JSON response: "${data}"`));
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
req.on('error', err => callback(err));
|
|
253
|
+
req.end();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = MongoDBAWS;
|
package/lib/core/auth/plain.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
2
|
const retrieveBSON = require('../connection/utils').retrieveBSON;
|
|
4
3
|
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
5
4
|
|
|
@@ -7,19 +6,13 @@ const AuthProvider = require('./auth_provider').AuthProvider;
|
|
|
7
6
|
const BSON = retrieveBSON();
|
|
8
7
|
const Binary = BSON.Binary;
|
|
9
8
|
|
|
10
|
-
/**
|
|
11
|
-
* Creates a new Plain authentication mechanism
|
|
12
|
-
*
|
|
13
|
-
* @extends AuthProvider
|
|
14
|
-
*/
|
|
15
9
|
class Plain extends AuthProvider {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
|
10
|
+
auth(authContext, callback) {
|
|
11
|
+
const connection = authContext.connection;
|
|
12
|
+
const credentials = authContext.credentials;
|
|
21
13
|
const username = credentials.username;
|
|
22
14
|
const password = credentials.password;
|
|
15
|
+
|
|
23
16
|
const payload = new Binary(`\x00${username}\x00${password}`);
|
|
24
17
|
const command = {
|
|
25
18
|
saslStart: 1,
|
|
@@ -28,7 +21,7 @@ class Plain extends AuthProvider {
|
|
|
28
21
|
autoAuthorize: 1
|
|
29
22
|
};
|
|
30
23
|
|
|
31
|
-
|
|
24
|
+
connection.command('$external.$cmd', command, callback);
|
|
32
25
|
}
|
|
33
26
|
}
|
|
34
27
|
|