diff --git a/clients/client-sesv2/package.json b/clients/client-sesv2/package.json index f1961b590622..7d5cb9ff8063 100644 --- a/clients/client-sesv2/package.json +++ b/clients/client-sesv2/package.json @@ -29,6 +29,7 @@ "@aws-sdk/middleware-recursion-detection": "*", "@aws-sdk/middleware-user-agent": "*", "@aws-sdk/region-config-resolver": "*", + "@aws-sdk/signature-v4-multi-region": "*", "@aws-sdk/types": "*", "@aws-sdk/util-endpoints": "*", "@aws-sdk/util-user-agent-browser": "*", diff --git a/clients/client-sesv2/src/SESv2Client.ts b/clients/client-sesv2/src/SESv2Client.ts index e6d7e96f51b3..1d497dff25b7 100644 --- a/clients/client-sesv2/src/SESv2Client.ts +++ b/clients/client-sesv2/src/SESv2Client.ts @@ -749,6 +749,7 @@ export class SESv2Client extends __Client< identityProviderConfigProvider: async (config: SESv2ClientResolvedConfig) => new DefaultIdentityProviderConfig({ "aws.auth#sigv4": config.credentials, + "aws.auth#sigv4a": config.credentials, }), }) ); diff --git a/clients/client-sesv2/src/auth/httpAuthSchemeProvider.ts b/clients/client-sesv2/src/auth/httpAuthSchemeProvider.ts index b2c1cadcdb7b..39653f09fbaf 100644 --- a/clients/client-sesv2/src/auth/httpAuthSchemeProvider.ts +++ b/clients/client-sesv2/src/auth/httpAuthSchemeProvider.ts @@ -1,26 +1,44 @@ // smithy-typescript generated code import { + AwsSdkSigV4AAuthInputConfig, + AwsSdkSigV4AAuthResolvedConfig, + AwsSdkSigV4APreviouslyResolved, AwsSdkSigV4AuthInputConfig, AwsSdkSigV4AuthResolvedConfig, AwsSdkSigV4PreviouslyResolved, + resolveAwsSdkSigV4AConfig, resolveAwsSdkSigV4Config, } from "@aws-sdk/core"; +import { signatureV4CrtContainer } from "@aws-sdk/signature-v4-multi-region"; +import { EndpointParameterInstructions, resolveParams } from "@smithy/middleware-endpoint"; import { + EndpointV2, HandlerExecutionContext, HttpAuthOption, HttpAuthScheme, + HttpAuthSchemeId, HttpAuthSchemeParameters, HttpAuthSchemeParametersProvider, HttpAuthSchemeProvider, + Logger, } from "@smithy/types"; import { getSmithyContext, normalizeProvider } from "@smithy/util-middleware"; +import { EndpointParameters } from "../endpoint/EndpointParameters"; +import { defaultEndpointResolver } from "../endpoint/endpointResolver"; import { SESv2ClientConfig, SESv2ClientResolvedConfig } from "../SESv2Client"; /** * @internal */ -export interface SESv2HttpAuthSchemeParameters extends HttpAuthSchemeParameters { +interface _SESv2HttpAuthSchemeParameters extends HttpAuthSchemeParameters { + region?: string; +} + +/** + * @internal + */ +export interface SESv2HttpAuthSchemeParameters extends _SESv2HttpAuthSchemeParameters, EndpointParameters { region?: string; } @@ -38,11 +56,71 @@ export interface SESv2HttpAuthSchemeParametersProvider /** * @internal */ -export const defaultSESv2HttpAuthSchemeParametersProvider = async ( +interface EndpointRuleSetSmithyContext { + commandInstance?: { + constructor?: { + getEndpointParameterInstructions(): EndpointParameterInstructions; + }; + }; +} +/** + * @internal + */ +interface EndpointRuleSetHttpAuthSchemeParametersProvider< + TConfig extends object, + TContext extends HandlerExecutionContext, + TParameters extends HttpAuthSchemeParameters & EndpointParameters, + TInput extends object +> extends HttpAuthSchemeParametersProvider {} +/** + * @internal + */ +const createEndpointRuleSetHttpAuthSchemeParametersProvider = + < + TConfig extends object, + TContext extends HandlerExecutionContext, + THttpAuthSchemeParameters extends HttpAuthSchemeParameters, + TEndpointParameters extends EndpointParameters, + TParameters extends THttpAuthSchemeParameters & TEndpointParameters, + TInput extends object + >( + defaultHttpAuthSchemeParametersProvider: HttpAuthSchemeParametersProvider< + TConfig, + TContext, + THttpAuthSchemeParameters, + TInput + > + ): EndpointRuleSetHttpAuthSchemeParametersProvider< + TConfig, + TContext, + THttpAuthSchemeParameters & TEndpointParameters, + TInput + > => + async (config: TConfig, context: TContext, input: TInput): Promise => { + if (!input) { + throw new Error(`Could not find \`input\` for \`defaultEndpointRuleSetHttpAuthSchemeParametersProvider\``); + } + const defaultParameters = await defaultHttpAuthSchemeParametersProvider(config, context, input); + const instructionsFn = (getSmithyContext(context) as EndpointRuleSetSmithyContext)?.commandInstance?.constructor + ?.getEndpointParameterInstructions; + if (!instructionsFn) { + throw new Error(`getEndpointParameterInstructions() is not defined on \`${context.commandName!}\``); + } + const endpointParameters = await resolveParams( + input as Record, + { getEndpointParameterInstructions: instructionsFn! }, + config as Record + ); + return Object.assign(defaultParameters, endpointParameters) as TParameters; + }; +/** + * @internal + */ +const _defaultSESv2HttpAuthSchemeParametersProvider = async ( config: SESv2ClientResolvedConfig, context: HandlerExecutionContext, input: object -): Promise => { +): Promise<_SESv2HttpAuthSchemeParameters> => { return { operation: getSmithyContext(context).operation as string, region: @@ -52,6 +130,11 @@ export const defaultSESv2HttpAuthSchemeParametersProvider = async ( })(), }; }; +/** + * @internal + */ +export const defaultSESv2HttpAuthSchemeParametersProvider: SESv2HttpAuthSchemeParametersProvider = + createEndpointRuleSetHttpAuthSchemeParametersProvider(_defaultSESv2HttpAuthSchemeParametersProvider); function createAwsAuthSigv4HttpAuthOption(authParameters: SESv2HttpAuthSchemeParameters): HttpAuthOption { return { @@ -72,6 +155,30 @@ function createAwsAuthSigv4HttpAuthOption(authParameters: SESv2HttpAuthSchemePar }; } +function createAwsAuthSigv4aHttpAuthOption(authParameters: SESv2HttpAuthSchemeParameters): HttpAuthOption { + return { + schemeId: "aws.auth#sigv4a", + signingProperties: { + name: "ses", + region: authParameters.region, + }, + propertiesExtractor: (config: Partial, context) => ({ + /** + * @internal + */ + signingProperties: { + config, + context, + }, + }), + }; +} + +/** + * @internal + */ +interface _SESv2HttpAuthSchemeProvider extends HttpAuthSchemeProvider {} + /** * @internal */ @@ -80,20 +187,102 @@ export interface SESv2HttpAuthSchemeProvider extends HttpAuthSchemeProvider { +interface EndpointRuleSetHttpAuthSchemeProvider< + EndpointParametersT extends EndpointParameters, + HttpAuthSchemeParametersT extends HttpAuthSchemeParameters +> extends HttpAuthSchemeProvider {} +/** + * @internal + */ +interface DefaultEndpointResolver { + (params: EndpointParametersT, context?: { logger?: Logger }): EndpointV2; +} +/** + * @internal + */ +const createEndpointRuleSetHttpAuthSchemeProvider = < + EndpointParametersT extends EndpointParameters, + HttpAuthSchemeParametersT extends HttpAuthSchemeParameters +>( + defaultEndpointResolver: DefaultEndpointResolver, + defaultHttpAuthSchemeResolver: HttpAuthSchemeProvider, + createHttpAuthOptionFunctions: Record< + HttpAuthSchemeId, + (authParameters: EndpointParametersT & HttpAuthSchemeParametersT) => HttpAuthOption + > +): EndpointRuleSetHttpAuthSchemeProvider => { + const endpointRuleSetHttpAuthSchemeProvider: EndpointRuleSetHttpAuthSchemeProvider< + EndpointParametersT, + HttpAuthSchemeParametersT + > = (authParameters) => { + const endpoint: EndpointV2 = defaultEndpointResolver(authParameters); + const authSchemes = endpoint.properties?.authSchemes; + if (!authSchemes) { + return defaultHttpAuthSchemeResolver(authParameters); + } + const options: HttpAuthOption[] = []; + for (const scheme of authSchemes) { + const { name: resolvedName, properties = {}, ...rest } = scheme; + const name = resolvedName.toLowerCase(); + if (resolvedName !== name) { + console.warn(`HttpAuthScheme has been normalized with lowercasing: \`${resolvedName}\` to \`${name}\``); + } + let schemeId; + if (name === "sigv4a") { + schemeId = "aws.auth#sigv4a"; + const sigv4Present = authSchemes.find((s) => { + const name = s.name.toLowerCase(); + return name !== "sigv4a" && name.startsWith("sigv4"); + }); + if (!signatureV4CrtContainer.CrtSignerV4 && sigv4Present) { + // sigv4a -> sigv4 fallback. + continue; + } + } else if (name.startsWith("sigv4")) { + schemeId = "aws.auth#sigv4"; + } else { + throw new Error(`Unknown HttpAuthScheme found in \`@smithy.rules#endpointRuleSet\`: \`${name}\``); + } + const createOption = createHttpAuthOptionFunctions[schemeId]; + if (!createOption) { + throw new Error(`Could not find HttpAuthOption create function for \`${schemeId}\``); + } + const option = createOption(authParameters); + option.schemeId = schemeId; + option.signingProperties = { ...(option.signingProperties || {}), ...rest, ...properties }; + options.push(option); + } + return options; + }; + + return endpointRuleSetHttpAuthSchemeProvider; +}; +/** + * @internal + */ +const _defaultSESv2HttpAuthSchemeProvider: _SESv2HttpAuthSchemeProvider = (authParameters) => { const options: HttpAuthOption[] = []; switch (authParameters.operation) { default: { options.push(createAwsAuthSigv4HttpAuthOption(authParameters)); + options.push(createAwsAuthSigv4aHttpAuthOption(authParameters)); } } return options; }; +/** + * @internal + */ +export const defaultSESv2HttpAuthSchemeProvider: SESv2HttpAuthSchemeProvider = + createEndpointRuleSetHttpAuthSchemeProvider(defaultEndpointResolver, _defaultSESv2HttpAuthSchemeProvider, { + "aws.auth#sigv4": createAwsAuthSigv4HttpAuthOption, + "aws.auth#sigv4a": createAwsAuthSigv4aHttpAuthOption, + }); /** * @internal */ -export interface HttpAuthSchemeInputConfig extends AwsSdkSigV4AuthInputConfig { +export interface HttpAuthSchemeInputConfig extends AwsSdkSigV4AuthInputConfig, AwsSdkSigV4AAuthInputConfig { /** * Configuration of HttpAuthSchemes for a client which provides default identity providers and signers per auth scheme. * @internal @@ -110,7 +299,7 @@ export interface HttpAuthSchemeInputConfig extends AwsSdkSigV4AuthInputConfig { /** * @internal */ -export interface HttpAuthSchemeResolvedConfig extends AwsSdkSigV4AuthResolvedConfig { +export interface HttpAuthSchemeResolvedConfig extends AwsSdkSigV4AuthResolvedConfig, AwsSdkSigV4AAuthResolvedConfig { /** * Configuration of HttpAuthSchemes for a client which provides default identity providers and signers per auth scheme. * @internal @@ -128,10 +317,11 @@ export interface HttpAuthSchemeResolvedConfig extends AwsSdkSigV4AuthResolvedCon * @internal */ export const resolveHttpAuthSchemeConfig = ( - config: T & HttpAuthSchemeInputConfig & AwsSdkSigV4PreviouslyResolved + config: T & HttpAuthSchemeInputConfig & AwsSdkSigV4PreviouslyResolved & AwsSdkSigV4APreviouslyResolved ): T & HttpAuthSchemeResolvedConfig => { const config_0 = resolveAwsSdkSigV4Config(config); + const config_1 = resolveAwsSdkSigV4AConfig(config_0); return { - ...config_0, + ...config_1, } as T & HttpAuthSchemeResolvedConfig; }; diff --git a/clients/client-sesv2/src/runtimeConfig.shared.ts b/clients/client-sesv2/src/runtimeConfig.shared.ts index e7687653e4a0..1c984da9ecd1 100644 --- a/clients/client-sesv2/src/runtimeConfig.shared.ts +++ b/clients/client-sesv2/src/runtimeConfig.shared.ts @@ -1,5 +1,6 @@ // smithy-typescript generated code -import { AwsSdkSigV4Signer } from "@aws-sdk/core"; +import { AwsSdkSigV4ASigner, AwsSdkSigV4Signer } from "@aws-sdk/core"; +import { SignatureV4MultiRegion } from "@aws-sdk/signature-v4-multi-region"; import { NoOpLogger } from "@smithy/smithy-client"; import { IdentityProviderConfig } from "@smithy/types"; import { parseUrl } from "@smithy/url-parser"; @@ -28,9 +29,15 @@ export const getRuntimeConfig = (config: SESv2ClientConfig) => { identityProvider: (ipc: IdentityProviderConfig) => ipc.getIdentityProvider("aws.auth#sigv4"), signer: new AwsSdkSigV4Signer(), }, + { + schemeId: "aws.auth#sigv4a", + identityProvider: (ipc: IdentityProviderConfig) => ipc.getIdentityProvider("aws.auth#sigv4a"), + signer: new AwsSdkSigV4ASigner(), + }, ], logger: config?.logger ?? new NoOpLogger(), serviceId: config?.serviceId ?? "SESv2", + signerConstructor: config?.signerConstructor ?? SignatureV4MultiRegion, urlParser: config?.urlParser ?? parseUrl, utf8Decoder: config?.utf8Decoder ?? fromUtf8, utf8Encoder: config?.utf8Encoder ?? toUtf8, diff --git a/clients/client-sesv2/src/runtimeConfig.ts b/clients/client-sesv2/src/runtimeConfig.ts index ce93eef27297..196d53267f54 100644 --- a/clients/client-sesv2/src/runtimeConfig.ts +++ b/clients/client-sesv2/src/runtimeConfig.ts @@ -2,7 +2,7 @@ // @ts-ignore: package.json will be imported from dist folders import packageInfo from "../package.json"; // eslint-disable-line -import { emitWarningIfUnsupportedVersion as awsCheckVersion } from "@aws-sdk/core"; +import { NODE_SIGV4A_CONFIG_OPTIONS, emitWarningIfUnsupportedVersion as awsCheckVersion } from "@aws-sdk/core"; import { defaultProvider as credentialDefaultProvider } from "@aws-sdk/credential-provider-node"; import { NODE_APP_ID_CONFIG_OPTIONS, createDefaultUserAgentProvider } from "@aws-sdk/util-user-agent-node"; import { @@ -52,6 +52,7 @@ export const getRuntimeConfig = (config: SESv2ClientConfig) => { default: async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE, }), sha256: config?.sha256 ?? Hash.bind(null, "sha256"), + sigv4aSigningRegionSet: config?.sigv4aSigningRegionSet ?? loadNodeConfig(NODE_SIGV4A_CONFIG_OPTIONS), streamCollector: config?.streamCollector ?? streamCollector, useDualstackEndpoint: config?.useDualstackEndpoint ?? loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS), useFipsEndpoint: config?.useFipsEndpoint ?? loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS), diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsTraitsUtils.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsTraitsUtils.java index f55183ac300a..84b5108f2b33 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsTraitsUtils.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsTraitsUtils.java @@ -38,7 +38,8 @@ public final class AwsTraitsUtils { private static final Set ENDPOINT_RULESET_HTTP_AUTH_SCHEME_SERVICES = Set.of( ShapeId.from("com.amazonaws.s3#AmazonS3"), ShapeId.from("com.amazonaws.eventbridge#AWSEvents"), - ShapeId.from("com.amazonaws.cloudfrontkeyvaluestore#CloudFrontKeyValueStore") + ShapeId.from("com.amazonaws.cloudfrontkeyvaluestore#CloudFrontKeyValueStore"), + ShapeId.from("com.amazonaws.sesv2#SimpleEmailService_v2") ); private AwsTraitsUtils() {} diff --git a/yarn.lock b/yarn.lock index 923dc14bab1a..12ccfa4bbda5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20360,6 +20360,7 @@ __metadata: "@aws-sdk/middleware-recursion-detection": "npm:*" "@aws-sdk/middleware-user-agent": "npm:*" "@aws-sdk/region-config-resolver": "npm:*" + "@aws-sdk/signature-v4-multi-region": "npm:*" "@aws-sdk/types": "npm:*" "@aws-sdk/util-endpoints": "npm:*" "@aws-sdk/util-user-agent-browser": "npm:*"