Skip to content

Commit

Permalink
feat: added IAuditUser to request with middleware (#6857)
Browse files Browse the repository at this point in the history
Adds a middleware which adds our needed audit info as a separate object
to the request.
  • Loading branch information
chriswk committed Apr 18, 2024
1 parent 06f2f06 commit 633cae6
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { unless } from './middleware/unless-middleware';
import { catchAllErrorHandler } from './middleware/catch-all-error-handler';
import NotFoundError from './error/notfound-error';
import { bearerTokenMiddleware } from './middleware/bearer-token-middleware';
import { auditAccessMiddleware } from './middleware';

export default async function getApp(
config: IUnleashConfig,
Expand Down Expand Up @@ -176,6 +177,7 @@ export default async function getApp(
rbacMiddleware(config, stores, services.accessService),
);

app.use(`${baseUriPath}/api/admin`, auditAccessMiddleware(config));
app.use(
`${baseUriPath}/api/admin`,
maintenanceMiddleware(config, services.maintenanceService),
Expand Down
42 changes: 42 additions & 0 deletions src/lib/middleware/audit-middleware.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { auditAccessMiddleware } from './audit-middleware';
import { createTestConfig } from '../../test/config/test-config';
import express from 'express';
import noAuthentication from './no-authentication';
import type { IAuthRequest } from '../routes/unleash-types';
import type { IAuditUser } from '../types';
import supertest from 'supertest';

const config = createTestConfig();

describe('auditMiddleware testing', () => {
test('Adds username and id from an IAuthRequest', async () => {
const middleware = auditAccessMiddleware(config);
const app = express();
noAuthentication('', app);
app.use('', middleware);
let audit: IAuditUser | undefined;
app.get('/api/admin/test', (req: IAuthRequest, res) => {
audit = req.audit;
res.status(200).end();
});
const request = supertest(app);
await request.get('/api/admin/test').expect(200);
expect(audit).toBeDefined();
expect(audit!.id).toBe(-1);
expect(audit!.username).toBe('unknown');
expect(audit!.ip).toBe('::ffff:127.0.0.1');
});
test('If no auth in place, does not add the audit object', async () => {
const middleware = auditAccessMiddleware(config);
const app = express();
app.use('', middleware);
let audit: IAuditUser | undefined;
app.get('/api/admin/test', (req: IAuthRequest, res) => {
audit = req.audit;
res.status(200).end();
});
const request = supertest(app);
await request.get('/api/admin/test').expect(200);
expect(audit).toBeUndefined();
});
});
17 changes: 17 additions & 0 deletions src/lib/middleware/audit-middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { IUnleashConfig } from '../types';
import type { IApiRequest, IAuthRequest } from '../routes/unleash-types';
import { extractAuditInfo } from '../util';

export const auditAccessMiddleware = ({
getLogger,
}: Pick<IUnleashConfig, 'getLogger'>): any => {
const logger = getLogger('/middleware/audit-middleware.ts');
return (req: IAuthRequest | IApiRequest, _res, next) => {
if (!req.user) {
logger.info('Could not find user');
} else {
req.audit = extractAuditInfo(req);
}
next();
};
};
1 change: 1 addition & 0 deletions src/lib/middleware/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './api-token-middleware';
export * from './audit-middleware';
export * from './conditional-middleware';
export * from './content_type_checker';
export * from './cors-origin-middleware';
Expand Down
4 changes: 3 additions & 1 deletion src/lib/routes/unleash-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Request } from 'express';
import type { IUser } from '../types/user';
import type { IAuditUser, IUser } from '../types/user';
import type { IApiUser } from '../types';

export interface IAuthRequest<
Expand All @@ -11,6 +11,7 @@ export interface IAuthRequest<
user: IUser;
logout: (() => void) | ((callback: (err?: any) => void) => void);
session: any;
audit?: IAuditUser;
}

export interface IApiRequest<
Expand All @@ -22,6 +23,7 @@ export interface IApiRequest<
user: IApiUser;
logout: (() => void) | ((callback: (err?: any) => void) => void);
session: any;
audit?: IAuditUser;
}

export interface RequestBody<T> extends Express.Request {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
SYSTEM_USER,
} from './types';

import User, { type IUser } from './types/user';
import User, { type IAuditUser, type IUser } from './types/user';
import ApiUser, { type IApiUser } from './types/api-user';
import { type Logger, LogLevel } from './logger';
import AuthenticationRequired from './types/authentication-required';
Expand Down Expand Up @@ -220,6 +220,7 @@ export type {
IUnleashConfig,
IUser,
IApiUser,
IAuditUser,
IUnleashServices,
IAuthRequest,
IApiRequest,
Expand Down
6 changes: 6 additions & 0 deletions src/lib/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export interface IProjectUser extends IUser {
addedAt: Date;
}

export interface IAuditUser {
id: number;
username: string;
ip?: string;
}

export default class User implements IUser {
isAPI: boolean = false;

Expand Down
9 changes: 9 additions & 0 deletions src/lib/util/extract-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
IApiRequest,
IApiUser,
IAuthRequest,
IAuditUser,
IUser,
} from '../server-impl';

Expand All @@ -26,3 +27,11 @@ export const extractUserInfo = (req: IAuthRequest | IApiRequest) => ({
id: extractUserId(req),
username: extractUsername(req),
});

export const extractAuditInfo = (
req: IAuthRequest | IApiRequest,
): IAuditUser => ({
id: extractUserId(req),
username: extractUsername(req),
ip: req.ip,
});

0 comments on commit 633cae6

Please sign in to comment.