Skip to content

Commit

Permalink
UI: Fix OIDC login in fullscreen (#19071)
Browse files Browse the repository at this point in the history
  • Loading branch information
hashishaw committed Feb 8, 2023
1 parent 8ac283e commit 2e020d0
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 23 deletions.
3 changes: 3 additions & 0 deletions changelog/19071.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
ui: Fix bug where logging in via OIDC fails if browser is in fullscreen mode
```
34 changes: 17 additions & 17 deletions ui/app/components/auth-jwt.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Ember from 'ember';
import { inject as service } from '@ember/service';
import Component from './outer-html';
import { later } from '@ember/runloop';
import { task, timeout, waitForEvent } from 'ember-concurrency';
import { computed } from '@ember/object';
import { waitFor } from '@ember/test-waiters';
Expand Down Expand Up @@ -75,6 +74,17 @@ export default Component.extend({
})
).restartable(),

cancelLogin(oidcWindow, errorMessage) {
this.closeWindow(oidcWindow);
this.handleOIDCError(errorMessage);
},

closeWindow(oidcWindow) {
this.watchPopup.cancelAll();
this.watchCurrent.cancelAll();
oidcWindow.close();
},

handleOIDCError(err) {
this.onLoading(false);
this.prepareForOIDC.cancelAll();
Expand All @@ -93,10 +103,7 @@ export default Component.extend({
// ensure that postMessage event is from expected source
while (true) {
const event = yield waitForEvent(thisWindow, 'message');
if (event.origin !== thisWindow.origin || !event.isTrusted) {
return this.handleOIDCError();
}
if (event.data.source === 'oidc-callback') {
if (event.data.source === 'oidc-callback' && event.isTrusted && event.origin === thisWindow.origin) {
return this.exchangeOIDC.perform(event.data, oidcWindow);
}
// continue to wait for the correct message
Expand All @@ -118,12 +125,6 @@ export default Component.extend({
oidcWindow.close();
}),

closeWindow(oidcWindow) {
this.watchPopup.cancelAll();
this.watchCurrent.cancelAll();
oidcWindow.close();
},

exchangeOIDC: task(function* (oidcState, oidcWindow) {
if (oidcState === null || oidcState === undefined) {
return;
Expand All @@ -144,12 +145,8 @@ export default Component.extend({
}
}

// defer closing of the window, but continue executing the task
later(() => {
this.closeWindow(oidcWindow);
}, WAIT_TIME);
if (!path || !state || !code) {
return this.handleOIDCError(ERROR_MISSING_PARAMS);
return this.cancelLogin(oidcWindow, ERROR_MISSING_PARAMS);
}
let adapter = this.store.adapterFor('auth-method');
this.onNamespace(namespace);
Expand All @@ -158,8 +155,11 @@ export default Component.extend({
// and submit auth form
try {
resp = yield adapter.exchangeOIDC(path, state, code);
this.closeWindow(oidcWindow);
} catch (e) {
return this.handleOIDCError(e);
// If there was an error on Vault's end, close the popup
// and show the error on the login screen
return this.cancelLogin(oidcWindow, e);
}
yield this.onSubmit(null, null, resp.auth.client_token);
}),
Expand Down
17 changes: 11 additions & 6 deletions ui/tests/unit/components/auth-jwt-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { run } from '@ember/runloop';

const mockWindow = EmberObject.extend(Evented, {
origin: 'http://localhost:4200',
close: () => {},
});

module('Unit | Component | auth-jwt', function (hooks) {
Expand All @@ -18,21 +19,25 @@ module('Unit | Component | auth-jwt', function (hooks) {
this.errorSpy = sinon.spy(this.component, 'handleOIDCError');
});

test('it should handle error for cross origin messages while waiting for oidc callback', async function (assert) {
assert.expect(1);
test('it should ignore messages from cross origin windows while waiting for oidc callback', async function (assert) {
assert.expect(2);
this.component.prepareForOIDC.perform(mockWindow.create());
this.component.window.trigger('message', { origin: 'http://anotherdomain.com', isTrusted: true });
assert.ok(this.errorSpy.calledOnce, 'Error handled from cross origin window message event');

assert.ok(this.errorSpy.notCalled, 'Error handler not triggered while waiting for oidc callback message');
assert.strictEqual(this.component.exchangeOIDC.performCount, 0, 'exchangeOIDC method not fired');
run.cancelTimers();
});

test('it should handle error for untrusted messages while waiting for oidc callback', async function (assert) {
assert.expect(1);
test('it should ignore untrusted messages while waiting for oidc callback', async function (assert) {
assert.expect(2);
this.component.prepareForOIDC.perform(mockWindow.create());
this.component.window.trigger('message', { origin: 'http://localhost:4200', isTrusted: false });
assert.ok(this.errorSpy.calledOnce, 'Error handled from untrusted window message event');
assert.ok(this.errorSpy.notCalled, 'Error handler not triggered while waiting for oidc callback message');
assert.strictEqual(this.component.exchangeOIDC.performCount, 0, 'exchangeOIDC method not fired');
run.cancelTimers();
});

// test case for https://github.com/hashicorp/vault/issues/12436
test('it should ignore messages sent from outside the app while waiting for oidc callback', async function (assert) {
assert.expect(2);
Expand Down

0 comments on commit 2e020d0

Please sign in to comment.