@@ -4,7 +4,7 @@ import { promisify } from 'util';
4
4
5
5
import type { Binary , BSONSerializeOptions } from '../../bson' ;
6
6
import * as BSON from '../../bson' ;
7
- import { aws4 , getAwsCredentialProvider } from '../../deps' ;
7
+ import { aws4 , type AWSCredentials , getAwsCredentialProvider } from '../../deps' ;
8
8
import {
9
9
MongoAWSError ,
10
10
MongoCompatibilityError ,
@@ -57,12 +57,42 @@ interface AWSSaslContinuePayload {
57
57
}
58
58
59
59
export class MongoDBAWS extends AuthProvider {
60
- static credentialProvider : ReturnType < typeof getAwsCredentialProvider > | null = null ;
60
+ static credentialProvider : ReturnType < typeof getAwsCredentialProvider > ;
61
+ provider ?: ( ) => Promise < AWSCredentials > ;
61
62
randomBytesAsync : ( size : number ) => Promise < Buffer > ;
62
63
63
64
constructor ( ) {
64
65
super ( ) ;
65
66
this . randomBytesAsync = promisify ( crypto . randomBytes ) ;
67
+ MongoDBAWS . credentialProvider ??= getAwsCredentialProvider ( ) ;
68
+
69
+ let { AWS_STS_REGIONAL_ENDPOINTS = '' , AWS_REGION = '' } = process . env ;
70
+ AWS_STS_REGIONAL_ENDPOINTS = AWS_STS_REGIONAL_ENDPOINTS . toLowerCase ( ) ;
71
+ AWS_REGION = AWS_REGION . toLowerCase ( ) ;
72
+
73
+ /** The option setting should work only for users who have explicit settings in their environment, the driver should not encode "defaults" */
74
+ const awsRegionSettingsExist =
75
+ AWS_REGION . length !== 0 && AWS_STS_REGIONAL_ENDPOINTS . length !== 0 ;
76
+
77
+ /**
78
+ * If AWS_STS_REGIONAL_ENDPOINTS is set to regional, users are opting into the new behavior of respecting the region settings
79
+ *
80
+ * If AWS_STS_REGIONAL_ENDPOINTS is set to legacy, then "old" regions need to keep using the global setting.
81
+ * Technically the SDK gets this wrong, it reaches out to 'sts.us-east-1.amazonaws.com' when it should be 'sts.amazonaws.com'.
82
+ * That is not our bug to fix here. We leave that up to the SDK.
83
+ */
84
+ const useRegionalSts =
85
+ AWS_STS_REGIONAL_ENDPOINTS === 'regional' ||
86
+ ( AWS_STS_REGIONAL_ENDPOINTS === 'legacy' && ! LEGACY_REGIONS . has ( AWS_REGION ) ) ;
87
+
88
+ if ( 'fromNodeProviderChain' in MongoDBAWS . credentialProvider ) {
89
+ this . provider =
90
+ awsRegionSettingsExist && useRegionalSts
91
+ ? MongoDBAWS . credentialProvider . fromNodeProviderChain ( {
92
+ clientConfig : { region : AWS_REGION }
93
+ } )
94
+ : MongoDBAWS . credentialProvider . fromNodeProviderChain ( ) ;
95
+ }
66
96
}
67
97
68
98
override async auth ( authContext : AuthContext ) : Promise < void > {
@@ -83,7 +113,7 @@ export class MongoDBAWS extends AuthProvider {
83
113
}
84
114
85
115
if ( ! authContext . credentials . username ) {
86
- authContext . credentials = await makeTempCredentials ( authContext . credentials ) ;
116
+ authContext . credentials = await makeTempCredentials ( authContext . credentials , this . provider ) ;
87
117
}
88
118
89
119
const { credentials } = authContext ;
@@ -181,7 +211,10 @@ interface AWSTempCredentials {
181
211
Expiration ?: Date ;
182
212
}
183
213
184
- async function makeTempCredentials ( credentials : MongoCredentials ) : Promise < MongoCredentials > {
214
+ async function makeTempCredentials (
215
+ credentials : MongoCredentials ,
216
+ provider ?: ( ) => Promise < AWSCredentials >
217
+ ) : Promise < MongoCredentials > {
185
218
function makeMongoCredentialsFromAWSTemp ( creds : AWSTempCredentials ) {
186
219
if ( ! creds . AccessKeyId || ! creds . SecretAccessKey || ! creds . Token ) {
187
220
throw new MongoMissingCredentialsError ( 'Could not obtain temporary MONGODB-AWS credentials' ) ;
@@ -198,11 +231,31 @@ async function makeTempCredentials(credentials: MongoCredentials): Promise<Mongo
198
231
} ) ;
199
232
}
200
233
201
- MongoDBAWS . credentialProvider ??= getAwsCredentialProvider ( ) ;
202
-
203
234
// Check if the AWS credential provider from the SDK is present. If not,
204
235
// use the old method.
205
- if ( 'kModuleError' in MongoDBAWS . credentialProvider ) {
236
+ if ( provider && ! ( 'kModuleError' in MongoDBAWS . credentialProvider ) ) {
237
+ /*
238
+ * Creates a credential provider that will attempt to find credentials from the
239
+ * following sources (listed in order of precedence):
240
+ *
241
+ * - Environment variables exposed via process.env
242
+ * - SSO credentials from token cache
243
+ * - Web identity token credentials
244
+ * - Shared credentials and config ini files
245
+ * - The EC2/ECS Instance Metadata Service
246
+ */
247
+ try {
248
+ const creds = await provider ( ) ;
249
+ return makeMongoCredentialsFromAWSTemp ( {
250
+ AccessKeyId : creds . accessKeyId ,
251
+ SecretAccessKey : creds . secretAccessKey ,
252
+ Token : creds . sessionToken ,
253
+ Expiration : creds . expiration
254
+ } ) ;
255
+ } catch ( error ) {
256
+ throw new MongoAWSError ( error . message ) ;
257
+ }
258
+ } else {
206
259
// If the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
207
260
// is set then drivers MUST assume that it was set by an AWS ECS agent
208
261
if ( process . env . AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ) {
@@ -232,54 +285,6 @@ async function makeTempCredentials(credentials: MongoCredentials): Promise<Mongo
232
285
} ) ;
233
286
234
287
return makeMongoCredentialsFromAWSTemp ( creds ) ;
235
- } else {
236
- let { AWS_STS_REGIONAL_ENDPOINTS = '' , AWS_REGION = '' } = process . env ;
237
- AWS_STS_REGIONAL_ENDPOINTS = AWS_STS_REGIONAL_ENDPOINTS . toLowerCase ( ) ;
238
- AWS_REGION = AWS_REGION . toLowerCase ( ) ;
239
-
240
- /** The option setting should work only for users who have explicit settings in their environment, the driver should not encode "defaults" */
241
- const awsRegionSettingsExist =
242
- AWS_REGION . length !== 0 && AWS_STS_REGIONAL_ENDPOINTS . length !== 0 ;
243
-
244
- /**
245
- * If AWS_STS_REGIONAL_ENDPOINTS is set to regional, users are opting into the new behavior of respecting the region settings
246
- *
247
- * If AWS_STS_REGIONAL_ENDPOINTS is set to legacy, then "old" regions need to keep using the global setting.
248
- * Technically the SDK gets this wrong, it reaches out to 'sts.us-east-1.amazonaws.com' when it should be 'sts.amazonaws.com'.
249
- * That is not our bug to fix here. We leave that up to the SDK.
250
- */
251
- const useRegionalSts =
252
- AWS_STS_REGIONAL_ENDPOINTS === 'regional' ||
253
- ( AWS_STS_REGIONAL_ENDPOINTS === 'legacy' && ! LEGACY_REGIONS . has ( AWS_REGION ) ) ;
254
-
255
- const provider =
256
- awsRegionSettingsExist && useRegionalSts
257
- ? MongoDBAWS . credentialProvider . fromNodeProviderChain ( {
258
- clientConfig : { region : AWS_REGION }
259
- } )
260
- : MongoDBAWS . credentialProvider . fromNodeProviderChain ( ) ;
261
-
262
- /*
263
- * Creates a credential provider that will attempt to find credentials from the
264
- * following sources (listed in order of precedence):
265
- *
266
- * - Environment variables exposed via process.env
267
- * - SSO credentials from token cache
268
- * - Web identity token credentials
269
- * - Shared credentials and config ini files
270
- * - The EC2/ECS Instance Metadata Service
271
- */
272
- try {
273
- const creds = await provider ( ) ;
274
- return makeMongoCredentialsFromAWSTemp ( {
275
- AccessKeyId : creds . accessKeyId ,
276
- SecretAccessKey : creds . secretAccessKey ,
277
- Token : creds . sessionToken ,
278
- Expiration : creds . expiration
279
- } ) ;
280
- } catch ( error ) {
281
- throw new MongoAWSError ( error . message ) ;
282
- }
283
288
}
284
289
}
285
290
0 commit comments