diff --git a/services/web/app/src/Features/Authentication/AuthenticationController.js b/services/web/app/src/Features/Authentication/AuthenticationController.js index 7aaf242c8f..efac5fc7b6 100644 --- a/services/web/app/src/Features/Authentication/AuthenticationController.js +++ b/services/web/app/src/Features/Authentication/AuthenticationController.js @@ -81,6 +81,7 @@ const AuthenticationController = { } if (user) { // `user` is either a user object or false + AuthenticationController.setAuditInfo(req, { method: 'Password login' }) return AuthenticationController.finishLogin(user, req, res, next) } else { if (info.redir != null) { @@ -99,6 +100,8 @@ const AuthenticationController = { return res.redirect('/login') } // OAuth2 'state' mismatch + const auditInfo = AuthenticationController.getAuditInfo(req) + const anonymousAnalyticsId = req.session.analyticsId const isNewUser = req.session.justRegistered || false @@ -128,20 +131,27 @@ const AuthenticationController = { AuthenticationController._getRedirectFromSession(req) || '/project' _loginAsyncHandlers(req, user, anonymousAnalyticsId, isNewUser) const userId = user._id - UserAuditLogHandler.addEntry(userId, 'login', userId, req.ip, err => { - if (err) { - return next(err) - } - _afterLoginSessionSetup(req, user, function (err) { + UserAuditLogHandler.addEntry( + userId, + 'login', + userId, + req.ip, + auditInfo, + err => { if (err) { return next(err) } - AuthenticationController._clearRedirectFromSession(req) - AnalyticsRegistrationSourceHelper.clearSource(req.session) - AnalyticsRegistrationSourceHelper.clearInbound(req.session) - AsyncFormHelper.redirect(req, res, redir) - }) - }) + _afterLoginSessionSetup(req, user, function (err) { + if (err) { + return next(err) + } + AuthenticationController._clearRedirectFromSession(req) + AnalyticsRegistrationSourceHelper.clearSource(req.session) + AnalyticsRegistrationSourceHelper.clearInbound(req.session) + AsyncFormHelper.redirect(req, res, redir) + }) + } + ) } ) }, @@ -369,6 +379,17 @@ const AuthenticationController = { return AuthenticationController.requireBasicAuth(Settings.httpAuthUsers) }, + setAuditInfo(req, info) { + if (!req.__authAuditInfo) { + req.__authAuditInfo = {} + } + Object.assign(req.__authAuditInfo, info) + }, + + getAuditInfo(req) { + return req.__authAuditInfo || {} + }, + setRedirectInSession(req, value) { if (value == null) { value = diff --git a/services/web/app/src/Features/PasswordReset/PasswordResetController.js b/services/web/app/src/Features/PasswordReset/PasswordResetController.js index 1ae043a3db..ebf2d538a9 100644 --- a/services/web/app/src/Features/PasswordReset/PasswordResetController.js +++ b/services/web/app/src/Features/PasswordReset/PasswordResetController.js @@ -84,7 +84,9 @@ async function setNewUserPassword(req, res, next) { }) } } - + AuthenticationController.setAuditInfo(req, { + method: 'Password reset, set new password', + }) AuthenticationController.finishLogin(user, req, res, next) } diff --git a/services/web/test/acceptance/src/AuthenticationTests.js b/services/web/test/acceptance/src/AuthenticationTests.js index 47e3fe7231..1b5ccdf872 100644 --- a/services/web/test/acceptance/src/AuthenticationTests.js +++ b/services/web/test/acceptance/src/AuthenticationTests.js @@ -69,6 +69,7 @@ describe('Authentication', function () { operation: 'login', ipAddress: '127.0.0.1', initiatorId: ObjectId(user.id), + info: { method: 'Password login' }, }) }) }) diff --git a/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js b/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js index 20526dd825..a026a50180 100644 --- a/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js +++ b/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js @@ -1188,6 +1188,25 @@ describe('AuthenticationController', function () { expect(this.next).to.have.been.calledWith(theError) expect(this.req.login).to.not.have.been.called }) + + it('should pass along auditInfo when present', function () { + this.AuthenticationController.setAuditInfo(this.req, { + method: 'Login', + }) + this.AuthenticationController.finishLogin( + this.user, + this.req, + this.res, + this.next + ) + expect(this.UserAuditLogHandler.addEntry).to.have.been.calledWith( + this.user._id, + 'login', + this.user._id, + '42.42.42.42', + { method: 'Login' } + ) + }) }) describe('_afterLoginSessionSetup', function () { diff --git a/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js b/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js index b91d0e773e..d2410556d8 100644 --- a/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js +++ b/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js @@ -61,6 +61,7 @@ describe('PasswordResetController', function () { (this.AuthenticationController = { getLoggedInUserId: sinon.stub(), finishLogin: sinon.stub(), + setAuditInfo: sinon.stub(), }), '../User/UserGetter': (this.UserGetter = { promises: {