Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Commit

Permalink
fix(customs): Report errno to customs when password check fails.
Browse files Browse the repository at this point in the history
  • Loading branch information
rfk committed Jun 27, 2016
1 parent fe0b8c4 commit bdd5d0c
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 24 deletions.
49 changes: 30 additions & 19 deletions lib/routes/utils/password_check.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ var error = require('../../error')
module.exports = function (log, config, Password, customs, db) {
return function (emailRecord, authPW, clientAddress) {
if (butil.buffersAreEqual(emailRecord.authSalt, butil.ONES)) {
throw error.mustResetAccount(emailRecord.email)
return customs.flag(clientAddress, {
email: emailRecord.email,
errno: error.ERRNO.ACCOUNT_RESET
})
.then(
function () {
throw error.mustResetAccount(emailRecord.email)
}
)
}
var password = new Password(
authPW,
Expand All @@ -35,26 +43,29 @@ module.exports = function (log, config, Password, customs, db) {
return match
}

return customs.flag(clientAddress, emailRecord)
.then(
function (result) {
if (result.lockout) {
log.info({
op: 'account.lock',
email: emailRecord.email,
uid: emailRecord.uid.toString('hex')
})
if (config.lockoutEnabled) {
return db.lockAccount(emailRecord)
}
return customs.flag(clientAddress, {
email: emailRecord.email,
errno: error.ERRNO.INCORRECT_PASSWORD
})
.then(
function (result) {
if (result.lockout) {
log.info({
op: 'account.lock',
email: emailRecord.email,
uid: emailRecord.uid.toString('hex')
})
if (config.lockoutEnabled) {
return db.lockAccount(emailRecord)
}
}
)
.then(
function () {
return match
}
)
}
)
.then(
function () {
return match
}
)
}
)
}
Expand Down
67 changes: 62 additions & 5 deletions test/local/password_check_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var sinon = require('sinon')

var P = require('../../lib/promise')
var test = require('../ptaptest')
var mockLog = require('../mocks').mockLog()
var config = { lockoutEnabled: true }
var Password = require('../../lib/crypto/password')(mockLog, config)
var error = require('../../lib/error')
var butil = require('../../lib/crypto/butil')

var triggersLockout = false
var MockCustoms = {
flag: function (clientAddress, emailRecord) {
flag: sinon.spy(function (clientAddress, emailRecord) {
return P.resolve({ lockout: triggersLockout })
}
})
}

var MockDB = {
Expand All @@ -28,6 +32,8 @@ var MockDB = {
}
}

var CLIENT_ADDRESS = '10.0.0.1'

var checkPassword = require('../../lib/routes/utils/password_check')(mockLog, config, Password, MockCustoms, MockDB)

test(
Expand All @@ -40,6 +46,7 @@ test(
verifierVersion: 0,
authSalt: new Buffer('bbbbbbbbbbbbbbbb')
}
MockCustoms.flag.reset()

var password = new Password(
authPW, emailRecord.authSalt, emailRecord.verifierVersion)
Expand All @@ -49,12 +56,13 @@ test(
function (hash) {
emailRecord.verifyHash = hash

return checkPassword(emailRecord, authPW, '10.0.0.1')
return checkPassword(emailRecord, authPW, CLIENT_ADDRESS)
}
)
.then(
function (matches) {
t.ok(matches, 'password matches, checkPassword returns true')
t.equal(MockCustoms.flag.callCount, 0, 'customs.flag was not called')
}
)
}
Expand All @@ -66,10 +74,12 @@ test(
var authPW = new Buffer('aaaaaaaaaaaaaaaa')
var emailRecord = {
uid: 'not_locked',
email: 'test@example.com',
verifyHash: null,
verifierVersion: 0,
authSalt: new Buffer('bbbbbbbbbbbbbbbb')
}
MockCustoms.flag.reset()

var password = new Password(
authPW, emailRecord.authSalt, emailRecord.verifierVersion)
Expand All @@ -82,12 +92,18 @@ test(
var incorrectAuthPW = new Buffer('cccccccccccccccc')

triggersLockout = false
return checkPassword(emailRecord, incorrectAuthPW, '10.0.0.1')
return checkPassword(emailRecord, incorrectAuthPW, CLIENT_ADDRESS)
}
)
.then(
function (match) {
t.equal(!!match, false, 'password does not match, checkPassword returns false')
t.equal(MockCustoms.flag.callCount, 1, 'customs.flag was called')
t.equal(MockCustoms.flag.getCall(0).args[0], CLIENT_ADDRESS, 'customs.flag was called with client ip')
t.deepEqual(MockCustoms.flag.getCall(0).args[1], {
email: emailRecord.email,
errno: error.ERRNO.INCORRECT_PASSWORD
}, 'customs.flag was called with correct event details')
t.equal(MockDB.isLocked('not_locked'), false, 'account was not marked as locked')
}
)
Expand All @@ -100,10 +116,12 @@ test(
var authPW = new Buffer('aaaaaaaaaaaaaaaa')
var emailRecord = {
uid: 'locked',
email: 'test@example.com',
verifyHash: null,
verifierVersion: 0,
authSalt: new Buffer('bbbbbbbbbbbbbbbb')
}
MockCustoms.flag.reset()

var password = new Password(
authPW, emailRecord.authSalt, emailRecord.verifierVersion)
Expand All @@ -116,14 +134,53 @@ test(
var incorrectAuthPW = new Buffer('cccccccccccccccc')

triggersLockout = true
return checkPassword(emailRecord, incorrectAuthPW, '10.0.0.1')
return checkPassword(emailRecord, incorrectAuthPW, CLIENT_ADDRESS)
}
)
.then(
function (match) {
t.equal(!!match, false, 'password does not match, checkPassword returns false')
t.equal(MockCustoms.flag.callCount, 1, 'customs.flag was called')
t.equal(MockCustoms.flag.getCall(0).args[0], CLIENT_ADDRESS, 'customs.flag was called with client ip')
t.deepEqual(MockCustoms.flag.getCall(0).args[1], {
email: emailRecord.email,
errno: error.ERRNO.INCORRECT_PASSWORD
}, 'customs.flag was called with correct event details')
t.equal(MockDB.isLocked('locked'), true, 'account was not marked as locked')
}
)
}
)

test(
'password check with account whose password must be reset',
function (t) {
var emailRecord = {
uid: 'must_reset',
email: 'test@example.com',
verifyHash: null,
verifierVersion: 0,
authSalt: butil.ONES
}
MockCustoms.flag.reset()
triggersLockout = false

var incorrectAuthPW = new Buffer('cccccccccccccccc')

return checkPassword(emailRecord, incorrectAuthPW, CLIENT_ADDRESS)
.then(
function (match) {
t.fail('password check should not have succeeded')
},
function (err) {
t.equal(err.errno, error.ERRNO.ACCOUNT_RESET, 'an ACCOUNT_RESET error was thrown')
t.equal(MockCustoms.flag.callCount, 1, 'customs.flag was called')
t.equal(MockCustoms.flag.getCall(0).args[0], CLIENT_ADDRESS, 'customs.flag was called with client ip')
t.deepEqual(MockCustoms.flag.getCall(0).args[1], {
email: emailRecord.email,
errno: error.ERRNO.ACCOUNT_RESET
}, 'customs.flag was called with correct event details')
}
)
}
)

0 comments on commit bdd5d0c

Please sign in to comment.