Skip to content

Commit 561b2a9

Browse files
VIA-537 AS/SB Delete config and apimConfig
1 parent 2faf1ea commit 561b2a9

File tree

11 files changed

+96
-414
lines changed

11 files changed

+96
-414
lines changed

src/app/_components/vaccine/Vaccine.integration.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@ import { auth } from "@project/auth";
22
import Vaccine from "@src/app/_components/vaccine/Vaccine";
33
import { VaccineType } from "@src/models/vaccine";
44
import { fetchEligibilityContent } from "@src/services/eligibility-api/gateway/fetch-eligibility-content";
5-
import { configProvider } from "@src/utils/config";
5+
import lazyConfig from "@src/utils/lazy-config";
66
import { mockNHSAppJSFunctions } from "@src/utils/nhsapp-js.test";
7+
import { AsyncConfigMock, lazyConfigBuilder } from "@test-data/config/builders";
78
import { eligibilityApiResponseBuilder } from "@test-data/eligibility-api/builders";
89
import { render, screen } from "@testing-library/react";
910
import { ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers";
1011
import { headers } from "next/headers";
1112

1213
jest.mock("@src/utils/auth/generate-auth-payload", () => jest.fn());
13-
jest.mock("@src/utils/config", () => ({
14-
configProvider: jest.fn(),
15-
}));
1614
jest.mock("@src/services/eligibility-api/gateway/fetch-eligibility-content", () => ({
1715
fetchEligibilityContent: jest.fn(),
1816
}));
@@ -33,11 +31,13 @@ jest.mock("sanitize-data", () => ({ sanitize: jest.fn() }));
3331
const nhsNumber = "5123456789";
3432

3533
describe("Vaccine", () => {
34+
const mockedConfig = lazyConfig as AsyncConfigMock;
3635
beforeAll(() => {
37-
(configProvider as jest.Mock).mockImplementation(() => ({
38-
CONTENT_CACHE_PATH: "wiremock/__files/",
39-
PINO_LOG_LEVEL: "info",
40-
}));
36+
const defaultConfig = lazyConfigBuilder()
37+
.withContentCachePath("wiremock/__files/")
38+
.withPinoLogLevel("info")
39+
.build();
40+
Object.assign(mockedConfig, defaultConfig);
4141
(fetchEligibilityContent as jest.Mock).mockResolvedValue(eligibilityApiResponseBuilder().build());
4242
mockNHSAppJSFunctions(jest.fn(), jest.fn());
4343
(auth as jest.Mock).mockResolvedValue({

src/app/api/auth/[...nextauth]/provider.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import NHSLoginAuthProvider from "@src/app/api/auth/[...nextauth]/provider";
22
import lazyConfig from "@src/utils/lazy-config";
33
import { AsyncConfigMock, lazyConfigBuilder } from "@test-data/config/builders";
44

5-
jest.mock("@src/utils/config");
65
jest.mock("@src/utils/auth/pem-to-crypto-key");
76
jest.mock("sanitize-data", () => ({ sanitize: jest.fn() }));
87

src/services/content-api/content-api.integration.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import lazyConfig from "@src/utils/lazy-config";
1010
import { AsyncConfigMock, lazyConfigBuilder } from "@test-data/config/builders";
1111
import { Readable } from "stream";
1212

13-
jest.mock("@src/utils/config");
1413
jest.mock("@aws-sdk/client-s3");
1514
jest.mock("sanitize-data", () => ({ sanitize: jest.fn() }));
1615

src/services/content-api/gateway/content-reader-service.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { readContentFromCache } from "@src/services/content-api/gateway/content-
99
import { Readable } from "stream";
1010

1111
jest.mock("@aws-sdk/client-s3");
12-
jest.mock("@src/utils/config");
1312
jest.mock("sanitize-data", () => ({ sanitize: jest.fn() }));
1413

1514
const mockRsvResponse = {

src/utils/apimConfig.test.ts

Lines changed: 0 additions & 83 deletions
This file was deleted.

src/utils/apimConfig.ts

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/**
22
* @jest-environment node
33
*/
4-
import { ApimConfig } from "@src/utils/apimConfig";
54
import { generateAPIMTokenPayload } from "@src/utils/auth/apim/fetch-apim-access-token";
65
import { APIMTokenPayload, IdToken } from "@src/utils/auth/types";
7-
import { apimConfigBuilder } from "@test-data/config/builders";
6+
import lazyConfig from "@src/utils/lazy-config";
7+
import { AsyncConfigMock, lazyConfigBuilder } from "@test-data/config/builders";
88
import jwt from "jsonwebtoken";
99

1010
jest.mock("jsonwebtoken", () => ({
@@ -17,18 +17,14 @@ const mockSignedJwt = "mock-signed-jwt";
1717
const mockIdToken = "id-token" as IdToken;
1818
const mockNowInSeconds = 1749052001;
1919

20-
const apimApiKey = "apim-api-key";
20+
const eligibilityApiKey = "eligibility-api-key";
2121
const apimKeyId = "apim-key-id";
2222
const apimPrivateKey = "apim-private-key";
23-
const mockApimConfig: ApimConfig = apimConfigBuilder()
24-
.withELIGIBILITY_API_KEY(apimApiKey)
25-
.andAPIM_AUTH_URL(new URL("https://apim-test-auth-url.com/test"))
26-
.andAPIM_KEY_ID(apimKeyId)
27-
.andAPIM_PRIVATE_KEY(apimPrivateKey)
28-
.build();
23+
const apimAuthUrl = new URL("https://apim-test-auth-url.com/test");
2924

3025
describe("generateAPIMTokenPayload", () => {
3126
let randomUUIDSpy: jest.SpyInstance;
27+
const mockedConfig = lazyConfig as AsyncConfigMock;
3228

3329
beforeAll(() => {
3430
randomUUIDSpy = jest.spyOn(global.crypto, "randomUUID").mockReturnValue(mockRandomUUID);
@@ -38,6 +34,13 @@ describe("generateAPIMTokenPayload", () => {
3834
randomUUIDSpy.mockClear();
3935
jest.useFakeTimers();
4036
jest.setSystemTime(mockNowInSeconds * 1000);
37+
const defaultConfig = lazyConfigBuilder()
38+
.withEligibilityApiKey(eligibilityApiKey)
39+
.andApimAuthUrl(apimAuthUrl)
40+
.andApimKeyId(apimKeyId)
41+
.andApimPrivateKey(apimPrivateKey)
42+
.build();
43+
Object.assign(mockedConfig, defaultConfig);
4144
});
4245

4346
afterAll(() => {
@@ -47,28 +50,28 @@ describe("generateAPIMTokenPayload", () => {
4750
});
4851

4952
describe("new access token requested", () => {
50-
it("should include signed client_assertion with expected iss sub and aud values", () => {
53+
it("should include signed client_assertion with expected iss sub and aud values", async () => {
5154
(jwt.sign as jest.Mock).mockReturnValue(mockSignedJwt);
5255

5356
const expectedClientAssertionPayloadContent = {
54-
iss: mockApimConfig.ELIGIBILITY_API_KEY,
55-
sub: mockApimConfig.ELIGIBILITY_API_KEY,
56-
aud: mockApimConfig.APIM_AUTH_URL.href,
57+
iss: eligibilityApiKey,
58+
sub: eligibilityApiKey,
59+
aud: apimAuthUrl.href,
5760
jti: mockRandomUUID,
5861
exp: mockNowInSeconds + 300,
5962
};
6063

61-
const apimTokenPayload: APIMTokenPayload = generateAPIMTokenPayload(mockApimConfig, mockIdToken);
64+
const apimTokenPayload: APIMTokenPayload = await generateAPIMTokenPayload(mockIdToken);
6265
const clientAssertionJWT = apimTokenPayload.client_assertion;
6366

64-
expect(jwt.sign).toHaveBeenCalledWith(expectedClientAssertionPayloadContent, mockApimConfig.APIM_PRIVATE_KEY, {
67+
expect(jwt.sign).toHaveBeenCalledWith(expectedClientAssertionPayloadContent, apimPrivateKey, {
6568
algorithm: "RS512",
66-
keyid: mockApimConfig.APIM_KEY_ID,
69+
keyid: apimKeyId,
6770
});
6871
expect(clientAssertionJWT).toEqual(mockSignedJwt);
6972
});
7073

71-
it("should use token-exchange grant type & id_token as subject_token field", () => {
74+
it("should use token-exchange grant type & id_token as subject_token field", async () => {
7275
// Given
7376
(jwt.sign as jest.Mock).mockReturnValue(mockSignedJwt);
7477

@@ -81,7 +84,7 @@ describe("generateAPIMTokenPayload", () => {
8184
};
8285

8386
// When
84-
const apimTokenPayload = generateAPIMTokenPayload(mockApimConfig, mockIdToken);
87+
const apimTokenPayload = await generateAPIMTokenPayload(mockIdToken);
8588

8689
// Then
8790
expect(apimTokenPayload).toEqual(expectedTokenPayload);
@@ -92,9 +95,9 @@ describe("generateAPIMTokenPayload", () => {
9295
throw new Error("Invalid key");
9396
});
9497

95-
expect(() => {
96-
generateAPIMTokenPayload(mockApimConfig, mockIdToken);
97-
}).toThrow("Invalid key");
98+
expect(async () => {
99+
await generateAPIMTokenPayload(mockIdToken);
100+
}).rejects.toThrow("Invalid key");
98101
});
99102
});
100103
});
Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { ApimConfig, apimConfigProvider } from "@src/utils/apimConfig";
21
import { ApimAuthError, ApimHttpError } from "@src/utils/auth/apim/exceptions";
32
import { ApimTokenResponse } from "@src/utils/auth/apim/types";
43
import { APIMClientAssertionPayload, APIMTokenPayload, IdToken } from "@src/utils/auth/types";
4+
import lazyConfig from "@src/utils/lazy-config";
55
import { logger } from "@src/utils/logger";
66
import axios, { AxiosResponse, HttpStatusCode } from "axios";
77
import jwt from "jsonwebtoken";
@@ -10,25 +10,34 @@ import { Logger } from "pino";
1010
const log: Logger = logger.child({ module: "utils-auth-apim-fetch-apim-access-token" });
1111

1212
const fetchAPIMAccessToken = async (idToken: IdToken): Promise<ApimTokenResponse> => {
13-
const apimConfig: ApimConfig = await apimConfigProvider();
14-
log.debug({ context: { apimConfig, idToken } }, "Fetching APIM Access Token");
13+
log.debug({ context: { idToken } }, "Fetching APIM Access Token");
1514

1615
try {
17-
const tokenPayload: APIMTokenPayload = generateAPIMTokenPayload(apimConfig, idToken);
16+
const tokenPayload: APIMTokenPayload = await generateAPIMTokenPayload(idToken);
1817
log.debug({ context: { tokenPayload } }, "APIM token payload");
1918

20-
const response: AxiosResponse<ApimTokenResponse> = await axios.post(apimConfig.APIM_AUTH_URL.href, tokenPayload, {
21-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
22-
timeout: 10000,
23-
validateStatus: (status) => status < HttpStatusCode.BadRequest,
24-
});
19+
const response: AxiosResponse<ApimTokenResponse> = await axios.post(
20+
((await lazyConfig.APIM_AUTH_URL) as URL).href,
21+
tokenPayload,
22+
{
23+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
24+
timeout: 10000,
25+
validateStatus: (status) => status < HttpStatusCode.BadRequest,
26+
},
27+
);
2528

2629
log.info({ context: { apimToken: response.data } }, "APIM access token fetched");
2730
return response.data;
2831
} catch (error) {
2932
if (axios.isAxiosError(error)) {
3033
log.error(
31-
{ error, context: { APIM_AUTH_URL: apimConfig.APIM_AUTH_URL.href, response_data: error.response?.data } },
34+
{
35+
error,
36+
context: {
37+
APIM_AUTH_URL: ((await lazyConfig.APIM_AUTH_URL) as URL).href,
38+
response_data: error.response?.data,
39+
},
40+
},
3241
"Error calling APIM token endpoint: HTTP request failed",
3342
);
3443
throw new ApimHttpError("Error getting APIM token");
@@ -42,8 +51,8 @@ const fetchAPIMAccessToken = async (idToken: IdToken): Promise<ApimTokenResponse
4251
}
4352
};
4453

45-
const generateAPIMTokenPayload = (apimConfig: ApimConfig, idToken: IdToken): APIMTokenPayload => {
46-
const clientAssertion: string = _generateClientAssertion(apimConfig);
54+
const generateAPIMTokenPayload = async (idToken: IdToken): Promise<APIMTokenPayload> => {
55+
const clientAssertion: string = await _generateClientAssertion();
4756

4857
return {
4958
grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
@@ -54,18 +63,18 @@ const generateAPIMTokenPayload = (apimConfig: ApimConfig, idToken: IdToken): API
5463
};
5564
};
5665

57-
const _generateClientAssertion = (apimConfig: ApimConfig): string => {
58-
const privateKey: string = apimConfig.APIM_PRIVATE_KEY;
66+
const _generateClientAssertion = async (): Promise<string> => {
67+
const privateKey: string = (await lazyConfig.APIM_PRIVATE_KEY) as string;
5968
const payload: APIMClientAssertionPayload = {
60-
iss: apimConfig.ELIGIBILITY_API_KEY,
61-
sub: apimConfig.ELIGIBILITY_API_KEY,
62-
aud: apimConfig.APIM_AUTH_URL.href,
69+
iss: (await lazyConfig.ELIGIBILITY_API_KEY) as string,
70+
sub: (await lazyConfig.ELIGIBILITY_API_KEY) as string,
71+
aud: ((await lazyConfig.APIM_AUTH_URL) as URL).href,
6372
jti: crypto.randomUUID(),
6473
exp: Math.floor(Date.now() / 1000) + 300,
6574
};
6675
log.debug({ context: { payload } }, "raw APIMClientAssertionPayload");
6776

68-
return jwt.sign(payload, privateKey, { algorithm: "RS512", keyid: apimConfig.APIM_KEY_ID });
77+
return jwt.sign(payload, privateKey, { algorithm: "RS512", keyid: (await lazyConfig.APIM_KEY_ID) as string });
6978
};
7079

7180
export { fetchAPIMAccessToken, generateAPIMTokenPayload };

0 commit comments

Comments
 (0)