Skip to content

Commit 7c891b2

Browse files
authored
feat(credential-provider-ini): refactor into modular components (#3289)
1 parent 616e038 commit 7c891b2

16 files changed

+1066
-1595
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { AssumeRoleWithWebIdentityParams } from "@aws-sdk/credential-provider-web-identity";
2+
import { CredentialProvider, Credentials } from "@aws-sdk/types";
3+
import { getMasterProfileName, parseKnownFiles } from "@aws-sdk/util-credentials";
4+
5+
import { fromIni } from "./fromIni";
6+
import { AssumeRoleParams } from "./resolveAssumeRoleCredentials";
7+
import { resolveProfileData } from "./resolveProfileData";
8+
9+
jest.mock("@aws-sdk/util-credentials");
10+
jest.mock("./resolveProfileData");
11+
12+
describe(fromIni.name, () => {
13+
const mockMasterProfileName = "mockMasterProfileName";
14+
const mockProfileName = "mockProfileName";
15+
const mockInit = { profile: mockProfileName };
16+
const mockProfiles = { [mockProfileName]: { key: "value" } };
17+
18+
beforeEach(() => {
19+
(parseKnownFiles as jest.Mock).mockResolvedValue(mockProfiles);
20+
(getMasterProfileName as jest.Mock).mockReturnValue(mockMasterProfileName);
21+
});
22+
23+
afterEach(() => {
24+
jest.clearAllMocks();
25+
});
26+
27+
it("rethrows error if parsing known files fails", async () => {
28+
const expectedError = new Error("from parseKnownFiles");
29+
(parseKnownFiles as jest.Mock).mockRejectedValue(expectedError);
30+
try {
31+
await fromIni(mockInit)();
32+
fail(`expected ${expectedError}`);
33+
} catch (error) {
34+
expect(error).toStrictEqual(expectedError);
35+
}
36+
expect(parseKnownFiles).toHaveBeenCalledWith(mockInit);
37+
expect(getMasterProfileName).not.toHaveBeenCalled();
38+
expect(resolveProfileData).not.toHaveBeenCalled();
39+
});
40+
41+
it("rethrows error if resolving process creds fails", async () => {
42+
const expectedError = new Error("from resolveProcessCredentials");
43+
(resolveProfileData as jest.Mock).mockRejectedValue(expectedError);
44+
try {
45+
await fromIni(mockInit)();
46+
fail(`expected ${expectedError}`);
47+
} catch (error) {
48+
expect(error).toStrictEqual(expectedError);
49+
}
50+
expect(parseKnownFiles).toHaveBeenCalledWith(mockInit);
51+
expect(getMasterProfileName).toHaveBeenCalledWith(mockInit);
52+
expect(resolveProfileData).toHaveBeenCalledWith(mockMasterProfileName, mockProfiles, mockInit);
53+
});
54+
55+
it("returns resolved process creds", async () => {
56+
const expectedCreds: Credentials = {
57+
accessKeyId: "mockAccessKeyId",
58+
secretAccessKey: "mockSecretAccessKey",
59+
};
60+
(resolveProfileData as jest.Mock).mockResolvedValue(expectedCreds);
61+
const receivedCreds = await fromIni(mockInit)();
62+
expect(receivedCreds).toStrictEqual(expectedCreds);
63+
expect(parseKnownFiles).toHaveBeenCalledWith(mockInit);
64+
expect(getMasterProfileName).toHaveBeenCalledWith(mockInit);
65+
expect(resolveProfileData).toHaveBeenCalledWith(mockMasterProfileName, mockProfiles, mockInit);
66+
});
67+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { AssumeRoleWithWebIdentityParams } from "@aws-sdk/credential-provider-web-identity";
2+
import { CredentialProvider, Credentials } from "@aws-sdk/types";
3+
import { getMasterProfileName, parseKnownFiles, SourceProfileInit } from "@aws-sdk/util-credentials";
4+
5+
import { AssumeRoleParams } from "./resolveAssumeRoleCredentials";
6+
import { resolveProfileData } from "./resolveProfileData";
7+
8+
export interface FromIniInit extends SourceProfileInit {
9+
/**
10+
* A function that returns a promise fulfilled with an MFA token code for
11+
* the provided MFA Serial code. If a profile requires an MFA code and
12+
* `mfaCodeProvider` is not a valid function, the credential provider
13+
* promise will be rejected.
14+
*
15+
* @param mfaSerial The serial code of the MFA device specified.
16+
*/
17+
mfaCodeProvider?: (mfaSerial: string) => Promise<string>;
18+
19+
/**
20+
* A function that assumes a role and returns a promise fulfilled with
21+
* credentials for the assumed role.
22+
*
23+
* @param sourceCreds The credentials with which to assume a role.
24+
* @param params
25+
*/
26+
roleAssumer?: (sourceCreds: Credentials, params: AssumeRoleParams) => Promise<Credentials>;
27+
28+
/**
29+
* A function that assumes a role with web identity and returns a promise fulfilled with
30+
* credentials for the assumed role.
31+
*
32+
* @param sourceCreds The credentials with which to assume a role.
33+
* @param params
34+
*/
35+
roleAssumerWithWebIdentity?: (params: AssumeRoleWithWebIdentityParams) => Promise<Credentials>;
36+
}
37+
38+
/**
39+
* Creates a credential provider that will read from ini files and supports
40+
* role assumption and multi-factor authentication.
41+
*/
42+
export const fromIni =
43+
(init: FromIniInit = {}): CredentialProvider =>
44+
async () => {
45+
const profiles = await parseKnownFiles(init);
46+
return resolveProfileData(getMasterProfileName(init), profiles, init);
47+
};

0 commit comments

Comments
 (0)