From b3b1abb72eca6bbd78259a66c1e6c25f426b496d Mon Sep 17 00:00:00 2001 From: Ann Katrin Gagnat Date: Fri, 14 Jun 2024 10:58:09 +0200 Subject: [PATCH] Register duration of express json body parser and verification of idporten token --- packages/fyllut-backend/src/app.ts | 3 +- .../middleware/expressJsonMetricHandler.ts | 21 ++++++++++++++ .../src/security/idportenAuthHandler.ts | 4 +++ .../fyllut-backend/src/services/AppMetrics.ts | 28 +++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 packages/fyllut-backend/src/middleware/expressJsonMetricHandler.ts diff --git a/packages/fyllut-backend/src/app.ts b/packages/fyllut-backend/src/app.ts index 4d975933a..a39eea63d 100644 --- a/packages/fyllut-backend/src/app.ts +++ b/packages/fyllut-backend/src/app.ts @@ -6,6 +6,7 @@ import { checkConfigConsistency, config } from './config/config'; import { NaisCluster } from './config/nais-cluster'; import { buildDirectory } from './context.js'; import { setupDeprecatedEndpoints } from './deprecatedEndpoints.js'; +import expressJsonMetricHandler from './middleware/expressJsonMetricHandler'; import globalErrorHandler from './middleware/globalErrorHandler.js'; import httpRequestLogger from './middleware/httpRequestLogger.js'; import { stripTrailingSlash } from './middleware/stripTrailingSlash'; @@ -20,7 +21,7 @@ export const createApp = (setupDev: boolean = false) => { const app = express(); app.use(httpRequestLogger); - app.use(express.json({ limit: '50mb' })); + app.use(expressJsonMetricHandler(express.json({ limit: '50mb' }))); app.use(express.urlencoded({ extended: true, limit: '50mb' })); app.use(correlator()); app.use(cors()); diff --git a/packages/fyllut-backend/src/middleware/expressJsonMetricHandler.ts b/packages/fyllut-backend/src/middleware/expressJsonMetricHandler.ts new file mode 100644 index 000000000..8fdabb7ad --- /dev/null +++ b/packages/fyllut-backend/src/middleware/expressJsonMetricHandler.ts @@ -0,0 +1,21 @@ +import { NextFunction, Request, Response } from 'express'; +import { appMetrics } from '../services'; + +const expressJsonMetricHandler = (fn: Function) => async (req: Request, res: Response, next: NextFunction) => { + if (req.method === 'PUT' && req.url.includes('/send-inn/utfyltsoknad')) { + const stopTimer = appMetrics.expressJsonBodyParserDuration.startTimer({ endpoint: 'put-utfyltsoknad' }); + let errorOccured = false; + try { + await fn(req, res, next); + } catch (err) { + errorOccured = true; + throw err; + } finally { + stopTimer({ error: String(errorOccured) }); + } + } else { + await fn(req, res, next); + } +}; + +export default expressJsonMetricHandler; diff --git a/packages/fyllut-backend/src/security/idportenAuthHandler.ts b/packages/fyllut-backend/src/security/idportenAuthHandler.ts index e3cbe10f4..bb90a81f0 100644 --- a/packages/fyllut-backend/src/security/idportenAuthHandler.ts +++ b/packages/fyllut-backend/src/security/idportenAuthHandler.ts @@ -3,6 +3,7 @@ import { FlattenedJWSInput, JWSHeaderParameters, createRemoteJWKSet, jwtVerify } import { GetKeyFunction } from 'jose/dist/types/types'; import { config } from '../config/config'; import { logger } from '../logger.js'; +import { appMetrics } from '../services'; import { IdportenTokenPayload } from '../types/custom'; const { isDevelopment, mockIdportenJwt, mockIdportenPid } = config; @@ -31,11 +32,14 @@ const idportenAuthHandler = async (req: Request, res: Response, next: NextFuncti logger.debug('Verifying jwt...'); let tokenContent: IdportenTokenPayload; + const stopTimer = appMetrics.idportenVerifyTokenDuration.startTimer(); try { tokenContent = await verifyToken(token); } catch (err) { logger.warn('Failed to verify jwt signature', err); return res.sendStatus(401); + } finally { + stopTimer(); } const currentTime = new Date().getTime() / 1000; const expired = tokenContent.exp! - 10 < currentTime; diff --git a/packages/fyllut-backend/src/services/AppMetrics.ts b/packages/fyllut-backend/src/services/AppMetrics.ts index 7e0fa6bb4..f14324d47 100644 --- a/packages/fyllut-backend/src/services/AppMetrics.ts +++ b/packages/fyllut-backend/src/services/AppMetrics.ts @@ -6,6 +6,8 @@ class AppMetrics { private readonly _exstreamPdfRequestsCounter: Counter; private readonly _exstreamPdfFailuresCounter: Counter; private readonly _outgoingRequestDuration: Histogram; + private readonly _expressJsonBodyParserDuration: Histogram; + private readonly _idportenVerifyTokenDuration: Histogram; constructor() { logger.info('Initializing metrics client'); @@ -36,6 +38,24 @@ class AppMetrics { this._outgoingRequestDuration.zero({ service: 'exstream', method: 'createPdf', error: 'false' }); this._outgoingRequestDuration.zero({ service: 'exstream', method: 'createPdf', error: 'true' }); + this._expressJsonBodyParserDuration = new Histogram({ + name: 'fyllut_express_json_body_parser_seconds', + help: 'Express json body parser duration', + labelNames: ['endpoint', 'error'], + buckets: [0.025, 0.05, 0.1, 0.2, 0.4, 0.8, 1.6, 3.2, 6.4, 12.8], + registers: [this._register], + }); + this._expressJsonBodyParserDuration.zero({ endpoint: 'put-utfyltsoknad', error: 'false' }); + this._expressJsonBodyParserDuration.zero({ endpoint: 'put-utfyltsoknad', error: 'true' }); + + this._idportenVerifyTokenDuration = new Histogram({ + name: 'fyllut_idporten_verify_token_seconds', + help: 'Idporten auth duration', + labelNames: [], + buckets: [0.025, 0.05, 0.1, 0.2, 0.4, 0.8, 1.6, 3.2, 6.4, 12.8], + registers: [this._register], + }); + collectDefaultMetrics({ register: this._register }); } @@ -54,6 +74,14 @@ class AppMetrics { public get outgoingRequestDuration() { return this._outgoingRequestDuration; } + + public get idportenVerifyTokenDuration() { + return this._idportenVerifyTokenDuration; + } + + public get expressJsonBodyParserDuration() { + return this._expressJsonBodyParserDuration; + } } export default AppMetrics;