diff --git a/package-lock.json b/package-lock.json index 44a81df..1c8f2cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "luxon": "^3.5.0", "nestjs-pino": "^4.1.0", "pino-http": "^10.3.0", + "pino-std-serializers": "^7.0.0", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "save": "^2.9.0" @@ -2115,16 +2116,16 @@ } }, "node_modules/@nestjs/platform-express": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.5.tgz", - "integrity": "sha512-a629r8R8KC4skhdieQ0aIWH5vDBUFntWnWKFyDXQrll6/CllSchfWm87mWF39seaW6bXYtQtAEZY66JrngdrGA==", + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.15.tgz", + "integrity": "sha512-63ZZPkXHjoDyO7ahGOVcybZCRa7/Scp6mObQKjcX/fTEq1YJeU75ELvMsuQgc8U2opMGOBD7GVuc4DV0oeDHoA==", "license": "MIT", "dependencies": { "body-parser": "1.20.3", "cors": "2.8.5", - "express": "4.21.1", + "express": "4.21.2", "multer": "1.4.4-lts.1", - "tslib": "2.7.0" + "tslib": "2.8.1" }, "funding": { "type": "opencollective", @@ -2135,6 +2136,12 @@ "@nestjs/core": "^10.0.0" } }, + "node_modules/@nestjs/platform-express/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/@nestjs/schematics": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.2.2.tgz", @@ -5591,9 +5598,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -5615,7 +5622,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -5630,6 +5637,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { @@ -5647,12 +5658,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "license": "MIT" - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -8793,6 +8798,12 @@ "dev": true, "license": "ISC" }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", diff --git a/package.json b/package.json index a617585..730d8ca 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "luxon": "^3.5.0", "nestjs-pino": "^4.1.0", "pino-http": "^10.3.0", + "pino-std-serializers": "^7.0.0", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "save": "^2.9.0" diff --git a/src/app.module.ts b/src/app.module.ts index d91f5f7..83dbdeb 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -9,6 +9,10 @@ import { HelpersModule } from './helpers/helpers.module'; import { LoggerModule } from 'nestjs-pino'; import { CacheModule } from '@nestjs/cache-manager'; import { ExternalApiModule } from './external-api/external-api.module'; +import { + wrapRequestSerializer, + wrapResponseSerializer, +} from 'pino-std-serializers'; @Module({ imports: [ @@ -23,15 +27,63 @@ import { ExternalApiModule } from './external-api/external-api.module'; customSuccessObject: (req, res, loggableObject) => { return { ...loggableObject, + res, buildNumber: configService.get('buildInfo.buildNumber'), }; }, customErrorObject: (req, res, loggableObject) => { return { ...loggableObject, + res, buildNumber: configService.get('buildInfo.buildNumber'), }; }, + customReceivedObject: (req, res, loggableObject) => { + return { + ...loggableObject, + buildNumber: configService.get('buildInfo.buildNumber'), + msg: 'Request received', + }; + }, + serializers: { + req: wrapRequestSerializer((req) => { + return { + id: req.raw.id, + method: req.raw.method, + path: req.raw.url, + query: req.query, + params: req.params, + // Allowlist useful headers + headers: { + host: req.raw.headers.host, + connection: req.raw.headers.connection, + 'x-forwarded-proto': req.raw.headers['x-forwarded-proto'], + 'x-forwarded-host': req.raw.headers['x-forwarded-host'], + 'x-forwarded-port': req.raw.headers['x-forwarded-port'], + 'x-forwarded-path': req.raw.headers['x-forwarded-path'], + 'x-real-ip': req.raw.headers['x-real-ip'], + 'user-agent': req.raw.headers['user-agent'], + accept: req.raw.headers.accept, + 'accept-language': req.raw.headers['accept-language'], + 'x-credential-identifier': + req.raw.headers['x-credential-identifier'], + 'x-idir-username': req.raw.headers['x-idir-username'], + 'x-authenticated-groups': + req.raw.headers['x-authenticated-groups'], + 'kong-request-id': req.raw.headers['kong-request-id'], + referer: req.raw.headers.referer, + }, + remoteAddress: req.remoteAddress, + remotePort: req.remotePort, + }; + }), + res: wrapResponseSerializer((res) => { + return { + statusCode: res.raw.statusCode, + headers: res.headers, + }; + }), + }, }, }), }), diff --git a/src/common/guards/auth/auth.guard.ts b/src/common/guards/auth/auth.guard.ts index 52791f7..f061e11 100644 --- a/src/common/guards/auth/auth.guard.ts +++ b/src/common/guards/auth/auth.guard.ts @@ -1,10 +1,16 @@ -import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; +import { + CanActivate, + ExecutionContext, + Injectable, + Logger, +} from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { AuthService } from './auth.service'; @Injectable() export class AuthGuard implements CanActivate { skip; + private readonly logger = new Logger(AuthGuard.name); constructor( private readonly authService: AuthService, private readonly configService: ConfigService, @@ -20,6 +26,15 @@ export class AuthGuard implements CanActivate { const request = context.switchToHttp().getRequest(); const controllerPath = Reflect.getMetadata('path', context.getClass()) || ''; - return await this.authService.getRecordAndValidate(request, controllerPath); + const isAuthorized = await this.authService.getRecordAndValidate( + request, + controllerPath, + ); + if (isAuthorized) { + this.logger.log({ msg: `Auth status: 200`, authStatusCode: 200 }); + } else { + this.logger.log({ msg: `Auth status: 403`, authStatusCode: 403 }); + } + return isAuthorized; } } diff --git a/src/common/guards/auth/auth.service.ts b/src/common/guards/auth/auth.service.ts index 814af0f..0c85e84 100644 --- a/src/common/guards/auth/auth.service.ts +++ b/src/common/guards/auth/auth.service.ts @@ -60,9 +60,12 @@ export class AuthService { if (upstreamResult === undefined) { this.logger.log(`Cache not hit, going upstream...`); upstreamResult = await this.getAssignedIdirUpstream(id, recordType); - await this.cacheManager.set(key, upstreamResult, this.cacheTime); + if (upstreamResult !== null) { + await this.cacheManager.set(key, upstreamResult, this.cacheTime); + } + this.logger.log(`Upstream result: '${upstreamResult}'`); } else { - this.logger.log(`Cache hit! Result: ${upstreamResult}`); + this.logger.log(`Cache hit! Result: '${upstreamResult}'`); } if (upstreamResult !== idir) { return false; @@ -118,16 +121,12 @@ export class AuthService { response = await firstValueFrom( this.httpService.get(url, { params, headers }), ); - this.logger.log(response); - const idir = - response.data['items'][0][ - this.configService.get(`upstreamAuth.${recordType}.idirField`) - ]; - this.logger.log(idir); + const fieldName = this.configService.get( + `upstreamAuth.${recordType}.idirField`, + ); + const idir = response.data['items'][0][`${fieldName}`]; if (idir === undefined) { - this.logger.error( - `${this.configService.get(`upstreamAuth.${recordType}.idirField`)} field not found in request`, - ); + this.logger.error(`${fieldName} field not found in request`); return null; } return idir; diff --git a/src/external-api/token-refresher/token-refresher.service.ts b/src/external-api/token-refresher/token-refresher.service.ts index f244954..4beee04 100644 --- a/src/external-api/token-refresher/token-refresher.service.ts +++ b/src/external-api/token-refresher/token-refresher.service.ts @@ -65,10 +65,6 @@ export class TokenRefresherService { response = await firstValueFrom( this.httpService.post(this.accessTokenUrl, data, { headers }), ); - this.logger.log({ - functionName: 'authenticateUpstream', - data: response.data, - }); const access_token = response.data['access_token']; const token_type = response.data['token_type']; const expirySeconds = response.data['expires_in'];