Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PRDP-186] Implement AES encryption and PDV Tokenizer #64

Merged
merged 25 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3ca146f
[PRDP-193] Updated README with tokenizer env
svariant Oct 31, 2023
a69b1f8
[PRDP-193] Defined PDV tokenizer client
svariant Oct 31, 2023
3a65308
[PRDP-193] Defined PDV tokenizer service
svariant Oct 31, 2023
992f547
[PRDP-186] Updated README with tokenizer env
svariant Oct 31, 2023
34f3953
[PRDP-186] Defined PDV tokenizer client
svariant Oct 31, 2023
d7851bd
[PRDP-186] Defined PDV tokenizer service
svariant Oct 31, 2023
ea9207c
[PRDP-186] Updated helm & README
svariant Nov 3, 2023
630c356
Merge remote-tracking branch 'origin/PRDP-186-implement-tokenizer' in…
svariant Nov 3, 2023
542534e
[PRDP-186] Fixed tokenizer client & service - defined unit tests
svariant Nov 3, 2023
5f18f35
[PRDP-186] Updated integration & performance tests
svariant Nov 3, 2023
7147a19
[PRDP-186] Base64 Encoding receipt-error message payload - updated un…
svariant Nov 6, 2023
f752ee4
[PRDP-186] Added AES256 encryption utils
svariant Nov 6, 2023
7f28a2b
[PRDP-186] Implemented aes enryption ManageReceiptPoisonQueue - updat…
svariant Nov 6, 2023
45cdfac
[PRDP-186] Implemented aes enryption RetryReviewedPoisonMessages - up…
svariant Nov 6, 2023
3a0090e
[PRDP-186] Updated README with new envs
svariant Nov 6, 2023
fd090ce
[PRDP-186] Warning about PDVTokenizer unused classes
svariant Nov 6, 2023
772d072
[PRDP-186] Added bizEventId to receipt-error - centralized AES salt&k…
svariant Nov 6, 2023
f4c334d
[PRDP-186] Updated integration tests
svariant Nov 6, 2023
67f7b12
[PRDP-186] Handled AES encryption/decription exceptions
svariant Nov 6, 2023
5c39502
[PRDP-186] Removed TODOs
svariant Nov 6, 2023
4f49fbd
[PRDP-186] Renamed integration test script
svariant Nov 7, 2023
ec30d65
[PRDP-186] Added secret AES salt&key env to helm
svariant Nov 7, 2023
138f802
[PRDP-186] feat: updated integration_test.yml
alessio-cialini Nov 7, 2023
25b23f8
[PRDP-186] Added comment on Padding vulnerability
svariant Nov 8, 2023
4920fc4
[PRDP-186] Fix refuso
svariant Nov 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/integration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
container_app_environment_name: ${{ vars.CONTAINER_APP_ENVIRONMENT_NAME }}
resource_group_name: ${{ vars.CONTAINER_APP_ENVIRONMENT_RESOURCE_GROUP_NAME }} # RG of the runner
pat_token: ${{ secrets.BOT_TOKEN_GITHUB }}
self_hosted_runner_image_tag: "v1.6.0"
# self_hosted_runner_image_tag: "v1.6.0"

integration_test:
needs: [ create_runner ]
Expand Down
38 changes: 23 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,29 @@ On terminal type:
then replace env variables with correct values
(if there is NO default value, the variable HAS to be defined)

| VARIABLE | USAGE | DEFAULT VALUE |
|-----------------------------------|----------------------------------------------------------------------------------|:-----------------------:|
| `RECEIPTS_STORAGE_CONN_STRING` | Connection string to the Receipt Storage | |
| `RECEIPT_QUEUE_TOPIC` | Topic name of the Receipt Queue | |
| `RECEIPT_QUEUE_MAX_RETRY` | Number of retry to complete the generation process before being tagged as FAILED | "5" |
| `RECEIPT_QUEUE_TOPIC_POISON` | Topic name of the Receipt Poison Queue | |
| `BLOB_STORAGE_ACCOUNT_ENDPOINT` | Endpoint to the Receipt Blob Storage | |
| `BLOB_STORAGE_CONTAINER_NAME` | Container name of the Receipt container in the Blob Storage | |
| `COSMOS_RECEIPTS_CONN_STRING` | Connection string to the Receipt CosmosDB | |
| `COSMOS_RECEIPT_SERVICE_ENDPOINT` | Endpoint to the Receipt CosmosDB | |
| `COSMOS_RECEIPT_KEY` | Key to the Receipt CosmosDB | |
| `COSMOS_RECEIPT_DB_NAME` | Database name of the Receipt database in CosmosDB | |
| `COSMOS_RECEIPT_CONTAINER_NAME` | Container name of the Receipt container in CosmosDB | |
| `PDF_ENGINE_ENDPOINT` | Endpoint to the PDF engine | |
| `OCP_APIM_SUBSCRIPTION_KEY` | Auth key for Azure to access the PDF Engine | |
| VARIABLE | USAGE | DEFAULT VALUE |
|---------------------------------------|----------------------------------------------------------------------------------|:------------------------------------------------------:|
| `RECEIPTS_STORAGE_CONN_STRING` | Connection string to the Receipt Storage | |
| `RECEIPT_QUEUE_TOPIC` | Topic name of the Receipt Queue | |
| `RECEIPT_QUEUE_MAX_RETRY` | Number of retry to complete the generation process before being tagged as FAILED | "5" |
| `RECEIPT_QUEUE_TOPIC_POISON` | Topic name of the Receipt Poison Queue | |
| `BLOB_STORAGE_ACCOUNT_ENDPOINT` | Endpoint to the Receipt Blob Storage | |
| `BLOB_STORAGE_CONTAINER_NAME` | Container name of the Receipt container in the Blob Storage | |
| `COSMOS_RECEIPTS_CONN_STRING` | Connection string to the Receipt CosmosDB | |
| `COSMOS_RECEIPT_SERVICE_ENDPOINT` | Endpoint to the Receipt CosmosDB | |
| `COSMOS_RECEIPT_KEY` | Key to the Receipt CosmosDB | |
| `COSMOS_RECEIPT_DB_NAME` | Database name of the Receipt database in CosmosDB | |
| `COSMOS_RECEIPT_CONTAINER_NAME` | Container name of the Receipt container in CosmosDB | |
| `PDF_ENGINE_ENDPOINT` | Endpoint to the PDF engine | |
| `OCP_APIM_SUBSCRIPTION_KEY` | Auth key for Azure to access the PDF Engine | |
| `PDV_TOKENIZER_BASE_PATH` | PDV Tokenizer API base path | "https://api.uat.tokenizer.pdv.pagopa.it/tokenizer/v1" |
| `PDV_TOKENIZER_SEARCH_TOKEN_ENDPOINT` | PDV Tokenizer API search token endpoint | "/tokens/search" |
| `PDV_TOKENIZER_FIND_PII_ENDPOINT` | PDV Tokenizer API find pii endpoint | "/tokens/%s/pii" |
| `PDV_TOKENIZER_CREATE_TOKEN_ENDPOINT` | PDV Tokenizer API create token endpoint | "/tokens" |
| `PDV_TOKENIZER_SUBSCRIPTION_KEY` | Tokenizer API azure ocp apim subscription key | |
| `TOKENIZER_APIM_HEADER_KEY` | Tokenizer APIM header key | x-api-key |
| `AES_SECRET_KEY` | AES encryption secret key | |
| `AES_SALT` | AES encryption salt | |

> to doc details about AZ fn config
> see [here](https://stackoverflow.com/questions/62669672/azure-functions-what-is-the-purpose-of-having-host-json-and-local-settings-jso)
Expand Down
4 changes: 4 additions & 0 deletions helm/values-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ microservice-chart:
BLOB_STORAGE_ACCOUNT_ENDPOINT: "https://pagopadweureceiptsfnsa.blob.core.windows.net/"
BLOB_STORAGE_CONTAINER_NAME: "pagopa-d-weu-receipts-azure-blob-receipt-st-attach"
WORKING_DIRECTORY_PATH: "/temp"
PDV_TOKENIZER_BASE_PATH: "https://api.uat.tokenizer.pdv.pagopa.it/tokenizer/v1"
ENABLE_ECS_CONSOLE: "true"
CONSOLE_LOG_THRESHOLD: "DEBUG"
CONSOLE_LOG_PATTERN: "%d{HH:mm:ss.SSS}[%thread]%-5level%logger{36}-%msg%n"
Expand All @@ -113,6 +114,9 @@ microservice-chart:
OCP_APIM_SUBSCRIPTION_KEY: "shared-apim-d-subscription-key"
COSMOS_RECEIPT_KEY: "cosmos-receipt-pkey"
OTEL_EXPORTER_OTLP_HEADERS: 'elastic-otl-secret-token'
PDV_TOKENIZER_SUBSCRIPTION_KEY: "tokenizer-api-key"
AES_SECRET_KEY: "aes-secret-key"
AES_SALT: "aes-salt"
keyvault:
name: "pagopa-d-receipts-kv"
tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d"
Expand Down
4 changes: 4 additions & 0 deletions helm/values-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ microservice-chart:
BLOB_STORAGE_ACCOUNT_ENDPOINT: "https://pagopapweureceiptsfnsa.blob.core.windows.net"
BLOB_STORAGE_CONTAINER_NAME: "pagopa-p-weu-receipts-azure-blob-receipt-st-attach"
WORKING_DIRECTORY_PATH: "/temp"
PDV_TOKENIZER_BASE_PATH: "https://api.tokenizer.pdv.pagopa.it"
ENABLE_ECS_CONSOLE: "true"
CONSOLE_LOG_THRESHOLD: "DEBUG"
CONSOLE_LOG_PATTERN: "%d{HH:mm:ss.SSS}[%thread]%-5level%logger{36}-%msg%n"
Expand All @@ -113,6 +114,9 @@ microservice-chart:
OCP_APIM_SUBSCRIPTION_KEY: "shared-apim-p-subscription-key"
COSMOS_RECEIPT_KEY: "cosmos-receipt-pkey"
OTEL_EXPORTER_OTLP_HEADERS: "elastic-otl-secret-token"
PDV_TOKENIZER_SUBSCRIPTION_KEY: "tokenizer-api-key"
AES_SECRET_KEY: "aes-secret-key"
AES_SALT: "aes-salt"
keyvault:
name: "pagopa-p-receipts-kv"
tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d"
Expand Down
4 changes: 4 additions & 0 deletions helm/values-uat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ microservice-chart:
BLOB_STORAGE_ACCOUNT_ENDPOINT: "https://pagopauweureceiptsfnsa.blob.core.windows.net"
BLOB_STORAGE_CONTAINER_NAME: "pagopa-u-weu-receipts-azure-blob-receipt-st-attach"
WORKING_DIRECTORY_PATH: "/temp"
PDV_TOKENIZER_BASE_PATH: "https://api.uat.tokenizer.pdv.pagopa.it/tokenizer/v1"
ENABLE_ECS_CONSOLE: "true"
CONSOLE_LOG_THRESHOLD: "DEBUG"
CONSOLE_LOG_PATTERN: "%d{HH:mm:ss.SSS}[%thread]%-5level%logger{36}-%msg%n"
Expand All @@ -113,6 +114,9 @@ microservice-chart:
OCP_APIM_SUBSCRIPTION_KEY: "shared-apim-u-subscription-key"
COSMOS_RECEIPT_KEY: "cosmos-receipt-pkey"
OTEL_EXPORTER_OTLP_HEADERS: "elastic-otl-secret-token"
PDV_TOKENIZER_SUBSCRIPTION_KEY: "tokenizer-api-key"
AES_SECRET_KEY: "aes-secret-key"
AES_SALT: "aes-salt"
keyvault:
name: "pagopa-u-receipts-kv"
tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d"
Expand Down
13 changes: 8 additions & 5 deletions integration-test/src/step_definitions/common.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
const FISCAL_CODE = "AAAAAA00A00A000A";
const TOKENIZED_FISCAL_CODE = "cd07268c-73e8-4df4-8305-a35085e32eff";

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Expand Down Expand Up @@ -43,7 +46,7 @@ function createEventForPoisonQueue(id, attemptedPoisonRetry) {
"debtor": {
"fullName": "paGetPaymentName",
"entityUniqueIdentifierType": "G",
"entityUniqueIdentifierValue": "JHNDOE00A01F205N",
"entityUniqueIdentifierValue": FISCAL_CODE,
"streetName": "paGetPaymentStreet",
"civicNumber": "paGetPayment99",
"postalCode": "20155",
Expand All @@ -55,7 +58,7 @@ function createEventForPoisonQueue(id, attemptedPoisonRetry) {
"payer": {
"fullName": "name",
"entityUniqueIdentifierType": "G",
"entityUniqueIdentifierValue": "JHNDOE00A01F205S",
"entityUniqueIdentifierValue": FISCAL_CODE,
"streetName": "street",
"civicNumber": "civic",
"postalCode": "postal",
Expand Down Expand Up @@ -98,7 +101,7 @@ function createEventForPoisonQueue(id, attemptedPoisonRetry) {
"user": {
"fullName": "John Doe",
"type": "F",
"fiscalCode": "JHNDOE00A01F205N",
"fiscalCode": FISCAL_CODE,
"notificationEmail": "john.doe@mail.it",
"userId": "1234",
"userStatus": "11",
Expand Down Expand Up @@ -128,8 +131,8 @@ function createReceipt(id) {
{
"eventId": id,
"eventData": {
"payerFiscalCode": "JHNDOE00A01F205N",
"debtorFiscalCode": "JHNDOE00A01F205N",
"payerFiscalCode": TOKENIZED_FISCAL_CODE,
"debtorFiscalCode": TOKENIZED_FISCAL_CODE,
"amount": "200",
"cart": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const assert = require('assert');
const { After, Given, When, Then, setDefaultTimeout } = require('@cucumber/cucumber');
const { sleep, createEventForQueue, createEventForPoisonQueue } = require("./common");
const { getDocumentByIdFromReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastoreByMessagePayload, deleteDocumentFromReceiptsDatastore, createDocumentInReceiptsDatastore, createDocumentInErrorReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastore, getDocumentByMessagePayloadFromErrorReceiptsDatastore } = require("./receipts_datastore_client");
const { putMessageOnPoisonQueue, putMessageOnReceiptQueue } = require("./reqeipt_queue_client");
const { getDocumentByIdFromReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastoreByBizEventId, deleteDocumentFromReceiptsDatastore, createDocumentInReceiptsDatastore, createDocumentInErrorReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastore, getDocumentByBizEventIdFromErrorReceiptsDatastore } = require("./receipts_datastore_client");
const { putMessageOnPoisonQueue, putMessageOnReceiptQueue } = require("./receipts_queue_client");
const { receiptPDFExist } = require("./receipts_blob_storage_client");

// set timeout for Hooks function, it allows to wait for long task
Expand Down Expand Up @@ -78,14 +78,14 @@ Then('the blob storage has the PDF document', async function () {
Given('a random biz event with id {string} enqueued on receipts poison queue with poison retry {string}', async function (id, value) {
let attemptedPoisonRetry = (value === 'true');
this.event = createEventForPoisonQueue(id, attemptedPoisonRetry);
await deleteDocumentFromErrorReceiptsDatastoreByMessagePayload(this.event);
await deleteDocumentFromErrorReceiptsDatastoreByBizEventId(id);
await putMessageOnPoisonQueue(this.event);
});

When('the biz event has been properly stored on receipt-message-error datastore after {int} ms', async function (time) {
// boundary time spent by azure function to process event
await sleep(time);
this.responseToCheck = await getDocumentByMessagePayloadFromErrorReceiptsDatastore(this.event);
this.responseToCheck = await getDocumentByBizEventIdFromErrorReceiptsDatastore(this.event.id);
});

Then('the receipt-message-error datastore returns the error receipt', async function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ async function deleteDocumentFromReceiptsDatastore(id, partitionKey) {

// receipts-message-error datastore

async function getDocumentByMessagePayloadFromErrorReceiptsDatastore(messagePayload) {
async function getDocumentByBizEventIdFromErrorReceiptsDatastore(bizEventId) {
return await errorReceiptContainer.items
.query({
query: "SELECT * from c WHERE c.messagePayload=@messagePayload",
parameters: [{ name: "@messagePayload", value: JSON.stringify(messagePayload) }]
query: "SELECT * from c WHERE c.bizEventId=@bizEventId",
parameters: [{ name: "@bizEventId", value: JSON.stringify(bizEventId) }]
})
.fetchNext();
}
Expand All @@ -61,6 +61,7 @@ async function createDocumentInErrorReceiptsDatastore(id) {
let event = createEventForPoisonQueue(id, true);
let payload = {
"messagePayload": JSON.stringify(event),
"bizEventId": id,
"status": "REVIEWED",
"id": id,
"_rid": "Z9AJAJpW0pIhAAAAAAAAAA==",
Expand All @@ -86,14 +87,14 @@ async function deleteDocumentFromErrorReceiptsDatastore(id) {
}
}

async function deleteDocumentFromErrorReceiptsDatastoreByMessagePayload(messagePayload) {
let documents = await getDocumentByMessagePayloadFromErrorReceiptsDatastore(messagePayload);
async function deleteDocumentFromErrorReceiptsDatastoreByBizEventId(bizEventId) {
let documents = await getDocumentByBizEventIdFromErrorReceiptsDatastore(bizEventId);

documents?.resources?.forEach((el) => {
deleteDocumentFromErrorReceiptsDatastore(el.id);
})
}

module.exports = {
getDocumentByIdFromReceiptsDatastore, deleteDocumentFromReceiptsDatastoreByEventId, createDocumentInReceiptsDatastore, deleteDocumentFromReceiptsDatastore, getDocumentByMessagePayloadFromErrorReceiptsDatastore, createDocumentInErrorReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastoreByMessagePayload
getDocumentByIdFromReceiptsDatastore, deleteDocumentFromReceiptsDatastoreByEventId, createDocumentInReceiptsDatastore, deleteDocumentFromReceiptsDatastore, getDocumentByBizEventIdFromErrorReceiptsDatastore, createDocumentInErrorReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastore, deleteDocumentFromErrorReceiptsDatastoreByBizEventId
}
12 changes: 7 additions & 5 deletions performance-test/src/modules/common.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const FISCAL_CODE = "AAAAAA00A00A000A";
const TOKENIZED_FISCAL_CODE = "cd07268c-73e8-4df4-8305-a35085e32eff";

export function randomString(length, charset) {
let res = '';
Expand Down Expand Up @@ -41,7 +43,7 @@ export function createEvent(id) {
"debtor": {
"fullName": "paGetPaymentName",
"entityUniqueIdentifierType": "G",
"entityUniqueIdentifierValue": "JHNDOE00A01F205N",
"entityUniqueIdentifierValue": FISCAL_CODE,
"streetName": "paGetPaymentStreet",
"civicNumber": "paGetPayment99",
"postalCode": "20155",
Expand All @@ -53,7 +55,7 @@ export function createEvent(id) {
"payer": {
"fullName": "name",
"entityUniqueIdentifierType": "G",
"entityUniqueIdentifierValue": "JHNDOE00A01F205S",
"entityUniqueIdentifierValue": FISCAL_CODE,
"streetName": "street",
"civicNumber": "civic",
"postalCode": "postal",
Expand Down Expand Up @@ -96,7 +98,7 @@ export function createEvent(id) {
"user": {
"fullName": "John Doe",
"type": "F",
"fiscalCode": "JHNDOE00A01F205N",
"fiscalCode": FISCAL_CODE,
"notificationEmail": "john.doe@mail.it",
"userId": "1234",
"userStatus": "11",
Expand Down Expand Up @@ -126,8 +128,8 @@ export function createReceipt(id) {
{
"eventId": id,
"eventData": {
"payerFiscalCode": "GENERATOR_PERF_TEST",
"debtorFiscalCode": "GENERATOR_PERF_TEST",
"payerFiscalCode": TOKENIZED_FISCAL_CODE,
"debtorFiscalCode": TOKENIZED_FISCAL_CODE,
"amount": "200",
"cart": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import it.gov.pagopa.receipt.pdf.generator.entity.event.BizEvent;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.ReceiptError;
import it.gov.pagopa.receipt.pdf.generator.entity.receipt.enumeration.ReceiptErrorStatusType;
import it.gov.pagopa.receipt.pdf.generator.exception.Aes256Exception;
import it.gov.pagopa.receipt.pdf.generator.exception.UnableToQueueException;
import it.gov.pagopa.receipt.pdf.generator.utils.Aes256Utils;
import it.gov.pagopa.receipt.pdf.generator.utils.ObjectMapperUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -92,18 +94,30 @@ public void processManageReceiptPoisonQueue(
logger.error("[{}] error for the function called at {} when attempting" +
"to requeue BizEvent wit id {}, saving to cosmos for review",
context.getFunctionName(), LocalDateTime.now(), bizEvent.getId(), e);
saveToDocument(context, errorMessage, documentdb);
saveToDocument(context, errorMessage, bizEvent.getId(), documentdb);
}
} else {
saveToDocument(context, errorMessage, documentdb);
saveToDocument(context, errorMessage, bizEvent != null ? bizEvent.getId() : null, documentdb);
}
}

private void saveToDocument(ExecutionContext context, String errorMessage,
private void saveToDocument(ExecutionContext context, String errorMessage, String bizEventId,
OutputBinding<ReceiptError> documentdb) {
logger.info("[{}] saving new entry to the retry error to review with payload {}",
context.getFunctionName(), errorMessage);
documentdb.setValue(ReceiptError.builder().messagePayload(errorMessage)
.status(ReceiptErrorStatusType.TO_REVIEW).build());

ReceiptError receiptError = ReceiptError.builder()
.bizEventId(bizEventId)
.status(ReceiptErrorStatusType.TO_REVIEW).build();

try {
String encodedEvent = Aes256Utils.encrypt(errorMessage);
receiptError.setMessagePayload(encodedEvent);

} catch (Aes256Exception e) {
receiptError.setMessageError(e.getMessage());
}

documentdb.setValue(receiptError);
}
}
Loading
Loading