UI: Fix OIDC login in fullscreen (#19071)

This commit is contained in:
Chelsea Shaw 2023-02-08 14:32:57 -06:00 committed by GitHub
parent e04a3d21a1
commit 1ec10bccd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 23 deletions

3
changelog/19071.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
ui: Fix bug where logging in via OIDC fails if browser is in fullscreen mode
```

View File

@ -2,7 +2,6 @@ import Ember from 'ember';
import { inject as service } from '@ember/service';
// ARG NOTE: Once you remove outer-html after glimmerizing you can remove the outer-html component
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';
@ -76,6 +75,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();
@ -94,10 +104,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
@ -119,12 +126,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;
@ -145,12 +146,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);
}
const adapter = this.store.adapterFor('auth-method');
this.onNamespace(namespace);
@ -159,8 +156,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);
}),

View File

@ -7,6 +7,7 @@ import { _cancelTimers as cancelTimers } from '@ember/runloop';
const mockWindow = EmberObject.extend(Evented, {
origin: 'http://localhost:4200',
close: () => {},
});
module('Unit | Component | auth-jwt', function (hooks) {
@ -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');
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');
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);