Skip to content

Commit

Permalink
feat(credential-provider-ini): defer other credential providers in in…
Browse files Browse the repository at this point in the history
…i provider
  • Loading branch information
kuhe committed Jan 29, 2024
1 parent ee8c4b9 commit b6c9839
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 37 deletions.
2 changes: 1 addition & 1 deletion packages/credential-provider-ini/src/fromIni.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AssumeRoleWithWebIdentityParams } from "@aws-sdk/credential-provider-web-identity";
import type { AssumeRoleWithWebIdentityParams } from "@aws-sdk/credential-provider-web-identity";
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { getProfileName, parseKnownFiles, SourceProfileInit } from "@smithy/shared-ini-file-loader";
import type { AwsCredentialIdentity, AwsCredentialIdentityProvider, Pluggable } from "@smithy/types";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CredentialsProviderError } from "@smithy/property-provider";
import { getProfileName } from "@smithy/shared-ini-file-loader";
import { ParsedIniData, Profile } from "@smithy/types";
import { AwsCredentialIdentity, ParsedIniData, Profile } from "@smithy/types";

import { FromIniInit } from "./fromIni";
import { resolveCredentialSource } from "./resolveCredentialSource";
Expand Down Expand Up @@ -101,12 +101,12 @@ export const resolveAssumeRoleCredentials = async (
);
}

const sourceCredsProvider = source_profile
const sourceCredsProvider: Promise<AwsCredentialIdentity> = source_profile
? resolveProfileData(source_profile, profiles, options, {
...visitedProfiles,
[source_profile]: true,
})
: resolveCredentialSource(data.credential_source!, profileName)(options)();
: (await resolveCredentialSource(data.credential_source!, profileName)(options))();

const params: AssumeRoleParams = {
RoleArn: data.role_arn!,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
jest.mock("@aws-sdk/credential-provider-env");
jest.mock("@smithy/credential-provider-imds");

import { fromEnv } from "@aws-sdk/credential-provider-env";
import { fromContainerMetadata, fromInstanceMetadata } from "@smithy/credential-provider-imds";
import { CredentialsProviderError } from "@smithy/property-provider";

import { resolveCredentialSource } from "./resolveCredentialSource";

jest.mock("@aws-sdk/credential-provider-env");
jest.mock("@smithy/credential-provider-imds");

describe(resolveCredentialSource.name, () => {
const mockProfileName = "mockProfileName";

const mockCreds = {
accessKeyId: "mockAccessKeyId",
secretAccessKey: "mockSecretAccessKey",
};

const mockFakeCreds = {
accessKeyId: "mockFakeAccessKeyId",
secretAccessKey: "mockFakeSecretAccessKey",
};

const mockCreds = {
accessKeyId: "mockAccessKeyId",
secretAccessKey: "mockSecretAccessKey",
};

beforeEach(() => {
(fromEnv as jest.Mock).mockReturnValue(() => Promise.resolve(mockFakeCreds));
(fromContainerMetadata as jest.Mock).mockReturnValue(() => Promise.resolve(mockFakeCreds));
Expand All @@ -36,9 +36,16 @@ describe(resolveCredentialSource.name, () => {
["Environment", fromEnv],
])("when credentialSource=%s, calls %p", async (credentialSource, fromFn) => {
(fromFn as jest.Mock).mockReturnValue(() => Promise.resolve(mockCreds));
const receivedCreds = await resolveCredentialSource(credentialSource, mockProfileName)()();
const providerFactory = resolveCredentialSource(credentialSource, mockProfileName);
expect(typeof providerFactory).toEqual("function");

const provider = await providerFactory();
expect(typeof provider).toEqual("function");

const receivedCreds = await provider();
expect(receivedCreds).toStrictEqual(mockCreds);
expect(fromFn).toHaveBeenCalledWith();

expect(fromFn).toHaveBeenCalled();
[fromContainerMetadata, fromInstanceMetadata, fromEnv]
.filter((fn) => fn !== fromFn)
.forEach((fnNotCalled) => {
Expand All @@ -53,7 +60,9 @@ describe(resolveCredentialSource.name, () => {
`expected EcsContainer or Ec2InstanceMetadata or Environment.`
);
try {
await resolveCredentialSource(mockCredentialSource, mockProfileName)()();
await (
await resolveCredentialSource(mockCredentialSource, mockProfileName)()
)();
fail(`expected ${expectedError}`);
} catch (error) {
expect(error).toStrictEqual(expectedError);
Expand Down
17 changes: 9 additions & 8 deletions packages/credential-provider-ini/src/resolveCredentialSource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { fromEnv } from "@aws-sdk/credential-provider-env";
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { fromContainerMetadata, fromInstanceMetadata } from "@smithy/credential-provider-imds";
import { CredentialsProviderError } from "@smithy/property-provider";
import { AwsCredentialIdentityProvider } from "@smithy/types";

Expand All @@ -16,14 +14,17 @@ import { AwsCredentialIdentityProvider } from "@smithy/types";
export const resolveCredentialSource = (
credentialSource: string,
profileName: string
): ((options?: CredentialProviderOptions) => AwsCredentialIdentityProvider) => {
const sourceProvidersMap: Record<string, (options?: CredentialProviderOptions) => AwsCredentialIdentityProvider> = {
EcsContainer: fromContainerMetadata,
Ec2InstanceMetadata: fromInstanceMetadata,
Environment: fromEnv,
): ((options?: CredentialProviderOptions) => Promise<AwsCredentialIdentityProvider>) => {
const sourceProvidersMap = {
EcsContainer: (options?: CredentialProviderOptions) =>
import("@smithy/credential-provider-imds").then(({ fromContainerMetadata }) => fromContainerMetadata(options)),
Ec2InstanceMetadata: (options?: CredentialProviderOptions) =>
import("@smithy/credential-provider-imds").then(({ fromInstanceMetadata }) => fromInstanceMetadata(options)),
Environment: (options?: CredentialProviderOptions) =>
import("@aws-sdk/credential-provider-env").then(({ fromEnv }) => fromEnv(options)),
};
if (credentialSource in sourceProvidersMap) {
return sourceProvidersMap[credentialSource];
return sourceProvidersMap[credentialSource as keyof typeof sourceProvidersMap];
} else {
throw new CredentialsProviderError(
`Unsupported credential source in profile ${profileName}. Got ${credentialSource}, ` +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { fromProcess } from "@aws-sdk/credential-provider-process";
import { Credentials } from "@aws-sdk/types";
import { Profile } from "@smithy/types";
import { Credentials, Profile } from "@aws-sdk/types";

import { FromIniInit } from "./fromIni";

Expand All @@ -21,7 +19,9 @@ export const isProcessProfile = (arg: any): arg is ProcessProfile =>
* @internal
*/
export const resolveProcessCredentials = async (options: FromIniInit, profile: string): Promise<Credentials> =>
fromProcess({
...options,
profile,
})();
import("@aws-sdk/credential-provider-process").then(({ fromProcess }) =>
fromProcess({
...options,
profile,
})()
);
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { fromTokenFile } from "@aws-sdk/credential-provider-web-identity";
import { AwsCredentialIdentity, Profile } from "@smithy/types";

import { FromIniInit } from "./fromIni";
Expand Down Expand Up @@ -29,9 +28,11 @@ export const resolveWebIdentityCredentials = async (
profile: WebIdentityProfile,
options: FromIniInit
): Promise<AwsCredentialIdentity> =>
fromTokenFile({
webIdentityTokenFile: profile.web_identity_token_file,
roleArn: profile.role_arn,
roleSessionName: profile.role_session_name,
roleAssumerWithWebIdentity: options.roleAssumerWithWebIdentity,
})();
import("@aws-sdk/credential-provider-web-identity").then(({ fromTokenFile }) =>
fromTokenFile({
webIdentityTokenFile: profile.web_identity_token_file,
roleArn: profile.role_arn,
roleSessionName: profile.role_session_name,
roleAssumerWithWebIdentity: options.roleAssumerWithWebIdentity,
})()
);

0 comments on commit b6c9839

Please sign in to comment.