From 4b148a3b3267d3e213d4336a4c0c5bb1451d8033 Mon Sep 17 00:00:00 2001 From: Allan Zheng Date: Tue, 7 Jul 2020 00:39:45 -0700 Subject: [PATCH 1/2] fix(middleware-sdk-transcribe-streaming): unsign the non host headers --- .../src/signer.spec.ts | 48 +++++++++++++++++++ .../src/signer.ts | 18 +++++-- 2 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts diff --git a/packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts b/packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts new file mode 100644 index 000000000000..b3c4aa949757 --- /dev/null +++ b/packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts @@ -0,0 +1,48 @@ +import { HttpRequest } from "@aws-sdk/protocol-http"; +import { SignatureV4 } from "./signer"; +describe("transcribe streaming", () => { + describe("WebSocket request signer", () => { + const toSign = new HttpRequest({ + headers: { + "x-amz-foo": "foo", + bar: "bar", + "amz-sdk-invocation-id": "123", + "amz-sdk-request": "attempt=1", + host: "aws.amazon.com" + }, + body: "hello world", + query: { + prop1: "A", + prop2: "B" + } + }); + beforeEach(() => { + jest.mock("@aws-sdk/protocol-http"); + ((HttpRequest as any) as jest.Mock).mockReturnValue({ + isInstance: () => true + }); + }); + it("should invoke base SigV4 signer correctly", async () => { + expect.assertions(5); + const mockBaseSigner = { + presign: jest + .fn() + .mockImplementation(request => Promise.resolve(request)) + }; + const signer = new SignatureV4({ signer: mockBaseSigner as any }); + const signed = await signer.sign(toSign); + expect(toSign).toMatchObject(signed); + expect(mockBaseSigner.presign).toBeCalled(); + // The request's body should not be presigned + expect(mockBaseSigner.presign.mock.calls[0][0].body).toEqual(""); + expect( + mockBaseSigner.presign.mock.calls[0][1]!.unsignableHeaders + ).toBeDefined(); + const unsignableHeaders: Set = mockBaseSigner.presign.mock + .calls[0][1]!.unsignableHeaders; + expect([...unsignableHeaders.entries()].map(([value]) => value)).toEqual( + Object.keys(toSign.headers).filter(a => a !== "host") + ); + }); + }); +}); diff --git a/packages/middleware-sdk-transcribe-streaming/src/signer.ts b/packages/middleware-sdk-transcribe-streaming/src/signer.ts index ea9849d15a4b..132b6917f146 100644 --- a/packages/middleware-sdk-transcribe-streaming/src/signer.ts +++ b/packages/middleware-sdk-transcribe-streaming/src/signer.ts @@ -27,10 +27,20 @@ export class SignatureV4 implements RequestSigner, RequestPresigner { ): Promise { if (HttpRequest.isInstance(toSign)) { // Presign the endpoint url with empty body, otherwise - // the payload hash would be UNSINGED_PAYLOAD - const signedRequest = await this.signer.presign({ ...toSign, body: "" }, { - expiresIn: 5 * 60 // presigned url must be expired within 5 mins - } as any); + // the payload hash would be UNSINGED-PAYLOAD + const signedRequest = await this.signer.presign( + { ...toSign, body: "" }, + { + // presigned url must be expired within 5 mins. + expiresIn: 5 * 60, + // Not to sign headers. Transcribe-streaming WebSocket + // request omits headers except for required 'host' header. If we sign + // the other headers, the signature could be mismatch. + unsignableHeaders: new Set( + Object.keys(toSign.headers).filter(header => header !== "host") + ) + } + ); return { ...signedRequest, body: toSign.body From 6e86721126c581a82b962d6e4a3ab5c0221dcbe1 Mon Sep 17 00:00:00 2001 From: Allan Zheng Date: Tue, 7 Jul 2020 14:24:59 -0700 Subject: [PATCH 2/2] fix: address PR feedbacks --- .../src/signer.spec.ts | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts b/packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts index b3c4aa949757..e8d9c5acbf57 100644 --- a/packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts +++ b/packages/middleware-sdk-transcribe-streaming/src/signer.spec.ts @@ -2,28 +2,22 @@ import { HttpRequest } from "@aws-sdk/protocol-http"; import { SignatureV4 } from "./signer"; describe("transcribe streaming", () => { describe("WebSocket request signer", () => { - const toSign = new HttpRequest({ - headers: { - "x-amz-foo": "foo", - bar: "bar", - "amz-sdk-invocation-id": "123", - "amz-sdk-request": "attempt=1", - host: "aws.amazon.com" - }, - body: "hello world", - query: { - prop1: "A", - prop2: "B" - } - }); - beforeEach(() => { - jest.mock("@aws-sdk/protocol-http"); - ((HttpRequest as any) as jest.Mock).mockReturnValue({ - isInstance: () => true - }); - }); it("should invoke base SigV4 signer correctly", async () => { expect.assertions(5); + const toSign = new HttpRequest({ + headers: { + "x-amz-foo": "foo", + bar: "bar", + "amz-sdk-invocation-id": "123", + "amz-sdk-request": "attempt=1", + host: "aws.amazon.com" + }, + body: "hello world", + query: { + prop1: "A", + prop2: "B" + } + }); const mockBaseSigner = { presign: jest .fn()