Merge pull request #5955 from acburdine/esa-1.0

deps: ember-simple-auth@1.0.0
This commit is contained in:
Kevin Ansfield 2015-10-19 10:40:35 +01:00
commit c3d656ad2c
30 changed files with 151 additions and 159 deletions

View File

@ -1,8 +1,18 @@
import Ember from 'ember';
import Authenticator from 'simple-auth-oauth2/authenticators/oauth2';
import Authenticator from 'ember-simple-auth/authenticators/oauth2-password-grant';
export default Authenticator.extend({
config: Ember.inject.service(),
ghostPaths: Ember.inject.service('ghost-paths'),
serverTokenEndpoint: Ember.computed('ghostPaths.apiRoot', function () {
return this.get('ghostPaths.apiRoot') + '/authentication/token';
}),
serverTokenRevocationEndpoint: Ember.computed('ghostPaths.apiRoot', function () {
return this.get('ghostPaths.apiRoot') + '/authentication/revoke';
}),
makeRequest: function (url, data) {
data.client_id = this.get('config.clientId');
data.client_secret = this.get('config.clientSecret');

View File

@ -0,0 +1,3 @@
import Oauth2Bearer from 'ember-simple-auth/authorizers/oauth2-bearer';
export default Oauth2Bearer;

View File

@ -6,6 +6,7 @@ export default Ember.Component.extend({
classNameBindings: ['open'],
config: Ember.inject.service(),
session: Ember.inject.service(),
open: false,

View File

@ -7,6 +7,7 @@ export default Ember.Controller.extend(ValidationEngine, {
application: Ember.inject.controller(),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
identification: Ember.computed('session.user.email', function () {
return this.get('session.user.email');
@ -15,13 +16,12 @@ export default Ember.Controller.extend(ValidationEngine, {
actions: {
authenticate: function () {
var appController = this.get('application'),
authStrategy = 'ghost-authenticator:oauth2-password-grant',
data = this.getProperties('identification', 'password'),
authStrategy = 'authenticator:oauth2',
self = this;
appController.set('skipAuthSuccessHandler', true);
this.get('session').authenticate(authStrategy, data).then(function () {
this.get('session').authenticate(authStrategy, this.get('identification'), this.get('password')).then(function () {
self.send('closeModal');
self.set('password', '');
}).catch(function () {

View File

@ -15,6 +15,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
config: Ember.inject.service(),
ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
initializeSelectedAuthor: Ember.observer('model', function () {
var self = this;

View File

@ -13,6 +13,7 @@ export default Ember.Controller.extend(ValidationEngine, {
ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
email: Ember.computed('token', function () {
// The token base64 encodes the email (and some other stuff),
@ -46,10 +47,7 @@ export default Ember.Controller.extend(ValidationEngine, {
}).then(function (resp) {
self.toggleProperty('submitting');
self.get('notifications').showAlert(resp.passwordreset[0].message, {type: 'warn', delayed: true, key: 'password.reset'});
self.get('session').authenticate('ghost-authenticator:oauth2-password-grant', {
identification: self.get('email'),
password: credentials.newPassword
});
self.get('session').authenticate('authenticator:oauth2', self.get('email'), credentials.newPassword);
}).catch(function (response) {
self.get('notifications').showAPIError(response, {key: 'password.reset'});
self.toggleProperty('submitting');

View File

@ -8,6 +8,7 @@ export default Ember.Controller.extend({
ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
labsJSON: Ember.computed('model.labs', function () {
return JSON.parse(this.get('model.labs') || {});

View File

@ -18,6 +18,7 @@ export default Ember.Controller.extend(ValidationEngine, {
notifications: Ember.inject.service(),
application: Ember.inject.controller(),
config: Ember.inject.service(),
session: Ember.inject.service(),
// ValidationEngine settings
validationType: 'setup',
@ -87,10 +88,7 @@ export default Ember.Controller.extend(ValidationEngine, {
config.set('blogTitle', data.blogTitle);
// Don't call the success handler, otherwise we will be redirected to admin
self.get('application').set('skipAuthSuccessHandler', true);
self.get('session').authenticate('ghost-authenticator:oauth2-password-grant', {
identification: self.get('email'),
password: self.get('password')
}).then(function () {
self.get('session').authenticate('authenticator:oauth2', self.get('email'), self.get('password')).then(function () {
self.set('blogCreated', true);
if (data.image) {
self.sendImage(result.users[0])

View File

@ -9,6 +9,8 @@ export default Ember.Controller.extend(ValidationEngine, {
ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
application: Ember.inject.controller(),
flowErrors: '',
// ValidationEngine settings
@ -18,29 +20,30 @@ export default Ember.Controller.extend(ValidationEngine, {
authenticate: function () {
var self = this,
model = this.get('model'),
authStrategy = 'ghost-authenticator:oauth2-password-grant',
data = model.getProperties(this.authProperties);
authStrategy = 'authenticator:oauth2';
// Authentication transitions to posts.index, we can leave spinner running unless there is an error
this.get('session').authenticate(authStrategy, data).catch(function (err) {
this.get('session').authenticate(authStrategy, model.get('identification'), model.get('password')).catch(function (error) {
self.toggleProperty('loggingIn');
if (err.errors) {
self.set('flowErrors', err.errors[0].message.string);
if (error.errors) {
error.errors.forEach(function (err) {
err.message = err.message.htmlSafe();
});
// this catches both 'no user' and 'user inactive' errors
// long term, we probably need to introduce error codes from the server
if (err.errors[0].message.string.match(/user with that email/)) {
self.set('flowErrors', error.errors[0].message.string);
if (error.errors[0].message.string.match(/user with that email/)) {
self.get('model.errors').add('identification', '');
}
if (err.errors[0].message.string.match(/password is incorrect/)) {
if (error.errors[0].message.string.match(/password is incorrect/)) {
self.get('model.errors').add('password', '');
}
} else {
// Connection errors don't return proper status message, only req.body
self.get('notifications').showAlert('There was a problem on the server.', {type: 'error', key: 'session.authenticate.failed'});
}
// if authentication fails a rejected promise will be returned.
// it needs to be caught so it doesn't generate an exception in the console,
// but it's actually "handled" by the sessionAuthenticationFailed action handler.
});
},

View File

@ -14,6 +14,7 @@ export default Ember.Controller.extend(ValidationEngine, {
ghostPaths: Ember.inject.service('ghost-paths'),
config: Ember.inject.service(),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
sendImage: function () {
var self = this,
@ -66,10 +67,7 @@ export default Ember.Controller.extend(ValidationEngine, {
}]
}
}).then(function () {
self.get('session').authenticate('ghost-authenticator:oauth2-password-grant', {
identification: self.get('model.email'),
password: self.get('model.password')
}).then(function () {
self.get('session').authenticate('authenticator:oauth2', self.get('model.email'), self.get('model.password')).then(function () {
if (image) {
self.sendImage();
}

View File

@ -2,6 +2,8 @@ import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service(),
users: Ember.computed.alias('model'),
activeUsers: Ember.computed.filter('users', function (user) {

View File

@ -11,6 +11,7 @@ export default Ember.Controller.extend(ValidationEngine, {
ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
currentUser: Ember.computed.alias('session.user'),

View File

@ -0,0 +1,17 @@
import ENV from '../config/environment';
import ghostPaths from '../utils/ghost-paths';
import Configuration from 'ember-simple-auth/configuration';
import setupSession from 'ember-simple-auth/initializers/setup-session';
import setupSessionService from 'ember-simple-auth/initializers/setup-session-service';
export default {
name: 'ember-simple-auth',
initialize: function (registry) {
const config = ENV['ember-simple-auth'] || {};
config.baseURL = ghostPaths().adminRoot;
Configuration.load(config);
setupSession(registry);
setupSessionService(registry);
}
};

View File

@ -1,12 +0,0 @@
import GhostOauth2Authenticator from 'ghost/authenticators/oauth2';
export default {
name: 'ghost-authentictor',
initialize: function (registry, application) {
application.register(
'ghost-authenticator:oauth2-password-grant',
GhostOauth2Authenticator
);
}
};

View File

@ -1,16 +0,0 @@
import ENV from '../config/environment';
import ghostPaths from 'ghost/utils/ghost-paths';
var Ghost = ghostPaths();
export default {
name: 'simple-auth-env',
before: 'simple-auth-oauth2',
initialize: function () {
ENV['simple-auth-oauth2'].serverTokenEndpoint = Ghost.apiRoot + '/authentication/token';
ENV['simple-auth-oauth2'].serverTokenRevocationEndpoint = Ghost.apiRoot + '/authentication/revoke';
ENV['simple-auth'].localStorageKey = 'ghost' + (Ghost.subdir.indexOf('/') === 0 ? '-' + Ghost.subdir.substr(1) : '') + ':session';
}
};

View File

@ -1,18 +0,0 @@
import Ember from 'ember';
export function initialize(instance) {
var store = instance.container.lookup('service:store'),
Session = instance.container.lookup('simple-auth-session:main');
Session.reopen({
user: Ember.computed(function () {
return store.findRecord('user', 'me');
})
});
}
export default {
name: 'authentication',
after: 'ember-data',
initialize: initialize
};

View File

@ -0,0 +1,19 @@
import Ember from 'ember';
export default {
name: 'oauth-prefilter',
after: 'ember-simple-auth',
initialize: function (application) {
var session = application.container.lookup('service:session');
Ember.$.ajaxPrefilter(function (options) {
session.authorize('authorizer:oauth2', function (headerName, headerValue) {
var headerObject = {};
headerObject[headerName] = headerValue;
options.headers = Ember.merge(options.headers || {}, headerObject);
});
});
}
};

View File

@ -1,12 +1,11 @@
/* global key */
import Ember from 'ember';
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
import Configuration from 'simple-auth/configuration';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
import ShortcutsRoute from 'ghost/mixins/shortcuts-route';
import ctrlOrCmd from 'ghost/utils/ctrl-or-cmd';
var shortcuts = {};
const shortcuts = {};
shortcuts.esc = {action: 'closeMenus', scope: 'all'};
shortcuts.enter = {action: 'confirmModal', scope: 'modal'};
@ -20,7 +19,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
notifications: Ember.inject.service(),
afterModel: function (model, transition) {
if (this.get('session').isAuthenticated) {
if (this.get('session.isAuthenticated')) {
transition.send('loadServerNotifications');
}
},
@ -29,6 +28,20 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
return tokens.join(' - ') + ' - ' + this.get('config.blogTitle');
},
sessionAuthenticated: function () {
const appController = this.controllerFor('application'),
self = this;
if (appController && appController.get('skipAuthSuccessHandler')) {
return;
}
this._super(...arguments);
this.get('session.user').then(function (user) {
self.send('signedIn', user);
});
},
actions: {
openMobileMenu: function () {
this.controller.set('showMobileMenu', true);
@ -57,45 +70,11 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
},
invalidateSession: function () {
this.get('session').invalidate();
},
sessionAuthenticationFailed: function (error) {
if (error.errors) {
// These are server side errors, which can be marked as htmlSafe
error.errors.forEach(function (err) {
err.message = err.message.htmlSafe();
});
} else {
// Connection errors don't return proper status message, only req.body
this.get('notifications').showAlert('There was a problem on the server.', {type: 'error', key: 'session.authenticate.failed'});
}
},
sessionAuthenticationSucceeded: function () {
var appController = this.controllerFor('application'),
self = this;
if (appController && appController.get('skipAuthSuccessHandler')) {
return;
}
this.get('session.user').then(function (user) {
self.send('signedIn', user);
var attemptedTransition = self.get('session').get('attemptedTransition');
if (attemptedTransition) {
attemptedTransition.retry();
self.get('session').set('attemptedTransition', null);
} else {
self.transitionTo(Configuration.routeAfterAuthentication);
}
this.get('session').invalidate().catch(function (error) {
this.get('notifications').showAlert(error.message, {type: 'error', key: 'session.invalidate.failed'});
});
},
sessionInvalidationFailed: function (error) {
this.get('notifications').showAlert(error.message, {type: 'error', key: 'session.invalidate.failed'});
},
openModal: function (modalName, model, type) {
this.get('dropdown').closeDropdowns();
key.setScope('modal');
@ -120,7 +99,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
},
confirmModal: function () {
var modalName = this.get('modalName');
let modalName = this.get('modalName');
this.send('closeModal');
@ -139,9 +118,9 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
},
loadServerNotifications: function (isDelayed) {
var self = this;
let self = this;
if (this.session.isAuthenticated) {
if (this.get('session.isAuthenticated')) {
this.get('session.user').then(function (user) {
if (!user.get('isAuthor') && !user.get('isEditor')) {
self.store.findAll('notification', {reload: true}).then(function (serverNotifications) {

View File

@ -1,4 +1,4 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin);

View File

@ -1,4 +1,4 @@
import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
import MobileIndexRoute from 'ghost/routes/mobile-index-route';
import mobileQuery from 'ghost/utils/mobile';

View File

@ -1,14 +1,15 @@
import Ember from 'ember';
import Configuration from 'simple-auth/configuration';
import Configuration from 'ember-simple-auth/configuration';
import styleBody from 'ghost/mixins/style-body';
export default Ember.Route.extend(styleBody, {
classNames: ['ghost-reset'],
notifications: Ember.inject.service(),
session: Ember.inject.service(),
beforeModel: function () {
if (this.get('session').isAuthenticated) {
if (this.get('session.isAuthenticated')) {
this.get('notifications').showAlert('You can\'t reset your password while you\'re signed in.', {type: 'warn', delayed: true, key: 'password.reset.signed-in'});
this.transitionTo(Configuration.routeAfterAuthentication);
}

View File

@ -1,6 +1,6 @@
import Ember from 'ember';
import {request as ajax} from 'ic-ajax';
import Configuration from 'simple-auth/configuration';
import Configuration from 'ember-simple-auth/configuration';
import styleBody from 'ghost/mixins/style-body';
export default Ember.Route.extend(styleBody, {
@ -9,15 +9,15 @@ export default Ember.Route.extend(styleBody, {
classNames: ['ghost-setup'],
ghostPaths: Ember.inject.service('ghost-paths'),
session: Ember.inject.service(),
// use the beforeModel hook to check to see whether or not setup has been
// previously completed. If it has, stop the transition into the setup page.
beforeModel: function () {
var self = this;
// If user is logged in, setup has already been completed.
if (this.get('session').isAuthenticated) {
this.transitionTo(Configuration.routeAfterAuthentication);
if (this.get('session.isAuthenticated')) {
this.transitionTo(Configuration.routeIfAlreadyAuthenticated);
return;
}

View File

@ -1,6 +1,6 @@
import Ember from 'ember';
import Configuration from 'simple-auth/configuration';
import styleBody from 'ghost/mixins/style-body';
import Configuration from 'ember-simple-auth/configuration';
import DS from 'ember-data';
export default Ember.Route.extend(styleBody, {
@ -8,9 +8,11 @@ export default Ember.Route.extend(styleBody, {
classNames: ['ghost-login'],
session: Ember.inject.service(),
beforeModel: function () {
if (this.get('session').isAuthenticated) {
this.transitionTo(Configuration.routeAfterAuthentication);
if (this.get('session.isAuthenticated')) {
this.transitionTo(Configuration.routeIfAlreadyAuthenticated);
}
},

View File

@ -1,7 +1,7 @@
import Ember from 'ember';
import DS from 'ember-data';
import {request as ajax} from 'ic-ajax';
import Configuration from 'simple-auth/configuration';
import Configuration from 'ember-simple-auth/configuration';
import styleBody from 'ghost/mixins/style-body';
export default Ember.Route.extend(styleBody, {
@ -9,11 +9,12 @@ export default Ember.Route.extend(styleBody, {
ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
session: Ember.inject.service(),
beforeModel: function () {
if (this.get('session').isAuthenticated) {
if (this.get('session.isAuthenticated')) {
this.get('notifications').showAlert('You need to sign out to register as a new user.', {type: 'warn', delayed: true, key: 'signup.create.already-authenticated'});
this.transitionTo(Configuration.routeAfterAuthentication);
this.transitionTo(Configuration.routeIfAlreadyAuthenticated);
}
},

10
app/services/session.js Normal file
View File

@ -0,0 +1,10 @@
import Ember from 'ember';
import SessionService from 'ember-simple-auth/services/session';
export default SessionService.extend({
store: Ember.inject.service(),
user: Ember.computed(function () {
return this.get('store').findRecord('user', 'me');
})
});

View File

@ -0,0 +1,5 @@
import LocalStorageStore from 'ember-simple-auth/session-stores/local-storage';
export default LocalStorageStore.extend({
key: 'ghost:session'
});

View File

@ -11,7 +11,6 @@
"ember-mocha": "0.8.4",
"ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5",
"ember-resolver": "0.1.18",
"ember-simple-auth": "0.8.0",
"fastclick": "1.0.6",
"google-caja": "5669.0.0",
"jquery": "2.1.4",

View File

@ -19,19 +19,10 @@ module.exports = function (environment) {
// when it is created
},
'simple-auth': {
'ember-simple-auth': {
authenticationRoute: 'signin',
routeAfterAuthentication: 'posts',
authorizer: 'simple-auth-authorizer:oauth2-bearer',
localStorageKey: '<overriden by initializers/simple-auth-env>'
},
'simple-auth-oauth2': {
refreshAccessTokens: true,
serverTokenEndpoint: '<overriden by initializers/simple-auth-env>',
serverTokenRevocationEndpoint: '<overriden by initializers/simple-auth-env>'
routeIfAlreadyAuthenticated: 'posts'
},
resizeServiceDefaults: {
@ -60,10 +51,6 @@ module.exports = function (environment) {
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
ENV['simple-auth'] = {
store: 'simple-auth-session-store:ephemeral'
};
}
return ENV;

View File

@ -34,9 +34,6 @@
"ember-cli-pretender": "0.5.0",
"ember-cli-release": "0.2.3",
"ember-cli-selectize": "0.4.0",
"ember-cli-simple-auth": "0.8.0",
"ember-cli-simple-auth-oauth2": "0.8.0",
"ember-cli-simple-auth-testing": "0.8.0",
"ember-cli-sri": "^1.0.3",
"ember-cli-uglify": "^1.2.0",
"ember-data": "1.13.13",
@ -45,6 +42,7 @@
"ember-export-application-global": "^1.0.3",
"ember-myth": "0.1.1",
"ember-resize": "0.0.10",
"ember-simple-auth": "1.0.0",
"ember-sinon": "0.2.1",
"ember-watson": "^0.6.4",
"fs-extra": "0.16.3",

View File

@ -9,9 +9,7 @@ import { expect } from 'chai';
import Ember from 'ember';
import startApp from '../../helpers/start-app';
import Pretender from 'pretender';
import initializeTestHelpers from 'simple-auth-testing/test-helpers';
initializeTestHelpers();
import { invalidateSession, authenticateSession } from 'ghost/tests/helpers/ember-simple-auth';
const {run} = Ember,
// TODO: Pull this into a fixture or similar when required elsewhere
@ -68,7 +66,7 @@ const {run} = Ember,
}];
describe('Acceptance: Settings - Navigation', function () {
var application,
let application,
store,
server;
@ -76,8 +74,14 @@ describe('Acceptance: Settings - Navigation', function () {
application = startApp();
store = application.__container__.lookup('store:main');
server = new Pretender(function () {
// TODO: This needs to either be fleshed out to include all user data, or be killed with fire
// as it needs to be loaded with all authenticated page loads
this.get('/ghost/api/v0.1/users/me', function () {
return [200, {'Content-Type': 'application/json'}, JSON.stringify({users: []})];
});
this.get('/ghost/api/v0.1/settings/', function (_request) {
var response = {meta: {filters: 'blog,theme'}};
let response = {meta: {filters: 'blog,theme'}};
response.settings = [{
created_at: '2015-09-11T09:44:30.810Z',
created_by: 1,
@ -104,7 +108,7 @@ describe('Acceptance: Settings - Navigation', function () {
});
this.put('/ghost/api/v0.1/settings/', function (_request) {
var response = {meta: {}};
let response = {meta: {}};
response.settings = [{
created_at: '2015-09-11T09:44:30.810Z',
created_by: 1,
@ -131,7 +135,7 @@ describe('Acceptance: Settings - Navigation', function () {
});
it('redirects to signin when not authenticated', function () {
invalidateSession();
invalidateSession(application);
visit('/settings/navigation');
andThen(function () {
@ -145,7 +149,7 @@ describe('Acceptance: Settings - Navigation', function () {
store.push('user', {id: 'me', roles: [role]});
});
authenticateSession();
authenticateSession(application);
visit('/settings/navigation');
andThen(function () {
@ -160,7 +164,7 @@ describe('Acceptance: Settings - Navigation', function () {
store.push('user', {id: 'me', roles: [role]});
});
authenticateSession();
authenticateSession(application);
});
it('can visit /settings/navigation', function () {