Ghost/core/server/auth/auth-strategies.js

150 lines
5.4 KiB
JavaScript
Raw Normal View History

var models = require('../models'),
utils = require('../utils'),
i18n = require('../i18n'),
errors = require('../errors'),
_ = require('lodash'),
strategies;
strategies = {
/**
* ClientPasswordStrategy
*
* This strategy is used to authenticate registered OAuth clients. It is
* employed to protect the `token` endpoint, which consumers use to obtain
* access tokens. The OAuth 2.0 specification suggests that clients use the
* HTTP Basic scheme to authenticate (not implemented yet).
* Use of the client password strategy is implemented to support ember-simple-auth.
*/
clientPasswordStrategy: function clientPasswordStrategy(clientId, clientSecret, done) {
return models.Client.findOne({slug: clientId}, {withRelated: ['trustedDomains']})
.then(function then(model) {
if (model) {
var client = model.toJSON({include: ['trustedDomains']});
if (client.status === 'enabled' && client.secret === clientSecret) {
return done(null, client);
}
}
return done(null, false);
});
},
/**
* BearerStrategy
*
* This strategy is used to authenticate users based on an access token (aka a
* bearer token). The user must have previously authorized a client
* application, which is issued an access token to make requests on behalf of
* the authorizing user.
*/
bearerStrategy: function bearerStrategy(accessToken, done) {
return models.Accesstoken.findOne({token: accessToken})
.then(function then(model) {
if (model) {
var token = model.toJSON();
if (token.expires > Date.now()) {
return models.User.findOne({id: token.user_id})
.then(function then(model) {
if (model) {
var user = model.toJSON(),
info = {scope: '*'};
return done(null, {id: user.id}, info);
}
return done(null, false);
});
} else {
return done(null, false);
}
} else {
return done(null, false);
}
});
},
/**
* Ghost Strategy
* patronusRefreshToken: will be null for now, because we don't need it right now
*
* CASES:
* - via invite token
* - via normal auth
* - via setup
*
* @TODO: validate patronus profile?
*/
ghostStrategy: function ghostStrategy(req, patronusAccessToken, patronusRefreshToken, profile, done) {
var inviteToken = req.body.inviteToken,
options = {context: {internal: true}},
handleInviteToken, handleSetup;
handleInviteToken = function handleInviteToken() {
var user, invite;
inviteToken = utils.decodeBase64URLsafe(inviteToken);
return models.Invite.findOne({token: inviteToken}, options)
.then(function addInviteUser(_invite) {
invite = _invite;
if (!invite) {
throw new errors.NotFoundError(i18n.t('errors.api.invites.inviteNotFound'));
}
if (invite.get('expires') < Date.now()) {
throw new errors.NotFoundError(i18n.t('errors.api.invites.inviteExpired'));
}
return models.User.add({
email: profile.email_address,
name: profile.email_address,
password: utils.uid(50),
roles: invite.toJSON().roles
}, options);
})
.then(function destroyInvite(_user) {
user = _user;
return invite.destroy(options);
})
.then(function () {
return user;
});
};
handleSetup = function handleSetup() {
return models.User.findOne({slug: 'ghost-owner', status: 'all'}, options)
.then(function fetchedOwner(owner) {
if (!owner) {
throw new errors.NotFoundError(i18n.t('errors.models.user.userNotFound'));
}
return models.User.edit({
email: profile.email_address,
status: 'active'
}, _.merge({id: owner.id}, options));
});
};
models.User.getByEmail(profile.email_address, options)
.then(function fetchedUser(user) {
if (user) {
return user;
}
if (inviteToken) {
return handleInviteToken();
}
return handleSetup();
})
.then(function updatePatronusToken(user) {
options.id = user.id;
return models.User.edit({patronus_access_token: patronusAccessToken}, options);
})
.then(function returnResponse(user) {
done(null, user, profile);
})
.catch(done);
}
};
module.exports = strategies;