mongodb 3.2.5 → 3.3.0-beta2
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 +0 -10
- package/index.js +4 -4
- package/lib/admin.js +56 -56
- package/lib/aggregation_cursor.js +7 -3
- package/lib/bulk/common.js +18 -13
- package/lib/change_stream.js +196 -89
- package/lib/collection.js +217 -169
- package/lib/command_cursor.js +17 -7
- package/lib/core/auth/auth_provider.js +158 -0
- package/lib/core/auth/defaultAuthProviders.js +29 -0
- package/lib/core/auth/gssapi.js +241 -0
- package/lib/core/auth/mongo_credentials.js +81 -0
- package/lib/core/auth/mongocr.js +51 -0
- package/lib/core/auth/plain.js +35 -0
- package/lib/core/auth/scram.js +293 -0
- package/lib/core/auth/sspi.js +131 -0
- package/lib/core/auth/x509.js +26 -0
- package/lib/core/connection/apm.js +236 -0
- package/lib/core/connection/command_result.js +36 -0
- package/lib/core/connection/commands.js +507 -0
- package/lib/core/connection/connect.js +370 -0
- package/lib/core/connection/connection.js +624 -0
- package/lib/core/connection/logger.js +246 -0
- package/lib/core/connection/msg.js +219 -0
- package/lib/core/connection/pool.js +1285 -0
- package/lib/core/connection/utils.js +57 -0
- package/lib/core/cursor.js +752 -0
- package/lib/core/error.js +186 -0
- package/lib/core/index.js +50 -0
- package/lib/core/sdam/monitoring.js +228 -0
- package/lib/core/sdam/server.js +467 -0
- package/lib/core/sdam/server_description.js +163 -0
- package/lib/core/sdam/server_selectors.js +244 -0
- package/lib/core/sdam/srv_polling.js +135 -0
- package/lib/core/sdam/topology.js +1151 -0
- package/lib/core/sdam/topology_description.js +408 -0
- package/lib/core/sessions.js +711 -0
- package/lib/core/tools/smoke_plugin.js +61 -0
- package/lib/core/topologies/mongos.js +1337 -0
- package/lib/core/topologies/read_preference.js +202 -0
- package/lib/core/topologies/replset.js +1507 -0
- package/lib/core/topologies/replset_state.js +1121 -0
- package/lib/core/topologies/server.js +984 -0
- package/lib/core/topologies/shared.js +453 -0
- package/lib/core/transactions.js +167 -0
- package/lib/core/uri_parser.js +631 -0
- package/lib/core/utils.js +165 -0
- package/lib/core/wireprotocol/command.js +170 -0
- package/lib/core/wireprotocol/compression.js +73 -0
- package/lib/core/wireprotocol/constants.js +13 -0
- package/lib/core/wireprotocol/get_more.js +86 -0
- package/lib/core/wireprotocol/index.js +18 -0
- package/lib/core/wireprotocol/kill_cursors.js +70 -0
- package/lib/core/wireprotocol/query.js +224 -0
- package/lib/core/wireprotocol/shared.js +115 -0
- package/lib/core/wireprotocol/write_command.js +50 -0
- package/lib/cursor.js +40 -46
- package/lib/db.js +141 -95
- package/lib/dynamic_loaders.js +32 -0
- package/lib/error.js +12 -10
- package/lib/gridfs/chunk.js +2 -2
- package/lib/gridfs/grid_store.js +31 -25
- package/lib/gridfs-stream/index.js +4 -4
- package/lib/gridfs-stream/upload.js +1 -1
- package/lib/mongo_client.js +37 -15
- package/lib/operations/add_user.js +96 -0
- package/lib/operations/aggregate.js +24 -13
- package/lib/operations/aggregate_operation.js +127 -0
- package/lib/operations/bulk_write.js +104 -0
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +28 -287
- package/lib/operations/collections.js +55 -0
- package/lib/operations/command.js +120 -0
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/common_functions.js +372 -0
- package/lib/operations/{mongo_client_ops.js → connect.js} +185 -157
- package/lib/operations/count.js +72 -0
- package/lib/operations/count_documents.js +46 -0
- package/lib/operations/create_collection.js +118 -0
- package/lib/operations/create_index.js +92 -0
- package/lib/operations/create_indexes.js +61 -0
- package/lib/operations/cursor_ops.js +3 -4
- package/lib/operations/db_ops.js +15 -12
- package/lib/operations/delete_many.js +25 -0
- package/lib/operations/delete_one.js +25 -0
- package/lib/operations/distinct.js +85 -0
- package/lib/operations/drop.js +53 -0
- package/lib/operations/drop_index.js +42 -0
- package/lib/operations/drop_indexes.js +23 -0
- package/lib/operations/estimated_document_count.js +33 -0
- package/lib/operations/execute_db_admin_command.js +34 -0
- package/lib/operations/execute_operation.js +165 -0
- package/lib/operations/explain.js +23 -0
- package/lib/operations/find_and_modify.js +98 -0
- package/lib/operations/find_one.js +33 -0
- package/lib/operations/find_one_and_delete.js +16 -0
- package/lib/operations/find_one_and_replace.js +18 -0
- package/lib/operations/find_one_and_update.js +19 -0
- package/lib/operations/geo_haystack_search.js +79 -0
- package/lib/operations/has_next.js +40 -0
- package/lib/operations/index_exists.js +39 -0
- package/lib/operations/index_information.js +23 -0
- package/lib/operations/indexes.js +22 -0
- package/lib/operations/insert_many.js +63 -0
- package/lib/operations/insert_one.js +75 -0
- package/lib/operations/is_capped.js +19 -0
- package/lib/operations/list_indexes.js +66 -0
- package/lib/operations/map_reduce.js +189 -0
- package/lib/operations/next.js +32 -0
- package/lib/operations/operation.js +63 -0
- package/lib/operations/options_operation.js +32 -0
- package/lib/operations/profiling_level.js +31 -0
- package/lib/operations/re_index.js +28 -0
- package/lib/operations/remove_user.js +52 -0
- package/lib/operations/rename.js +61 -0
- package/lib/operations/replace_one.js +47 -0
- package/lib/operations/set_profiling_level.js +48 -0
- package/lib/operations/stats.js +45 -0
- package/lib/operations/to_array.js +68 -0
- package/lib/operations/update_many.js +29 -0
- package/lib/operations/update_one.js +44 -0
- package/lib/operations/validate_collection.js +40 -0
- package/lib/read_concern.js +55 -0
- package/lib/topologies/mongos.js +3 -3
- package/lib/topologies/native_topology.js +22 -2
- package/lib/topologies/replset.js +3 -3
- package/lib/topologies/server.js +4 -4
- package/lib/topologies/topology_base.js +6 -6
- package/lib/url_parser.js +4 -3
- package/lib/utils.js +46 -59
- package/lib/write_concern.js +66 -0
- package/package.json +15 -6
- package/lib/.DS_Store +0 -0
package/lib/command_cursor.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const inherits = require('util').inherits;
|
|
4
|
-
const ReadPreference = require('
|
|
5
|
-
const MongoError = require('
|
|
4
|
+
const ReadPreference = require('./core').ReadPreference;
|
|
5
|
+
const MongoError = require('./core').MongoError;
|
|
6
6
|
const Readable = require('stream').Readable;
|
|
7
7
|
const CoreCursor = require('./cursor');
|
|
8
8
|
const SUPPORTS = require('./utils').SUPPORTS;
|
|
9
|
+
const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @fileOverview The **CommandCursor** class is an internal class that embodies a
|
|
@@ -54,10 +55,12 @@ const SUPPORTS = require('./utils').SUPPORTS;
|
|
|
54
55
|
* @fires CommandCursor#readable
|
|
55
56
|
* @return {CommandCursor} an CommandCursor instance.
|
|
56
57
|
*/
|
|
57
|
-
var CommandCursor = function(
|
|
58
|
+
var CommandCursor = function(topology, ns, cmd, options) {
|
|
58
59
|
CoreCursor.apply(this, Array.prototype.slice.call(arguments, 0));
|
|
59
60
|
var state = CommandCursor.INIT;
|
|
60
61
|
var streamOptions = {};
|
|
62
|
+
const bson = topology.s.bson;
|
|
63
|
+
const topologyOptions = topology.s.options;
|
|
61
64
|
|
|
62
65
|
// MaxTimeMS
|
|
63
66
|
var maxTimeMS = null;
|
|
@@ -79,7 +82,7 @@ var CommandCursor = function(bson, ns, cmd, options, topology, topologyOptions)
|
|
|
79
82
|
// BSON
|
|
80
83
|
bson: bson,
|
|
81
84
|
// Namespace
|
|
82
|
-
|
|
85
|
+
namespace: MongoDBNamespace.fromString(ns),
|
|
83
86
|
// Command
|
|
84
87
|
cmd: cmd,
|
|
85
88
|
// Options
|
|
@@ -95,6 +98,13 @@ var CommandCursor = function(bson, ns, cmd, options, topology, topologyOptions)
|
|
|
95
98
|
};
|
|
96
99
|
};
|
|
97
100
|
|
|
101
|
+
Object.defineProperty(CommandCursor.prototype, 'namespace', {
|
|
102
|
+
enumerable: true,
|
|
103
|
+
get: function() {
|
|
104
|
+
return this.s.namespace.toString();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
98
108
|
/**
|
|
99
109
|
* CommandCursor stream data event, fired for each document in the cursor.
|
|
100
110
|
*
|
|
@@ -142,14 +152,14 @@ var methodsToInherit = [
|
|
|
142
152
|
'kill',
|
|
143
153
|
'setCursorBatchSize',
|
|
144
154
|
'_find',
|
|
145
|
-
'
|
|
155
|
+
'_initializeCursor',
|
|
156
|
+
'_getMore',
|
|
146
157
|
'_killcursor',
|
|
147
158
|
'isDead',
|
|
148
159
|
'explain',
|
|
149
160
|
'isNotified',
|
|
150
161
|
'isKilled',
|
|
151
|
-
'_endSession'
|
|
152
|
-
'_initImplicitSession'
|
|
162
|
+
'_endSession'
|
|
153
163
|
];
|
|
154
164
|
|
|
155
165
|
// Only inherit the types we need
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MongoError = require('../error').MongoError;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new AuthProvider, which dictates how to authenticate for a given
|
|
7
|
+
* mechanism.
|
|
8
|
+
* @class
|
|
9
|
+
*/
|
|
10
|
+
class AuthProvider {
|
|
11
|
+
constructor(bson) {
|
|
12
|
+
this.bson = bson;
|
|
13
|
+
this.authStore = [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Authenticate
|
|
18
|
+
* @method
|
|
19
|
+
* @param {SendAuthCommand} sendAuthCommand Writes an auth command directly to a specific connection
|
|
20
|
+
* @param {Connection[]} connections Connections to authenticate using this authenticator
|
|
21
|
+
* @param {MongoCredentials} credentials Authentication credentials
|
|
22
|
+
* @param {authResultCallback} callback The callback to return the result from the authentication
|
|
23
|
+
*/
|
|
24
|
+
auth(sendAuthCommand, connections, credentials, callback) {
|
|
25
|
+
// Total connections
|
|
26
|
+
let count = connections.length;
|
|
27
|
+
|
|
28
|
+
if (count === 0) {
|
|
29
|
+
callback(null, null);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Valid connections
|
|
34
|
+
let numberOfValidConnections = 0;
|
|
35
|
+
let errorObject = null;
|
|
36
|
+
|
|
37
|
+
const execute = connection => {
|
|
38
|
+
this._authenticateSingleConnection(sendAuthCommand, connection, credentials, (err, r) => {
|
|
39
|
+
// Adjust count
|
|
40
|
+
count = count - 1;
|
|
41
|
+
|
|
42
|
+
// If we have an error
|
|
43
|
+
if (err) {
|
|
44
|
+
errorObject = new MongoError(err);
|
|
45
|
+
} else if (r && (r.$err || r.errmsg)) {
|
|
46
|
+
errorObject = new MongoError(r);
|
|
47
|
+
} else {
|
|
48
|
+
numberOfValidConnections = numberOfValidConnections + 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Still authenticating against other connections.
|
|
52
|
+
if (count !== 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// We have authenticated all connections
|
|
57
|
+
if (numberOfValidConnections > 0) {
|
|
58
|
+
// Store the auth details
|
|
59
|
+
this.addCredentials(credentials);
|
|
60
|
+
// Return correct authentication
|
|
61
|
+
callback(null, true);
|
|
62
|
+
} else {
|
|
63
|
+
if (errorObject == null) {
|
|
64
|
+
errorObject = new MongoError(`failed to authenticate using ${credentials.mechanism}`);
|
|
65
|
+
}
|
|
66
|
+
callback(errorObject, false);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const executeInNextTick = _connection => process.nextTick(() => execute(_connection));
|
|
72
|
+
|
|
73
|
+
// For each connection we need to authenticate
|
|
74
|
+
while (connections.length > 0) {
|
|
75
|
+
executeInNextTick(connections.shift());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Implementation of a single connection authenticating. Is meant to be overridden.
|
|
81
|
+
* Will error if called directly
|
|
82
|
+
* @ignore
|
|
83
|
+
*/
|
|
84
|
+
_authenticateSingleConnection(/*sendAuthCommand, connection, credentials, callback*/) {
|
|
85
|
+
throw new Error('_authenticateSingleConnection must be overridden');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Adds credentials to store only if it does not exist
|
|
90
|
+
* @param {MongoCredentials} credentials credentials to add to store
|
|
91
|
+
*/
|
|
92
|
+
addCredentials(credentials) {
|
|
93
|
+
const found = this.authStore.some(cred => cred.equals(credentials));
|
|
94
|
+
|
|
95
|
+
if (!found) {
|
|
96
|
+
this.authStore.push(credentials);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Re authenticate pool
|
|
102
|
+
* @method
|
|
103
|
+
* @param {SendAuthCommand} sendAuthCommand Writes an auth command directly to a specific connection
|
|
104
|
+
* @param {Connection[]} connections Connections to authenticate using this authenticator
|
|
105
|
+
* @param {authResultCallback} callback The callback to return the result from the authentication
|
|
106
|
+
*/
|
|
107
|
+
reauthenticate(sendAuthCommand, connections, callback) {
|
|
108
|
+
const authStore = this.authStore.slice(0);
|
|
109
|
+
let count = authStore.length;
|
|
110
|
+
if (count === 0) {
|
|
111
|
+
return callback(null, null);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < authStore.length; i++) {
|
|
115
|
+
this.auth(sendAuthCommand, connections, authStore[i], function(err) {
|
|
116
|
+
count = count - 1;
|
|
117
|
+
if (count === 0) {
|
|
118
|
+
callback(err, null);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Remove credentials that have been previously stored in the auth provider
|
|
126
|
+
* @method
|
|
127
|
+
* @param {string} source Name of database we are removing authStore details about
|
|
128
|
+
* @return {object}
|
|
129
|
+
*/
|
|
130
|
+
logout(source) {
|
|
131
|
+
this.authStore = this.authStore.filter(credentials => credentials.source !== source);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* A function that writes authentication commands to a specific connection
|
|
137
|
+
* @callback SendAuthCommand
|
|
138
|
+
* @param {Connection} connection The connection to write to
|
|
139
|
+
* @param {Command} command A command with a toBin method that can be written to a connection
|
|
140
|
+
* @param {AuthWriteCallback} callback Callback called when command response is received
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* A callback for a specific auth command
|
|
145
|
+
* @callback AuthWriteCallback
|
|
146
|
+
* @param {Error} err If command failed, an error from the server
|
|
147
|
+
* @param {object} r The response from the server
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* This is a result from an authentication strategy
|
|
152
|
+
*
|
|
153
|
+
* @callback authResultCallback
|
|
154
|
+
* @param {error} error An error object. Set to null if no error present
|
|
155
|
+
* @param {boolean} result The result of the authentication process
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
module.exports = { AuthProvider };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MongoCR = require('./mongocr');
|
|
4
|
+
const X509 = require('./x509');
|
|
5
|
+
const Plain = require('./plain');
|
|
6
|
+
const GSSAPI = require('./gssapi');
|
|
7
|
+
const SSPI = require('./sspi');
|
|
8
|
+
const ScramSHA1 = require('./scram').ScramSHA1;
|
|
9
|
+
const ScramSHA256 = require('./scram').ScramSHA256;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns the default authentication providers.
|
|
13
|
+
*
|
|
14
|
+
* @param {BSON} bson Bson definition
|
|
15
|
+
* @returns {Object} a mapping of auth names to auth types
|
|
16
|
+
*/
|
|
17
|
+
function defaultAuthProviders(bson) {
|
|
18
|
+
return {
|
|
19
|
+
mongocr: new MongoCR(bson),
|
|
20
|
+
x509: new X509(bson),
|
|
21
|
+
plain: new Plain(bson),
|
|
22
|
+
gssapi: new GSSAPI(bson),
|
|
23
|
+
sspi: new SSPI(bson),
|
|
24
|
+
'scram-sha-1': new ScramSHA1(bson),
|
|
25
|
+
'scram-sha-256': new ScramSHA256(bson)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { defaultAuthProviders };
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
4
|
+
const retrieveKerberos = require('../utils').retrieveKerberos;
|
|
5
|
+
let kerberos;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new GSSAPI authentication mechanism
|
|
9
|
+
* @class
|
|
10
|
+
* @extends AuthProvider
|
|
11
|
+
*/
|
|
12
|
+
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;
|
|
19
|
+
const username = credentials.username;
|
|
20
|
+
const password = credentials.password;
|
|
21
|
+
const mechanismProperties = credentials.mechanismProperties;
|
|
22
|
+
const gssapiServiceName =
|
|
23
|
+
mechanismProperties['gssapiservicename'] ||
|
|
24
|
+
mechanismProperties['gssapiServiceName'] ||
|
|
25
|
+
'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);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
super.auth(sendAuthCommand, connections, credentials, callback);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
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 = {
|
|
124
|
+
saslStart: 1,
|
|
125
|
+
mechanism: 'GSSAPI',
|
|
126
|
+
payload: payload,
|
|
127
|
+
autoAuthorize: 1
|
|
128
|
+
};
|
|
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 = {
|
|
172
|
+
saslContinue: 1,
|
|
173
|
+
conversationId: doc.conversationId,
|
|
174
|
+
payload: payload
|
|
175
|
+
};
|
|
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
|
+
});
|
|
200
|
+
});
|
|
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);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
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;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Resolves the default auth mechanism according to
|
|
4
|
+
// https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
|
|
5
|
+
function getDefaultAuthMechanism(ismaster) {
|
|
6
|
+
if (ismaster) {
|
|
7
|
+
// If ismaster contains saslSupportedMechs, use scram-sha-256
|
|
8
|
+
// if it is available, else scram-sha-1
|
|
9
|
+
if (Array.isArray(ismaster.saslSupportedMechs)) {
|
|
10
|
+
return ismaster.saslSupportedMechs.indexOf('SCRAM-SHA-256') >= 0
|
|
11
|
+
? 'scram-sha-256'
|
|
12
|
+
: 'scram-sha-1';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Fallback to legacy selection method. If wire version >= 3, use scram-sha-1
|
|
16
|
+
if (ismaster.maxWireVersion >= 3) {
|
|
17
|
+
return 'scram-sha-1';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Default for wireprotocol < 3
|
|
22
|
+
return 'mongocr';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A representation of the credentials used by MongoDB
|
|
27
|
+
* @class
|
|
28
|
+
* @property {string} mechanism The method used to authenticate
|
|
29
|
+
* @property {string} [username] The username used for authentication
|
|
30
|
+
* @property {string} [password] The password used for authentication
|
|
31
|
+
* @property {string} [source] The database that the user should authenticate against
|
|
32
|
+
* @property {object} [mechanismProperties] Special properties used by some types of auth mechanisms
|
|
33
|
+
*/
|
|
34
|
+
class MongoCredentials {
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new MongoCredentials object
|
|
37
|
+
* @param {object} [options]
|
|
38
|
+
* @param {string} [options.username] The username used for authentication
|
|
39
|
+
* @param {string} [options.password] The password used for authentication
|
|
40
|
+
* @param {string} [options.source] The database that the user should authenticate against
|
|
41
|
+
* @param {string} [options.mechanism] The method used to authenticate
|
|
42
|
+
* @param {object} [options.mechanismProperties] Special properties used by some types of auth mechanisms
|
|
43
|
+
*/
|
|
44
|
+
constructor(options) {
|
|
45
|
+
options = options || {};
|
|
46
|
+
this.username = options.username;
|
|
47
|
+
this.password = options.password;
|
|
48
|
+
this.source = options.source || options.db;
|
|
49
|
+
this.mechanism = options.mechanism || 'default';
|
|
50
|
+
this.mechanismProperties = options.mechanismProperties;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Determines if two MongoCredentials objects are equivalent
|
|
55
|
+
* @param {MongoCredentials} other another MongoCredentials object
|
|
56
|
+
* @returns {boolean} true if the two objects are equal.
|
|
57
|
+
*/
|
|
58
|
+
equals(other) {
|
|
59
|
+
return (
|
|
60
|
+
this.mechanism === other.mechanism &&
|
|
61
|
+
this.username === other.username &&
|
|
62
|
+
this.password === other.password &&
|
|
63
|
+
this.source === other.source
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* If the authentication mechanism is set to "default", resolves the authMechanism
|
|
69
|
+
* based on the server version and server supported sasl mechanisms.
|
|
70
|
+
*
|
|
71
|
+
* @param {Object} [ismaster] An ismaster response from the server
|
|
72
|
+
*/
|
|
73
|
+
resolveAuthMechanism(ismaster) {
|
|
74
|
+
// 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);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { MongoCredentials };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new MongoCR authentication mechanism
|
|
8
|
+
*
|
|
9
|
+
* @extends AuthProvider
|
|
10
|
+
*/
|
|
11
|
+
class MongoCR extends AuthProvider {
|
|
12
|
+
/**
|
|
13
|
+
* Implementation of authentication for a single connection
|
|
14
|
+
* @override
|
|
15
|
+
*/
|
|
16
|
+
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
|
17
|
+
const username = credentials.username;
|
|
18
|
+
const password = credentials.password;
|
|
19
|
+
const source = credentials.source;
|
|
20
|
+
|
|
21
|
+
sendAuthCommand(connection, `${source}.$cmd`, { getnonce: 1 }, (err, r) => {
|
|
22
|
+
let nonce = null;
|
|
23
|
+
let key = null;
|
|
24
|
+
|
|
25
|
+
// Get nonce
|
|
26
|
+
if (err == null) {
|
|
27
|
+
nonce = r.nonce;
|
|
28
|
+
// Use node md5 generator
|
|
29
|
+
let md5 = crypto.createHash('md5');
|
|
30
|
+
// Generate keys used for authentication
|
|
31
|
+
md5.update(username + ':mongo:' + password, 'utf8');
|
|
32
|
+
const hash_password = md5.digest('hex');
|
|
33
|
+
// Final key
|
|
34
|
+
md5 = crypto.createHash('md5');
|
|
35
|
+
md5.update(nonce + username + hash_password, 'utf8');
|
|
36
|
+
key = md5.digest('hex');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const authenticateCommand = {
|
|
40
|
+
authenticate: 1,
|
|
41
|
+
user: username,
|
|
42
|
+
nonce,
|
|
43
|
+
key
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
sendAuthCommand(connection, `${source}.$cmd`, authenticateCommand, callback);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = MongoCR;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const retrieveBSON = require('../connection/utils').retrieveBSON;
|
|
4
|
+
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
5
|
+
|
|
6
|
+
// TODO: can we get the Binary type from this.bson instead?
|
|
7
|
+
const BSON = retrieveBSON();
|
|
8
|
+
const Binary = BSON.Binary;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new Plain authentication mechanism
|
|
12
|
+
*
|
|
13
|
+
* @extends AuthProvider
|
|
14
|
+
*/
|
|
15
|
+
class Plain extends AuthProvider {
|
|
16
|
+
/**
|
|
17
|
+
* Implementation of authentication for a single connection
|
|
18
|
+
* @override
|
|
19
|
+
*/
|
|
20
|
+
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
|
21
|
+
const username = credentials.username;
|
|
22
|
+
const password = credentials.password;
|
|
23
|
+
const payload = new Binary(`\x00${username}\x00${password}`);
|
|
24
|
+
const command = {
|
|
25
|
+
saslStart: 1,
|
|
26
|
+
mechanism: 'PLAIN',
|
|
27
|
+
payload: payload,
|
|
28
|
+
autoAuthorize: 1
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
sendAuthCommand(connection, '$external.$cmd', command, callback);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = Plain;
|