@@ -4,7 +4,7 @@ import { promisify } from 'util';
44
55import type { Binary , BSONSerializeOptions } from '../../bson' ;
66import * as BSON from '../../bson' ;
7- import { aws4 , getAwsCredentialProvider } from '../../deps' ;
7+ import { aws4 , type AWSCredentials , getAwsCredentialProvider } from '../../deps' ;
88import {
99 MongoAWSError ,
1010 MongoCompatibilityError ,
@@ -57,12 +57,42 @@ interface AWSSaslContinuePayload {
5757}
5858
5959export class MongoDBAWS extends AuthProvider {
60- static credentialProvider : ReturnType < typeof getAwsCredentialProvider > | null = null ;
60+ static credentialProvider : ReturnType < typeof getAwsCredentialProvider > ;
61+ provider ?: ( ) => Promise < AWSCredentials > ;
6162 randomBytesAsync : ( size : number ) => Promise < Buffer > ;
6263
6364 constructor ( ) {
6465 super ( ) ;
6566 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+ }
6696 }
6797
6898 override async auth ( authContext : AuthContext ) : Promise < void > {
@@ -83,7 +113,7 @@ export class MongoDBAWS extends AuthProvider {
83113 }
84114
85115 if ( ! authContext . credentials . username ) {
86- authContext . credentials = await makeTempCredentials ( authContext . credentials ) ;
116+ authContext . credentials = await makeTempCredentials ( authContext . credentials , this . provider ) ;
87117 }
88118
89119 const { credentials } = authContext ;
@@ -181,7 +211,10 @@ interface AWSTempCredentials {
181211 Expiration ?: Date ;
182212}
183213
184- async function makeTempCredentials ( credentials : MongoCredentials ) : Promise < MongoCredentials > {
214+ async function makeTempCredentials (
215+ credentials : MongoCredentials ,
216+ provider ?: ( ) => Promise < AWSCredentials >
217+ ) : Promise < MongoCredentials > {
185218 function makeMongoCredentialsFromAWSTemp ( creds : AWSTempCredentials ) {
186219 if ( ! creds . AccessKeyId || ! creds . SecretAccessKey || ! creds . Token ) {
187220 throw new MongoMissingCredentialsError ( 'Could not obtain temporary MONGODB-AWS credentials' ) ;
@@ -198,11 +231,31 @@ async function makeTempCredentials(credentials: MongoCredentials): Promise<Mongo
198231 } ) ;
199232 }
200233
201- MongoDBAWS . credentialProvider ??= getAwsCredentialProvider ( ) ;
202-
203234 // Check if the AWS credential provider from the SDK is present. If not,
204235 // 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 {
206259 // If the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
207260 // is set then drivers MUST assume that it was set by an AWS ECS agent
208261 if ( process . env . AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ) {
@@ -232,54 +285,6 @@ async function makeTempCredentials(credentials: MongoCredentials): Promise<Mongo
232285 } ) ;
233286
234287 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- }
283288 }
284289}
285290
0 commit comments