Skip to content

Commit

Permalink
chore(credential-providers): move base fromTempCreds impl to non-brow…
Browse files Browse the repository at this point in the history
…ser file (#6836)
  • Loading branch information
kuhe authored Jan 21, 2025
1 parent 62ba401 commit 84d6c18
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 79 deletions.
75 changes: 75 additions & 0 deletions packages/credential-providers/src/fromTemporaryCredentials.base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import type { AssumeRoleCommandInput, STSClient, STSClientConfig } from "@aws-sdk/nested-clients/sts";
import type {
AwsIdentityProperties,
CredentialProviderOptions,
RuntimeConfigAwsCredentialIdentityProvider,
} from "@aws-sdk/types";
import { CredentialsProviderError } from "@smithy/property-provider";
import { AwsCredentialIdentity, AwsCredentialIdentityProvider, Pluggable } from "@smithy/types";

export interface FromTemporaryCredentialsOptions extends CredentialProviderOptions {
params: Omit<AssumeRoleCommandInput, "RoleSessionName"> & { RoleSessionName?: string };
masterCredentials?: AwsCredentialIdentity | AwsCredentialIdentityProvider;
clientConfig?: STSClientConfig;
clientPlugins?: Pluggable<any, any>[];
mfaCodeProvider?: (mfaSerial: string) => Promise<string>;
}

export const fromTemporaryCredentials = (
options: FromTemporaryCredentialsOptions,
credentialDefaultProvider?: () => AwsCredentialIdentityProvider
): RuntimeConfigAwsCredentialIdentityProvider => {
let stsClient: STSClient;
return async (awsIdentityProperties: AwsIdentityProperties = {}): Promise<AwsCredentialIdentity> => {
options.logger?.debug("@aws-sdk/credential-providers - fromTemporaryCredentials (STS)");
const params = { ...options.params, RoleSessionName: options.params.RoleSessionName ?? "aws-sdk-js-" + Date.now() };
if (params?.SerialNumber) {
if (!options.mfaCodeProvider) {
throw new CredentialsProviderError(
`Temporary credential requires multi-factor authentication, but no MFA code callback was provided.`,
{
tryNextLink: false,
logger: options.logger,
}
);
}
params.TokenCode = await options.mfaCodeProvider(params?.SerialNumber);
}

const { AssumeRoleCommand, STSClient } = await import("./loadSts");

if (!stsClient) {
const defaultCredentialsOrError =
typeof credentialDefaultProvider === "function" ? credentialDefaultProvider() : undefined;

const { callerClientConfig } = awsIdentityProperties;
stsClient = new STSClient({
...options.clientConfig,
credentials:
options.masterCredentials ??
options.clientConfig?.credentials ??
callerClientConfig?.credentialDefaultProvider?.() ??
defaultCredentialsOrError,
});
}
if (options.clientPlugins) {
for (const plugin of options.clientPlugins) {
stsClient.middlewareStack.use(plugin);
}
}
const { Credentials } = await stsClient.send(new AssumeRoleCommand(params));
if (!Credentials || !Credentials.AccessKeyId || !Credentials.SecretAccessKey) {
throw new CredentialsProviderError(`Invalid response from STS.assumeRole call with role ${params.RoleArn}`, {
logger: options.logger,
});
}
return {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
expiration: Credentials.Expiration,
// TODO(credentialScope): access normally when shape is updated.
credentialScope: (Credentials as any).CredentialScope,
};
};
};
Original file line number Diff line number Diff line change
@@ -1,75 +1 @@
import type { AssumeRoleCommandInput, STSClient, STSClientConfig } from "@aws-sdk/nested-clients/sts";
import type {
AwsIdentityProperties,
CredentialProviderOptions,
RuntimeConfigAwsCredentialIdentityProvider,
} from "@aws-sdk/types";
import { CredentialsProviderError } from "@smithy/property-provider";
import { AwsCredentialIdentity, AwsCredentialIdentityProvider, Pluggable } from "@smithy/types";

export interface FromTemporaryCredentialsOptions extends CredentialProviderOptions {
params: Omit<AssumeRoleCommandInput, "RoleSessionName"> & { RoleSessionName?: string };
masterCredentials?: AwsCredentialIdentity | AwsCredentialIdentityProvider;
clientConfig?: STSClientConfig;
clientPlugins?: Pluggable<any, any>[];
mfaCodeProvider?: (mfaSerial: string) => Promise<string>;
}

export const fromTemporaryCredentials = (
options: FromTemporaryCredentialsOptions,
credentialDefaultProvider?: () => AwsCredentialIdentityProvider
): RuntimeConfigAwsCredentialIdentityProvider => {
let stsClient: STSClient;
return async (awsIdentityProperties: AwsIdentityProperties = {}): Promise<AwsCredentialIdentity> => {
options.logger?.debug("@aws-sdk/credential-providers - fromTemporaryCredentials (STS)");
const params = { ...options.params, RoleSessionName: options.params.RoleSessionName ?? "aws-sdk-js-" + Date.now() };
if (params?.SerialNumber) {
if (!options.mfaCodeProvider) {
throw new CredentialsProviderError(
`Temporary credential requires multi-factor authentication, but no MFA code callback was provided.`,
{
tryNextLink: false,
logger: options.logger,
}
);
}
params.TokenCode = await options.mfaCodeProvider(params?.SerialNumber);
}

const { AssumeRoleCommand, STSClient } = await import("./loadSts");

if (!stsClient) {
const defaultCredentialsOrError =
typeof credentialDefaultProvider === "function" ? credentialDefaultProvider() : undefined;

const { callerClientConfig } = awsIdentityProperties;
stsClient = new STSClient({
...options.clientConfig,
credentials:
options.masterCredentials ??
options.clientConfig?.credentials ??
callerClientConfig?.credentialDefaultProvider?.() ??
defaultCredentialsOrError,
});
}
if (options.clientPlugins) {
for (const plugin of options.clientPlugins) {
stsClient.middlewareStack.use(plugin);
}
}
const { Credentials } = await stsClient.send(new AssumeRoleCommand(params));
if (!Credentials || !Credentials.AccessKeyId || !Credentials.SecretAccessKey) {
throw new CredentialsProviderError(`Invalid response from STS.assumeRole call with role ${params.RoleArn}`, {
logger: options.logger,
});
}
return {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
expiration: Credentials.Expiration,
// TODO(credentialScope): access normally when shape is updated.
credentialScope: (Credentials as any).CredentialScope,
};
};
};
export { FromTemporaryCredentialsOptions, fromTemporaryCredentials } from "./fromTemporaryCredentials.base";
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { AssumeRoleCommand, STSClient } from "@aws-sdk/nested-clients/sts";
import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest";
import { beforeEach, describe, expect, test as it, vi } from "vitest";

import { fromTemporaryCredentials as fromTemporaryCredentialsNode } from "./fromTemporaryCredentials";
import { fromTemporaryCredentials } from "./fromTemporaryCredentials.browser";
import { fromTemporaryCredentials } from "./fromTemporaryCredentials.base";

const mockSend = vi.fn();
const mockUsePlugin = vi.fn();
Expand Down
4 changes: 2 additions & 2 deletions packages/credential-providers/src/fromTemporaryCredentials.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { RuntimeConfigAwsCredentialIdentityProvider } from "@aws-sdk/types";

import { fromNodeProviderChain } from "./fromNodeProviderChain";
import type { FromTemporaryCredentialsOptions } from "./fromTemporaryCredentials.browser";
import { fromTemporaryCredentials as fromTemporaryCredentialsBase } from "./fromTemporaryCredentials.browser";
import type { FromTemporaryCredentialsOptions } from "./fromTemporaryCredentials.base";
import { fromTemporaryCredentials as fromTemporaryCredentialsBase } from "./fromTemporaryCredentials.base";

/**
* @public
Expand Down

0 comments on commit 84d6c18

Please sign in to comment.