Skip to content

Commit 326bce1

Browse files
committed
Audit requests by plugging into the request chain
1 parent 7360230 commit 326bce1

File tree

5 files changed

+58
-18
lines changed

5 files changed

+58
-18
lines changed

common/interfaces/SecurityInterfaces.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ export interface IChatMessageAudit {
2727
clientsOnline: number;
2828
}
2929

30-
export type AuditDetails = ILoginAudit | IRegistrationAudit | IChatMessageAudit;
30+
export interface IRequestAudit {
31+
verb: string;
32+
url: string;
33+
}
34+
35+
export type AuditDetails = ILoginAudit | IRegistrationAudit | IChatMessageAudit | IRequestAudit;
3136

3237
export interface IAuditRecord {
3338
username: string;

server/decorators/audit.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export function audit(description: string) {
2+
3+
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
4+
5+
var originalMethod = descriptor.value; // save a reference to the original method
6+
7+
// NOTE: Do not use arrow syntax here. Use a function expression in
8+
// order to use the correct value of `this` in this method
9+
// See http://stackoverflow.com/questions/29775830/how-to-implement-a-typescript-decorator
10+
11+
descriptor.value = function(...args: any[]) {
12+
console.log(`Audit has intercepted method ${propertyKey}. Our description is ${description}.`);
13+
console.log('The method args are: ' + JSON.stringify(args)); // pre
14+
var result = originalMethod.apply(this, args); // run and store the result
15+
console.log('The return value is: ' + result); // post
16+
17+
return result; // return the result of the original method
18+
};
19+
20+
return descriptor;
21+
};
22+
}

server/routing/ApiRouting.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ export class ApiRouting {
4949
configBasicRoutes() {
5050

5151
this.router.get('/users', this.addResponseHeaders, this.getUsers.bind(this));
52-
this.router.post('/roles/:roleName/members', this.addResponseHeaders,
52+
this.router.post('/roles/:roleName/members',
5353
this.secureApiHandler, this.addResponseHeaders, this.addRoleMembers.bind(this));
5454
this.router.get('/roles/:roleName/members', this.addResponseHeaders, this.getRoleMembers.bind(this));
5555
this.router.get('/roles', this.addResponseHeaders, this.getRoles.bind(this));
56-
this.router.post('/roles', this.addResponseHeaders, this.secureApiHandler,
56+
this.router.post('/roles', this.secureApiHandler,
5757
this.addResponseHeaders, this.addRole.bind(this));
5858
this.router.post('/users/register', this.addResponseHeaders, this.registerUser.bind(this));
5959
this.router.post('/login/token', this.addResponseHeaders, this.tokenLogin.bind(this));
@@ -62,10 +62,10 @@ export class ApiRouting {
6262
this.router.get('/animals/questions/:questionId', this.addResponseHeaders, this.getQuestion.bind(this));
6363
this.router.get('/animals/questions', this.addResponseHeaders, this.getAllQuestions.bind(this));
6464
this.router.post('/animals', this.addResponseHeaders, this.saveNewAnimal.bind(this));
65-
this.router.delete('/animals/:animalId', this.addResponseHeaders, this.secureApiHandler,
65+
this.router.delete('/animals/:animalId', this.secureApiHandler,
6666
this.addResponseHeaders, this.deleteAnimal.bind(this));
67-
this.router.get('/celldata/people', this.addResponseHeaders, this.getPeople.bind(this));
68-
this.router.post('/celldata/people', this.addResponseHeaders, this.secureApiHandler,
67+
this.router.get('/celldata/people', this.auditCall.bind(this), this.addResponseHeaders, this.getPeople.bind(this));
68+
this.router.post('/celldata/people', this.secureApiHandler, this.auditCall.bind(this),
6969
this.addResponseHeaders, this.addPerson.bind(this));
7070
this.router.get('/celldata/cycles', this.addResponseHeaders, this.getCycles.bind(this));
7171
this.router.post('/celldata/cycles', this.addResponseHeaders, this.addCycle.bind(this));
@@ -74,22 +74,22 @@ export class ApiRouting {
7474
this.router.get('/celldata/periodusage', this.addResponseHeaders, this.getPeriodUsage.bind(this));
7575

7676
this.router.get('/quiz/questions', this.addResponseHeaders, this.getQuizQuestions.bind(this));
77-
this.router.post('/quiz/questions', this.addResponseHeaders, this.secureApiHandler,
77+
this.router.post('/quiz/questions', this.secureApiHandler,
7878
this.addResponseHeaders, this.saveNewQuizQuestion.bind(this));
7979
this.router.get('/quiz/questions/:questionId', this.addResponseHeaders, this.getQuizQuestion.bind(this));
80-
this.router.put('/quiz/questions/:questionId', this.addResponseHeaders, this.secureApiHandler,
80+
this.router.put('/quiz/questions/:questionId', this.secureApiHandler,
8181
this.addResponseHeaders, this.updateQuestion.bind(this));
8282
this.router.get('/quiz/categories', this.addResponseHeaders, this.getQuizCategories.bind(this));
8383
this.router.get('/quiz/answercategories', this.addResponseHeaders, this.getQuizAnswerCategories.bind(this));
8484
this.router.get('/quiz/test/user/:username', this.addResponseHeaders, this.getUserTests.bind(this));
85-
this.router.post('/quiz/test/:testId/score', this.addResponseHeaders, this.secureApiHandler,
85+
this.router.post('/quiz/test/:testId/score', this.secureApiHandler,
8686
this.addResponseHeaders, this.scoreTest.bind(this));
87-
this.router.post('/quiz/test/:testId/answer/:questionNumber', this.addResponseHeaders,
87+
this.router.post('/quiz/test/:testId/answer/:questionNumber',
8888
this.secureApiHandler, this.addResponseHeaders, this.recordTestAnswer.bind(this));
8989
this.router.get('/quiz/test/:testId', this.addResponseHeaders, this.getTest.bind(this));
90-
this.router.post('/quiz/test', this.addResponseHeaders, this.secureApiHandler,
90+
this.router.post('/quiz/test', this.secureApiHandler,
9191
this.addResponseHeaders, this.createTest.bind(this));
92-
this.router.post('/quiz', this.addResponseHeaders, this.secureApiHandler,
92+
this.router.post('/quiz', this.secureApiHandler,
9393
this.addResponseHeaders, this.createQuiz.bind(this));
9494
this.router.get('/quiz/:quizId', this.addResponseHeaders, this.getQuiz.bind(this));
9595

@@ -106,6 +106,19 @@ export class ApiRouting {
106106
res.set('Access-Control-Allow-Origin', '*');
107107
next();
108108
}
109+
110+
auditCall(req:express.Request, res:express.Response, next:express.NextFunction) {
111+
let user:IUser = req.user;
112+
let username:string = user ? user.username : 'unauthenticated';
113+
let url = req.url;
114+
let verb = req.method;
115+
116+
this.securityService.saveAuditRecord(username, 'request', { verb: verb, url: url})
117+
.then(rec => {
118+
next();
119+
});
120+
}
121+
109122
getUsers(req, res, next) {
110123
this.securityService.getUsers()
111124
.then(users => res.send(users))
@@ -244,6 +257,9 @@ export class ApiRouting {
244257

245258
addPerson(req, res, next) {
246259
var person:IPerson = req.body;
260+
var user:IUser = req.user;
261+
console.log('Adding person by user: ', user.username);
262+
247263
this.cellDataPersistenceService.addPerson(person)
248264
.then(p => res.send(p))
249265
.catch(err => next(err));

server/services/CellDataPersistenceService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Q = require('q');
22
var mongoskin = require('mongoskin');
33
import {IPerson, ICycle, IUsage} from '../../common/interfaces/CellDataInterfaces';
44
import fs = require('fs');
5+
import {audit} from '../decorators/audit';
56

67
var config = {
78
mongo_url: process.env.CELLDATA_URL || 'mongodb://@localhost:27017/celldata'
@@ -21,6 +22,7 @@ export class CellDataPersistenceService {
2122
this.usageCollection = this.db.collection('usage');
2223
}
2324

25+
@audit('getPeople')
2426
public getPeople():Q.Promise<IPerson[]> {
2527
let defer = Q.defer<IPerson[]>();
2628
this.peopleCollection.find({}).sort({lastName:1, firstName: 1}).toArray(function(e, people:IPerson[]){
@@ -33,6 +35,7 @@ export class CellDataPersistenceService {
3335
return defer.promise;
3436
}
3537

38+
@audit('Adding Person')
3639
public addPerson(person:IPerson):Q.Promise<IPerson> {
3740
let defer = Q.defer<IPerson>();
3841
var coll = this.peopleCollection;

src/decorators/authorize.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)