mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Fixed "Authorization Failed" error screens when not logged in
no issue - `/config/` can only be requested when authenticated - updated `/config/` mock to look for an Authentication header and return a 403 if it's missing - updated `ajax` service to add an `Authentication` header when authenticated in testing env (cookies are not present when testing) - updated `config` service to add `fetchUnauthenticated()` and `fetchAuthenticated()` methods in addition to `.fetch()` - updated `application` route to only fetch authenticated config when authenticated - updated `signin` controller to correctly fetch config after sign-in
This commit is contained in:
parent
ef857d25ba
commit
738823d8f8
5 changed files with 59 additions and 18 deletions
|
@ -45,7 +45,7 @@ export default Controller.extend(ValidationEngine, {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
|
|
||||||
promises.pushObject(this.get('settings').fetch());
|
promises.pushObject(this.get('settings').fetch());
|
||||||
promises.pushObject(this.get('config').fetchPrivate());
|
promises.pushObject(this.get('config').fetchAuthenticated());
|
||||||
|
|
||||||
// fetch settings and private config for synchronous access
|
// fetch settings and private config for synchronous access
|
||||||
yield RSVP.all(promises);
|
yield RSVP.all(promises);
|
||||||
|
|
|
@ -43,7 +43,7 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
||||||
routeAfterAuthentication: 'posts',
|
routeAfterAuthentication: 'posts',
|
||||||
|
|
||||||
beforeModel() {
|
beforeModel() {
|
||||||
return this.get('config').fetch();
|
return this.get('config').fetchUnauthenticated();
|
||||||
},
|
},
|
||||||
|
|
||||||
afterModel(model, transition) {
|
afterModel(model, transition) {
|
||||||
|
@ -53,6 +53,7 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
||||||
this.set('appLoadTransition', transition);
|
this.set('appLoadTransition', transition);
|
||||||
transition.send('loadServerNotifications');
|
transition.send('loadServerNotifications');
|
||||||
|
|
||||||
|
let configPromise = this.get('config').fetchAuthenticated();
|
||||||
let featurePromise = this.get('feature').fetch();
|
let featurePromise = this.get('feature').fetch();
|
||||||
let settingsPromise = this.get('settings').fetch();
|
let settingsPromise = this.get('settings').fetch();
|
||||||
let tourPromise = this.get('tour').fetchViewed();
|
let tourPromise = this.get('tour').fetchViewed();
|
||||||
|
@ -60,6 +61,7 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
||||||
// return the feature/settings load promises so that we block until
|
// return the feature/settings load promises so that we block until
|
||||||
// they are loaded to enable synchronous access everywhere
|
// they are loaded to enable synchronous access everywhere
|
||||||
return RSVP.all([
|
return RSVP.all([
|
||||||
|
configPromise,
|
||||||
featurePromise,
|
featurePromise,
|
||||||
settingsPromise,
|
settingsPromise,
|
||||||
tourPromise
|
tourPromise
|
||||||
|
|
|
@ -118,6 +118,8 @@ export function isThemeValidationError(errorOrStatus, payload) {
|
||||||
let ajaxService = AjaxService.extend({
|
let ajaxService = AjaxService.extend({
|
||||||
session: service(),
|
session: service(),
|
||||||
|
|
||||||
|
isTesting: undefined,
|
||||||
|
|
||||||
// flag to tell our ESA authenticator not to try an invalidate DELETE request
|
// flag to tell our ESA authenticator not to try an invalidate DELETE request
|
||||||
// because it's been triggered by this service's 401 handling which means the
|
// because it's been triggered by this service's 401 handling which means the
|
||||||
// DELETE would fail and get stuck in an infinite loop
|
// DELETE would fail and get stuck in an infinite loop
|
||||||
|
@ -130,9 +132,20 @@ let ajaxService = AjaxService.extend({
|
||||||
headers['X-Ghost-Version'] = config.APP.version;
|
headers['X-Ghost-Version'] = config.APP.version;
|
||||||
headers['App-Pragma'] = 'no-cache';
|
headers['App-Pragma'] = 'no-cache';
|
||||||
|
|
||||||
|
if (this.session.isAuthenticated && this.isTesting) {
|
||||||
|
headers.Authorization = 'Test';
|
||||||
|
}
|
||||||
|
|
||||||
return headers;
|
return headers;
|
||||||
}).volatile(),
|
}).volatile(),
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super(...arguments);
|
||||||
|
if (this.isTesting === undefined) {
|
||||||
|
this.isTesting = config.environment === 'test';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// ember-ajax recognises `application/vnd.api+json` as a JSON-API request
|
// ember-ajax recognises `application/vnd.api+json` as a JSON-API request
|
||||||
// and formats appropriately, we want to handle `application/json` the same
|
// and formats appropriately, we want to handle `application/json` the same
|
||||||
_makeRequest(hash) {
|
_makeRequest(hash) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ const {_ProxyMixin} = Ember;
|
||||||
export default Service.extend(_ProxyMixin, {
|
export default Service.extend(_ProxyMixin, {
|
||||||
ajax: service(),
|
ajax: service(),
|
||||||
ghostPaths: service(),
|
ghostPaths: service(),
|
||||||
|
session: service(),
|
||||||
|
|
||||||
content: null,
|
content: null,
|
||||||
|
|
||||||
|
@ -18,23 +19,37 @@ export default Service.extend(_ProxyMixin, {
|
||||||
},
|
},
|
||||||
|
|
||||||
fetch() {
|
fetch() {
|
||||||
|
let promises = [];
|
||||||
|
|
||||||
|
promises.push(this.fetchUnauthenticated());
|
||||||
|
|
||||||
|
if (this.session.isAuthenticated) {
|
||||||
|
promises.push(this.fetchAuthenticated());
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSVP.all(promises);
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchUnauthenticated() {
|
||||||
let siteUrl = this.ghostPaths.url.api('site');
|
let siteUrl = this.ghostPaths.url.api('site');
|
||||||
|
return this.ajax.request(siteUrl).then(({site}) => {
|
||||||
|
// normalize url to non-trailing-slash
|
||||||
|
site.blogUrl = site.url.replace(/\/$/, '');
|
||||||
|
site.blogTitle = site.title;
|
||||||
|
delete site.url;
|
||||||
|
delete site.title;
|
||||||
|
|
||||||
|
Object.assign(this.content, site);
|
||||||
|
}).then(() => {
|
||||||
|
this.notifyPropertyChange('content');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchAuthenticated() {
|
||||||
let configUrl = this.ghostPaths.url.api('config');
|
let configUrl = this.ghostPaths.url.api('config');
|
||||||
|
return this.ajax.request(configUrl).then(({config}) => {
|
||||||
return RSVP.all([
|
Object.assign(this.content, config);
|
||||||
this.ajax.request(siteUrl).then(({site}) => {
|
}).then(() => {
|
||||||
// normalize url to non-trailing-slash
|
|
||||||
site.blogUrl = site.url.replace(/\/$/, '');
|
|
||||||
site.blogTitle = site.title;
|
|
||||||
delete site.url;
|
|
||||||
delete site.title;
|
|
||||||
|
|
||||||
Object.assign(this.content, site);
|
|
||||||
}),
|
|
||||||
this.ajax.request(configUrl).then(({config}) => {
|
|
||||||
Object.assign(this.content, config);
|
|
||||||
})
|
|
||||||
]).then(() => {
|
|
||||||
this.notifyPropertyChange('content');
|
this.notifyPropertyChange('content');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
|
import {Response} from 'ember-cli-mirage';
|
||||||
import {isEmpty} from '@ember/utils';
|
import {isEmpty} from '@ember/utils';
|
||||||
|
|
||||||
export default function mockConfig(server) {
|
export default function mockConfig(server) {
|
||||||
server.get('/config/', function ({db}) {
|
server.get('/config/', function ({db}, request) {
|
||||||
|
if (!request.requestHeaders.Authorization) {
|
||||||
|
return new Response(403, {}, {
|
||||||
|
errors: [{
|
||||||
|
type: 'NoPermissionError',
|
||||||
|
message: 'Authorization failed',
|
||||||
|
context: 'Unable to determine the authenticated user or integration. Check that cookies are being passed through if using session authentication.'
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (isEmpty(db.configs)) {
|
if (isEmpty(db.configs)) {
|
||||||
server.loadFixtures('configs');
|
server.loadFixtures('configs');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue