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
@@ -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
- * Implementation of authentication for a single connection
15
- * @override
16
- */
17
- _authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
18
- const source = credentials.source;
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 gssapiServiceName =
35
+ const serviceName =
23
36
  mechanismProperties['gssapiservicename'] ||
24
37
  mechanismProperties['gssapiServiceName'] ||
25
38
  'mongodb';
26
-
27
- GSSAPIInitialize(
28
- this,
29
- kerberos.processes.MongoAuthProcess,
30
- source,
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
- super.auth(sendAuthCommand, connections, credentials, callback);
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
- // Initialize step
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: payload,
103
+ payload,
127
104
  autoAuthorize: 1
128
105
  };
129
-
130
- // Write the commmand on the connection
131
- sendAuthCommand(connection, '$external.$cmd', command, (err, doc) => {
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: doc.conversationId,
174
- payload: payload
110
+ conversationId,
111
+ payload
175
112
  };
176
-
177
- // Execute the command
178
- // Write the commmand on the connection
179
- sendAuthCommand(connection, '$external.$cmd', command, (err, doc) => {
180
- if (err) return callback(err, false);
181
- // Call next transition for kerberos
182
- mongo_auth_process.transition(doc.payload, function(err, payload) {
183
- if (err) return callback(err, false);
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
- var MongoDBGSSAPIThirdStep = function(
204
- self,
205
- mongo_auth_process,
206
- payload,
207
- doc,
208
- db,
209
- username,
210
- password,
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
- * This is a result from a authentication strategy
235
- *
236
- * @callback authResultCallback
237
- * @param {error} error An error object. Set to null if no error present
238
- * @param {boolean} result The result of the authentication process
239
- */
240
-
241
- module.exports = GSSAPI;
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.toLowerCase() === 'default') {
76
- this.mechanism = getDefaultAuthMechanism(ismaster);
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
 
@@ -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
- * Implementation of authentication for a single connection
14
- * @override
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
- sendAuthCommand(connection, `${source}.$cmd`, { getnonce: 1 }, (err, r) => {
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
- sendAuthCommand(connection, `${source}.$cmd`, authenticateCommand, callback);
40
+ connection.command(`${source}.$cmd`, authenticateCommand, callback);
47
41
  });
48
42
  }
49
43
  }