Skip to content

Commit

Permalink
feat(core): add AWS SDK @aws.auth#sigv4a support and scaffold generic
Browse files Browse the repository at this point in the history
  • Loading branch information
syall committed Dec 14, 2023
1 parent f3837c0 commit cdb5312
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 1 deletion.
72 changes: 72 additions & 0 deletions packages/core/src/httpAuthSchemes/aws-sdk/AWSSDKSigV4ASigner.ts
@@ -0,0 +1,72 @@
import { HttpRequest } from "@smithy/protocol-http";
import {
AuthScheme,
AwsCredentialIdentity,
HandlerExecutionContext,
HttpRequest as IHttpRequest,
RequestSigner,
} from "@smithy/types";

import { AWSSDKSigV4Config, AWSSDKSigV4Signer } from "./AWSSDKSigV4Signer";
import { getSkewCorrectedDate } from "../utils";
import { throwAWSSDKSigningPropertyError } from "./throwAWSSDKSigningPropertyError";

/**
* @internal
*/
interface AWSSDKSigV4AAuthSigningProperties {
config: AWSSDKSigV4Config;
signer: RequestSigner;
signingRegionSet?: string;
signingName?: string;
}

const validateSigningProperties = async (
signingProperties: Record<string, unknown>
): Promise<AWSSDKSigV4AAuthSigningProperties> => {
const context = throwAWSSDKSigningPropertyError(
"context",
signingProperties.context as HandlerExecutionContext | undefined
);
const config = throwAWSSDKSigningPropertyError("config", signingProperties.config as AWSSDKSigV4Config | undefined);
const authScheme = context.endpointV2?.properties?.authSchemes?.[0];
const signerFunction = throwAWSSDKSigningPropertyError(
"signer",
config.signer as ((authScheme?: AuthScheme) => Promise<RequestSigner>) | undefined
);
const signer = await signerFunction(authScheme);
const signingRegionSet = (signingProperties?.signingRegionSet as string[] | undefined)?.join(",");
const signingName = signingProperties?.signingName as string | undefined;
return {
config,
signer,
signingRegionSet,
signingName,
};
};

/**
* @internal
*/
export class AWSSDKSigV4ASigner extends AWSSDKSigV4Signer {
async sign(
httpRequest: IHttpRequest,
/**
* `identity` is bound in {@link resolveAWSSDKSigV4Config}
*/
identity: AwsCredentialIdentity,
signingProperties: Record<string, unknown>
): Promise<IHttpRequest> {
if (!HttpRequest.isInstance(httpRequest)) {
throw new Error("The request is not an instance of `HttpRequest` and cannot be signed");
}
const { config, signer, signingRegionSet, signingName } = await validateSigningProperties(signingProperties);

// TODO(experimentalIdentityAndAuth): sigv4a signer
return await signer.sign(httpRequest, {
signingDate: getSkewCorrectedDate(config.systemClockOffset),
signingRegion: signingRegionSet,
signingService: signingName,
});
}
}
Expand Up @@ -16,7 +16,7 @@ import { throwAWSSDKSigningPropertyError } from "./throwAWSSDKSigningPropertyErr
/**
* @internal
*/
interface AWSSDKSigV4Config {
export interface AWSSDKSigV4Config {
systemClockOffset: number;
signer: (authScheme?: AuthScheme) => Promise<RequestSigner>;
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/httpAuthSchemes/aws-sdk/index.ts
@@ -1,2 +1,3 @@
export * from "./AWSSDKSigV4Signer";
export * from "./AWSSDKSigV4ASigner";
export * from "./resolveAWSSDKSigV4Config";
Empty file.
Empty file.
49 changes: 49 additions & 0 deletions packages/core/src/httpAuthSchemes/sigv4/resolveSigV4Config.ts
@@ -0,0 +1,49 @@
import { ChecksumConstructor, HashConstructor, Provider } from "@smithy/types";

/**
* @public
*/
export interface SigV4AuthInputConfig {
/**
* Whether to escape request path when signing the request.
*/
signingEscapePath?: boolean;

/**
* An offset value in milliseconds to apply to all signing times.
*/
systemClockOffset?: number;
}

interface SigV4PreviouslyResolved {
region: string | Provider<string>;
sha256: ChecksumConstructor | HashConstructor;
signingName: string;
}

export interface SigV4AuthResolvedConfig {
/**
* Resolved value for input config {@link AwsAuthInputConfig.signingEscapePath}
*/
signingEscapePath: boolean;
/**
* Resolved value for input config {@link AwsAuthInputConfig.systemClockOffset}
*/
systemClockOffset: number;
}

export const resolveSigV4AuthConfig = <T>(
input: T & SigV4AuthInputConfig & SigV4PreviouslyResolved
): T & SigV4AuthResolvedConfig => {
const {
// Default for signingEscapePath
signingEscapePath = true,
// Default for systemClockOffset
systemClockOffset = input.systemClockOffset || 0,
} = input;
return {
...input,
systemClockOffset,
signingEscapePath,
};
};

0 comments on commit cdb5312

Please sign in to comment.