Skip to content

Commit b61a6cb

Browse files
committed
chore(credential-provider-web-identity): update unit tests
1 parent 52de007 commit b61a6cb

File tree

5 files changed

+147
-132
lines changed

5 files changed

+147
-132
lines changed

packages/credential-provider-web-identity/README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,6 @@ After you have both an IAM role with configured privileges and an application re
5050
providers, you can set up the SDK to get credentials for the IAM role using helper code, as follows:
5151

5252
```javascript
53-
= new AWS.WebIdentityCredentials({
54-
RoleArn: 'arn:aws:iam::<AWS_ACCOUNT_ID>/:role/<WEB_IDENTITY_ROLE_NAME>',
55-
ProviderId: 'graph.facebook.com|www.amazon.com', // this is null for Google
56-
WebIdentityToken: ACCESS_TOKEN
57-
});
58-
5953
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
6054
import { STSClient, AssumeRoleWithWebIdentityCommand } from "@aws-sdk/client-sts";
6155
import { fromWebToken } from "@aws-sdk/credential-provider-web-identity";
Lines changed: 60 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { ProviderError } from "@aws-sdk/property-provider";
21
import { readFileSync } from "fs";
3-
4-
import { fromTokenFile, FromTokenFileInit } from "./fromTokenFile";
5-
import { AssumeRoleWithWebIdentityParams } from "./index";
2+
jest.mock("./fromWebToken", () => ({
3+
fromWebToken: jest.fn().mockReturnValue(() => Promise.resolve(MOCK_CREDS)),
4+
}));
5+
import { fromTokenFile } from "./fromTokenFile";
6+
import { fromWebToken } from "./fromWebToken";
67

78
const ENV_TOKEN_FILE = "AWS_WEB_IDENTITY_TOKEN_FILE";
89
const ENV_ROLE_ARN = "AWS_ROLE_ARN";
@@ -31,57 +32,6 @@ describe(fromTokenFile.name, () => {
3132
jest.restoreAllMocks();
3233
});
3334

34-
const testRoleAssumerWithWebIdentityNotDefined = async (init: FromTokenFileInit, roleArn: string) => {
35-
try {
36-
// @ts-ignore An argument for 'init' was not provided.
37-
await fromTokenFile(init)();
38-
fail(`Expected error to be thrown`);
39-
} catch (error) {
40-
expect(error).toEqual(
41-
new ProviderError(
42-
`Role Arn '${roleArn}' needs to be assumed with web identity, but no role assumption callback was provided.`,
43-
false
44-
)
45-
);
46-
}
47-
};
48-
49-
const testReadFileSyncError = async (init: FromTokenFileInit) => {
50-
const readFileSyncError = new Error("readFileSyncError");
51-
(readFileSync as jest.Mock).mockImplementation(() => {
52-
throw readFileSyncError;
53-
});
54-
try {
55-
await fromTokenFile(init)();
56-
fail(`Expected error to be thrown`);
57-
} catch (error) {
58-
expect(error).toEqual(readFileSyncError);
59-
}
60-
expect(readFileSync).toHaveBeenCalledTimes(1);
61-
};
62-
63-
const testRoleAssumerWithWebIdentitySuccess = async (init: FromTokenFileInit) => {
64-
const creds = await fromTokenFile(init)();
65-
expect(creds).toEqual(MOCK_CREDS);
66-
expect(readFileSync).toHaveBeenCalledTimes(1);
67-
expect(readFileSync).toHaveBeenCalledWith(mockTokenFile, { encoding: "ascii" });
68-
};
69-
70-
const testRandomValueForRoleSessionName = async (init: FromTokenFileInit) => {
71-
const mockDateNow = Date.now();
72-
const spyDateNow = jest.spyOn(Date, "now").mockReturnValueOnce(mockDateNow);
73-
74-
const creds = await fromTokenFile({
75-
...init,
76-
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityParams) => {
77-
expect(params.RoleSessionName).toEqual(`aws-sdk-js-session-${mockDateNow}`);
78-
return MOCK_CREDS;
79-
},
80-
})();
81-
expect(creds).toEqual(MOCK_CREDS);
82-
expect(spyDateNow).toHaveBeenCalledTimes(1);
83-
};
84-
8535
describe("reads config from env", () => {
8636
const original_ENV_TOKEN_FILE = process.env[ENV_TOKEN_FILE];
8737
const original_ENV_ROLE_ARN = process.env[ENV_ROLE_ARN];
@@ -99,83 +49,70 @@ describe(fromTokenFile.name, () => {
9949
process.env[ENV_ROLE_SESSION_NAME] = original_ENV_ROLE_SESSION_NAME;
10050
});
10151

102-
it("throws if roleAssumerWithWebIdentity is not defined", async () => {
103-
return testRoleAssumerWithWebIdentityNotDefined({}, process.env[ENV_ROLE_ARN]);
52+
it(`passes values to ${fromWebToken.name}`, async () => {
53+
const roleAssumerWithWebIdentity = jest.fn();
54+
const creds = await fromTokenFile({
55+
roleAssumerWithWebIdentity,
56+
})();
57+
expect(creds).toEqual(MOCK_CREDS);
58+
expect(fromWebToken as jest.Mock).toBeCalledTimes(1);
59+
const webTokenInit = (fromWebToken as jest.Mock).mock.calls[0][0];
60+
expect(webTokenInit.webIdentityToken).toBe(mockTokenValue);
61+
expect(webTokenInit.roleSessionName).toBe(mockRoleSessionName);
62+
expect(webTokenInit.roleArn).toBe(mockRoleArn);
63+
expect(webTokenInit.roleAssumerWithWebIdentity).toBe(roleAssumerWithWebIdentity);
10464
});
10565

106-
it("throws if ENV_TOKEN_FILE read from disk failed", async () => {
107-
return testReadFileSyncError({
108-
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityParams) => {
109-
return MOCK_CREDS;
110-
},
111-
});
66+
it("prefers init parameters over environmental variables", async () => {
67+
const roleAssumerWithWebIdentity = jest.fn();
68+
const init = {
69+
webIdentityTokenFile: "anotherTokenFile",
70+
roleArn: "anotherRoleArn",
71+
roleSessionName: "anotherRoleSessionName",
72+
roleAssumerWithWebIdentity,
73+
};
74+
const creds = await fromTokenFile(init)();
75+
expect(creds).toEqual(MOCK_CREDS);
76+
expect(fromWebToken as jest.Mock).toBeCalledTimes(1);
77+
const webTokenInit = (fromWebToken as jest.Mock).mock.calls[0][0];
78+
expect(webTokenInit.roleSessionName).toBe(init.roleSessionName);
79+
expect(webTokenInit.roleArn).toBe(init.roleArn);
80+
expect(webTokenInit.roleAssumerWithWebIdentity).toBe(roleAssumerWithWebIdentity);
81+
expect(readFileSync as jest.Mock).toBeCalledTimes(1);
82+
expect((readFileSync as jest.Mock).mock.calls[0][0]).toBe(init.webIdentityTokenFile);
11283
});
11384

114-
it("passes values to roleAssumerWithWebIdentity", async () => {
115-
return testRoleAssumerWithWebIdentitySuccess({
116-
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityParams) => {
117-
expect(params.WebIdentityToken).toEqual(mockTokenValue);
118-
expect(params.RoleArn).toEqual(mockRoleArn);
119-
expect(params.RoleSessionName).toEqual(mockRoleSessionName);
120-
return MOCK_CREDS;
121-
},
85+
it("throws if ENV_TOKEN_FILE read from disk failed", async () => {
86+
const readFileSyncError = new Error("readFileSyncError");
87+
(readFileSync as jest.Mock).mockImplementation(() => {
88+
throw readFileSyncError;
12289
});
123-
});
124-
125-
it("generates a random value for RoleSessionName if not available", async () => {
126-
delete process.env[ENV_ROLE_SESSION_NAME];
127-
return testRandomValueForRoleSessionName({});
128-
});
129-
});
130-
131-
describe("reads config from configuration keys", () => {
132-
const original_ENV_TOKEN_FILE = process.env[ENV_TOKEN_FILE];
133-
const original_ENV_ROLE_ARN = process.env[ENV_ROLE_ARN];
134-
const original_ENV_ROLE_SESSION_NAME = process.env[ENV_ROLE_SESSION_NAME];
135-
136-
beforeAll(() => {
137-
delete process.env[ENV_TOKEN_FILE];
138-
delete process.env[ENV_ROLE_ARN];
139-
delete process.env[ENV_ROLE_SESSION_NAME];
140-
});
141-
142-
afterAll(() => {
143-
process.env[ENV_TOKEN_FILE] = original_ENV_TOKEN_FILE;
144-
process.env[ENV_ROLE_ARN] = original_ENV_ROLE_ARN;
145-
process.env[ENV_ROLE_SESSION_NAME] = original_ENV_ROLE_SESSION_NAME;
146-
});
147-
148-
it("throws if roleAssumerWithWebIdentity is not defined", async () => {
149-
return testRoleAssumerWithWebIdentityNotDefined({ roleArn: mockRoleArn }, mockRoleArn);
90+
try {
91+
await fromTokenFile({ roleAssumerWithWebIdentity: jest.fn() })();
92+
fail(`Expected error to be thrown`);
93+
} catch (error) {
94+
expect(error).toEqual(readFileSyncError);
95+
}
96+
expect(readFileSync).toHaveBeenCalledTimes(1);
15097
});
15198

15299
it("throws if web_identity_token_file read from disk failed", async () => {
153-
return testReadFileSyncError({
154-
webIdentityTokenFile: mockTokenFile,
155-
roleArn: mockRoleArn,
156-
roleSessionName: mockRoleSessionName,
157-
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityParams) => {
158-
return MOCK_CREDS;
159-
},
160-
});
161-
});
162-
163-
it("passes values to roleAssumerWithWebIdentity", async () => {
164-
return testRoleAssumerWithWebIdentitySuccess({
165-
webIdentityTokenFile: mockTokenFile,
166-
roleArn: mockRoleArn,
167-
roleSessionName: mockRoleSessionName,
168-
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityParams) => {
169-
expect(params.WebIdentityToken).toEqual(mockTokenValue);
170-
expect(params.RoleArn).toEqual(mockRoleArn);
171-
expect(params.RoleSessionName).toEqual(mockRoleSessionName);
172-
return MOCK_CREDS;
173-
},
100+
const readFileSyncError = new Error("readFileSyncError");
101+
(readFileSync as jest.Mock).mockImplementation(() => {
102+
throw readFileSyncError;
174103
});
175-
});
176-
177-
it("generates a random value for RoleSessionName if not available", async () => {
178-
return testRandomValueForRoleSessionName({ webIdentityTokenFile: mockTokenFile, roleArn: mockRoleArn });
104+
try {
105+
await fromTokenFile({
106+
webIdentityTokenFile: mockTokenFile,
107+
roleArn: mockRoleArn,
108+
roleSessionName: mockRoleSessionName,
109+
roleAssumerWithWebIdentity: jest.fn(),
110+
})();
111+
fail(`Expected error to be thrown`);
112+
} catch (error) {
113+
expect(error).toEqual(readFileSyncError);
114+
}
115+
expect(readFileSync).toHaveBeenCalledTimes(1);
179116
});
180117
});
181118
});

packages/credential-provider-web-identity/src/fromTokenFile.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const ENV_TOKEN_FILE = "AWS_WEB_IDENTITY_TOKEN_FILE";
77
const ENV_ROLE_ARN = "AWS_ROLE_ARN";
88
const ENV_ROLE_SESSION_NAME = "AWS_ROLE_SESSION_NAME";
99

10-
export interface FromTokenFileInit extends Partial<FromWebTokenInit> {
10+
export interface FromTokenFileInit extends Partial<Omit<FromWebTokenInit, "webIdentityToken">> {
1111
/**
1212
* File location of where the `OIDC` token is stored.
1313
*/
@@ -24,6 +24,6 @@ export const fromTokenFile = (init: FromTokenFileInit): CredentialProvider => {
2424
...init,
2525
webIdentityToken: readFileSync(webIdentityTokenFile ?? process.env[ENV_TOKEN_FILE]!, { encoding: "ascii" }),
2626
roleArn: roleArn ?? process.env[ENV_ROLE_ARN]!,
27-
roleSessionName: roleSessionName ?? process.env[ENV_ROLE_SESSION_NAME] ?? `aws-sdk-js-session-${Date.now()}`,
27+
roleSessionName: roleSessionName ?? process.env[ENV_ROLE_SESSION_NAME],
2828
});
2929
};
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { ProviderError } from "@aws-sdk/property-provider";
2+
3+
import { fromWebToken } from "./fromWebToken";
4+
5+
const mockToken = "exampletoken";
6+
const mockRoleArn = "mockRoleArn";
7+
const mockRoleSessionName = "mockRoleSessionName";
8+
const mockPolicy = "mockPolicy";
9+
const mockPolicyArns = [{ arn: "policyArn" }];
10+
const mockProviderId = "mockProviderId";
11+
const mockDurationSeconds = 7200;
12+
const MOCK_CREDS = {
13+
accessKeyId: "accessKeyId",
14+
secretAccessKey: "secretAccessKey",
15+
sessionToken: "sessionToken",
16+
};
17+
18+
describe("fromWebToken", () => {
19+
afterEach(() => {
20+
jest.clearAllMocks();
21+
jest.restoreAllMocks();
22+
});
23+
it("throws if roleAssumerWithWebIdentity is not defined", async () => {
24+
try {
25+
await fromWebToken({
26+
webIdentityToken: mockToken,
27+
roleArn: mockRoleArn,
28+
})();
29+
fail(`Expected error to be thrown`);
30+
} catch (error) {
31+
expect(error).toEqual(
32+
new ProviderError(
33+
`Role Arn '${mockRoleArn}' needs to be assumed with web identity, but no role assumption callback was provided.`,
34+
false
35+
)
36+
);
37+
}
38+
});
39+
40+
it("passes values to roleAssumerWithWebIdentity", async () => {
41+
expect.assertions(2);
42+
const init = {
43+
webIdentityToken: mockToken,
44+
roleArn: mockRoleArn,
45+
roleSessionName: mockRoleSessionName,
46+
providerId: mockProviderId,
47+
policyArns: mockPolicyArns,
48+
policy: mockPolicy,
49+
durationSeconds: mockDurationSeconds,
50+
};
51+
const creds = await fromWebToken({
52+
...init,
53+
roleAssumerWithWebIdentity: async (params) => {
54+
expect(params).toMatchObject({
55+
WebIdentityToken: mockToken,
56+
RoleArn: mockRoleArn,
57+
RoleSessionName: mockRoleSessionName,
58+
ProviderId: mockProviderId,
59+
PolicyArns: mockPolicyArns,
60+
Policy: mockPolicy,
61+
DurationSeconds: mockDurationSeconds,
62+
});
63+
return MOCK_CREDS;
64+
},
65+
})();
66+
expect(creds).toEqual(MOCK_CREDS);
67+
});
68+
69+
it("generates a random value for RoleSessionName if not available", async () => {
70+
const mockDateNow = Date.now();
71+
const spyDateNow = jest.spyOn(Date, "now").mockReturnValueOnce(mockDateNow);
72+
73+
const creds = await fromWebToken({
74+
webIdentityToken: mockToken,
75+
roleArn: mockRoleArn,
76+
roleAssumerWithWebIdentity: async (params) => {
77+
expect(params.RoleSessionName).toEqual(`aws-sdk-js-session-${mockDateNow}`);
78+
return MOCK_CREDS;
79+
},
80+
})();
81+
expect(creds).toEqual(MOCK_CREDS);
82+
expect(spyDateNow).toHaveBeenCalledTimes(1);
83+
});
84+
});

packages/credential-provider-web-identity/src/fromWebToken.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export const fromWebToken = (init: FromWebTokenInit): CredentialProvider => () =
148148

149149
return roleAssumerWithWebIdentity({
150150
RoleArn: roleArn,
151-
RoleSessionName: roleSessionName ?? "web-identity",
151+
RoleSessionName: roleSessionName ?? `aws-sdk-js-session-${Date.now()}`,
152152
WebIdentityToken: webIdentityToken,
153153
ProviderId: providerId,
154154
PolicyArns: policyArns,

0 commit comments

Comments
 (0)