mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-03 03:58:01 +00:00
Glimmerize Saml Auth (#24100)
* glimmerize saml * update roleName * remove constructor
This commit is contained in:
@@ -4,14 +4,14 @@
|
|||||||
~}}
|
~}}
|
||||||
|
|
||||||
{{#if this.canLoginSaml}}
|
{{#if this.canLoginSaml}}
|
||||||
<form id="auth-form" onsubmit={{action "startSAMLAuth" @onSubmit (hash role=this.roleName)}}>
|
<form id="auth-form" {{on "submit" (fn this.startSAMLAuth @onSubmit (hash role=@roleName))}}>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="role" class="is-label">Role</label>
|
<label for="role" class="is-label">Role</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input
|
<input
|
||||||
value={{@roleName}}
|
value={{@roleName}}
|
||||||
placeholder="Default"
|
placeholder="Default"
|
||||||
oninput={{action "setRole" value="target.value"}}
|
{{on "input" this.setRole}}
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
name="role"
|
name="role"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
@sizeSmall={{true}}
|
@sizeSmall={{true}}
|
||||||
@paddingTop={{true}}
|
@paddingTop={{true}}
|
||||||
@type="info"
|
@type="info"
|
||||||
@message="Leave blank to sign in with the default role if one is configured"
|
@message="Leave blank to sign in with the default role if one is configured."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div data-test-yield-content>
|
<div data-test-yield-content>
|
||||||
@@ -4,9 +4,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Component from './outer-html';
|
|
||||||
import { task, timeout, waitForEvent } from 'ember-concurrency';
|
import { task, timeout, waitForEvent } from 'ember-concurrency';
|
||||||
import { computed } from '@ember/object';
|
import Component from '@glimmer/component';
|
||||||
|
import { tracked } from '@glimmer/tracking';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
|
||||||
import errorMessage from 'vault/utils/error-message';
|
import errorMessage from 'vault/utils/error-message';
|
||||||
|
|
||||||
const WAIT_TIME = 500;
|
const WAIT_TIME = 500;
|
||||||
@@ -17,58 +19,47 @@ const ERROR_MISSING_PARAMS =
|
|||||||
'The callback from the provider did not supply all of the required parameters. Please click Sign In to try again. If the problem persists, you may want to contact your administrator.';
|
'The callback from the provider did not supply all of the required parameters. Please click Sign In to try again. If the problem persists, you may want to contact your administrator.';
|
||||||
export { ERROR_WINDOW_CLOSED, ERROR_MISSING_PARAMS };
|
export { ERROR_WINDOW_CLOSED, ERROR_MISSING_PARAMS };
|
||||||
|
|
||||||
export default Component.extend({
|
export default class AuthSaml extends Component {
|
||||||
store: service(),
|
@service store;
|
||||||
featureFlagService: service('featureFlag'),
|
@service featureFlag;
|
||||||
|
|
||||||
selectedAuthPath: null,
|
@tracked errorMessage;
|
||||||
selectedAuthType: null,
|
|
||||||
roleName: null,
|
|
||||||
errorMessage: null,
|
|
||||||
onRoleName() {},
|
|
||||||
onLoading() {},
|
|
||||||
onError() {},
|
|
||||||
onNamespace() {},
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
|
||||||
this._super();
|
|
||||||
this.set('errorMessage', null);
|
|
||||||
},
|
|
||||||
|
|
||||||
getWindow() {
|
getWindow() {
|
||||||
return this.window || window;
|
return this.window || window;
|
||||||
},
|
}
|
||||||
|
|
||||||
canLoginSaml: computed('getWindow', function () {
|
get canLoginSaml() {
|
||||||
return this.getWindow().isSecureContext;
|
return this.getWindow().isSecureContext;
|
||||||
}),
|
}
|
||||||
|
|
||||||
async fetchRole(roleName) {
|
async fetchRole(roleName) {
|
||||||
const path = this.selectedAuthPath || this.selectedAuthType;
|
const path = this.args.selectedAuthPath || this.args.selectedAuthType;
|
||||||
const id = JSON.stringify([path, roleName]);
|
const id = JSON.stringify([path, roleName]);
|
||||||
return this.store.findRecord('role-saml', id, {
|
return this.store.findRecord('role-saml', id, {
|
||||||
adapterOptions: { namespace: this.namespace },
|
adapterOptions: { namespace: this.args.namespace },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
cancelLogin(samlWindow, errorMessage) {
|
cancelLogin(samlWindow, errorMessage) {
|
||||||
this.closeWindow(samlWindow);
|
this.closeWindow(samlWindow);
|
||||||
this.handleSAMLError(errorMessage);
|
this.handleSAMLError(errorMessage);
|
||||||
this.exchangeSAMLTokenPollID.cancelAll();
|
this.exchangeSAMLTokenPollID.cancelAll();
|
||||||
},
|
}
|
||||||
|
|
||||||
closeWindow(samlWindow) {
|
closeWindow(samlWindow) {
|
||||||
this.watchPopup.cancelAll();
|
this.watchPopup.cancelAll();
|
||||||
this.watchCurrent.cancelAll();
|
this.watchCurrent.cancelAll();
|
||||||
samlWindow.close();
|
samlWindow.close();
|
||||||
},
|
}
|
||||||
|
|
||||||
handleSAMLError(err) {
|
handleSAMLError(err) {
|
||||||
this.onLoading(false);
|
this.args.onLoading(false);
|
||||||
this.onError(err);
|
this.args.onError(err);
|
||||||
},
|
}
|
||||||
|
|
||||||
watchPopup: task(function* (samlWindow) {
|
@task
|
||||||
|
*watchPopup(samlWindow) {
|
||||||
while (true) {
|
while (true) {
|
||||||
yield timeout(WAIT_TIME);
|
yield timeout(WAIT_TIME);
|
||||||
if (!samlWindow || samlWindow.closed) {
|
if (!samlWindow || samlWindow.closed) {
|
||||||
@@ -76,24 +67,26 @@ export default Component.extend({
|
|||||||
return this.handleSAMLError(ERROR_WINDOW_CLOSED);
|
return this.handleSAMLError(ERROR_WINDOW_CLOSED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
|
|
||||||
watchCurrent: task(function* (samlWindow) {
|
@task
|
||||||
|
*watchCurrent(samlWindow) {
|
||||||
// when user is about to change pages, close the popup window
|
// when user is about to change pages, close the popup window
|
||||||
yield waitForEvent(this.getWindow(), 'beforeunload');
|
yield waitForEvent(this.getWindow(), 'beforeunload');
|
||||||
samlWindow?.close();
|
samlWindow?.close();
|
||||||
}),
|
}
|
||||||
|
|
||||||
exchangeSAMLTokenPollID: task(function* (samlWindow, role) {
|
@task
|
||||||
this.onLoading(true);
|
*exchangeSAMLTokenPollID(samlWindow, role) {
|
||||||
|
this.args.onLoading(true);
|
||||||
|
|
||||||
// start watching the popup window and the current one
|
// start watching the popup window and the current one
|
||||||
this.watchPopup.perform(samlWindow);
|
this.watchPopup.perform(samlWindow);
|
||||||
this.watchCurrent.perform(samlWindow);
|
this.watchCurrent.perform(samlWindow);
|
||||||
|
|
||||||
const path = this.selectedAuthPath || this.selectedAuthType;
|
const path = this.args.selectedAuthPath || this.args.selectedAuthType;
|
||||||
const adapter = this.store.adapterFor('auth-method');
|
const adapter = this.store.adapterFor('auth-method');
|
||||||
this.onNamespace(this.namespace);
|
this.args.onNamespace(this.args.namespace);
|
||||||
|
|
||||||
// Wait up to 3 minutes for the token to become available
|
// Wait up to 3 minutes for the token to become available
|
||||||
let resp;
|
let resp;
|
||||||
@@ -105,7 +98,7 @@ export default Component.extend({
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// We've obtained the Vault token for the authentication flow, now log in.
|
// We've obtained the Vault token for the authentication flow, now log in.
|
||||||
yield this.onSubmit(null, null, resp.auth.client_token);
|
yield this.args.onSubmit(null, null, resp.auth.client_token);
|
||||||
this.closeWindow(samlWindow);
|
this.closeWindow(samlWindow);
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -117,46 +110,45 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.cancelLogin(samlWindow, ERROR_TIMEOUT);
|
this.cancelLogin(samlWindow, ERROR_TIMEOUT);
|
||||||
}),
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
setRole(roleName) {
|
setRole(event) {
|
||||||
this.onRoleName(roleName);
|
this.args.onRoleName(event.target.value);
|
||||||
},
|
}
|
||||||
/* Saml auth flow on login button click:
|
/* Saml auth flow on login button click:
|
||||||
* 1. find role-saml record which returns role info
|
* 1. find role-saml record which returns role info
|
||||||
* 2. open popup at url defined returned from role
|
* 2. open popup at url defined returned from role
|
||||||
* 3. watch popup window for close (and cancel polling if it closes)
|
* 3. watch popup window for close (and cancel polling if it closes)
|
||||||
* 4. poll vault for 200 token response
|
* 4. poll vault for 200 token response
|
||||||
* 5. close popup, stop polling, and trigger onSubmit with token data
|
* 5. close popup, stop polling, and trigger onSubmit with token data
|
||||||
*/
|
*/
|
||||||
async startSAMLAuth(callback, data, e) {
|
@action async startSAMLAuth(callback, data, e) {
|
||||||
this.onError(null);
|
this.args.onError(null);
|
||||||
this.onLoading(true);
|
this.args.onLoading(true);
|
||||||
if (e && e.preventDefault) {
|
if (e && e.preventDefault) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
const roleName = data.role;
|
const roleName = data.role;
|
||||||
let role;
|
let role;
|
||||||
try {
|
try {
|
||||||
role = await this.fetchRole(roleName);
|
role = await this.fetchRole(roleName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.handleSAMLError(error);
|
this.handleSAMLError(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const win = this.getWindow();
|
const win = this.getWindow();
|
||||||
const POPUP_WIDTH = 500;
|
const POPUP_WIDTH = 500;
|
||||||
const POPUP_HEIGHT = 600;
|
const POPUP_HEIGHT = 600;
|
||||||
const left = win.screen.width / 2 - POPUP_WIDTH / 2;
|
const left = win.screen.width / 2 - POPUP_WIDTH / 2;
|
||||||
const top = win.screen.height / 2 - POPUP_HEIGHT / 2;
|
const top = win.screen.height / 2 - POPUP_HEIGHT / 2;
|
||||||
const samlWindow = win.open(
|
const samlWindow = win.open(
|
||||||
role.ssoServiceURL,
|
role.ssoServiceURL,
|
||||||
'vaultSAMLWindow',
|
'vaultSAMLWindow',
|
||||||
`width=${POPUP_WIDTH},height=${POPUP_HEIGHT},resizable,scrollbars=yes,top=${top},left=${left}`
|
`width=${POPUP_WIDTH},height=${POPUP_HEIGHT},resizable,scrollbars=yes,top=${top},left=${left}`
|
||||||
);
|
);
|
||||||
|
|
||||||
this.exchangeSAMLTokenPollID.perform(samlWindow, role);
|
this.exchangeSAMLTokenPollID.perform(samlWindow, role);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
Reference in New Issue
Block a user