Skip to content
This repository has been archived by the owner on Jan 15, 2025. It is now read-only.

Commit

Permalink
init integration test for getAssertion
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreaPagoPa authored and gquadrati committed Mar 2, 2023
1 parent 7613fb0 commit ed8a69d
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 1 deletion.
253 changes: 253 additions & 0 deletions __integrations__/__tests__/getAssertion.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable sort-keys */
import { exit } from "process";

import { CosmosClient } from "@azure/cosmos";
import { createBlobService } from "azure-storage";

import * as TE from "fp-ts/TaskEither";
import * as jose from "jose";
import { pipe } from "fp-ts/lib/function";
import {
createCosmosDbAndCollections,
LOLLIPOP_COSMOSDB_COLLECTION_NAME
} from "../__mocks__/fixtures";

import { getNodeFetch } from "../utils/fetch";
import { log } from "../utils/logger";
import {
LolliPOPKeysModel} from "../../model/lollipop_keys";

import {
WAIT_MS,
SHOW_LOGS,
COSMOSDB_URI,
COSMOSDB_KEY,
COSMOSDB_NAME,
BEARER_AUTH_HEADER,
QueueStorageConnection
} from "../env";
import { createBlobs } from "../__mocks__/utils/azure_storage";
import {
aFiscalCode} from "../../__mocks__/lollipopPubKey.mock";
import { ActivatePubKeyPayload } from "../../generated/definitions/internal/ActivatePubKeyPayload";
import { AssertionTypeEnum } from "../../generated/definitions/internal/AssertionType";
import { NonEmptyString } from "@pagopa/ts-commons/lib/strings";
import { fetchGetAssertion } from "../utils/client";
import { AssertionRef } from "../../generated/definitions/internal/AssertionRef";
import { JwkPublicKey } from "@pagopa/ts-commons/lib/jwk";
import { JwkPubKeyHashAlgorithmEnum } from "../../generated/definitions/internal/JwkPubKeyHashAlgorithm";
import { ProblemJson } from "@pagopa/ts-commons/lib/responses";

const MAX_ATTEMPT = 50;

jest.setTimeout(WAIT_MS * MAX_ATTEMPT);

const customHeaders = {
"x-user-groups": "ApiLollipopAssertionRead",
"x-subscription-id": "anEnabledServiceId",
"x-user-email": "[email protected]",
"x-user-id": "unused",
"x-user-note": "unused",
"x-functions-key": "unused",
"x-forwarded-for": "0.0.0.0",
"Ocp-Apim-Subscription-Key": "aSubscriptionKey"
};

const baseUrl = "http://function:7071";
const myFetch = getNodeFetch(customHeaders) as unknown as typeof fetch;

const LOLLIPOP_ASSERTION_STORAGE_CONTAINER_NAME = "assertions";

// ----------------
// Setup dbs
// ----------------

const blobService = createBlobService(QueueStorageConnection);

// @ts-ignore
const cosmosClient = new CosmosClient({
endpoint: COSMOSDB_URI,
key: COSMOSDB_KEY
});

// Wait some time
beforeAll(async () => {
await pipe(
createCosmosDbAndCollections(cosmosClient, COSMOSDB_NAME),
TE.getOrElse(() => {
throw Error("Cannot create infra resources");
})
)();
await pipe(
createBlobs(blobService, [LOLLIPOP_ASSERTION_STORAGE_CONTAINER_NAME]),
TE.getOrElse(() => {
throw Error("Cannot create azure storage");
})
)();

await waitFunctionToSetup();
});

beforeEach(() => {
jest.clearAllMocks();
});

const cosmosInstance = cosmosClient.database(COSMOSDB_NAME);
const container = cosmosInstance.container(LOLLIPOP_COSMOSDB_COLLECTION_NAME);
const lolliPOPKeysModel = new LolliPOPKeysModel(container);

const expires = new Date();

const validActivatePubKeyPayload: ActivatePubKeyPayload = {
assertion_type: AssertionTypeEnum.SAML,
assertion: "aValidAssertion" as NonEmptyString,
expired_at: expires,
fiscal_code: aFiscalCode
};

// this method generates new JWK for use in the describe below
const generateJwkForTest = async (): Promise<JwkPublicKey> => {
const keyPair = await jose.generateKeyPair("ES256");
return (await jose.exportJWK(keyPair.publicKey)) as JwkPublicKey;
};

const generateAssertionRefForTest = async (
jwk: JwkPublicKey,
algo: JwkPubKeyHashAlgorithmEnum = JwkPubKeyHashAlgorithmEnum.sha256
): Promise<AssertionRef> => {
const thumbprint = await jose.calculateJwkThumbprint(jwk, algo);
return `${algo}-${thumbprint}` as AssertionRef;
};

// -------------------------
// Tests
// -------------------------

describe("getAssertion |> Validation Failures", () => {
it("should fail when the required permissions are not met", async () => {
const myFetchWithoutHeaders = getNodeFetch() as unknown as typeof fetch;

const response = await fetchGetAssertion(
"",
"",
"",
baseUrl,
myFetchWithoutHeaders
);

expect(response.status).toEqual(403);
const problemJson = (await response.json()) as ProblemJson;
expect(problemJson).toMatchObject({
detail: "You do not have enough permissions",
title: "You are not allowed here",
status: 403
});
});

it("should fail when an empty assertionRef is passed to the endpoint", async () => {
const response = await fetchGetAssertion(
"",
"",
"",
baseUrl,
myFetch
);

expect(response.status).toEqual(400);
const body = await response.json();
expect(body).toMatchObject({
status: 400,
title: "Invalid AssertionRef"
});
});

it("should fail when an invalid assertionRef is passed to the endpoint", async () => {
const anInvalidAssertionRef = "anInvalidAssertionRef";

const response = await fetchGetAssertion(
anInvalidAssertionRef,
"",
"",
baseUrl,
myFetch
);

expect(response.status).toEqual(400);
const body = await response.json();
expect(body).toMatchObject({
status: 400,
title: "Invalid AssertionRef"
});
});

it("should fail when an invalid jwt is passed to the endpoint", async () => {
const anInvalidJwt = "anInvalidJwt";
const randomJwk = await generateJwkForTest();
const randomAssertionRef = await generateAssertionRefForTest(randomJwk);

const response = await fetchGetAssertion(
randomAssertionRef,
BEARER_AUTH_HEADER,
anInvalidJwt,
baseUrl,
myFetch
);

expect(response.status).toEqual(403);
const body = await response.json();
expect(body).toMatchObject({
status: 403,
title: `Invalid or missing JWT in header ${BEARER_AUTH_HEADER}`
});
});

// it("should fail when the assertionRef in the endpoint does not match the one in the jwt", async () => {
// const anInvalidJwt = "anInvalidJwt";
// const randomJwk = await generateJwkForTest();
// const randomAssertionRef = await generateAssertionRefForTest(randomJwk);

// const response = await fetchGetAssertion(
// randomAssertionRef,
// BEARER_AUTH_HEADER,
// anInvalidJwt,
// baseUrl,
// myFetch
// );

// expect(response.status).toEqual(403);
// const body = await response.json();
// expect(body).toMatchObject({
// status: 403,
// title: `Invalid or missing JWT in header ${BEARER_AUTH_HEADER}`
// });
// });
});

// -----------------------
// utils
// -----------------------

const delay = (ms: number): Promise<void> =>
new Promise(resolve => setTimeout(resolve, ms));

const waitFunctionToSetup = async (): Promise<void> => {
log("ENV: ", COSMOSDB_URI, WAIT_MS, SHOW_LOGS);
// eslint-disable-next-line functional/no-let
let i = 0;
while (i < MAX_ATTEMPT) {
log("Waiting the function to setup..");
try {
await myFetch(baseUrl + "/info");
break;
} catch (e) {
log("Waiting the function to setup..");
await delay(WAIT_MS);
i++;
}
}
if (i >= MAX_ATTEMPT) {
log("Function unable to setup in time");
exit(1);
}
};
3 changes: 3 additions & 0 deletions __integrations__/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ export const COSMOSDB_KEY = process.env.COSMOSDB_KEY ?? "";
export const COSMOSDB_NAME = process.env.COSMOSDB_NAME ?? "db";
export const LOLLIPOP_ASSERTION_STORAGE_CONNECTION_STRING =
process.env.LOLLIPOP_ASSERTION_STORAGE_CONNECTION_STRING ?? "";

export const BEARER_AUTH_HEADER = process.env.BEARER_AUTH_HEADER ?? "";

1 change: 1 addition & 0 deletions __integrations__/environments/env.base
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ SHOW_LOGS=false
# Test Data
# ----------

BEARER_AUTH_HEADER=x-jwt-header
4 changes: 3 additions & 1 deletion __integrations__/environments/env.function
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ PRIMARY_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAhn/zS3oYEU

PRIMARY_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhn/zS3oYEUORgxbWCp4V\nQomR4io5g/GLKkZi0pfjSFElIFmfoSnsztEJP1OxC7SSGiJjbozvVIRvH/2icpj9\nwSR86Er2f+yvmvKA6fQ1PMsVEfnsyvfkDUIurpzCksSp3kR0IUgIiZaLcAGfig7q\nSlJEXUb4AKdMSnzqq9QIUNRSb+s34lF9yiuced0HypiQKmf8652aC45RBB3uhhIk\nB2P7tTE3exLyHJQlg52Nzm0ZEMpEB4mqeQLUKWxnF0GqejVVvAUC8i6iJ7hPQgS9\n5qKgSl8qk0ATYruXgH6MdAYMiQkCDCDdo+fRwy2gEmjA9uvNaUHo3gAxCcP6717n\nZwIDAQAB\n-----END PUBLIC KEY-----"

SECONDARY_PUBLIC_KEY=<(not required) a Secondary Public Key>
SECONDARY_PUBLIC_KEY=<(not required) a Secondary Public Key>

BEARER_AUTH_HEADER=${BEARER_AUTH_HEADER}
2 changes: 2 additions & 0 deletions __integrations__/environments/env.integration-tests
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ SHOW_LOGS=${SHOW_LOGS}


FF_TYPE=${FF_TYPE}

BEARER_AUTH_HEADER=${BEARER_AUTH_HEADER}
17 changes: 17 additions & 0 deletions __integrations__/utils/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,20 @@ export const fetchGenerateLcParams = (
body: JSON.stringify(body)
}
);

export const GET_ASSERTION_PATH = "api/v1/assertions";
export const fetchGetAssertion = (
assertionRef: string,
jwtHeaderName: string,
jwt: string,
baseUrl: string,
nodeFetch: typeof fetch
) =>
nodeFetch(`${baseUrl}/${GET_ASSERTION_PATH}/${assertionRef}`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
[jwtHeaderName]: jwt
}
});

0 comments on commit ed8a69d

Please sign in to comment.