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.
Files changed (68) hide show
  1. package/HISTORY.md +42 -21
  2. package/lib/admin.js +1 -0
  3. package/lib/bulk/common.js +48 -4
  4. package/lib/change_stream.js +0 -1
  5. package/lib/cmap/connection.js +9 -6
  6. package/lib/cmap/connection_pool.js +4 -10
  7. package/lib/collection.js +59 -81
  8. package/lib/core/auth/auth_provider.js +29 -132
  9. package/lib/core/auth/defaultAuthProviders.js +2 -2
  10. package/lib/core/auth/gssapi.js +124 -214
  11. package/lib/core/auth/mongo_credentials.js +29 -3
  12. package/lib/core/auth/mongocr.js +6 -12
  13. package/lib/core/auth/mongodb_aws.js +256 -0
  14. package/lib/core/auth/plain.js +5 -12
  15. package/lib/core/auth/scram.js +229 -212
  16. package/lib/core/auth/x509.js +25 -16
  17. package/lib/core/connection/connect.js +97 -161
  18. package/lib/core/connection/connection.js +71 -3
  19. package/lib/core/connection/pool.js +2 -2
  20. package/lib/core/cursor.js +18 -11
  21. package/lib/core/error.js +82 -8
  22. package/lib/core/sdam/common.js +8 -0
  23. package/lib/core/sdam/monitor.js +240 -78
  24. package/lib/core/sdam/server.js +81 -15
  25. package/lib/core/sdam/server_description.js +37 -2
  26. package/lib/core/sdam/topology.js +41 -8
  27. package/lib/core/sdam/topology_description.js +21 -3
  28. package/lib/core/sessions.js +38 -51
  29. package/lib/core/topologies/mongos.js +18 -6
  30. package/lib/core/topologies/read_preference.js +15 -3
  31. package/lib/core/topologies/replset.js +4 -4
  32. package/lib/core/topologies/server.js +1 -1
  33. package/lib/core/topologies/shared.js +39 -16
  34. package/lib/core/uri_parser.js +41 -6
  35. package/lib/core/utils.js +30 -0
  36. package/lib/core/wireprotocol/command.js +1 -4
  37. package/lib/core/wireprotocol/constants.js +2 -2
  38. package/lib/core/wireprotocol/query.js +4 -0
  39. package/lib/cursor.js +0 -1
  40. package/lib/db.js +6 -5
  41. package/lib/error.js +6 -1
  42. package/lib/gridfs-stream/download.js +13 -2
  43. package/lib/mongo_client.js +6 -4
  44. package/lib/operations/collection_ops.js +0 -20
  45. package/lib/operations/command_v2.js +1 -1
  46. package/lib/operations/common_functions.js +3 -0
  47. package/lib/operations/connect.js +11 -14
  48. package/lib/operations/create_collection.js +37 -52
  49. package/lib/operations/create_indexes.js +111 -35
  50. package/lib/operations/find.js +7 -1
  51. package/lib/operations/find_and_modify.js +17 -0
  52. package/lib/operations/find_one_and_delete.js +5 -0
  53. package/lib/operations/find_one_and_replace.js +13 -0
  54. package/lib/operations/find_one_and_update.js +13 -0
  55. package/lib/operations/map_reduce.js +1 -1
  56. package/lib/operations/re_index.js +22 -17
  57. package/lib/operations/replace_one.js +11 -4
  58. package/lib/operations/update_many.js +5 -0
  59. package/lib/operations/update_one.js +5 -0
  60. package/lib/operations/validate_collection.js +1 -2
  61. package/lib/topologies/mongos.js +1 -1
  62. package/lib/topologies/replset.js +1 -1
  63. package/lib/topologies/server.js +1 -1
  64. package/lib/utils.js +18 -1
  65. package/lib/write_concern.js +10 -0
  66. package/package.json +1 -1
  67. package/lib/core/auth/sspi.js +0 -131
  68. 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;
@@ -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
- * Implementation of authentication for a single connection
18
- * @override
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
- sendAuthCommand(connection, '$external.$cmd', command, callback);
24
+ connection.command('$external.$cmd', command, callback);
32
25
  }
33
26
  }
34
27