Skip to content

Commit 486f1fb

Browse files
committed
feat(credential-providers): fix tests, add chaining support
1 parent d9cb1ac commit 486f1fb

File tree

4 files changed

+70
-9
lines changed

4 files changed

+70
-9
lines changed

packages/credential-provider-ini/src/fromIni.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ export interface FromIniInit extends SourceProfileInit, CredentialProviderOption
5757
*/
5858
export const fromIni =
5959
(_init: FromIniInit = {}): RegionalAwsCredentialIdentityProvider =>
60-
async (props = {}) => {
60+
async ({ contextClientConfig } = {}) => {
6161
const init: FromIniInit = {
6262
..._init,
6363
};
64-
if (props.contextClientConfig?.region) {
64+
if (contextClientConfig?.region) {
6565
init.parentClientConfig = {
66-
region: props.contextClientConfig.region,
66+
region: contextClientConfig.region,
6767
..._init.parentClientConfig,
6868
};
6969
}

packages/credential-provider-web-identity/src/fromWebToken.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export const fromWebToken =
169169
{
170170
...init.clientConfig,
171171
credentialProviderLogger: init.logger,
172-
...(awsIdentityProperties?.contextClientConfig?.region
172+
...(awsIdentityProperties?.contextClientConfig?.region || init.parentClientConfig
173173
? {
174174
parentClientConfig: {
175175
region: awsIdentityProperties?.contextClientConfig?.region,

packages/credential-providers/src/createCredentialChain.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { RegionalAwsCredentialIdentityProvider } from "@aws-sdk/types";
12
import { ProviderError } from "@smithy/property-provider";
23
import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from "@smithy/types";
34
import { describe, expect, test as it } from "vitest";
@@ -79,4 +80,33 @@ describe(createCredentialChain.name, () => {
7980
"@aws-sdk/credential-providers - createCredentialChain(...).expireAfter(ms) may not be called with a duration lower than five minutes."
8081
);
8182
});
83+
84+
it("is compatible with contextual-region-aware credential providers", async () => {
85+
const provider: RegionalAwsCredentialIdentityProvider = async ({ contextClientConfig } = {}) => {
86+
return {
87+
accessKeyId: "",
88+
secretAccessKey: "",
89+
sessionToken: (await contextClientConfig?.region()) ?? "wrong_region",
90+
};
91+
};
92+
const errorProvider = async () => {
93+
throw new ProviderError("", { tryNextLink: true });
94+
};
95+
96+
const chain = createCredentialChain(errorProvider, provider);
97+
98+
expect(
99+
await chain({
100+
contextClientConfig: {
101+
async region() {
102+
return "ap-northeast-1";
103+
},
104+
},
105+
})
106+
).toEqual({
107+
accessKeyId: "",
108+
secretAccessKey: "",
109+
sessionToken: "ap-northeast-1",
110+
});
111+
});
82112
});

packages/credential-providers/src/createCredentialChain.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { chain as propertyProviderChain } from "@smithy/property-provider";
1+
import type {
2+
AwsIdentityProperties,
3+
RegionalAwsCredentialIdentityProvider,
4+
RegionalIdentityProvider,
5+
} from "@aws-sdk/types";
6+
import { ProviderError } from "@smithy/property-provider";
27
import type { AwsCredentialIdentityProvider } from "@smithy/types";
38

49
export interface CustomCredentialChainOptions {
@@ -52,11 +57,11 @@ type Mutable<Type> = {
5257
* providers in sequence until one succeeds or all fail.
5358
*/
5459
export const createCredentialChain = (
55-
...credentialProviders: AwsCredentialIdentityProvider[]
56-
): AwsCredentialIdentityProvider & CustomCredentialChainOptions => {
60+
...credentialProviders: RegionalAwsCredentialIdentityProvider[]
61+
): RegionalAwsCredentialIdentityProvider & CustomCredentialChainOptions => {
5762
let expireAfter = -1;
58-
const baseFunction = async () => {
59-
const credentials = await propertyProviderChain(...credentialProviders)();
63+
const baseFunction = async (awsIdentityProperties?: AwsIdentityProperties) => {
64+
const credentials = await propertyProviderChain(...credentialProviders)(awsIdentityProperties);
6065
if (!credentials.expiration && expireAfter !== -1) {
6166
(credentials as Mutable<typeof credentials>).expiration = new Date(Date.now() + expireAfter);
6267
}
@@ -75,3 +80,29 @@ export const createCredentialChain = (
7580
});
7681
return withOptions;
7782
};
83+
84+
/**
85+
* @internal
86+
*/
87+
export const propertyProviderChain =
88+
<T>(...providers: Array<RegionalIdentityProvider<T>>): RegionalIdentityProvider<T> =>
89+
async (awsIdentityProperties?: AwsIdentityProperties) => {
90+
if (providers.length === 0) {
91+
throw new ProviderError("No providers in chain");
92+
}
93+
94+
let lastProviderError: Error | undefined;
95+
for (const provider of providers) {
96+
try {
97+
const credentials = await provider(awsIdentityProperties);
98+
return credentials;
99+
} catch (err) {
100+
lastProviderError = err;
101+
if (err?.tryNextLink) {
102+
continue;
103+
}
104+
throw err;
105+
}
106+
}
107+
throw lastProviderError;
108+
};

0 commit comments

Comments
 (0)