Skip to content
This repository was archived by the owner on Feb 4, 2022. It is now read-only.

Commit a1cba2a

Browse files
committed
refactor(uri-parser): support authentication expectations
NODE-1437
1 parent 386de6f commit a1cba2a

File tree

1 file changed

+81
-3
lines changed

1 file changed

+81
-3
lines changed

lib/uri_parser.js

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,76 @@ function applyConnectionStringOption(obj, key, value, options) {
296296
obj[key] = value;
297297
}
298298

299+
const USERNAME_REQUIRED_MECHANISMS = new Set([
300+
'GSSAPI',
301+
'MONGODB-CR',
302+
'PLAIN',
303+
'SCRAM-SHA-1',
304+
'SCRAM-SHA-256'
305+
]);
306+
307+
/**
308+
* Modifies the parsed connection string object taking into account expectations we
309+
* have for authentication-related options.
310+
*
311+
* @param {object} parsed The parsed connection string result
312+
* @return The parsed connection string result possibly modified for auth expectations
313+
*/
314+
function applyAuthExpectations(parsed) {
315+
if (parsed.options == null) {
316+
return;
317+
}
318+
319+
const options = parsed.options;
320+
const authSource = options.authsource || options.authSource;
321+
if (authSource != null) {
322+
parsed.auth = Object.assign({}, parsed.auth, { db: authSource });
323+
}
324+
325+
const authMechanism = options.authmechanism || options.authMechanism;
326+
if (authMechanism != null) {
327+
if (
328+
USERNAME_REQUIRED_MECHANISMS.has(authMechanism) &&
329+
(!parsed.auth || parsed.auth.username == null)
330+
) {
331+
throw new MongoParseError(`Username required for mechanism \`${authMechanism}\``);
332+
}
333+
334+
if (authMechanism === 'GSSAPI') {
335+
if (authSource != null && authSource !== '$external') {
336+
throw new MongoParseError(`Invalid auth source \`${authMechanism}\` specified`);
337+
}
338+
339+
parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
340+
}
341+
342+
if (authMechanism === 'MONGODB-X509') {
343+
if (parsed.auth && parsed.auth.password != null) {
344+
throw new MongoParseError(`Password not allowed for mechanism \`${authMechanism}\``);
345+
}
346+
347+
if (authSource != null && authSource !== '$external') {
348+
throw new MongoParseError(`Invalid auth source \`${authMechanism}\` specified`);
349+
}
350+
351+
parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
352+
}
353+
354+
if (authMechanism === 'PLAIN') {
355+
if (parsed.auth && parsed.auth.db == null) {
356+
parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
357+
}
358+
}
359+
}
360+
361+
// default to `admin` if nothing else was resolved
362+
if (parsed.auth && parsed.auth.db == null) {
363+
parsed.auth = Object.assign({}, parsed.auth, { db: 'admin' });
364+
}
365+
366+
return parsed;
367+
}
368+
299369
/**
300370
* Parses a query string according the connection string spec.
301371
*
@@ -376,7 +446,7 @@ function parseConnectionString(uri, options, callback) {
376446
}
377447

378448
parsedOptions = Object.assign({}, parsedOptions, options);
379-
const auth = { username: null, password: null, db: db && db !== '' ? qs.unescape(db) : 'admin' };
449+
const auth = { username: null, password: null, db: db && db !== '' ? qs.unescape(db) : null };
380450
if (cap[4].split('?')[0].indexOf('@') !== -1) {
381451
return callback(new MongoParseError('Unescaped slash in userinfo section'));
382452
}
@@ -450,11 +520,19 @@ function parseConnectionString(uri, options, callback) {
450520
return callback(new MongoParseError('No hostname or hostnames provided in connection string'));
451521
}
452522

453-
callback(null, {
523+
const result = {
454524
hosts: hosts,
455525
auth: auth.db || auth.username ? auth : null,
456526
options: Object.keys(parsedOptions).length ? parsedOptions : null
457-
});
527+
};
528+
529+
try {
530+
applyAuthExpectations(result);
531+
} catch (authError) {
532+
return callback(authError);
533+
}
534+
535+
callback(null, result);
458536
}
459537

460538
module.exports = parseConnectionString;

0 commit comments

Comments
 (0)