1
- import * as crypto from 'crypto' ;
2
1
import * as process from 'process' ;
3
- import { promisify } from 'util' ;
4
2
5
3
import type { Binary , BSONSerializeOptions } from '../../bson' ;
6
4
import * as BSON from '../../bson' ;
7
- import { aws4 , getAwsCredentialProvider } from '../../deps' ;
5
+ import { aws4 , type AWSCredentials , getAwsCredentialProvider } from '../../deps' ;
8
6
import {
9
7
MongoAWSError ,
10
8
MongoCompatibilityError ,
11
9
MongoMissingCredentialsError ,
12
10
MongoRuntimeError
13
11
} from '../../error' ;
14
- import { ByteUtils , maxWireVersion , ns , request } from '../../utils' ;
12
+ import { ByteUtils , maxWireVersion , ns , randomBytes , request } from '../../utils' ;
15
13
import { type AuthContext , AuthProvider } from './auth_provider' ;
16
14
import { MongoCredentials } from './mongo_credentials' ;
17
15
import { AuthMechanism } from './providers' ;
@@ -57,12 +55,40 @@ interface AWSSaslContinuePayload {
57
55
}
58
56
59
57
export class MongoDBAWS extends AuthProvider {
60
- static credentialProvider : ReturnType < typeof getAwsCredentialProvider > | null = null ;
61
- randomBytesAsync : ( size : number ) => Promise < Buffer > ;
58
+ static credentialProvider : ReturnType < typeof getAwsCredentialProvider > ;
59
+ provider ? : ( ) => Promise < AWSCredentials > ;
62
60
63
61
constructor ( ) {
64
62
super ( ) ;
65
- this . randomBytesAsync = promisify ( crypto . randomBytes ) ;
63
+ MongoDBAWS . credentialProvider ??= getAwsCredentialProvider ( ) ;
64
+
65
+ let { AWS_STS_REGIONAL_ENDPOINTS = '' , AWS_REGION = '' } = process . env ;
66
+ AWS_STS_REGIONAL_ENDPOINTS = AWS_STS_REGIONAL_ENDPOINTS . toLowerCase ( ) ;
67
+ AWS_REGION = AWS_REGION . toLowerCase ( ) ;
68
+
69
+ /** The option setting should work only for users who have explicit settings in their environment, the driver should not encode "defaults" */
70
+ const awsRegionSettingsExist =
71
+ AWS_REGION . length !== 0 && AWS_STS_REGIONAL_ENDPOINTS . length !== 0 ;
72
+
73
+ /**
74
+ * If AWS_STS_REGIONAL_ENDPOINTS is set to regional, users are opting into the new behavior of respecting the region settings
75
+ *
76
+ * If AWS_STS_REGIONAL_ENDPOINTS is set to legacy, then "old" regions need to keep using the global setting.
77
+ * Technically the SDK gets this wrong, it reaches out to 'sts.us-east-1.amazonaws.com' when it should be 'sts.amazonaws.com'.
78
+ * That is not our bug to fix here. We leave that up to the SDK.
79
+ */
80
+ const useRegionalSts =
81
+ AWS_STS_REGIONAL_ENDPOINTS === 'regional' ||
82
+ ( AWS_STS_REGIONAL_ENDPOINTS === 'legacy' && ! LEGACY_REGIONS . has ( AWS_REGION ) ) ;
83
+
84
+ if ( 'fromNodeProviderChain' in MongoDBAWS . credentialProvider ) {
85
+ this . provider =
86
+ awsRegionSettingsExist && useRegionalSts
87
+ ? MongoDBAWS . credentialProvider . fromNodeProviderChain ( {
88
+ clientConfig : { region : AWS_REGION }
89
+ } )
90
+ : MongoDBAWS . credentialProvider . fromNodeProviderChain ( ) ;
91
+ }
66
92
}
67
93
68
94
override async auth ( authContext : AuthContext ) : Promise < void > {
@@ -83,7 +109,7 @@ export class MongoDBAWS extends AuthProvider {
83
109
}
84
110
85
111
if ( ! authContext . credentials . username ) {
86
- authContext . credentials = await makeTempCredentials ( authContext . credentials ) ;
112
+ authContext . credentials = await makeTempCredentials ( authContext . credentials , this . provider ) ;
87
113
}
88
114
89
115
const { credentials } = authContext ;
@@ -101,7 +127,7 @@ export class MongoDBAWS extends AuthProvider {
101
127
: undefined ;
102
128
103
129
const db = credentials . source ;
104
- const nonce = await this . randomBytesAsync ( 32 ) ;
130
+ const nonce = await randomBytes ( 32 ) ;
105
131
106
132
const saslStart = {
107
133
saslStart : 1 ,
@@ -181,7 +207,10 @@ interface AWSTempCredentials {
181
207
Expiration ?: Date ;
182
208
}
183
209
184
- async function makeTempCredentials ( credentials : MongoCredentials ) : Promise < MongoCredentials > {
210
+ async function makeTempCredentials (
211
+ credentials : MongoCredentials ,
212
+ provider ?: ( ) => Promise < AWSCredentials >
213
+ ) : Promise < MongoCredentials > {
185
214
function makeMongoCredentialsFromAWSTemp ( creds : AWSTempCredentials ) {
186
215
if ( ! creds . AccessKeyId || ! creds . SecretAccessKey || ! creds . Token ) {
187
216
throw new MongoMissingCredentialsError ( 'Could not obtain temporary MONGODB-AWS credentials' ) ;
@@ -198,11 +227,31 @@ async function makeTempCredentials(credentials: MongoCredentials): Promise<Mongo
198
227
} ) ;
199
228
}
200
229
201
- MongoDBAWS . credentialProvider ??= getAwsCredentialProvider ( ) ;
202
-
203
230
// Check if the AWS credential provider from the SDK is present. If not,
204
231
// use the old method.
205
- if ( 'kModuleError' in MongoDBAWS . credentialProvider ) {
232
+ if ( provider && ! ( 'kModuleError' in MongoDBAWS . credentialProvider ) ) {
233
+ /*
234
+ * Creates a credential provider that will attempt to find credentials from the
235
+ * following sources (listed in order of precedence):
236
+ *
237
+ * - Environment variables exposed via process.env
238
+ * - SSO credentials from token cache
239
+ * - Web identity token credentials
240
+ * - Shared credentials and config ini files
241
+ * - The EC2/ECS Instance Metadata Service
242
+ */
243
+ try {
244
+ const creds = await provider ( ) ;
245
+ return makeMongoCredentialsFromAWSTemp ( {
246
+ AccessKeyId : creds . accessKeyId ,
247
+ SecretAccessKey : creds . secretAccessKey ,
248
+ Token : creds . sessionToken ,
249
+ Expiration : creds . expiration
250
+ } ) ;
251
+ } catch ( error ) {
252
+ throw new MongoAWSError ( error . message ) ;
253
+ }
254
+ } else {
206
255
// If the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
207
256
// is set then drivers MUST assume that it was set by an AWS ECS agent
208
257
if ( process . env . AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ) {
@@ -232,54 +281,6 @@ async function makeTempCredentials(credentials: MongoCredentials): Promise<Mongo
232
281
} ) ;
233
282
234
283
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
284
}
284
285
}
285
286
0 commit comments