Skip to content

Commit

Permalink
feat(credential-providers): fix tests, add chaining support
Browse files Browse the repository at this point in the history
  • Loading branch information
kuhe committed Dec 12, 2024
1 parent d9cb1ac commit 486f1fb
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 9 deletions.
6 changes: 3 additions & 3 deletions packages/credential-provider-ini/src/fromIni.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ export interface FromIniInit extends SourceProfileInit, CredentialProviderOption
*/
export const fromIni =
(_init: FromIniInit = {}): RegionalAwsCredentialIdentityProvider =>
async (props = {}) => {
async ({ contextClientConfig } = {}) => {
const init: FromIniInit = {
..._init,
};
if (props.contextClientConfig?.region) {
if (contextClientConfig?.region) {
init.parentClientConfig = {
region: props.contextClientConfig.region,
region: contextClientConfig.region,
..._init.parentClientConfig,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export const fromWebToken =
{
...init.clientConfig,
credentialProviderLogger: init.logger,
...(awsIdentityProperties?.contextClientConfig?.region
...(awsIdentityProperties?.contextClientConfig?.region || init.parentClientConfig
? {
parentClientConfig: {
region: awsIdentityProperties?.contextClientConfig?.region,
Expand Down
30 changes: 30 additions & 0 deletions packages/credential-providers/src/createCredentialChain.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RegionalAwsCredentialIdentityProvider } from "@aws-sdk/types";
import { ProviderError } from "@smithy/property-provider";
import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from "@smithy/types";
import { describe, expect, test as it } from "vitest";
Expand Down Expand Up @@ -79,4 +80,33 @@ describe(createCredentialChain.name, () => {
"@aws-sdk/credential-providers - createCredentialChain(...).expireAfter(ms) may not be called with a duration lower than five minutes."
);
});

it("is compatible with contextual-region-aware credential providers", async () => {
const provider: RegionalAwsCredentialIdentityProvider = async ({ contextClientConfig } = {}) => {
return {
accessKeyId: "",
secretAccessKey: "",
sessionToken: (await contextClientConfig?.region()) ?? "wrong_region",
};
};
const errorProvider = async () => {
throw new ProviderError("", { tryNextLink: true });
};

const chain = createCredentialChain(errorProvider, provider);

expect(
await chain({
contextClientConfig: {
async region() {
return "ap-northeast-1";
},
},
})
).toEqual({
accessKeyId: "",
secretAccessKey: "",
sessionToken: "ap-northeast-1",
});
});
});
41 changes: 36 additions & 5 deletions packages/credential-providers/src/createCredentialChain.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { chain as propertyProviderChain } from "@smithy/property-provider";
import type {
AwsIdentityProperties,
RegionalAwsCredentialIdentityProvider,
RegionalIdentityProvider,
} from "@aws-sdk/types";
import { ProviderError } from "@smithy/property-provider";
import type { AwsCredentialIdentityProvider } from "@smithy/types";

export interface CustomCredentialChainOptions {
Expand Down Expand Up @@ -52,11 +57,11 @@ type Mutable<Type> = {
* providers in sequence until one succeeds or all fail.
*/
export const createCredentialChain = (
...credentialProviders: AwsCredentialIdentityProvider[]
): AwsCredentialIdentityProvider & CustomCredentialChainOptions => {
...credentialProviders: RegionalAwsCredentialIdentityProvider[]
): RegionalAwsCredentialIdentityProvider & CustomCredentialChainOptions => {
let expireAfter = -1;
const baseFunction = async () => {
const credentials = await propertyProviderChain(...credentialProviders)();
const baseFunction = async (awsIdentityProperties?: AwsIdentityProperties) => {
const credentials = await propertyProviderChain(...credentialProviders)(awsIdentityProperties);
if (!credentials.expiration && expireAfter !== -1) {
(credentials as Mutable<typeof credentials>).expiration = new Date(Date.now() + expireAfter);
}
Expand All @@ -75,3 +80,29 @@ export const createCredentialChain = (
});
return withOptions;
};

/**
* @internal
*/
export const propertyProviderChain =
<T>(...providers: Array<RegionalIdentityProvider<T>>): RegionalIdentityProvider<T> =>
async (awsIdentityProperties?: AwsIdentityProperties) => {
if (providers.length === 0) {
throw new ProviderError("No providers in chain");
}

let lastProviderError: Error | undefined;
for (const provider of providers) {
try {
const credentials = await provider(awsIdentityProperties);
return credentials;
} catch (err) {
lastProviderError = err;
if (err?.tryNextLink) {
continue;
}
throw err;
}
}
throw lastProviderError;
};

0 comments on commit 486f1fb

Please sign in to comment.