0a744c2781
* 🎨 use updateClient function to update redirectUri refs #7654 * 🎨 name instead of clientName * 🎨 config.get('theme:title') for client name - initial read can happen from config * ✨ register public client: client name and description - no update yet - for initial client creation - we forward title/description to Ghost Auth - TODO: use settings-cache when merged * ✨ store blog_uri in db * 🎨 passport logic changes - use updateClient instead of changeCallbackURL - be able to update: blog title, blog description, redirectUri and blogUri - remove retries, they get implemented in passport-ghost soon - reorder logic a bit * 🛠 passport-ghost 1.2.0 * 🎨 tests: extend DataGenerator createClient - set some defaults * 🎨 tests - extend tests - 👻 * ✨ run auth.init in background - no need to block the bootstrap process - if client can't be registered, you will see an error - ensure Ghost-Admin renders correctly * 🛠 passport-ghost 1.3.0 - retries * 🎨 use client_uri in Client Schema - adapt changes - use blog_uri only when calling the passport-ghost instance - Ghost uses the client_uri notation to improve readability * ✨ read blog title/description from settings cache * 🚨 Ghost Auth returns email instead of email_address - adapt Ghost
186 lines
7.1 KiB
JavaScript
186 lines
7.1 KiB
JavaScript
var ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy,
|
|
BearerStrategy = require('passport-http-bearer').Strategy,
|
|
GhostOAuth2Strategy = require('passport-ghost').Strategy,
|
|
passport = require('passport'),
|
|
_ = require('lodash'),
|
|
debug = require('debug')('ghost:auth'),
|
|
Promise = require('bluebird'),
|
|
authStrategies = require('./auth-strategies'),
|
|
errors = require('../errors'),
|
|
events = require('../events'),
|
|
logging = require('../logging'),
|
|
models = require('../models'),
|
|
_private = {};
|
|
|
|
/**
|
|
* Update client name and description if changes in the blog settings
|
|
*/
|
|
_private.registerEvents = function registerEvents() {
|
|
events.on('settings.edited', function onSettingsChanged(settingModel) {
|
|
var titleHasChanged = settingModel.attributes.key === 'title' && settingModel.attributes.value !== settingModel._updatedAttributes.value,
|
|
descriptionHasChanged = settingModel.attributes.key === 'description' && settingModel.attributes.value !== settingModel._updatedAttributes.value,
|
|
options = {
|
|
ghostOAuth2Strategy: passport._strategies.ghost
|
|
};
|
|
|
|
if (!titleHasChanged && !descriptionHasChanged) {
|
|
return;
|
|
}
|
|
|
|
if (titleHasChanged) {
|
|
options.clientName = settingModel.attributes.value;
|
|
debug('Ghost Auth Client title has changed: ' + options.clientName);
|
|
}
|
|
|
|
if (descriptionHasChanged) {
|
|
options.clientDescription = settingModel.attributes.value;
|
|
debug('Ghost AuthClient description has changed: ' + options.clientDescription);
|
|
}
|
|
|
|
_private.updateClient(options).catch(function onUpdatedClientError(err) {
|
|
// @TODO: see https://github.com/TryGhost/Ghost/issues/7627
|
|
if (_.isArray(err)) {
|
|
err = err[0];
|
|
}
|
|
|
|
logging.error(err);
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* smart function
|
|
*/
|
|
_private.updateClient = function updateClient(options) {
|
|
var ghostOAuth2Strategy = options.ghostOAuth2Strategy,
|
|
redirectUri = options.redirectUri,
|
|
clientUri = options.clientUri,
|
|
clientName = options.clientName,
|
|
clientDescription = options.clientDescription;
|
|
|
|
return models.Client.findOne({slug: 'ghost-auth'}, {context: {internal: true}})
|
|
.then(function (client) {
|
|
// CASE: we have to create the client
|
|
if (!client) {
|
|
debug('Client does not exist');
|
|
|
|
return ghostOAuth2Strategy.registerClient({
|
|
name: clientName,
|
|
description: clientDescription
|
|
}).then(function registeredRemoteClient(credentials) {
|
|
debug('Registered remote client: ' + JSON.stringify(credentials));
|
|
|
|
return models.Client.add({
|
|
name: credentials.name,
|
|
description: credentials.description,
|
|
slug: 'ghost-auth',
|
|
uuid: credentials.client_id,
|
|
secret: credentials.client_secret,
|
|
redirection_uri: credentials.redirect_uri,
|
|
client_uri: credentials.blog_uri
|
|
}, {context: {internal: true}});
|
|
}).then(function addedLocalClient(client) {
|
|
debug('Added local client: ' + JSON.stringify(client.toJSON()));
|
|
|
|
return {
|
|
client_id: client.get('uuid'),
|
|
client_secret: client.get('secret')
|
|
};
|
|
});
|
|
}
|
|
|
|
// CASE: nothing changed
|
|
if (client.get('redirection_uri') === redirectUri &&
|
|
client.get('name') === clientName &&
|
|
client.get('description') === clientDescription &&
|
|
client.get('client_uri') === clientUri) {
|
|
debug('Client did not change');
|
|
|
|
return {
|
|
client_id: client.get('uuid'),
|
|
client_secret: client.get('secret')
|
|
};
|
|
}
|
|
|
|
debug('Update client...');
|
|
return ghostOAuth2Strategy.updateClient(_.omit({
|
|
clientId: client.get('uuid'),
|
|
clientSecret: client.get('secret'),
|
|
redirectUri: redirectUri,
|
|
blogUri: clientUri,
|
|
name: clientName,
|
|
description: clientDescription
|
|
}, _.isUndefined)).then(function updatedRemoteClient(updatedRemoteClient) {
|
|
debug('Update remote client: ' + JSON.stringify(updatedRemoteClient));
|
|
|
|
client.set('redirection_uri', updatedRemoteClient.redirect_uri);
|
|
client.set('client_uri', updatedRemoteClient.blog_uri);
|
|
client.set('name', updatedRemoteClient.name);
|
|
client.set('description', updatedRemoteClient.description);
|
|
|
|
return client.save(null, {context: {internal: true}});
|
|
}).then(function updatedLocalClient() {
|
|
return {
|
|
client_id: client.get('uuid'),
|
|
client_secret: client.get('secret')
|
|
};
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* auth types:
|
|
* - password: local login
|
|
* - ghost: remote login at Ghost.org
|
|
*/
|
|
exports.init = function initPassport(options) {
|
|
var authType = options.authType,
|
|
clientName = options.clientName,
|
|
clientDescription = options.clientDescription,
|
|
ghostAuthUrl = options.ghostAuthUrl,
|
|
redirectUri = options.redirectUri,
|
|
clientUri = options.clientUri;
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
passport.use(new ClientPasswordStrategy(authStrategies.clientPasswordStrategy));
|
|
passport.use(new BearerStrategy(authStrategies.bearerStrategy));
|
|
|
|
if (authType !== 'ghost') {
|
|
return resolve({passport: passport.initialize()});
|
|
}
|
|
|
|
var ghostOAuth2Strategy = new GhostOAuth2Strategy({
|
|
redirectUri: redirectUri,
|
|
blogUri: clientUri,
|
|
url: ghostAuthUrl,
|
|
passReqToCallback: true
|
|
}, authStrategies.ghostStrategy);
|
|
|
|
_private.updateClient({
|
|
ghostOAuth2Strategy: ghostOAuth2Strategy,
|
|
clientName: clientName,
|
|
clientDescription: clientDescription,
|
|
redirectUri: redirectUri,
|
|
clientUri: clientUri
|
|
}).then(function setClient(client) {
|
|
ghostOAuth2Strategy.setClient(client);
|
|
passport.use(ghostOAuth2Strategy);
|
|
_private.registerEvents();
|
|
return resolve({passport: passport.initialize()});
|
|
}).catch(function onError(err) {
|
|
// @TODO: see https://github.com/TryGhost/Ghost/issues/7627
|
|
if (_.isArray(err)) {
|
|
err = err[0];
|
|
}
|
|
|
|
debug('Public registration failed:' + err.message);
|
|
|
|
return reject(new errors.GhostError({
|
|
err: err,
|
|
context: 'Public client registration failed',
|
|
help: 'Please verify the configured url: ' + ghostOAuth2Strategy.url
|
|
}));
|
|
});
|
|
});
|
|
};
|