@@ -296,6 +296,76 @@ function applyConnectionStringOption(obj, key, value, options) {
296
296
obj [ key ] = value ;
297
297
}
298
298
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
+
299
369
/**
300
370
* Parses a query string according the connection string spec.
301
371
*
@@ -376,7 +446,7 @@ function parseConnectionString(uri, options, callback) {
376
446
}
377
447
378
448
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 } ;
380
450
if ( cap [ 4 ] . split ( '?' ) [ 0 ] . indexOf ( '@' ) !== - 1 ) {
381
451
return callback ( new MongoParseError ( 'Unescaped slash in userinfo section' ) ) ;
382
452
}
@@ -450,11 +520,19 @@ function parseConnectionString(uri, options, callback) {
450
520
return callback ( new MongoParseError ( 'No hostname or hostnames provided in connection string' ) ) ;
451
521
}
452
522
453
- callback ( null , {
523
+ const result = {
454
524
hosts : hosts ,
455
525
auth : auth . db || auth . username ? auth : null ,
456
526
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 ) ;
458
536
}
459
537
460
538
module . exports = parseConnectionString ;
0 commit comments