Skip to content

Commit d4a36a0

Browse files
committed
Create an audit record for logins and registrations
1 parent d406410 commit d4a36a0

File tree

3 files changed

+57
-10
lines changed

3 files changed

+57
-10
lines changed

common/interfaces/SecurityInterfaces.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,21 @@ export interface IUser {
1111
lastName:string;
1212
roles: string[];
1313
}
14+
15+
export interface ILoginAudit {
16+
ip: string;
17+
}
18+
19+
export interface IRegistrationAudit {
20+
firstName: string;
21+
lastName: string;
22+
}
23+
24+
export type AuditDetails = ILoginAudit | IRegistrationAudit;
25+
26+
export interface IAuditRecord {
27+
username: string;
28+
time: Date;
29+
recType: string;
30+
details: AuditDetails;
31+
}

server/routing/ApiRouting.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export class ApiRouting {
128128
// Login a user
129129
login(req, res, next) {
130130
var loginRequest:ILoginRequest = req.body;
131-
this.securityService.login(loginRequest.username, loginRequest.password)
131+
this.securityService.login(loginRequest.username, loginRequest.password, req)
132132
.then(resp => res.send(resp))
133133
.catch(err => next(err));
134134
}

server/services/SecurityService.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import bcrypt = require('bcrypt');
33

44
var mongoskin = require('mongoskin');
55
import {IRegistration, IRegistrationResponse, IRegisteredUser, ILoginResult} from '../../common/interfaces/RegistrationInterfaces';
6-
import {IRole, IUser} from '../../common/interfaces/SecurityInterfaces';
6+
import {IRole, IUser, IAuditRecord, AuditDetails} from '../../common/interfaces/SecurityInterfaces';
77

88
var config = {
99
mongo_url: process.env.SECURITYDATA_URL || 'mongodb://@localhost:27017/security'
@@ -16,11 +16,13 @@ export class SecurityService {
1616
db: any;
1717
usersCollection: any;
1818
rolesCollection: any;
19+
auditCollection: any;
1920

2021
constructor() {
2122
this.db = mongoskin.db(config.mongo_url, { safe: true });
2223
this.usersCollection = this.db.collection('users');
2324
this.rolesCollection = this.db.collection('roles');
25+
this.auditCollection = this.db.collection('audit');
2426
}
2527

2628
public getUsers(): Q.Promise<IUser[]> {
@@ -113,7 +115,7 @@ export class SecurityService {
113115
return defer.promise;
114116
}
115117

116-
public login(username:string, password:string) : Q.Promise<ILoginResult> {
118+
public login(username:string, password:string, req:any) : Q.Promise<ILoginResult> {
117119

118120
var defer = Q.defer<ILoginResult>();
119121

@@ -124,7 +126,10 @@ export class SecurityService {
124126
if (!registeredUser) {
125127
defer.resolve({succeeded: false});
126128
} else if (bcrypt.compareSync(password, registeredUser.hashedPassword)) {
127-
defer.resolve({succeeded: true, userInfo: this.mapUser(registeredUser)});
129+
this.saveAuditRecord(username, 'login', { ip: req.ip})
130+
.then(auditRec => {
131+
defer.resolve({succeeded: true, userInfo: this.mapUser(registeredUser)});
132+
});
128133
} else {
129134
defer.resolve({succeeded: false});
130135
}
@@ -161,7 +166,7 @@ export class SecurityService {
161166
defer.resolve({ succeeded: false, failureReason: 'Username is not available.' });
162167
} else {
163168
var coll = this.usersCollection;
164-
coll.find({}, { _id: 0, userId: 1 }).sort({ userId: -1 }).toArray(function(e, users: any[]) {
169+
coll.find({}, { _id: 0, userId: 1 }).sort({ userId: -1 }).toArray((e, users: any[]) => {
165170
if (e) {
166171
defer.reject(e);
167172
} else {
@@ -177,15 +182,19 @@ export class SecurityService {
177182
hashedPassword: bcrypt.hashSync(registration.password, 10)
178183
};
179184

180-
coll.insert(newUser, {}, function(e, results) {
185+
coll.insert(newUser, {}, (e, results) => {
181186
if (e) {
182187
defer.reject(e);
183188
} else {
184189
newUser.hashedPassword = null;
185-
defer.resolve({
186-
succeeded: true,
187-
failureReason: ''
188-
});
190+
this.saveAuditRecord(newUser.username, 'register', newUser)
191+
.then(auditRec => {
192+
defer.resolve({
193+
succeeded: true,
194+
failureReason: ''
195+
});
196+
});
197+
189198
}
190199
});
191200
}
@@ -210,6 +219,26 @@ export class SecurityService {
210219
};
211220
}
212221

222+
private saveAuditRecord(username:string, recType:string, details:AuditDetails) : Q.Promise<IAuditRecord> {
223+
let defer = Q.defer<IAuditRecord>();
224+
let auditRecord:IAuditRecord = {
225+
username: username,
226+
recType: recType,
227+
time: new Date(),
228+
details: details
229+
};
230+
231+
this.auditCollection.insert(auditRecord, {}, function (e, inserted:IAuditRecord[]) {
232+
if (e) {
233+
defer.reject(e);
234+
} else {
235+
defer.resolve(inserted[0]);
236+
}
237+
});
238+
239+
return defer.promise;
240+
}
241+
213242
private getUserByUsernameInternal(username: string): Q.Promise<IRegisteredUser> {
214243
let defer = Q.defer<IRegisteredUser>();
215244
var coll = this.usersCollection;

0 commit comments

Comments
 (0)