Ghost/core/test/unit/auth/auth-strategies_spec.js
Katharina Irrgang 27f17c973d 🎨 handle case: sync email after logout (#8097)
no issue

If the user changes the email in the remote auth service and executes a logout directly afterwards, the user would lock himself out of his blog, because the email sync happens once per hour right now.
For that case, we have to store the ghost auth id.
2017-03-08 14:31:22 +00:00

351 lines
13 KiB
JavaScript

var should = require('should'),
sinon = require('sinon'),
Promise = require('bluebird'),
_ = require('lodash'),
authStrategies = require('../../../server/auth/auth-strategies'),
Models = require('../../../server/models'),
errors = require('../../../server/errors'),
globalUtils = require('../../../server/utils'),
sandbox = sinon.sandbox.create(),
fakeClient = {
slug: 'ghost-admin',
secret: 'not_available',
status: 'enabled'
},
fakeValidToken = {
user_id: 3,
token: 'valid-token',
client_id: 1,
expires: Date.now() + globalUtils.ONE_DAY_MS
},
fakeInvalidToken = {
user_id: 3,
token: 'expired-token',
client_id: 1,
expires: Date.now() - globalUtils.ONE_DAY_MS
};
describe('Auth Strategies', function () {
var next;
before(function () {
// Loads all the models
Models.init();
});
beforeEach(function () {
next = sandbox.spy();
});
afterEach(function () {
sandbox.restore();
});
describe('Client Password Strategy', function () {
var clientStub;
beforeEach(function () {
clientStub = sandbox.stub(Models.Client, 'findOne');
clientStub.returns(new Promise.resolve());
clientStub.withArgs({slug: fakeClient.slug}).returns(new Promise.resolve({
toJSON: function () {
return fakeClient;
}
}));
});
it('should find client', function (done) {
var clientId = 'ghost-admin',
clientSecret = 'not_available';
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
clientStub.calledOnce.should.be.true();
clientStub.calledWith({slug: clientId}).should.be.true();
next.called.should.be.true();
next.firstCall.args.length.should.eql(2);
should.equal(next.firstCall.args[0], null);
next.firstCall.args[1].slug.should.eql(clientId);
done();
}).catch(done);
});
it('shouldn\'t find client with invalid id', function (done) {
var clientId = 'invalid_id',
clientSecret = 'not_available';
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
clientStub.calledOnce.should.be.true();
clientStub.calledWith({slug: clientId}).should.be.true();
next.called.should.be.true();
next.calledWith(null, false).should.be.true();
done();
}).catch(done);
});
it('shouldn\'t find client with invalid secret', function (done) {
var clientId = 'ghost-admin',
clientSecret = 'invalid_secret';
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
clientStub.calledOnce.should.be.true();
clientStub.calledWith({slug: clientId}).should.be.true();
next.called.should.be.true();
next.calledWith(null, false).should.be.true();
done();
}).catch(done);
});
it('shouldn\'t auth client that is disabled', function (done) {
var clientId = 'ghost-admin',
clientSecret = 'not_available';
fakeClient.status = 'disabled';
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
clientStub.calledOnce.should.be.true();
clientStub.calledWith({slug: clientId}).should.be.true();
next.called.should.be.true();
next.calledWith(null, false).should.be.true();
done();
}).catch(done);
});
});
describe('Bearer Strategy', function () {
var tokenStub, userStub;
beforeEach(function () {
tokenStub = sandbox.stub(Models.Accesstoken, 'findOne');
tokenStub.returns(new Promise.resolve());
tokenStub.withArgs({token: fakeValidToken.token}).returns(new Promise.resolve({
toJSON: function () {
return fakeValidToken;
}
}));
tokenStub.withArgs({token: fakeInvalidToken.token}).returns(new Promise.resolve({
toJSON: function () {
return fakeInvalidToken;
}
}));
userStub = sandbox.stub(Models.User, 'findOne');
userStub.returns(new Promise.resolve());
userStub.withArgs({id: 3}).returns(new Promise.resolve({
toJSON: function () {
return {id: 3};
}
}));
});
it('should find user with valid token', function (done) {
var accessToken = 'valid-token',
userId = 3;
authStrategies.bearerStrategy(accessToken, next).then(function () {
tokenStub.calledOnce.should.be.true();
tokenStub.calledWith({token: accessToken}).should.be.true();
userStub.calledOnce.should.be.true();
userStub.calledWith({id: userId}).should.be.true();
next.calledOnce.should.be.true();
next.firstCall.args.length.should.eql(3);
next.calledWith(null, {id: userId}, {scope: '*'}).should.be.true();
done();
}).catch(done);
});
it('shouldn\'t find user with invalid token', function (done) {
var accessToken = 'invalid_token';
authStrategies.bearerStrategy(accessToken, next).then(function () {
tokenStub.calledOnce.should.be.true();
tokenStub.calledWith({token: accessToken}).should.be.true();
userStub.called.should.be.false();
next.called.should.be.true();
next.calledWith(null, false).should.be.true();
done();
}).catch(done);
});
it('should find user that doesn\'t exist', function (done) {
var accessToken = 'valid-token',
userId = 2;
// override user
fakeValidToken.user_id = userId;
authStrategies.bearerStrategy(accessToken, next).then(function () {
tokenStub.calledOnce.should.be.true();
tokenStub.calledWith({token: accessToken}).should.be.true();
userStub.calledOnce.should.be.true();
userStub.calledWith({id: userId}).should.be.true();
next.called.should.be.true();
next.calledWith(null, false).should.be.true();
done();
}).catch(done);
});
it('should find user with expired token', function (done) {
var accessToken = 'expired-token';
authStrategies.bearerStrategy(accessToken, next).then(function () {
tokenStub.calledOnce.should.be.true();
tokenStub.calledWith({token: accessToken}).should.be.true();
userStub.calledOnce.should.be.false();
next.called.should.be.true();
next.calledWith(null, false).should.be.true();
done();
}).catch(done);
});
});
describe('Ghost Strategy', function () {
var inviteStub, userAddStub, userEditStub, userFindOneStub;
beforeEach(function () {
userFindOneStub = sandbox.stub(Models.User, 'findOne');
userAddStub = sandbox.stub(Models.User, 'add');
userEditStub = sandbox.stub(Models.User, 'edit');
inviteStub = sandbox.stub(Models.Invite, 'findOne');
});
it('with invite, but with wrong invite token', function (done) {
var ghostAuthAccessToken = '12345',
req = {body: {inviteToken: 'wrong'}},
profile = {email: 'test@example.com', id: '1234'};
userFindOneStub.returns(Promise.resolve(null));
inviteStub.returns(Promise.reject(new errors.NotFoundError()));
authStrategies.ghostStrategy(req, ghostAuthAccessToken, null, profile, function (err) {
should.exist(err);
(err instanceof errors.NotFoundError).should.eql(true);
userFindOneStub.calledOnce.should.be.true();
inviteStub.calledOnce.should.be.true();
done();
});
});
it('with correct invite token, but expired', function (done) {
var ghostAuthAccessToken = '12345',
req = {body: {inviteToken: 'token'}},
profile = {email: 'test@example.com', id: '1234'};
userFindOneStub.returns(Promise.resolve(null));
inviteStub.returns(Promise.resolve(Models.Invite.forge({
id: 1,
token: 'token',
expires: Date.now() - 1000
})));
authStrategies.ghostStrategy(req, ghostAuthAccessToken, null, profile, function (err) {
should.exist(err);
(err instanceof errors.NotFoundError).should.eql(true);
userFindOneStub.calledOnce.should.be.true();
inviteStub.calledOnce.should.be.true();
done();
});
});
it('with correct invite token', function (done) {
var ghostAuthAccessToken = '12345',
req = {body: {inviteToken: 'token'}},
invitedProfile = {email: 'test@example.com', id: '1234'},
invitedUser = {id: 2},
inviteModel = Models.Invite.forge({
id: 1,
token: 'token',
expires: Date.now() + 1000
});
userFindOneStub.returns(Promise.resolve(null));
userAddStub.returns(Promise.resolve(invitedUser));
userEditStub.returns(Promise.resolve(invitedUser));
inviteStub.returns(Promise.resolve(inviteModel));
sandbox.stub(inviteModel, 'destroy').returns(Promise.resolve());
authStrategies.ghostStrategy(req, ghostAuthAccessToken, null, invitedProfile, function (err, user, profile) {
should.not.exist(err);
should.exist(user);
should.exist(profile);
user.should.eql(invitedUser);
profile.should.eql(invitedProfile);
userFindOneStub.calledOnce.should.be.true();
inviteStub.calledOnce.should.be.true();
done();
});
});
it('setup', function (done) {
var ghostAuthAccessToken = '12345',
req = {body: {}},
ownerProfile = {email: 'test@example.com', id: '1234'},
owner = {id: 2};
userFindOneStub.withArgs({ghost_auth_id: ownerProfile.id})
.returns(Promise.resolve(null));
userFindOneStub.withArgs({slug: 'ghost-owner', status: 'inactive'})
.returns(Promise.resolve(_.merge({}, {status: 'inactive'}, owner)));
userEditStub.withArgs({status: 'active', email: 'test@example.com'}, {
context: {internal: true},
id: owner.id
}).returns(Promise.resolve(owner));
userEditStub.withArgs({
ghost_auth_access_token: ghostAuthAccessToken,
ghost_auth_id: ownerProfile.id,
email: ownerProfile.email
}, {
context: {internal: true},
id: owner.id
}).returns(Promise.resolve(owner));
authStrategies.ghostStrategy(req, ghostAuthAccessToken, null, ownerProfile, function (err, user, profile) {
should.not.exist(err);
userFindOneStub.calledTwice.should.be.true();
inviteStub.calledOnce.should.be.false();
should.exist(user);
should.exist(profile);
user.should.eql(owner);
profile.should.eql(ownerProfile);
done();
});
});
it('auth', function (done) {
var ghostAuthAccessToken = '12345',
req = {body: {}},
ownerProfile = {email: 'test@example.com', id: '12345'},
owner = {id: 2};
userFindOneStub.returns(Promise.resolve(owner));
userEditStub.withArgs({
ghost_auth_access_token: ghostAuthAccessToken,
ghost_auth_id: ownerProfile.id,
email: ownerProfile.email
}, {
context: {internal: true},
id: owner.id
}).returns(Promise.resolve(owner));
authStrategies.ghostStrategy(req, ghostAuthAccessToken, null, ownerProfile, function (err, user, profile) {
should.not.exist(err);
userFindOneStub.calledOnce.should.be.true();
userEditStub.calledOnce.should.be.true();
inviteStub.calledOnce.should.be.false();
should.exist(user);
should.exist(profile);
user.should.eql(owner);
profile.should.eql(ownerProfile);
done();
});
});
});
});