@@ -59,6 +59,15 @@ export interface AwsSdkSigV4AuthInputConfig {
59
59
signerConstructor ?: new ( options : SignatureV4Init & SignatureV4CryptoInit ) => RequestSigner ;
60
60
}
61
61
62
+ /**
63
+ * Used to indicate whether a credential provider function was memoized by this resolver.
64
+ * @public
65
+ */
66
+ export type AwsSdkSigV4Memoized = {
67
+ memoized ?: boolean ;
68
+ configBound ?: boolean ;
69
+ } ;
70
+
62
71
/**
63
72
* @internal
64
73
*/
@@ -82,7 +91,8 @@ export interface AwsSdkSigV4AuthResolvedConfig {
82
91
* Resolved value for input config {@link AwsSdkSigV4AuthInputConfig.credentials}
83
92
* This provider MAY memoize the loaded credentials for certain period.
84
93
*/
85
- credentials : MergeFunctions < AwsCredentialIdentityProvider , MemoizedProvider < AwsCredentialIdentity > > ;
94
+ credentials : MergeFunctions < AwsCredentialIdentityProvider , MemoizedProvider < AwsCredentialIdentity > > &
95
+ AwsSdkSigV4Memoized ;
86
96
/**
87
97
* Resolved value for input config {@link AwsSdkSigV4AuthInputConfig.signer}
88
98
*/
@@ -103,33 +113,39 @@ export interface AwsSdkSigV4AuthResolvedConfig {
103
113
export const resolveAwsSdkSigV4Config = < T > (
104
114
config : T & AwsSdkSigV4AuthInputConfig & AwsSdkSigV4PreviouslyResolved
105
115
) : T & AwsSdkSigV4AuthResolvedConfig => {
106
- let isUserSupplied = false ;
107
- // Normalize credentials
108
- let credentialsProvider : AwsCredentialIdentityProvider | undefined ;
109
- if ( config . credentials ) {
110
- isUserSupplied = true ;
111
- credentialsProvider = memoizeIdentityProvider ( config . credentials , isIdentityExpired , doesIdentityRequireRefresh ) ;
112
- }
113
- if ( ! credentialsProvider ) {
114
- // credentialDefaultProvider should always be populated, but in case
115
- // it isn't, set a default identity provider that throws an error
116
- if ( config . credentialDefaultProvider ) {
117
- credentialsProvider = normalizeProvider (
118
- config . credentialDefaultProvider (
119
- Object . assign ( { } , config as any , {
120
- parentClientConfig : config ,
121
- } )
122
- )
123
- ) ;
124
- } else {
125
- credentialsProvider = async ( ) => {
126
- throw new Error ( "`credentials` is missing" ) ;
127
- } ;
128
- }
129
- }
116
+ let inputCredentials = config . credentials ;
117
+ let isUserSupplied = ! ! config . credentials ;
118
+ let resolvedCredentials : AwsSdkSigV4AuthResolvedConfig [ "credentials" ] | undefined = undefined ;
130
119
131
- const boundCredentialsProvider = async ( options : Record < string , any > | undefined ) =>
132
- credentialsProvider ! ( { ...options , callerClientConfig : config } ) ;
120
+ Object . defineProperty ( config , "credentials" , {
121
+ set ( credentials : AwsSdkSigV4AuthInputConfig [ "credentials" ] ) {
122
+ if ( credentials && credentials !== inputCredentials && credentials !== resolvedCredentials ) {
123
+ isUserSupplied = true ;
124
+ }
125
+ inputCredentials = credentials ;
126
+ const normalized = normalizeCredentialProvider ( config , {
127
+ credentials : inputCredentials ,
128
+ credentialDefaultProvider : config . credentialDefaultProvider ,
129
+ } ) ;
130
+ const boundProvider = bindCallerConfig ( config , normalized ) ;
131
+ if ( isUserSupplied ) {
132
+ resolvedCredentials = async ( options : Record < string , any > | undefined ) =>
133
+ boundProvider ( options ) . then ( ( creds : AttributedAwsCredentialIdentity ) =>
134
+ setCredentialFeature ( creds , "CREDENTIALS_CODE" , "e" )
135
+ ) ;
136
+ } else {
137
+ resolvedCredentials = boundProvider ;
138
+ }
139
+ } ,
140
+ get ( ) : AwsSdkSigV4AuthResolvedConfig [ "credentials" ] {
141
+ return resolvedCredentials ! ;
142
+ } ,
143
+ enumerable : true ,
144
+ configurable : true ,
145
+ } ) ;
146
+
147
+ // invoke setter so that resolvedCredentials is set.
148
+ config . credentials = inputCredentials ;
133
149
134
150
// Populate sigv4 arguments
135
151
const {
@@ -172,7 +188,7 @@ export const resolveAwsSdkSigV4Config = <T>(
172
188
173
189
const params : SignatureV4Init & SignatureV4CryptoInit = {
174
190
...config ,
175
- credentials : boundCredentialsProvider ,
191
+ credentials : config . credentials as AwsSdkSigV4AuthResolvedConfig [ "credentials" ] ,
176
192
region : config . signingRegion ,
177
193
service : config . signingName ,
178
194
sha256,
@@ -208,7 +224,7 @@ export const resolveAwsSdkSigV4Config = <T>(
208
224
209
225
const params : SignatureV4Init & SignatureV4CryptoInit = {
210
226
...config ,
211
- credentials : boundCredentialsProvider ,
227
+ credentials : config . credentials as AwsSdkSigV4AuthResolvedConfig [ "credentials" ] ,
212
228
region : config . signingRegion ,
213
229
service : config . signingName ,
214
230
sha256,
@@ -220,19 +236,78 @@ export const resolveAwsSdkSigV4Config = <T>(
220
236
} ;
221
237
}
222
238
223
- return Object . assign ( config , {
239
+ const resolvedConfig = Object . assign ( config , {
224
240
systemClockOffset,
225
241
signingEscapePath,
226
- credentials : isUserSupplied
227
- ? async ( options : Record < string , any > | undefined ) =>
228
- boundCredentialsProvider ! ( options ) . then ( ( creds : AttributedAwsCredentialIdentity ) =>
229
- setCredentialFeature ( creds , "CREDENTIALS_CODE" , "e" )
230
- )
231
- : boundCredentialsProvider ! ,
232
242
signer,
233
243
} ) ;
244
+
245
+ return resolvedConfig as typeof resolvedConfig & {
246
+ // this was set earlier with Object.defineProperty.
247
+ credentials : AwsSdkSigV4AuthResolvedConfig [ "credentials" ] ;
248
+ } ;
234
249
} ;
235
250
251
+ /**
252
+ * Normalizes the credentials to a memoized provider and sets memoized=true on the function
253
+ * object. This prevents multiple layering of the memoization process.
254
+ */
255
+ function normalizeCredentialProvider (
256
+ config : Parameters < typeof resolveAwsSdkSigV4Config > [ 0 ] ,
257
+ {
258
+ credentials,
259
+ credentialDefaultProvider,
260
+ } : Pick < Parameters < typeof resolveAwsSdkSigV4Config > [ 0 ] , "credentials" | "credentialDefaultProvider" >
261
+ ) : AwsSdkSigV4AuthResolvedConfig [ "credentials" ] {
262
+ let credentialsProvider : AwsSdkSigV4AuthResolvedConfig [ "credentials" ] | undefined ;
263
+
264
+ if ( credentials ) {
265
+ if ( ! ( credentials as typeof credentials & AwsSdkSigV4Memoized ) ?. memoized ) {
266
+ credentialsProvider = memoizeIdentityProvider ( credentials , isIdentityExpired , doesIdentityRequireRefresh ) ! ;
267
+ credentialsProvider . memoized = true ;
268
+ } else {
269
+ credentialsProvider = credentials as AwsSdkSigV4AuthResolvedConfig [ "credentials" ] ;
270
+ }
271
+ } else {
272
+ // credentialDefaultProvider should always be populated, but in case
273
+ // it isn't, set a default identity provider that throws an error
274
+ if ( credentialDefaultProvider ) {
275
+ credentialsProvider = normalizeProvider (
276
+ credentialDefaultProvider (
277
+ Object . assign ( { } , config as any , {
278
+ parentClientConfig : config ,
279
+ } )
280
+ )
281
+ ) ;
282
+ } else {
283
+ credentialsProvider = async ( ) => {
284
+ throw new Error (
285
+ "@aws-sdk/core::resolveAwsSdkSigV4Config - `credentials` not provided and no credentialDefaultProvider was configured."
286
+ ) ;
287
+ } ;
288
+ }
289
+ }
290
+ return credentialsProvider ;
291
+ }
292
+
293
+ /**
294
+ * Binds the caller client config as an argument to the credentialsProvider function.
295
+ * Uses a state marker on the function to avoid doing this more than once.
296
+ */
297
+ function bindCallerConfig (
298
+ config : Parameters < typeof resolveAwsSdkSigV4Config > [ 0 ] ,
299
+ credentialsProvider : AwsSdkSigV4AuthResolvedConfig [ "credentials" ]
300
+ ) : AwsSdkSigV4AuthResolvedConfig [ "credentials" ] {
301
+ if ( credentialsProvider . configBound && credentialsProvider . memoized ) {
302
+ return credentialsProvider ;
303
+ }
304
+ const fn : typeof credentialsProvider = async ( options : Parameters < typeof credentialsProvider > [ 0 ] ) =>
305
+ credentialsProvider ( { ...options , callerClientConfig : config } ) ;
306
+ fn . memoized = credentialsProvider . memoized ;
307
+ fn . configBound = true ;
308
+ return fn ;
309
+ }
310
+
236
311
/**
237
312
* @internal
238
313
* @deprecated renamed to {@link AwsSdkSigV4AuthInputConfig}
0 commit comments