Skip to content

Commit

Permalink
feat(signature-v4): add support to override the set of unsignableHead…
Browse files Browse the repository at this point in the history
…ers (#420)

Co-Authored-By: Trivikram Kamat <16024985+trivikr@users.noreply.github.com>
  • Loading branch information
ronak2121 and trivikr committed Oct 29, 2019
1 parent ae71c3e commit 8d6b27a
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 8 deletions.
21 changes: 21 additions & 0 deletions packages/signature-v4/src/SignatureV4.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,27 @@ describe("SignatureV4", () => {
);
});

it("should allow specifying custom signable headers to override custom and always unsignable ones", async () => {
const { headers } = await signer.sign(
{
...minimalRequest,
headers: {
host: "foo.us-bar-1.amazonaws.com",
foo: "bar",
"user-agent": "baz"
}
},
{
signingDate: new Date("2000-01-01T00:00:00.000Z"),
unsignableHeaders: new Set(["foo"]),
signableHeaders: new Set(["foo", "user-agent"])
}
);
expect(headers[AUTH_HEADER]).toMatch(
/^AWS4-HMAC-SHA256 Credential=foo\/20000101\/us-bar-1\/foo\/aws4_request, SignedHeaders=foo;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=/
);
});

it("should support signing with asynchronously resolved credentials", async () => {
const credsProvider = () =>
Promise.resolve({
Expand Down
29 changes: 23 additions & 6 deletions packages/signature-v4/src/SignatureV4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ export class SignatureV4
this.credentialProvider()
]);

const { signingDate = new Date(), unsignableHeaders } = options;
const {
signingDate = new Date(),
unsignableHeaders,
signableHeaders
} = options;

const { longDate, shortDate } = formatDate(signingDate);
const ttl = getTtl(signingDate, expiration);
Expand All @@ -158,7 +162,11 @@ export class SignatureV4
request.query[AMZ_DATE_QUERY_PARAM] = longDate;
request.query[EXPIRES_QUERY_PARAM] = ttl.toString(10);

const canonicalHeaders = getCanonicalHeaders(request, unsignableHeaders);
const canonicalHeaders = getCanonicalHeaders(
request,
unsignableHeaders,
signableHeaders
);
request.query[SIGNED_HEADERS_QUERY_PARAM] = getCanonicalHeaderList(
canonicalHeaders
);
Expand Down Expand Up @@ -205,14 +213,18 @@ export class SignatureV4
credentials
) as Promise<T>;
} else {
const { unsignableHeaders } = options as RequestSigningArguments;
const {
unsignableHeaders,
signableHeaders
} = options as RequestSigningArguments;

return this.signRequest(
toSign as HttpRequest<any>,
signingDate,
region,
credentials,
unsignableHeaders
unsignableHeaders,
signableHeaders
) as Promise<T>;
}
}
Expand All @@ -237,7 +249,8 @@ export class SignatureV4
signingDate: DateInput,
region: string,
credentials: Credentials,
unsignableHeaders?: Set<string>
unsignableHeaders?: Set<string>,
signableHeaders?: Set<string>
): Promise<HttpRequest<any>> {
const request = prepareRequest(originalRequest);
const { longDate, shortDate } = formatDate(signingDate);
Expand All @@ -253,7 +266,11 @@ export class SignatureV4
request.headers[SHA256_HEADER] = payloadHash;
}

const canonicalHeaders = getCanonicalHeaders(request, unsignableHeaders);
const canonicalHeaders = getCanonicalHeaders(
request,
unsignableHeaders,
signableHeaders
);
const signature = await this.getSignature(
longDate,
scope,
Expand Down
26 changes: 26 additions & 0 deletions packages/signature-v4/src/getCanonicalHeaders.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,30 @@ describe("getCanonicalHeaders", () => {
host: "foo.us-east-1.amazonaws.com"
});
});

it("should allow specifying custom signable headers that override unsignable ones", () => {
const request: HttpRequest<never> = {
method: "POST",
protocol: "https:",
path: "/",
headers: {
host: "foo.us-east-1.amazonaws.com",
foo: "bar",
"user-agent": "foo-user"
},
hostname: "foo.us-east-1.amazonaws.com"
};

expect(
getCanonicalHeaders(
request,
new Set(["foo"]),
new Set(["foo", "user-agent"])
)
).toEqual({
host: "foo.us-east-1.amazonaws.com",
foo: "bar",
"user-agent": "foo-user"
});
});
});
10 changes: 8 additions & 2 deletions packages/signature-v4/src/getCanonicalHeaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
*/
export function getCanonicalHeaders(
{ headers }: HttpRequest<any>,
unsignableHeaders?: Set<string>
unsignableHeaders?: Set<string>,
signableHeaders?: Set<string>
): HeaderBag {
const canonical: HeaderBag = {};
for (let headerName of Object.keys(headers).sort()) {
Expand All @@ -21,7 +22,12 @@ export function getCanonicalHeaders(
PROXY_HEADER_PATTERN.test(canonicalHeaderName) ||
SEC_HEADER_PATTERN.test(canonicalHeaderName)
) {
continue;
if (
!signableHeaders ||
(signableHeaders && !signableHeaders.has(canonicalHeaderName))
) {
continue;
}
}

canonical[canonicalHeaderName] = headers[headerName]
Expand Down
10 changes: 10 additions & 0 deletions packages/types/src/signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ export interface RequestSigningArguments extends SigningArguments {
* lower case and then checked for existence in the unsignableHeaders set.
*/
unsignableHeaders?: Set<string>;

/**
* A set of strings whose members represents headers that should be signed.
* Any values passed here will override those provided via unsignableHeaders,
* allowing them to be signed.
*
* All headers in the provided request will have their names converted to
* lower case before signing.
*/
signableHeaders?: Set<string>;
}

export interface RequestPresigner {
Expand Down

0 comments on commit 8d6b27a

Please sign in to comment.