diff --git a/src/auth.js b/src/auth.js index b5477904a..668eb3e46 100644 --- a/src/auth.js +++ b/src/auth.js @@ -44,7 +44,7 @@ function initialize(callback) { passport.use(new LocalStrategy(function (username, password, callback) { if (username.indexOf('@') === -1) { - user.verify(username, password, function (error, result) { + user.verifyWithUsername(username, password, function (error, result) { if (error && error.reason === UserError.NOT_FOUND) return callback(null, false); if (error && error.reason === UserError.WRONG_PASSWORD) return callback(null, false); if (error) return callback(error); @@ -74,7 +74,7 @@ function initialize(callback) { return callback(null, client); }); } else { - user.verify(username, password, function (error, result) { + user.verifyWithUsername(username, password, function (error, result) { if (error && error.reason === UserError.NOT_FOUND) return callback(null, false); if (error && error.reason === UserError.WRONG_PASSWORD) return callback(null, false); if (error) return callback(error); diff --git a/src/routes/user.js b/src/routes/user.js index ca93f4e77..b5d9d7f9c 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -196,7 +196,7 @@ function verifyPassword(req, res, next) { // Only allow admins or users, operating on themselves if (req.params.userId && !(req.user.id === req.params.userId || isAdmin)) return next(new HttpError(403, 'Not allowed')); - user.verify(req.user.username, req.body.password, function (error) { + user.verifyWithUsername(req.user.username, req.body.password, function (error) { if (error && error.reason === UserError.WRONG_PASSWORD) return next(new HttpError(403, 'Password incorrect')); if (error && error.reason === UserError.NOT_FOUND) return next(new HttpError(403, 'Password incorrect')); if (error) return next(new HttpError(500, error)); diff --git a/src/test/user-test.js b/src/test/user-test.js index 7d3f29e0c..6034875a1 100644 --- a/src/test/user-test.js +++ b/src/test/user-test.js @@ -202,8 +202,8 @@ describe('User', function () { before(createOwner); after(cleanupUsers); - it('fails due to non existing username', function (done) { - user.verify(USERNAME+USERNAME, PASSWORD, function (error, result) { + it('fails due to non existing user', function (done) { + user.verify('somerandomid', PASSWORD, function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); expect(error.reason).to.equal(UserError.NOT_FOUND); @@ -213,7 +213,7 @@ describe('User', function () { }); it('fails due to empty password', function (done) { - user.verify(USERNAME, '', function (error, result) { + user.verify(userObject.id, '', function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); expect(error.reason).to.equal(UserError.WRONG_PASSWORD); @@ -223,7 +223,7 @@ describe('User', function () { }); it('fails due to wrong password', function (done) { - user.verify(USERNAME, PASSWORD+PASSWORD, function (error, result) { + user.verify(userObject.id, PASSWORD+PASSWORD, function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); expect(error.reason).to.equal(UserError.WRONG_PASSWORD); @@ -233,7 +233,51 @@ describe('User', function () { }); it('succeeds', function (done) { - user.verify(USERNAME, PASSWORD, function (error, result) { + user.verify(userObject.id, PASSWORD, function (error, result) { + expect(error).to.not.be.ok(); + expect(result).to.be.ok(); + + done(); + }); + }); + }); + + describe('verifyWithUsername', function () { + before(createOwner); + after(cleanupUsers); + + it('fails due to non existing username', function (done) { + user.verifyWithUsername(USERNAME+USERNAME, PASSWORD, function (error, result) { + expect(error).to.be.ok(); + expect(result).to.not.be.ok(); + expect(error.reason).to.equal(UserError.NOT_FOUND); + + done(); + }); + }); + + it('fails due to empty password', function (done) { + user.verifyWithUsername(USERNAME, '', function (error, result) { + expect(error).to.be.ok(); + expect(result).to.not.be.ok(); + expect(error.reason).to.equal(UserError.WRONG_PASSWORD); + + done(); + }); + }); + + it('fails due to wrong password', function (done) { + user.verifyWithUsername(USERNAME, PASSWORD+PASSWORD, function (error, result) { + expect(error).to.be.ok(); + expect(result).to.not.be.ok(); + expect(error.reason).to.equal(UserError.WRONG_PASSWORD); + + done(); + }); + }); + + it('succeeds', function (done) { + user.verifyWithUsername(USERNAME, PASSWORD, function (error, result) { expect(error).to.not.be.ok(); expect(result).to.be.ok(); @@ -493,7 +537,7 @@ describe('User', function () { }); it('actually changed the password (unable to login with old pasword)', function (done) { - user.verify(USERNAME, PASSWORD, function (error, result) { + user.verifyWithUsername(USERNAME, PASSWORD, function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); expect(error.reason).to.equal(UserError.WRONG_PASSWORD); @@ -502,7 +546,7 @@ describe('User', function () { }); it('actually changed the password (login with new password)', function (done) { - user.verify(USERNAME, NEW_PASSWORD, function (error, result) { + user.verifyWithUsername(USERNAME, NEW_PASSWORD, function (error, result) { expect(error).to.not.be.ok(); expect(result).to.be.ok(); done(); diff --git a/src/user.js b/src/user.js index 8cff6d9db..e8858e716 100644 --- a/src/user.js +++ b/src/user.js @@ -8,6 +8,7 @@ exports = module.exports = { list: listUsers, create: createUser, verify: verify, + verifyWithUsername: verifyWithUsername, verifyWithEmail: verifyWithEmail, remove: removeUser, get: getUser, @@ -167,7 +168,28 @@ function createUser(username, password, email, displayName, options, callback) { }); } -function verify(username, password, callback) { +function verify(userId, password, callback) { + assert.strictEqual(typeof userId, 'string'); + assert.strictEqual(typeof password, 'string'); + assert.strictEqual(typeof callback, 'function'); + + userdb.get(userId, function (error, user) { + if (error && error.reason == DatabaseError.NOT_FOUND) return callback(new UserError(UserError.NOT_FOUND)); + if (error) return callback(new UserError(UserError.INTERNAL_ERROR, error)); + + var saltBinary = new Buffer(user.salt, 'hex'); + crypto.pbkdf2(password, saltBinary, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, function (error, derivedKey) { + if (error) return callback(new UserError(UserError.INTERNAL_ERROR, error)); + + var derivedKeyHex = new Buffer(derivedKey, 'binary').toString('hex'); + if (derivedKeyHex !== user.password) return callback(new UserError(UserError.WRONG_PASSWORD)); + + callback(null, user); + }); + }); +} + +function verifyWithUsername(username, password, callback) { assert.strictEqual(typeof username, 'string'); assert.strictEqual(typeof password, 'string'); assert.strictEqual(typeof callback, 'function'); @@ -398,7 +420,7 @@ function changePassword(username, oldPassword, newPassword, callback) { var error = validatePassword(newPassword); if (error) return callback(new UserError(UserError.BAD_PASSWORD, error.message)); - verify(username, oldPassword, function (error, user) { + verifyWithUsername(username, oldPassword, function (error, user) { if (error) return callback(error); setPassword(user.id, newPassword, callback);