@@ -16,16 +16,19 @@ import {
16
16
CONNECTION_READY
17
17
} from '../constants' ;
18
18
import {
19
+ AnyError ,
20
+ MONGODB_ERROR_CODES ,
19
21
MongoError ,
20
22
MongoInvalidArgumentError ,
23
+ MongoMissingCredentialsError ,
21
24
MongoNetworkError ,
22
25
MongoRuntimeError ,
23
26
MongoServerError
24
27
} from '../error' ;
25
28
import { CancellationToken , TypedEventEmitter } from '../mongo_types' ;
26
29
import type { Server } from '../sdam/server' ;
27
30
import { Callback , eachAsync , List , makeCounter } from '../utils' ;
28
- import { connect } from './connect' ;
31
+ import { AUTH_PROVIDERS , connect } from './connect' ;
29
32
import { Connection , ConnectionEvents , ConnectionOptions } from './connection' ;
30
33
import {
31
34
ConnectionCheckedInEvent ,
@@ -537,32 +540,30 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
537
540
withConnection (
538
541
conn : Connection | undefined ,
539
542
fn : WithConnectionCallback ,
540
- callback ? : Callback < Connection >
543
+ callback : Callback < Connection >
541
544
) : void {
542
545
if ( conn ) {
543
546
// use the provided connection, and do _not_ check it in after execution
544
547
fn ( undefined , conn , ( fnErr , result ) => {
545
- if ( typeof callback === 'function' ) {
546
- if ( fnErr ) {
547
- callback ( fnErr ) ;
548
- } else {
549
- callback ( undefined , result ) ;
550
- }
548
+ if ( fnErr ) {
549
+ return this . withReauthentication ( fnErr , conn , fn , callback ) ;
551
550
}
551
+ callback ( undefined , result ) ;
552
552
} ) ;
553
-
554
553
return ;
555
554
}
556
555
557
556
this . checkOut ( ( err , conn ) => {
558
557
// don't callback with `err` here, we might want to act upon it inside `fn`
559
558
fn ( err as MongoError , conn , ( fnErr , result ) => {
560
- if ( typeof callback === 'function' ) {
561
- if ( fnErr ) {
562
- callback ( fnErr ) ;
559
+ if ( fnErr ) {
560
+ if ( conn ) {
561
+ this . withReauthentication ( fnErr , conn , fn , callback ) ;
563
562
} else {
564
- callback ( undefined , result ) ;
563
+ callback ( fnErr ) ;
565
564
}
565
+ } else {
566
+ callback ( undefined , result ) ;
566
567
}
567
568
568
569
if ( conn ) {
@@ -572,6 +573,66 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
572
573
} ) ;
573
574
}
574
575
576
+ private withReauthentication (
577
+ fnErr : AnyError ,
578
+ conn : Connection ,
579
+ fn : WithConnectionCallback ,
580
+ callback : Callback < Connection >
581
+ ) {
582
+ if ( fnErr instanceof MongoError && fnErr . code === MONGODB_ERROR_CODES . Reauthenticate ) {
583
+ this . reauthenticate ( conn , fn , ( error , res ) => {
584
+ if ( error ) {
585
+ return callback ( error ) ;
586
+ }
587
+ callback ( undefined , res ) ;
588
+ } ) ;
589
+ } else {
590
+ callback ( fnErr ) ;
591
+ }
592
+ }
593
+
594
+ /**
595
+ * Reauthenticate on the same connection and then retry the operation.
596
+ */
597
+ private reauthenticate (
598
+ connection : Connection ,
599
+ fn : WithConnectionCallback ,
600
+ callback : Callback
601
+ ) : void {
602
+ const authContext = connection . authContext ;
603
+ if ( ! authContext ) {
604
+ return callback ( new MongoRuntimeError ( 'No auth context found on connection.' ) ) ;
605
+ }
606
+ const credentials = authContext . credentials ;
607
+ if ( ! credentials ) {
608
+ return callback (
609
+ new MongoMissingCredentialsError (
610
+ 'Connection is missing credentials when asked to reauthenticate'
611
+ )
612
+ ) ;
613
+ }
614
+ const resolvedCredentials = credentials . resolveAuthMechanism ( connection . hello || undefined ) ;
615
+ const provider = AUTH_PROVIDERS . get ( resolvedCredentials . mechanism ) ;
616
+ if ( ! provider ) {
617
+ return callback (
618
+ new MongoMissingCredentialsError (
619
+ `Reauthenticate failed due to no auth provider for ${ credentials . mechanism } `
620
+ )
621
+ ) ;
622
+ }
623
+ provider . reauth ( authContext , error => {
624
+ if ( error ) {
625
+ return callback ( error ) ;
626
+ }
627
+ return fn ( undefined , connection , ( fnErr , fnResult ) => {
628
+ if ( fnErr ) {
629
+ return callback ( fnErr ) ;
630
+ }
631
+ callback ( undefined , fnResult ) ;
632
+ } ) ;
633
+ } ) ;
634
+ }
635
+
575
636
/** Clear the min pool size timer */
576
637
private clearMinPoolSizeTimer ( ) : void {
577
638
const minPoolSizeTimer = this [ kMinPoolSizeTimer ] ;
0 commit comments