From e7875849ecee2faeb27dacb623801009c5bb327a Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Tue, 18 Aug 2020 16:20:32 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20move=20headers=20to=20pro?= =?UTF-8?q?totype=20and=20send=20with=20scopes=20requests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/authenticators/password.js | 45 ++++++++++++++++- ui/core/app/session-stores/application.js | 34 +------------ .../unit/authenticators/password-test.js | 50 +++++++++++++++++++ .../unit/session-stores/application-test.js | 41 --------------- 4 files changed, 95 insertions(+), 75 deletions(-) create mode 100644 ui/core/tests/unit/authenticators/password-test.js delete mode 100644 ui/core/tests/unit/session-stores/application-test.js diff --git a/ui/core/app/authenticators/password.js b/ui/core/app/authenticators/password.js index a70c89ac7..88bf63c0a 100644 --- a/ui/core/app/authenticators/password.js +++ b/ui/core/app/authenticators/password.js @@ -37,9 +37,52 @@ export default class PasswordAuthenticator extends BasePasswordAuthenticator { * @param {string} scopeID * @return {string} */ - buildDeauthEndpointURL({ org_id: scopeID }) { + buildDeauthEndpointURL({ scope: { id: scopeID } }) { const adapter = this.store.adapterFor('application'); const options = { adapterOptions: { method: 'deauthenticate' } }; return adapter.buildURL('scope', scopeID, options, 'findRecord'); } + + /** + * Intercepts the authenticate response, if any, and assigns the returned + * token to all future requests via `addTokenToAuthorization`. + * Returns the response data as normal. + * @override + */ + authenticate() { + return super.authenticate(...arguments) + .then(data => { + const token = data?.token; + if (token) this.addTokenToAuthorization(token); + return data; + }); + } + + /** + * When restoring the session (say, on load), assigns the session token + * to all future requests via `addTokenToAuthorization`. + * @override + * @param {object} data + * @return {object} + */ + restore(data) { + const token = data?.token; + if (token) this.addTokenToAuthorization(token); + return super.restore(data); + } + + /** + * Assigns a token string all future requests via the `Authorization` header + * on the application adapter prototype. Only application and adapters that + * extend the application adapter receive this header (which is most). + * @param {string} token + */ + addTokenToAuthorization(token) { + const adapterPrototype = + this.store.adapterFor('application').constructor.prototype; + const headers = adapterPrototype?.headers; + if (!headers) adapterPrototype.headers = {}; + adapterPrototype.headers.Authorization = null; + if (token) adapterPrototype.headers.Authorization = `Bearer ${token}`; + } } diff --git a/ui/core/app/session-stores/application.js b/ui/core/app/session-stores/application.js index 401a98b44..681b7b12e 100644 --- a/ui/core/app/session-stores/application.js +++ b/ui/core/app/session-stores/application.js @@ -1,38 +1,6 @@ import LocalStorageSessionStore from 'auth/session-stores/local-storage'; -import { inject as service } from '@ember/service'; -import { get } from '@ember/object'; -//import config from '../config/environment'; -export default class ApplicationSessionStore extends LocalStorageSessionStore { - @service store; - - /** - * If the auth sessionData includes a token, apply it as a bearer token in the - * application adapter's Authorization header. Otherwise clear the header. - * @param {object} sessionData - * @return {object} - */ - persist(sessionData) { - this.addTokenToAuthorization(sessionData); - //this.addScopeToSession(sessionData); - return super.persist(...arguments); - } - - /** - * If the session has a full token, it is added as a bearer token to the - * `Authorization` header for all API requests. - * @param {object} sessionData - */ - addTokenToAuthorization(sessionData) { - const token = get(sessionData, 'authenticated.token'); - const adapter = this.store.adapterFor('application'); - const headers = get(adapter, 'headers'); - if (!headers) adapter.headers = {}; - adapter.headers.Authorization = null; - if (token) adapter.headers.Authorization = `Bearer ${token}`; - } - -} +export default class ApplicationSessionStore extends LocalStorageSessionStore {} // import CookieSessionStore from 'auth/session-stores/cookie'; // import config from '../config/environment'; diff --git a/ui/core/tests/unit/authenticators/password-test.js b/ui/core/tests/unit/authenticators/password-test.js new file mode 100644 index 000000000..21786ec86 --- /dev/null +++ b/ui/core/tests/unit/authenticators/password-test.js @@ -0,0 +1,50 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; + +module('Unit | Authenticator | password', function (hooks) { + setupTest(hooks); + setupMirage(hooks); + + let store; + let applicationAdapter; + let session; + let authenticator; + + hooks.beforeEach(function () { + store = this.owner.lookup('service:store'); + applicationAdapter = store.adapterFor('application'); + session = this.owner.lookup('service:session'); + authenticator = this.owner.lookup('authenticator:password'); + session.invalidate(); + }); + + hooks.afterEach(function () { + session.invalidate(); + }); + + test('it does not add an authorization header to application adapter on restore if no token is present', async function (assert) { + assert.expect(1); + authenticator.restore({ token: null }); + assert.notOk(applicationAdapter?.headers?.Authorization); + }); + + test('it adds an authorization header to application adapter on restore', async function (assert) { + assert.expect(1); + authenticator.restore({ token: 'token1234' }); + assert.equal(applicationAdapter.headers.Authorization, 'Bearer token1234'); + }); + + test('it adds an authorization header to application adapter on authenticate', async function (assert) { + assert.expect(1); + const creds = { identification: 'foo', password: 'bar' }; + const scope = { id: 'global' }; + const authMethod = { id: 'paum_1234' }; + await authenticator.authenticate( + creds, + null, + { scope, authMethod } + ); + assert.equal(applicationAdapter.headers.Authorization, 'Bearer thetokenstring'); + }); +}); diff --git a/ui/core/tests/unit/session-stores/application-test.js b/ui/core/tests/unit/session-stores/application-test.js deleted file mode 100644 index 6a3e908bc..000000000 --- a/ui/core/tests/unit/session-stores/application-test.js +++ /dev/null @@ -1,41 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -module('Unit | Session Store | application', function (hooks) { - setupTest(hooks); - - let store; - let applicationAdapter; - let sessionStore; - - hooks.beforeEach(function () { - store = this.owner.lookup('service:store'); - applicationAdapter = store.adapterFor('application'); - sessionStore = this.owner.lookup('session-store:application'); - sessionStore.clear(); - }); - - hooks.afterEach(function () { - sessionStore.clear(); - }); - - test('it does not add an authorization header to application adapter on persist if no token is present', async function (assert) { - assert.expect(1); - sessionStore.persist({ authenticated: { token: null } }); - assert.notOk(applicationAdapter.headers.Authorization); - }); - - test('it adds an authorization header to application adapter on persist', async function (assert) { - assert.expect(1); - sessionStore.persist({ authenticated: { token: 'token1234' } }); - assert.equal(applicationAdapter.headers.Authorization, 'Bearer token1234'); - }); - - test('it adds an authorization header to application adapter which already has headers on persist', async function (assert) { - assert.expect(2); - applicationAdapter.headers = { foo: 'bar' }; - sessionStore.persist({ authenticated: { token: 'token1234' } }); - assert.equal(applicationAdapter.headers.foo, 'bar'); - assert.equal(applicationAdapter.headers.Authorization, 'Bearer token1234'); - }); -});