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

New audit log implementation #64

Merged
merged 45 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
28592ae
feat(op-app): new audit use case
acuiuli Jul 10, 2024
463320a
prettier fix
acuiuli Jul 10, 2024
e2ca7f9
fixed infra events queue
acuiuli Jul 10, 2024
789cf39
lint fix
acuiuli Jul 10, 2024
e475433
new implementation to manage id_token for audit
acuiuli Jul 16, 2024
6414b10
lint and format fix
acuiuli Jul 16, 2024
65a8b58
fixed terraform variables for event queue
acuiuli Jul 16, 2024
a5b2650
lint fix
acuiuli Jul 16, 2024
7d23672
fixed error in consentSchema
acuiuli Jul 16, 2024
0ab2cf4
fix audit use case execution
acuiuli Jul 22, 2024
d7c9d59
Merge branch 'main' of https://github.com/pagopa/io-fims into IOCOM-1383
acuiuli Jul 23, 2024
dd7b42c
fixes after merge from main
acuiuli Jul 24, 2024
a583883
audit use case fixed and queue handler
acuiuli Jul 29, 2024
7dd29cb
Merge branch 'main' of https://github.com/pagopa/io-fims into IOCOM-1383
acuiuli Jul 29, 2024
6bac044
removed unused config
acuiuli Jul 29, 2024
3fb9c20
fixed lint and format
acuiuli Jul 29, 2024
35c3f67
Merge branch 'main' of https://github.com/pagopa/io-fims into IOCOM-1383
acuiuli Jul 30, 2024
0cdc459
fixed env vars
acuiuli Jul 30, 2024
acb5c79
fixed user meta data
acuiuli Jul 30, 2024
43035dc
adde container_name var to storage event
acuiuli Jul 30, 2024
0678695
fixed op-app tests
acuiuli Jul 30, 2024
2b1d7a4
format fix
acuiuli Jul 30, 2024
06f1a89
fixed userMetaData import
acuiuli Jul 30, 2024
7d07b33
fixed user-metadata in commons package
acuiuli Aug 8, 2024
8a5764c
lint fix
acuiuli Aug 8, 2024
0bf84c0
fixed container_name in event storage account
acuiuli Aug 8, 2024
cd25595
removed IO_BASE_URL env var
acuiuli Aug 8, 2024
e073701
ip request validation
acuiuli Aug 8, 2024
5776360
fixed send event message use case
acuiuli Aug 8, 2024
94a89bc
lint fix
acuiuli Aug 8, 2024
5a052c0
fixed error management for send event message
acuiuli Aug 8, 2024
e823a3d
small fix in send-event-message use case
acuiuli Sep 6, 2024
7b42fe7
small fixes to send-event-message use case
acuiuli Sep 6, 2024
f093c15
Merge branch 'main' into IOCOM-1383
lucacavallaro Nov 21, 2024
5a23564
fix audit events
lucacavallaro Dec 1, 2024
04b51ac
fix lint
lucacavallaro Dec 2, 2024
4bcdcdd
fix infra
lucacavallaro Dec 2, 2024
19cd613
Update federated_identities.tf
lucacavallaro Dec 2, 2024
c71a303
fix: add key vault crypto officer to gh runner identity
christian-calabrese Dec 2, 2024
5a929d4
fix: add key vault crypto officer to gh runner identity
christian-calabrese Dec 2, 2024
e0aa30d
add environment variables
lucacavallaro Dec 2, 2024
d022802
fix op-func
lucacavallaro Dec 2, 2024
975f93c
add blob perm
lucacavallaro Dec 3, 2024
5e1ce96
fix environment variable
lucacavallaro Dec 3, 2024
a752fae
fix timestamp
lucacavallaro Dec 3, 2024
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
1 change: 1 addition & 0 deletions apps/op-app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SESSION_MANAGER_BASE_URL=https://io-p-weu-session-manager-app-03.azurewebsites.n
LOLLIPOP_BASE_URL=https://api.io.pagopa.it
LOLLIPOP_API_KEY=api-key-here
ACCESS_QUEUE_URL=https://lcavallaro.queue.core.windows.net/access-queue
AUDIT_EVENT_QUEUE_URL=https://lcavallaro.queue.core.windows.net/audit-events-queue
REDIS_URL=redis-url-here
REDIS_PASSWORD=redis-password-here
REDIS_PING_INTERVAL=540000
Expand Down
2 changes: 2 additions & 0 deletions apps/op-app/src/adapters/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { redisConfigSchema } from "./redis/config.js";

export const storageQueueConfigSchema = z.object({
accessQueueUrl: z.string().url(),
eventsQueueUrl: z.string().url(),
});

export const configSchema = z.object({
Expand Down Expand Up @@ -51,6 +52,7 @@ export const configFromEnvironment = envSchema.transform(
},
storageQueue: {
accessQueueUrl: env.ACCESS_QUEUE_URL,
eventsQueueUrl: env.AUDIT_EVENT_QUEUE_URL,
},
}),
);
1 change: 1 addition & 0 deletions apps/op-app/src/adapters/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { z } from "zod";
export const envSchema = nodeEnvSchema.and(cosmosEnvSchema).and(
z.object({
ACCESS_QUEUE_URL: z.string().min(1),
AUDIT_EVENT_QUEUE_URL: z.string().url(),
KEY_VAULT_KEY_NAME: z.string().min(1),
KEY_VAULT_URL: z.string().url(),
LOLLIPOP_API_KEY: z.string().min(1),
Expand Down
4 changes: 3 additions & 1 deletion apps/op-app/src/adapters/express/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type Provider from "oidc-provider";

import { HealthUseCase } from "@/use-cases/health.js";
import { LogAccessUseCase } from "@/use-cases/log-access.js";
import { SendEventMessageUseCase } from "@/use-cases/send-event-messge.js";
import cookieParser from "cookie-parser";
import express from "express";
import helmet from "helmet";
Expand All @@ -17,6 +18,7 @@ import interactionRouter from "./routes/interaction.js";
export const createApplication = (
oidc: Provider,
login: LoginUseCase,
event: SendEventMessageUseCase,
logAccess: LogAccessUseCase,
health: HealthUseCase,
logger: Logger,
Expand All @@ -37,7 +39,7 @@ export const createApplication = (
}),
);

app.use(interactionRouter(oidc, login, logAccess));
app.use(interactionRouter(oidc, login, event, logAccess));

app.use(healthRouter(health));

Expand Down
30 changes: 26 additions & 4 deletions apps/op-app/src/adapters/express/routes/interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type Provider from "oidc-provider";

import { metadataForConsentFromScopes } from "@/domain/user-metadata.js";
import { LogAccessUseCase } from "@/use-cases/log-access.js";
import { SendEventMessageUseCase } from "@/use-cases/send-event-messge.js";
import * as express from "express";
import { requestParamsSchema } from "io-fims-common/domain/audit-event";
import * as assert from "node:assert/strict";
import { z } from "zod";

Expand Down Expand Up @@ -54,9 +56,11 @@ export const parseRedirectDisplayName = (
return redirectDisplayName.it;
};

/* eslint-disable max-lines-per-function */
export default function createInteractionRouter(
oidcProvider: Provider,
login: LoginUseCase,
eventUseCase: SendEventMessageUseCase,
logAccess: LogAccessUseCase,
) {
const router = express.Router();
Expand Down Expand Up @@ -118,6 +122,9 @@ export default function createInteractionRouter(

req.log.debug("using %s as baseUrl for links", baseUrl);

const userMetadata = metadataForConsentFromScopes(
consent.prompt.details.missingOIDCScope,
);
const apiModel = schemas.Consent.safeParse({
_links: {
abort: {
Expand All @@ -132,9 +139,7 @@ export default function createInteractionRouter(
},
service_id: consent.params.client_id,
type: interactionType,
user_metadata: metadataForConsentFromScopes(
consent.prompt.details.missingOIDCScope,
).map((name) => ({
user_metadata: userMetadata.map((name) => ({
// name can be "firstName", "lastName", ..
display_name: req.__(name),
// localize each metadata name using i18n-node
Expand Down Expand Up @@ -163,8 +168,9 @@ export default function createInteractionRouter(
assert.equal(
interaction.prompt.name,
"login",
new Error("Interaction type mismatch, login expected"),
"Interaction type mismatch, login expected",
);

const cookiesSchema = z.object({
_io_fims_token: z.string().min(1),
});
Expand All @@ -174,10 +180,25 @@ export default function createInteractionRouter(
new HttpBadRequestError(`Unable to parse the "_io_fims_token" cookie.`),
);
req.log.debug("_io_fims_token parsed from cookies");
const rpParams = requestParamsSchema.safeParse(interaction.params);
assert.ok(
rpParams.success,
new HttpBadRequestError(`Unable to parse the query params.`),
);
assert.ok(
req.ip,
new HttpBadRequestError(`Unable to retrieve ip address from request`),
);
const accountId = await login.execute(
cookies.data._io_fims_token,
interaction.jti,
);
await eventUseCase.execute({
ipAddress: req.ip,
requestParams: rpParams.data,
sessionId: accountId,
type: "rpStep",
});
return oidcProvider.interactionFinished(req, res, {
login: {
accountId,
Expand Down Expand Up @@ -249,3 +270,4 @@ export default function createInteractionRouter(

return router;
}
/* eslint-enable max-lines-per-function */
7 changes: 2 additions & 5 deletions apps/op-app/src/adapters/io/user-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import {
IdentityProvider,
UserMetadata,
userMetadataSchema,
} from "@/domain/user-metadata.js";
import { IdentityProvider } from "@/domain/user-metadata.js";
import { NonEmptyString } from "@pagopa/ts-commons/lib/strings.js";
import * as E from "fp-ts/lib/Either.js";
import { userMetadataSchema } from "io-fims-common/domain/user-metadata";
import * as assert from "node:assert/strict";
import { ZodError, z } from "zod";

Expand Down
26 changes: 26 additions & 0 deletions apps/op-app/src/adapters/oidc/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { SendEventMessageUseCase } from "@/use-cases/send-event-messge.js";
import Provider from "oidc-provider";
import { Logger } from "pino";

export function createTokenMiddleware(
provider: Provider,
eventUseCase: SendEventMessageUseCase,
logger: Logger,
) {
provider.use(async (ctx, next) => {
await next();
acuiuli marked this conversation as resolved.
Show resolved Hide resolved
if (ctx.oidc && ctx.oidc.route === "token") {
logger.info(`started post middleware for the route 'token'`);
const tokenResponse = ctx.response;
if (tokenResponse.status === 200) {
const responseBody = tokenResponse.body;
if (responseBody["id_token"]) {
eventUseCase.execute({
idToken: responseBody["id_token"],
type: "idToken",
});
}
}
}
});
}
44 changes: 44 additions & 0 deletions apps/op-app/src/adapters/redis/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
Event,
EventRepository,
auditEventSessionSchema,
} from "@/domain/session.js";
import * as assert from "node:assert/strict";
import {
RedisClientType,
RedisDefaultModules,
RedisFunctions,
RedisScripts,
} from "redis";

export default class RedisEventRepository implements EventRepository {
#client: RedisClientType<RedisDefaultModules, RedisFunctions, RedisScripts>;

constructor(
client: RedisClientType<RedisDefaultModules, RedisFunctions, RedisScripts>,
) {
this.#client = client;
}

#key(clientId: string, fiscalCode: string) {
return `audit:${clientId}:${fiscalCode}`;
}

async get(clientId: string, fiscalCode: string) {
const blobName = await this.#client.GET(this.#key(clientId, fiscalCode));
const event = auditEventSessionSchema.parse({
blobName,
clientId,
fiscalCode,
});
return event;
}

async upsert(event: Event) {
const result = await this.#client.SET(
this.#key(event.clientId, event.fiscalCode),
event.blobName,
);
assert.equal(result, "OK");
}
}
Loading
Loading