diff --git a/core/server/api/authentication.js b/core/server/api/authentication.js index 915eecefc4..004a47f74e 100644 --- a/core/server/api/authentication.js +++ b/core/server/api/authentication.js @@ -136,7 +136,12 @@ authentication = { return settings.read({context: {internal: true}, key: 'dbHash'}).then(function (response) { var dbHash = response.settings[0].value; - return dataProvider.User.resetPassword(resetToken, newPassword, ne2Password, dbHash); + return dataProvider.User.resetPassword({ + token: resetToken, + newPassword: newPassword, + ne2Password: ne2Password, + dbHash: dbHash + }); }).then(function () { return Promise.resolve({passwordreset: [{message: 'Password changed successfully.'}]}); }).catch(function (error) { @@ -174,7 +179,12 @@ authentication = { return settings.read({context: {internal: true}, key: 'dbHash'}).then(function (response) { var dbHash = response.settings[0].value; - return dataProvider.User.resetPassword(resetToken, newPassword, ne2Password, dbHash); + return dataProvider.User.resetPassword({ + token: resetToken, + newPassword: newPassword, + ne2Password: ne2Password, + dbHash: dbHash + }); }).then(function (user) { // Setting the slug to '' has the model regenerate the slug from the user's name return dataProvider.User.edit({name: name, email: email, slug: ''}, {id: user.id}); diff --git a/core/server/middleware/middleware.js b/core/server/middleware/middleware.js index f4893da8ee..1d56b5cba0 100644 --- a/core/server/middleware/middleware.js +++ b/core/server/middleware/middleware.js @@ -112,7 +112,7 @@ middleware = { if (subPath.indexOf('/ghost/api/') === 0 && (path.indexOf('/ghost/api/v0.1/authentication/') !== 0 - || (path.indexOf('/ghost/api/v0.1/authentication/') === 0 && req.method === 'PUT'))) { + || (path.indexOf('/ghost/api/v0.1/authentication/setup/') === 0 && req.method === 'PUT'))) { return passport.authenticate('bearer', {session: false, failWithError: true}, function authenticate(err, user, info) { if (err) { diff --git a/core/test/integration/api/api_authentication_spec.js b/core/test/integration/api/api_authentication_spec.js index f753151f0e..98e31359bc 100644 --- a/core/test/integration/api/api_authentication_spec.js +++ b/core/test/integration/api/api_authentication_spec.js @@ -2,19 +2,53 @@ /*jshint expr:true*/ var testUtils = require('../../utils'), should = require('should'), + sinon = require('sinon'), Promise = require('bluebird'), - rewire = require('rewire'), // Stuff we are testing - mail = rewire('../../../server/api/mail'), + AuthAPI = require('../../../server/api/authentication'), - context = testUtils.context; + mail = require('../../../server/api/mail'), + context = testUtils.context, + + sandbox = sinon.sandbox.create(); describe('Authentication API', function () { + var testInvite = { + invitation: [{ + token: 'abc', + password: 'abcdefgh', + email: 'test@testghost.org', + name: 'Jo Bloggs' + }] + }, + testGenerateReset = { + passwordreset: [{ + email: 'jbloggs@example.com' + }] + }, + testReset = { + passwordreset: [{ + token: 'abc', + newPassword: 'abcdefgh', + ne2Password: 'abcdefgh' + }] + }; + // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); + // Stub mail + beforeEach(function () { + sandbox.stub(mail, 'send', function () { + return Promise.resolve(); + }); + }); + afterEach(function () { + sandbox.restore(); + }); + should.exist(AuthAPI); describe('Setup', function () { @@ -37,13 +71,7 @@ describe('Authentication API', function () { email: 'test@example.com', password: 'areallygoodpassword', blogTitle: 'a test blog' - }, - - send = mail.__get__('mail.send'); - - mail.__set__('mail.send', function () { - return Promise.resolve(); - }); + }; AuthAPI.setup({setup: [setupData]}).then(function (result) { should.exist(result); @@ -59,14 +87,51 @@ describe('Authentication API', function () { newUser.email.should.equal(setupData.email); done(); - }).catch(done).finally(function () { - mail.__set__('mail.send', send); + }).catch(done); + }); + + it('should not allow an invitation to be accepted', function (done) { + AuthAPI.acceptInvitation(testInvite).then(function () { + done(new Error('Invitation was allowed to be accepted')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('NoPermissionError'); + err.code.should.equal(403); + + done(); + }); + }); + + it('should not generate a password reset token', function (done) { + AuthAPI.generateResetToken(testGenerateReset).then(function () { + done(new Error('Reset token was generated')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('NoPermissionError'); + err.code.should.equal(403); + + done(); + }); + }); + + it('should not allow a password reset', function (done) { + AuthAPI.resetPassword(testReset).then(function () { + done(new Error('Password was reset')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('NoPermissionError'); + err.code.should.equal(403); + + done(); }); }); }); describe('Completed', function () { - beforeEach(testUtils.setup('owner')); + beforeEach(testUtils.setup('roles', 'owner', 'settings', 'perms:setting', 'perms:mail', 'perms:init')); it('should report that setup has been completed', function (done) { AuthAPI.isSetup().then(function (result) { @@ -96,6 +161,41 @@ describe('Authentication API', function () { done(); }); }); + + it('should allow an invitation to be accepted, but fail on token validation', function (done) { + AuthAPI.acceptInvitation(testInvite).then(function () { + done(new Error('invitation did not fail on token validation')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('UnauthorizedError'); + err.code.should.equal(401); + err.message.should.equal('Invalid token structure'); + done(); + }); + }); + + it('should generate a password reset token', function (done) { + AuthAPI.generateResetToken(testGenerateReset).then(function (result) { + result.should.exist; + result.passwordreset.should.be.an.Array.with.lengthOf(1); + result.passwordreset[0].should.have.property('message', 'Check your email for further instructions.'); + done(); + }).catch(done); + }); + + it('should allow a password reset', function (done) { + AuthAPI.resetPassword(testReset).then(function () { + done(new Error('password reset did not fail on token validation')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('UnauthorizedError'); + err.code.should.equal(401); + err.message.should.equal('Invalid token structure'); + done(); + }); + }); }); }); @@ -204,51 +304,4 @@ describe('Authentication API', function () { }); }); }); - - // describe('Authentication', function () { - - // describe('Setup not completed', function () { - - // beforeEach(testUtils.setup()); - - // it('should not allow an invitation to be accepted', function (done) { - // AuthAPI.acceptInvitation().then(function () { - // done(new Error('Invitation was allowed to be accepted')); - // }).catch(function (err) { - // should.exist(err); - - // err.name.should.equal('NoPermissionError'); - // err.code.should.equal(403); - - // done(); - // }); - // }); - - // it('should not generate a password reset token', function (done) { - // AuthAPI.generateResetToken().then(function () { - // done(new Error('Reset token was generated')); - // }).catch(function (err) { - // should.exist(err); - - // err.name.should.equal('NoPermissionError'); - // err.code.should.equal(403); - - // done(); - // }); - // }); - - // it('should not allow a password reset', function (done) { - // AuthAPI.resetPassword().then(function () { - // done(new Error('Password was reset')); - // }).catch(function (err) { - // should.exist(err); - - // err.name.should.equal('NoPermissionError'); - // err.code.should.equal(403); - - // done(); - // }); - // }); - // }); - // }); });