@@ -11,10 +11,10 @@ import {
11
11
hookLoggerToMongoLogWriter as oidcPluginHookLoggerToMongoLogWriter ,
12
12
} from '@mongodb-js/oidc-plugin' ;
13
13
import { oidcServerRequestHandler } from '@mongodb-js/devtools-connect' ;
14
- // TODO(https://github.com/node-fetch/node-fetch/issues/1652): Remove this when
15
- // node-fetch types match the built in AbortSignal from node.
16
- import type { AbortSignal as NodeFetchAbortSignal } from 'node-fetch/externals' ;
14
+ import { systemCertsAsync } from 'system-ca' ;
15
+ import type { Options as SystemCAOptions } from 'system-ca' ;
17
16
import type { RequestInfo , RequestInit , Response } from 'node-fetch' ;
17
+ import https from 'https' ;
18
18
import nodeFetch from 'node-fetch' ;
19
19
import type { IntrospectInfo , AtlasUserInfo , AtlasServiceConfig } from './util' ;
20
20
import { throwIfAborted } from '@mongodb-js/compass-utils' ;
@@ -37,6 +37,15 @@ const redirectRequestHandler = oidcServerRequestHandler.bind(null, {
37
37
productDocsLink : 'https://www.mongodb.com/docs/compass' ,
38
38
} ) ;
39
39
40
+ async function getSystemCA ( ) {
41
+ // It is possible for OIDC login flow to fail if system CA certs are different from
42
+ // the ones packaged with the application. To avoid this, we include the system CA
43
+ // certs in the OIDC plugin options. See COMPASS-7950 for more details.
44
+ const systemCAOpts : SystemCAOptions = { includeNodeCertificates : true } ;
45
+ const ca = await systemCertsAsync ( systemCAOpts ) ;
46
+ return ca . join ( '\n' ) ;
47
+ }
48
+
40
49
const TOKEN_TYPE_TO_HINT = {
41
50
accessToken : 'access_token' ,
42
51
refreshToken : 'refresh_token' ,
@@ -63,7 +72,7 @@ export class CompassAuthService {
63
72
) : Promise < Response > => {
64
73
await this . initPromise ;
65
74
this . throwIfNetworkTrafficDisabled ( ) ;
66
- throwIfAborted ( init . signal as AbortSignal ) ;
75
+ throwIfAborted ( init . signal ?? undefined ) ;
67
76
log . info (
68
77
mongoLogId ( 1_001_000_299 ) ,
69
78
'AtlasService' ,
@@ -72,6 +81,14 @@ export class CompassAuthService {
72
81
) ;
73
82
try {
74
83
const res = await nodeFetch ( url , {
84
+ // Tests use 'http'.
85
+ ...( url . toString ( ) . includes ( 'https' )
86
+ ? {
87
+ agent : new https . Agent ( {
88
+ ca : await getSystemCA ( ) ,
89
+ } ) ,
90
+ }
91
+ : { } ) ,
75
92
...init ,
76
93
headers : {
77
94
...init . headers ,
@@ -129,7 +146,7 @@ export class CompassAuthService {
129
146
130
147
private static createMongoDBOIDCPlugin = createMongoDBOIDCPlugin ;
131
148
132
- private static setupPlugin ( serializedState ?: string ) {
149
+ private static async setupPlugin ( serializedState ?: string ) {
133
150
this . plugin = this . createMongoDBOIDCPlugin ( {
134
151
redirectServerRequestHandler : ( data ) => {
135
152
if ( data . result === 'redirecting' ) {
@@ -150,6 +167,9 @@ export class CompassAuthService {
150
167
allowedFlows : this . getAllowedAuthFlows . bind ( this ) ,
151
168
logger : this . oidcPluginLogger ,
152
169
serializedState,
170
+ customHttpOptions : {
171
+ ca : await getSystemCA ( ) ,
172
+ } ,
153
173
} ) ;
154
174
oidcPluginHookLoggerToMongoLogWriter (
155
175
this . oidcPluginLogger ,
@@ -180,7 +200,7 @@ export class CompassAuthService {
180
200
{ config : this . config }
181
201
) ;
182
202
const serializedState = await this . secretStore . getState ( ) ;
183
- this . setupPlugin ( serializedState ) ;
203
+ await this . setupPlugin ( serializedState ) ;
184
204
} ) ( ) ) ;
185
205
}
186
206
@@ -301,7 +321,7 @@ export class CompassAuthService {
301
321
this . attachOidcPluginLoggerEvents ( ) ;
302
322
// Destroy old plugin and setup new one
303
323
await this . plugin ?. destroy ( ) ;
304
- this . setupPlugin ( ) ;
324
+ await this . setupPlugin ( ) ;
305
325
// Revoke tokens. Revoking refresh token will also revoke associated access
306
326
// tokens
307
327
// https://developer.okta.com/docs/guides/revoke-tokens/main/#revoke-an-access-token-or-a-refresh-token
@@ -362,7 +382,7 @@ export class CompassAuthService {
362
382
Authorization : `Bearer ${ token ?? '' } ` ,
363
383
Accept : 'application/json' ,
364
384
} ,
365
- signal : signal as NodeFetchAbortSignal | undefined ,
385
+ signal : signal ,
366
386
}
367
387
) ;
368
388
@@ -403,7 +423,7 @@ export class CompassAuthService {
403
423
Accept : 'application/json' ,
404
424
'Content-Type' : 'application/x-www-form-urlencoded' ,
405
425
} ,
406
- signal : signal as NodeFetchAbortSignal | undefined ,
426
+ signal : signal ,
407
427
} ) ;
408
428
409
429
await throwIfNotOk ( res ) ;
@@ -438,7 +458,7 @@ export class CompassAuthService {
438
458
Accept : 'application/json' ,
439
459
'Content-Type' : 'application/x-www-form-urlencoded' ,
440
460
} ,
441
- signal : signal as NodeFetchAbortSignal | undefined ,
461
+ signal : signal ,
442
462
} ) ;
443
463
444
464
await throwIfNotOk ( res ) ;
0 commit comments