Skip to content

Commit d7b1610

Browse files
authored
fix(credential-providers): avoid sharing http2 requestHandler with inner STS (#6389)
1 parent 84fd78b commit d7b1610

File tree

4 files changed

+94
-14
lines changed

4 files changed

+94
-14
lines changed

clients/client-sts/src/defaultStsRoleAssumers.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,13 @@ export const getDefaultRoleAssumer = (
101101
stsOptions?.parentClientConfig?.region,
102102
credentialProviderLogger
103103
);
104+
const isCompatibleRequestHandler = !isH2(requestHandler);
105+
104106
stsClient = new stsClientCtor({
105107
// A hack to make sts client uses the credential in current closure.
106108
credentialDefaultProvider: () => async () => closureSourceCreds,
107109
region: resolvedRegion,
108-
requestHandler: requestHandler as any,
110+
requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined,
109111
logger: logger as any,
110112
});
111113
}
@@ -157,9 +159,11 @@ export const getDefaultRoleAssumerWithWebIdentity = (
157159
stsOptions?.parentClientConfig?.region,
158160
credentialProviderLogger
159161
);
162+
const isCompatibleRequestHandler = !isH2(requestHandler);
163+
160164
stsClient = new stsClientCtor({
161165
region: resolvedRegion,
162-
requestHandler: requestHandler as any,
166+
requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined,
163167
logger: logger as any,
164168
});
165169
}
@@ -206,3 +210,7 @@ export const decorateDefaultCredentialProvider =
206210
),
207211
...input,
208212
});
213+
214+
const isH2 = (requestHandler: any): boolean => {
215+
return requestHandler?.metadata?.handlerProtocol === "h2";
216+
};

clients/client-sts/test/defaultRoleAssumers.spec.ts

+44-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Please do not touch this file. It's generated from template in:
22
// https://github.com/aws/aws-sdk-js-v3/blob/main/codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultRoleAssumers.spec.ts
3-
import { NodeHttpHandler, streamCollector } from "@smithy/node-http-handler";
3+
import { NodeHttp2Handler, NodeHttpHandler, streamCollector } from "@smithy/node-http-handler";
44
import { HttpResponse } from "@smithy/protocol-http";
55
import { Readable } from "stream";
66

@@ -25,8 +25,22 @@ jest.mock("@smithy/node-http-handler", () => {
2525
destroy() {}
2626
handle = mockHandle;
2727
}
28+
class MockNodeHttp2Handler {
29+
public metadata = {
30+
handlerProtocol: "h2",
31+
};
32+
static create(instanceOrOptions?: any) {
33+
if (typeof instanceOrOptions?.handle === "function") {
34+
return instanceOrOptions;
35+
}
36+
return new MockNodeHttp2Handler();
37+
}
38+
destroy() {}
39+
handle = mockHandle;
40+
}
2841
return {
2942
NodeHttpHandler: MockNodeHttpHandler,
43+
NodeHttp2Handler: MockNodeHttp2Handler,
3044
streamCollector: jest.fn(),
3145
};
3246
});
@@ -95,7 +109,7 @@ describe("getDefaultRoleAssumer", () => {
95109
RoleArn: "arn:aws:foo",
96110
RoleSessionName: "session",
97111
};
98-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
112+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
99113
const assumedRole = await roleAssumer(sourceCred, params);
100114
expect(assumedRole.accountId).toEqual("123");
101115
});
@@ -118,7 +132,7 @@ describe("getDefaultRoleAssumer", () => {
118132
RoleArn: "arn:aws:foo",
119133
RoleSessionName: "session",
120134
};
121-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
135+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
122136
await roleAssumer(sourceCred, params);
123137
expect(mockConstructorInput).toHaveBeenCalledTimes(1);
124138
expect(mockConstructorInput.mock.calls[0][0]).toMatchObject({
@@ -143,7 +157,7 @@ describe("getDefaultRoleAssumer", () => {
143157
RoleArn: "arn:aws:foo",
144158
RoleSessionName: "session",
145159
};
146-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
160+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
147161
await roleAssumer(sourceCred, params);
148162
expect(mockConstructorInput).toHaveBeenCalledTimes(1);
149163
expect(mockConstructorInput.mock.calls[0][0]).toMatchObject({
@@ -153,6 +167,31 @@ describe("getDefaultRoleAssumer", () => {
153167
});
154168
});
155169

170+
it("should not pass through an Http2 requestHandler", async () => {
171+
const logger = console;
172+
const region = "some-region";
173+
const handler = new NodeHttp2Handler();
174+
const roleAssumer = getDefaultRoleAssumer({
175+
parentClientConfig: {
176+
region,
177+
logger,
178+
requestHandler: handler,
179+
},
180+
});
181+
const params: AssumeRoleCommandInput = {
182+
RoleArn: "arn:aws:foo",
183+
RoleSessionName: "session",
184+
};
185+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
186+
await roleAssumer(sourceCred, params);
187+
expect(mockConstructorInput).toHaveBeenCalledTimes(1);
188+
expect(mockConstructorInput.mock.calls[0][0]).toMatchObject({
189+
logger,
190+
requestHandler: undefined,
191+
region,
192+
});
193+
});
194+
156195
it("should use the STS client middleware", async () => {
157196
const customMiddlewareFunction = jest.fn();
158197
const roleAssumer = getDefaultRoleAssumer({}, [
@@ -169,7 +208,7 @@ describe("getDefaultRoleAssumer", () => {
169208
RoleArn: "arn:aws:foo",
170209
RoleSessionName: "session",
171210
};
172-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
211+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
173212
await Promise.all([roleAssumer(sourceCred, params), roleAssumer(sourceCred, params)]);
174213
expect(customMiddlewareFunction).toHaveBeenCalledTimes(2); // make sure the middleware is not added to stack multiple times.
175214
expect(customMiddlewareFunction).toHaveBeenNthCalledWith(1, expect.objectContaining({ input: params }));

codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultRoleAssumers.spec.ts

+30-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NodeHttpHandler, streamCollector } from "@smithy/node-http-handler";
1+
import { NodeHttp2Handler, NodeHttpHandler, streamCollector } from "@smithy/node-http-handler";
22
import { HttpResponse } from "@smithy/protocol-http";
33
import { Readable } from "stream";
44

@@ -93,7 +93,7 @@ describe("getDefaultRoleAssumer", () => {
9393
RoleArn: "arn:aws:foo",
9494
RoleSessionName: "session",
9595
};
96-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
96+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
9797
const assumedRole = await roleAssumer(sourceCred, params);
9898
expect(assumedRole.accountId).toEqual("123");
9999
});
@@ -116,7 +116,7 @@ describe("getDefaultRoleAssumer", () => {
116116
RoleArn: "arn:aws:foo",
117117
RoleSessionName: "session",
118118
};
119-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
119+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
120120
await roleAssumer(sourceCred, params);
121121
expect(mockConstructorInput).toHaveBeenCalledTimes(1);
122122
expect(mockConstructorInput.mock.calls[0][0]).toMatchObject({
@@ -141,7 +141,7 @@ describe("getDefaultRoleAssumer", () => {
141141
RoleArn: "arn:aws:foo",
142142
RoleSessionName: "session",
143143
};
144-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
144+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
145145
await roleAssumer(sourceCred, params);
146146
expect(mockConstructorInput).toHaveBeenCalledTimes(1);
147147
expect(mockConstructorInput.mock.calls[0][0]).toMatchObject({
@@ -151,6 +151,31 @@ describe("getDefaultRoleAssumer", () => {
151151
});
152152
});
153153

154+
it("should not pass through an Http2 requestHandler", async () => {
155+
const logger = console;
156+
const region = "some-region";
157+
const handler = new NodeHttp2Handler();
158+
const roleAssumer = getDefaultRoleAssumer({
159+
parentClientConfig: {
160+
region,
161+
logger,
162+
requestHandler: handler,
163+
},
164+
});
165+
const params: AssumeRoleCommandInput = {
166+
RoleArn: "arn:aws:foo",
167+
RoleSessionName: "session",
168+
};
169+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
170+
await roleAssumer(sourceCred, params);
171+
expect(mockConstructorInput).toHaveBeenCalledTimes(1);
172+
expect(mockConstructorInput.mock.calls[0][0]).toMatchObject({
173+
logger,
174+
requestHandler: undefined,
175+
region,
176+
});
177+
});
178+
154179
it("should use the STS client middleware", async () => {
155180
const customMiddlewareFunction = jest.fn();
156181
const roleAssumer = getDefaultRoleAssumer({}, [
@@ -167,7 +192,7 @@ describe("getDefaultRoleAssumer", () => {
167192
RoleArn: "arn:aws:foo",
168193
RoleSessionName: "session",
169194
};
170-
const sourceCred = { accessKeyId: "key", secretAccessKey: "secrete" };
195+
const sourceCred = { accessKeyId: "key", secretAccessKey: "secret" };
171196
await Promise.all([roleAssumer(sourceCred, params), roleAssumer(sourceCred, params)]);
172197
expect(customMiddlewareFunction).toHaveBeenCalledTimes(2); // make sure the middleware is not added to stack multiple times.
173198
expect(customMiddlewareFunction).toHaveBeenNthCalledWith(1, expect.objectContaining({ input: params }));

codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultStsRoleAssumers.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ export const getDefaultRoleAssumer = (
9898
stsOptions?.parentClientConfig?.region,
9999
credentialProviderLogger
100100
);
101+
const isCompatibleRequestHandler = !isH2(requestHandler);
102+
101103
stsClient = new stsClientCtor({
102104
// A hack to make sts client uses the credential in current closure.
103105
credentialDefaultProvider: () => async () => closureSourceCreds,
104106
region: resolvedRegion,
105-
requestHandler: requestHandler as any,
107+
requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined,
106108
logger: logger as any,
107109
});
108110
}
@@ -154,9 +156,11 @@ export const getDefaultRoleAssumerWithWebIdentity = (
154156
stsOptions?.parentClientConfig?.region,
155157
credentialProviderLogger
156158
);
159+
const isCompatibleRequestHandler = !isH2(requestHandler);
160+
157161
stsClient = new stsClientCtor({
158162
region: resolvedRegion,
159-
requestHandler: requestHandler as any,
163+
requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined,
160164
logger: logger as any,
161165
});
162166
}
@@ -203,3 +207,7 @@ export const decorateDefaultCredentialProvider =
203207
),
204208
...input,
205209
});
210+
211+
const isH2 = (requestHandler: any): boolean => {
212+
return requestHandler?.metadata?.handlerProtocol === "h2";
213+
};

0 commit comments

Comments
 (0)